Refactored clips module into layered architecture.
CI / Formatting (push) Successful in 5s
CI / Linting (push) Successful in 6s
CI / Tests (Python 3.12) (push) Successful in 15s
CI / Tests (Python 3.13) (push) Successful in 18s
CI / Tests (Python 3.14) (push) Successful in 12s
CI / Type Checking (push) Successful in 10s
CI / Spelling (push) Successful in 5s

This commit is contained in:
2026-04-13 13:11:20 -04:00
parent 5e712d2059
commit d3e3460ce8
10 changed files with 1142 additions and 909 deletions
+117
View File
@@ -0,0 +1,117 @@
# Copyright 2026 Logan Fick
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Persistence layer for the clips module."""
from __future__ import annotations
from typing import TYPE_CHECKING
from owlbot.api import StorageError
from .types import Clip, ClipNotFoundError
if TYPE_CHECKING:
from owlbot.api import ModuleStorage
class ClipRepository:
"""All database operations for clip entities.
:param storage: Module-scoped SQLite storage instance.
"""
def __init__(self, storage: ModuleStorage) -> None:
"""Initialize with a module-scoped storage instance.
:param storage: The SQLite storage for this module.
"""
self._storage = storage
async def setup(self) -> None:
"""Create the clips table if it does not exist."""
await self._storage.execute(
"""
CREATE TABLE IF NOT EXISTS clips (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
creator TEXT NOT NULL,
created_at TEXT NOT NULL,
duration REAL
)
"""
)
async def create(
self,
title: str | None,
creator: str,
created_at: str,
duration: float,
) -> Clip:
"""Insert a new clip and return its snapshot.
:param title: Optional clip title.
:param creator: Display name of the clip creator.
:param created_at: ISO 8601 timestamp.
:param duration: Clip duration in seconds.
:return: The created Clip.
"""
row = await self._storage.fetch_one(
"INSERT INTO clips (title, creator, created_at, duration) "
"VALUES (?, ?, ?, ?) RETURNING *",
(title, creator, created_at, duration),
)
if row is None:
msg = "INSERT ... RETURNING * returned no row."
raise StorageError(msg)
return Clip.from_row(row)
async def get(self, clip_id: int) -> Clip:
"""Fetch a clip by ID.
:param clip_id: The clip's primary key.
:return: The Clip snapshot.
:raises ClipNotFoundError: If no clip with that ID exists.
"""
row = await self._storage.fetch_one(
"SELECT * FROM clips WHERE id = ?", (clip_id,)
)
if row is None:
raise ClipNotFoundError(clip_id)
return Clip.from_row(row)
async def delete(self, clip_id: int) -> Clip:
"""Delete a clip by ID and return its snapshot.
:param clip_id: The clip's primary key.
:return: The deleted Clip snapshot.
:raises ClipNotFoundError: If no clip with that ID exists.
"""
row = await self._storage.fetch_one(
"DELETE FROM clips WHERE id = ? RETURNING *", (clip_id,)
)
if row is None:
raise ClipNotFoundError(clip_id)
return Clip.from_row(row)
async def list_all(self) -> list[Clip]:
"""Return all clips ordered by creation date descending.
:return: List of Clip snapshots.
"""
rows = await self._storage.fetch_all(
"SELECT * FROM clips ORDER BY created_at DESC"
)
return [Clip.from_row(row) for row in rows]