diff --git a/.gitignore b/.gitignore index 3d83af0..0530c87 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ # Ignore noise: .DS_Store +*.pyc diff --git a/src/music_catalogue/__init__.py b/src/music_catalogue/__init__.py index 7cd229a..0eb90b2 100644 --- a/src/music_catalogue/__init__.py +++ b/src/music_catalogue/__init__.py @@ -11,65 +11,68 @@ from ._generated._core import ( NoRowError as NoRowError, ) +from ._generated._core import ( + Statement as Statement, +) from ._generated._register import ( register_types as register_types, ) from ._generated.statements.insert_album import ( - InsertAlbumRow as InsertAlbumRow, + InsertAlbum as InsertAlbum, ) from ._generated.statements.insert_album import ( - insert_album as insert_album, + InsertAlbumRow as InsertAlbumRow, ) from ._generated.statements.insert_multiple_albums import ( - InsertMultipleAlbumsRow as InsertMultipleAlbumsRow, + InsertMultipleAlbums as InsertMultipleAlbums, ) from ._generated.statements.insert_multiple_albums import ( - insert_multiple_albums as insert_multiple_albums, + InsertMultipleAlbumsRow as InsertMultipleAlbumsRow, ) from ._generated.statements.select_album_by_format import ( - SelectAlbumByFormatRow as SelectAlbumByFormatRow, + SelectAlbumByFormat as SelectAlbumByFormat, ) from ._generated.statements.select_album_by_format import ( - select_album_by_format as select_album_by_format, + SelectAlbumByFormatRow as SelectAlbumByFormatRow, ) from ._generated.statements.select_album_by_id import ( - SelectAlbumByIdRow as SelectAlbumByIdRow, + SelectAlbumById as SelectAlbumById, ) from ._generated.statements.select_album_by_id import ( - select_album_by_id as select_album_by_id, + SelectAlbumByIdRow as SelectAlbumByIdRow, ) from ._generated.statements.select_album_by_name import ( - SelectAlbumByNameRow as SelectAlbumByNameRow, + SelectAlbumByName as SelectAlbumByName, ) from ._generated.statements.select_album_by_name import ( - select_album_by_name as select_album_by_name, + SelectAlbumByNameRow as SelectAlbumByNameRow, ) from ._generated.statements.select_album_with_filters import ( - SelectAlbumWithFiltersRow as SelectAlbumWithFiltersRow, + SelectAlbumWithFilters as SelectAlbumWithFilters, ) from ._generated.statements.select_album_with_filters import ( - select_album_with_filters as select_album_with_filters, + SelectAlbumWithFiltersRow as SelectAlbumWithFiltersRow, ) from ._generated.statements.select_album_with_tracks import ( - SelectAlbumWithTracksRow as SelectAlbumWithTracksRow, + SelectAlbumWithTracks as SelectAlbumWithTracks, ) from ._generated.statements.select_album_with_tracks import ( - select_album_with_tracks as select_album_with_tracks, + SelectAlbumWithTracksRow as SelectAlbumWithTracksRow, ) from ._generated.statements.select_genre_by_artist import ( - SelectGenreByArtistRow as SelectGenreByArtistRow, + SelectGenreByArtist as SelectGenreByArtist, ) from ._generated.statements.select_genre_by_artist import ( - select_genre_by_artist as select_genre_by_artist, + SelectGenreByArtistRow as SelectGenreByArtistRow, ) from ._generated.statements.update_album_recording_returning import ( - UpdateAlbumRecordingReturningRow as UpdateAlbumRecordingReturningRow, + UpdateAlbumRecordingReturning as UpdateAlbumRecordingReturning, ) from ._generated.statements.update_album_recording_returning import ( - update_album_recording_returning as update_album_recording_returning, + UpdateAlbumRecordingReturningRow as UpdateAlbumRecordingReturningRow, ) from ._generated.statements.update_album_released import ( - update_album_released as update_album_released, + UpdateAlbumReleased as UpdateAlbumReleased, ) from ._generated.types.album_format import ( AlbumFormat as AlbumFormat, @@ -87,6 +90,7 @@ __all__ = [ "JsonValue", "NoRowError", + "Statement", ] __all__ += [ "AlbumFormat", @@ -106,16 +110,16 @@ "UpdateAlbumRecordingReturningRow", ] __all__ += [ - "insert_album", - "insert_multiple_albums", - "select_album_by_format", - "select_album_by_id", - "select_album_by_name", - "select_album_with_filters", - "select_album_with_tracks", - "select_genre_by_artist", - "update_album_recording_returning", - "update_album_released", + "InsertAlbum", + "InsertMultipleAlbums", + "SelectAlbumByFormat", + "SelectAlbumById", + "SelectAlbumByName", + "SelectAlbumWithFilters", + "SelectAlbumWithTracks", + "SelectGenreByArtist", + "UpdateAlbumRecordingReturning", + "UpdateAlbumReleased", ] __all__ += [ "register_types", diff --git a/src/music_catalogue/_generated/_core.py b/src/music_catalogue/_generated/_core.py index a19b9a0..27d3728 100644 --- a/src/music_catalogue/_generated/_core.py +++ b/src/music_catalogue/_generated/_core.py @@ -6,6 +6,10 @@ from __future__ import annotations +from typing import ClassVar, Protocol + +from psycopg import AsyncConnection, Connection + type JsonValue = None | bool | int | float | str | list["JsonValue"] | dict[str, "JsonValue"] @@ -15,3 +19,13 @@ class NoRowError(RuntimeError): def __init__(self, sql: str) -> None: self.sql = sql super().__init__(f"single-row query returned no rows: {sql}") + + +class Statement[R](Protocol): + # SQL is exposed on the class itself so generic concerns (logging, metrics, tracing) + # can read it off any statement without executing it. + SQL: ClassVar[str] + + async def execute(self, conn: AsyncConnection[object]) -> R: ... + + def execute_sync(self, conn: Connection[object]) -> R: ... diff --git a/src/music_catalogue/_generated/statements/insert_album.py b/src/music_catalogue/_generated/statements/insert_album.py index ff56786..ed64c09 100644 --- a/src/music_catalogue/_generated/statements/insert_album.py +++ b/src/music_catalogue/_generated/statements/insert_album.py @@ -6,55 +6,49 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_single as _fetch_single from ..sync._runtime import fetch_single as _fetch_single_sync -SQL = """\ -insert into album (name, released, format, recording) -values (%(name)s, %(released)s, %(format)s, %(recording)s) -returning id -""" - @dataclass(frozen=True, slots=True) class InsertAlbumRow: id: int -async def insert_album( - conn: AsyncConnection[object], - *, - name: str, - released: date, - format: _db_types.AlbumFormat, - recording: _db_types.RecordingInfo, -) -> InsertAlbumRow: - params: dict[str, object] = { - "name": name, - "released": released, - "format": format, - "recording": recording, - } - return await _fetch_single(conn, SQL, params, _args_row(InsertAlbumRow)) - - -def insert_album_sync( - conn: Connection[object], - *, - name: str, - released: date, - format: _db_types.AlbumFormat, - recording: _db_types.RecordingInfo, -) -> InsertAlbumRow: - params: dict[str, object] = { - "name": name, - "released": released, - "format": format, - "recording": recording, - } - return _fetch_single_sync(conn, SQL, params, _args_row(InsertAlbumRow)) +@dataclass(frozen=True, slots=True) +class InsertAlbum(Statement[InsertAlbumRow]): + name: str + released: date + format: _db_types.AlbumFormat + recording: _db_types.RecordingInfo + + SQL: ClassVar[str] = """\ +insert into album (name, released, format, recording) +values (%(name)s, %(released)s, %(format)s, %(recording)s) +returning id +""" + + async def execute(self, conn: AsyncConnection[object]) -> InsertAlbumRow: + params: dict[str, object] = { + "name": self.name, + "released": self.released, + "format": self.format, + "recording": self.recording, + } + return await _fetch_single(conn, self.SQL, params, _args_row(InsertAlbumRow)) + + def execute_sync(self, conn: Connection[object]) -> InsertAlbumRow: + params: dict[str, object] = { + "name": self.name, + "released": self.released, + "format": self.format, + "recording": self.recording, + } + return _fetch_single_sync(conn, self.SQL, params, _args_row(InsertAlbumRow)) diff --git a/src/music_catalogue/_generated/statements/insert_multiple_albums.py b/src/music_catalogue/_generated/statements/insert_multiple_albums.py index 37bc5f3..9b041fc 100644 --- a/src/music_catalogue/_generated/statements/insert_multiple_albums.py +++ b/src/music_catalogue/_generated/statements/insert_multiple_albums.py @@ -6,15 +6,29 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ + +@dataclass(frozen=True, slots=True) +class InsertMultipleAlbumsRow: + id: int + + +@dataclass(frozen=True, slots=True) +class InsertMultipleAlbums(Statement[list[InsertMultipleAlbumsRow]]): + name: list[str] + released: list[date] + format: list[_db_types.AlbumFormat] + + SQL: ClassVar[str] = """\ -- This is an example of a bulk-insert (batch-insert) technique. -- We pass in all fields as arrays of the same size, and we unnest it to insert multiple rows at once. insert into album (name, released, format) @@ -27,37 +41,18 @@ returning id """ - -@dataclass(frozen=True, slots=True) -class InsertMultipleAlbumsRow: - id: int - - -async def insert_multiple_albums( - conn: AsyncConnection[object], - *, - name: list[str], - released: list[date], - format: list[_db_types.AlbumFormat], -) -> list[InsertMultipleAlbumsRow]: - params: dict[str, object] = { - "name": name, - "released": released, - "format": format, - } - return await _fetch_many(conn, SQL, params, _args_row(InsertMultipleAlbumsRow)) - - -def insert_multiple_albums_sync( - conn: Connection[object], - *, - name: list[str], - released: list[date], - format: list[_db_types.AlbumFormat], -) -> list[InsertMultipleAlbumsRow]: - params: dict[str, object] = { - "name": name, - "released": released, - "format": format, - } - return _fetch_many_sync(conn, SQL, params, _args_row(InsertMultipleAlbumsRow)) + async def execute(self, conn: AsyncConnection[object]) -> list[InsertMultipleAlbumsRow]: + params: dict[str, object] = { + "name": self.name, + "released": self.released, + "format": self.format, + } + return await _fetch_many(conn, self.SQL, params, _args_row(InsertMultipleAlbumsRow)) + + def execute_sync(self, conn: Connection[object]) -> list[InsertMultipleAlbumsRow]: + params: dict[str, object] = { + "name": self.name, + "released": self.released, + "format": self.format, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(InsertMultipleAlbumsRow)) diff --git a/src/music_catalogue/_generated/statements/select_album_by_format.py b/src/music_catalogue/_generated/statements/select_album_by_format.py index d4cb817..4b0ab75 100644 --- a/src/music_catalogue/_generated/statements/select_album_by_format.py +++ b/src/music_catalogue/_generated/statements/select_album_by_format.py @@ -6,25 +6,16 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ -select - id, - name, - released, - format, - recording -from album -where format = %(format)s -""" - @dataclass(frozen=True, slots=True) class SelectAlbumByFormatRow: @@ -35,23 +26,29 @@ class SelectAlbumByFormatRow: recording: _db_types.RecordingInfo | None -async def select_album_by_format( - conn: AsyncConnection[object], - *, - format: _db_types.AlbumFormat, -) -> list[SelectAlbumByFormatRow]: - params: dict[str, object] = { - "format": format, - } - return await _fetch_many(conn, SQL, params, _args_row(SelectAlbumByFormatRow)) - - -def select_album_by_format_sync( - conn: Connection[object], - *, - format: _db_types.AlbumFormat, -) -> list[SelectAlbumByFormatRow]: - params: dict[str, object] = { - "format": format, - } - return _fetch_many_sync(conn, SQL, params, _args_row(SelectAlbumByFormatRow)) +@dataclass(frozen=True, slots=True) +class SelectAlbumByFormat(Statement[list[SelectAlbumByFormatRow]]): + format: _db_types.AlbumFormat + + SQL: ClassVar[str] = """\ +select + id, + name, + released, + format, + recording +from album +where format = %(format)s +""" + + async def execute(self, conn: AsyncConnection[object]) -> list[SelectAlbumByFormatRow]: + params: dict[str, object] = { + "format": self.format, + } + return await _fetch_many(conn, self.SQL, params, _args_row(SelectAlbumByFormatRow)) + + def execute_sync(self, conn: Connection[object]) -> list[SelectAlbumByFormatRow]: + params: dict[str, object] = { + "format": self.format, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(SelectAlbumByFormatRow)) diff --git a/src/music_catalogue/_generated/statements/select_album_by_id.py b/src/music_catalogue/_generated/statements/select_album_by_id.py index ffd1bf8..5df1d13 100644 --- a/src/music_catalogue/_generated/statements/select_album_by_id.py +++ b/src/music_catalogue/_generated/statements/select_album_by_id.py @@ -6,22 +6,16 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_optional as _fetch_optional from ..sync._runtime import fetch_optional as _fetch_optional_sync -SQL = """\ --- Example of a query selecting 0 or 1 row. -select * -from album -where id = %(id)s -limit 1 -""" - @dataclass(frozen=True, slots=True) class SelectAlbumByIdRow: @@ -34,23 +28,26 @@ class SelectAlbumByIdRow: disc: _db_types.DiscInfo | None -async def select_album_by_id( - conn: AsyncConnection[object], - *, - id: int | None, -) -> SelectAlbumByIdRow | None: - params: dict[str, object] = { - "id": id, - } - return await _fetch_optional(conn, SQL, params, _args_row(SelectAlbumByIdRow)) - - -def select_album_by_id_sync( - conn: Connection[object], - *, - id: int | None, -) -> SelectAlbumByIdRow | None: - params: dict[str, object] = { - "id": id, - } - return _fetch_optional_sync(conn, SQL, params, _args_row(SelectAlbumByIdRow)) +@dataclass(frozen=True, slots=True) +class SelectAlbumById(Statement[SelectAlbumByIdRow | None]): + id: int | None + + SQL: ClassVar[str] = """\ +-- Example of a query selecting 0 or 1 row. +select * +from album +where id = %(id)s +limit 1 +""" + + async def execute(self, conn: AsyncConnection[object]) -> SelectAlbumByIdRow | None: + params: dict[str, object] = { + "id": self.id, + } + return await _fetch_optional(conn, self.SQL, params, _args_row(SelectAlbumByIdRow)) + + def execute_sync(self, conn: Connection[object]) -> SelectAlbumByIdRow | None: + params: dict[str, object] = { + "id": self.id, + } + return _fetch_optional_sync(conn, self.SQL, params, _args_row(SelectAlbumByIdRow)) diff --git a/src/music_catalogue/_generated/statements/select_album_by_name.py b/src/music_catalogue/_generated/statements/select_album_by_name.py index a01a4ca..fca9b3d 100644 --- a/src/music_catalogue/_generated/statements/select_album_by_name.py +++ b/src/music_catalogue/_generated/statements/select_album_by_name.py @@ -6,25 +6,16 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ -select - id, - name, - released, - format, - recording -from album -where name = %(name)s -""" - @dataclass(frozen=True, slots=True) class SelectAlbumByNameRow: @@ -35,23 +26,29 @@ class SelectAlbumByNameRow: recording: _db_types.RecordingInfo | None -async def select_album_by_name( - conn: AsyncConnection[object], - *, - name: str, -) -> list[SelectAlbumByNameRow]: - params: dict[str, object] = { - "name": name, - } - return await _fetch_many(conn, SQL, params, _args_row(SelectAlbumByNameRow)) - - -def select_album_by_name_sync( - conn: Connection[object], - *, - name: str, -) -> list[SelectAlbumByNameRow]: - params: dict[str, object] = { - "name": name, - } - return _fetch_many_sync(conn, SQL, params, _args_row(SelectAlbumByNameRow)) +@dataclass(frozen=True, slots=True) +class SelectAlbumByName(Statement[list[SelectAlbumByNameRow]]): + name: str + + SQL: ClassVar[str] = """\ +select + id, + name, + released, + format, + recording +from album +where name = %(name)s +""" + + async def execute(self, conn: AsyncConnection[object]) -> list[SelectAlbumByNameRow]: + params: dict[str, object] = { + "name": self.name, + } + return await _fetch_many(conn, self.SQL, params, _args_row(SelectAlbumByNameRow)) + + def execute_sync(self, conn: Connection[object]) -> list[SelectAlbumByNameRow]: + params: dict[str, object] = { + "name": self.name, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(SelectAlbumByNameRow)) diff --git a/src/music_catalogue/_generated/statements/select_album_with_filters.py b/src/music_catalogue/_generated/statements/select_album_with_filters.py index 321ba73..b841e02 100644 --- a/src/music_catalogue/_generated/statements/select_album_with_filters.py +++ b/src/music_catalogue/_generated/statements/select_album_with_filters.py @@ -6,15 +6,45 @@ from dataclasses import dataclass from datetime import date, datetime +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ + +@dataclass(frozen=True, slots=True) +class SelectAlbumWithFiltersRow: + id: int + name: str | None + released: date | None + format: _db_types.AlbumFormat | None + recording: _db_types.RecordingInfo | None + tracks: list[_db_types.TrackInfo] | None + disc: _db_types.DiscInfo | None + + +@dataclass(frozen=True, slots=True) +class SelectAlbumWithFilters(Statement[list[SelectAlbumWithFiltersRow]]): + include_name: bool + include_released: bool + include_format: bool + include_recording: bool + include_tracks: bool + include_disc: bool + artist_name: str | None + genre_name: str | None + format: _db_types.AlbumFormat | None + released_after: datetime | None + name_like: str | None + order_by_name: bool + order_by_released: bool + + SQL: ClassVar[str] = """\ -- Demonstrates static query equivalent of dynamic field selection. -- Boolean flags control which fields are included in the result, -- returning NULL for fields the caller opts out of. @@ -43,83 +73,38 @@ CASE WHEN %(order_by_released)s THEN album.released END DESC """ + async def execute(self, conn: AsyncConnection[object]) -> list[SelectAlbumWithFiltersRow]: + params: dict[str, object] = { + "include_name": self.include_name, + "include_released": self.include_released, + "include_format": self.include_format, + "include_recording": self.include_recording, + "include_tracks": self.include_tracks, + "include_disc": self.include_disc, + "artist_name": self.artist_name, + "genre_name": self.genre_name, + "format": self.format, + "released_after": self.released_after, + "name_like": self.name_like, + "order_by_name": self.order_by_name, + "order_by_released": self.order_by_released, + } + return await _fetch_many(conn, self.SQL, params, _args_row(SelectAlbumWithFiltersRow)) -@dataclass(frozen=True, slots=True) -class SelectAlbumWithFiltersRow: - id: int - name: str | None - released: date | None - format: _db_types.AlbumFormat | None - recording: _db_types.RecordingInfo | None - tracks: list[_db_types.TrackInfo] | None - disc: _db_types.DiscInfo | None - - -async def select_album_with_filters( - conn: AsyncConnection[object], - *, - include_name: bool, - include_released: bool, - include_format: bool, - include_recording: bool, - include_tracks: bool, - include_disc: bool, - artist_name: str | None, - genre_name: str | None, - format: _db_types.AlbumFormat | None, - released_after: datetime | None, - name_like: str | None, - order_by_name: bool, - order_by_released: bool, -) -> list[SelectAlbumWithFiltersRow]: - params: dict[str, object] = { - "include_name": include_name, - "include_released": include_released, - "include_format": include_format, - "include_recording": include_recording, - "include_tracks": include_tracks, - "include_disc": include_disc, - "artist_name": artist_name, - "genre_name": genre_name, - "format": format, - "released_after": released_after, - "name_like": name_like, - "order_by_name": order_by_name, - "order_by_released": order_by_released, - } - return await _fetch_many(conn, SQL, params, _args_row(SelectAlbumWithFiltersRow)) - - -def select_album_with_filters_sync( - conn: Connection[object], - *, - include_name: bool, - include_released: bool, - include_format: bool, - include_recording: bool, - include_tracks: bool, - include_disc: bool, - artist_name: str | None, - genre_name: str | None, - format: _db_types.AlbumFormat | None, - released_after: datetime | None, - name_like: str | None, - order_by_name: bool, - order_by_released: bool, -) -> list[SelectAlbumWithFiltersRow]: - params: dict[str, object] = { - "include_name": include_name, - "include_released": include_released, - "include_format": include_format, - "include_recording": include_recording, - "include_tracks": include_tracks, - "include_disc": include_disc, - "artist_name": artist_name, - "genre_name": genre_name, - "format": format, - "released_after": released_after, - "name_like": name_like, - "order_by_name": order_by_name, - "order_by_released": order_by_released, - } - return _fetch_many_sync(conn, SQL, params, _args_row(SelectAlbumWithFiltersRow)) + def execute_sync(self, conn: Connection[object]) -> list[SelectAlbumWithFiltersRow]: + params: dict[str, object] = { + "include_name": self.include_name, + "include_released": self.include_released, + "include_format": self.include_format, + "include_recording": self.include_recording, + "include_tracks": self.include_tracks, + "include_disc": self.include_disc, + "artist_name": self.artist_name, + "genre_name": self.genre_name, + "format": self.format, + "released_after": self.released_after, + "name_like": self.name_like, + "order_by_name": self.order_by_name, + "order_by_released": self.order_by_released, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(SelectAlbumWithFiltersRow)) diff --git a/src/music_catalogue/_generated/statements/select_album_with_tracks.py b/src/music_catalogue/_generated/statements/select_album_with_tracks.py index 0e3dd07..265a9cf 100644 --- a/src/music_catalogue/_generated/statements/select_album_with_tracks.py +++ b/src/music_catalogue/_generated/statements/select_album_with_tracks.py @@ -5,20 +5,16 @@ from __future__ import annotations from dataclasses import dataclass +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ -select id, name, tracks, disc -from album -where id = %(id)s -""" - @dataclass(frozen=True, slots=True) class SelectAlbumWithTracksRow: @@ -28,23 +24,24 @@ class SelectAlbumWithTracksRow: disc: _db_types.DiscInfo | None -async def select_album_with_tracks( - conn: AsyncConnection[object], - *, - id: int, -) -> list[SelectAlbumWithTracksRow]: - params: dict[str, object] = { - "id": id, - } - return await _fetch_many(conn, SQL, params, _args_row(SelectAlbumWithTracksRow)) - - -def select_album_with_tracks_sync( - conn: Connection[object], - *, - id: int, -) -> list[SelectAlbumWithTracksRow]: - params: dict[str, object] = { - "id": id, - } - return _fetch_many_sync(conn, SQL, params, _args_row(SelectAlbumWithTracksRow)) +@dataclass(frozen=True, slots=True) +class SelectAlbumWithTracks(Statement[list[SelectAlbumWithTracksRow]]): + id: int + + SQL: ClassVar[str] = """\ +select id, name, tracks, disc +from album +where id = %(id)s +""" + + async def execute(self, conn: AsyncConnection[object]) -> list[SelectAlbumWithTracksRow]: + params: dict[str, object] = { + "id": self.id, + } + return await _fetch_many(conn, self.SQL, params, _args_row(SelectAlbumWithTracksRow)) + + def execute_sync(self, conn: Connection[object]) -> list[SelectAlbumWithTracksRow]: + params: dict[str, object] = { + "id": self.id, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(SelectAlbumWithTracksRow)) diff --git a/src/music_catalogue/_generated/statements/select_genre_by_artist.py b/src/music_catalogue/_generated/statements/select_genre_by_artist.py index 10cd818..334c94c 100644 --- a/src/music_catalogue/_generated/statements/select_genre_by_artist.py +++ b/src/music_catalogue/_generated/statements/select_genre_by_artist.py @@ -5,21 +5,15 @@ from __future__ import annotations from dataclasses import dataclass +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ -select id, genre.name -from genre -left join album_genre on album_genre.genre = genre.id -left join album_artist on album_artist.album = album_genre.album -where album_artist.artist = %(artist)s -""" - @dataclass(frozen=True, slots=True) class SelectGenreByArtistRow: @@ -27,23 +21,26 @@ class SelectGenreByArtistRow: name: str -async def select_genre_by_artist( - conn: AsyncConnection[object], - *, - artist: int, -) -> list[SelectGenreByArtistRow]: - params: dict[str, object] = { - "artist": artist, - } - return await _fetch_many(conn, SQL, params, _args_row(SelectGenreByArtistRow)) - - -def select_genre_by_artist_sync( - conn: Connection[object], - *, - artist: int, -) -> list[SelectGenreByArtistRow]: - params: dict[str, object] = { - "artist": artist, - } - return _fetch_many_sync(conn, SQL, params, _args_row(SelectGenreByArtistRow)) +@dataclass(frozen=True, slots=True) +class SelectGenreByArtist(Statement[list[SelectGenreByArtistRow]]): + artist: int + + SQL: ClassVar[str] = """\ +select id, genre.name +from genre +left join album_genre on album_genre.genre = genre.id +left join album_artist on album_artist.album = album_genre.album +where album_artist.artist = %(artist)s +""" + + async def execute(self, conn: AsyncConnection[object]) -> list[SelectGenreByArtistRow]: + params: dict[str, object] = { + "artist": self.artist, + } + return await _fetch_many(conn, self.SQL, params, _args_row(SelectGenreByArtistRow)) + + def execute_sync(self, conn: Connection[object]) -> list[SelectGenreByArtistRow]: + params: dict[str, object] = { + "artist": self.artist, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(SelectGenreByArtistRow)) diff --git a/src/music_catalogue/_generated/statements/update_album_recording_returning.py b/src/music_catalogue/_generated/statements/update_album_recording_returning.py index b177bdc..8273712 100644 --- a/src/music_catalogue/_generated/statements/update_album_recording_returning.py +++ b/src/music_catalogue/_generated/statements/update_album_recording_returning.py @@ -6,22 +6,16 @@ from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection from psycopg.rows import args_row as _args_row from .. import types as _db_types +from .._core import Statement from .._runtime import fetch_many as _fetch_many from ..sync._runtime import fetch_many as _fetch_many_sync -SQL = """\ --- Update album recording information -update album -set recording = %(recording)s -where id = %(id)s -returning * -""" - @dataclass(frozen=True, slots=True) class UpdateAlbumRecordingReturningRow: @@ -34,27 +28,29 @@ class UpdateAlbumRecordingReturningRow: disc: _db_types.DiscInfo | None -async def update_album_recording_returning( - conn: AsyncConnection[object], - *, - recording: _db_types.RecordingInfo | None, - id: int, -) -> list[UpdateAlbumRecordingReturningRow]: - params: dict[str, object] = { - "recording": recording, - "id": id, - } - return await _fetch_many(conn, SQL, params, _args_row(UpdateAlbumRecordingReturningRow)) - - -def update_album_recording_returning_sync( - conn: Connection[object], - *, - recording: _db_types.RecordingInfo | None, - id: int, -) -> list[UpdateAlbumRecordingReturningRow]: - params: dict[str, object] = { - "recording": recording, - "id": id, - } - return _fetch_many_sync(conn, SQL, params, _args_row(UpdateAlbumRecordingReturningRow)) +@dataclass(frozen=True, slots=True) +class UpdateAlbumRecordingReturning(Statement[list[UpdateAlbumRecordingReturningRow]]): + recording: _db_types.RecordingInfo | None + id: int + + SQL: ClassVar[str] = """\ +-- Update album recording information +update album +set recording = %(recording)s +where id = %(id)s +returning * +""" + + async def execute(self, conn: AsyncConnection[object]) -> list[UpdateAlbumRecordingReturningRow]: + params: dict[str, object] = { + "recording": self.recording, + "id": self.id, + } + return await _fetch_many(conn, self.SQL, params, _args_row(UpdateAlbumRecordingReturningRow)) + + def execute_sync(self, conn: Connection[object]) -> list[UpdateAlbumRecordingReturningRow]: + params: dict[str, object] = { + "recording": self.recording, + "id": self.id, + } + return _fetch_many_sync(conn, self.SQL, params, _args_row(UpdateAlbumRecordingReturningRow)) diff --git a/src/music_catalogue/_generated/statements/update_album_released.py b/src/music_catalogue/_generated/statements/update_album_released.py index 60a273b..6230295 100644 --- a/src/music_catalogue/_generated/statements/update_album_released.py +++ b/src/music_catalogue/_generated/statements/update_album_released.py @@ -4,41 +4,38 @@ from __future__ import annotations +from dataclasses import dataclass from datetime import date +from typing import ClassVar from psycopg import AsyncConnection, Connection +from .._core import Statement from .._runtime import execute_rows_affected as _execute_rows_affected from ..sync._runtime import execute_rows_affected as _execute_rows_affected_sync -SQL = """\ + +@dataclass(frozen=True, slots=True) +class UpdateAlbumReleased(Statement[int]): + released: date | None + id: int + + SQL: ClassVar[str] = """\ update album set released = %(released)s where id = %(id)s """ - -async def update_album_released( - conn: AsyncConnection[object], - *, - released: date | None, - id: int, -) -> int: - params: dict[str, object] = { - "released": released, - "id": id, - } - return await _execute_rows_affected(conn, SQL, params) - - -def update_album_released_sync( - conn: Connection[object], - *, - released: date | None, - id: int, -) -> int: - params: dict[str, object] = { - "released": released, - "id": id, - } - return _execute_rows_affected_sync(conn, SQL, params) + async def execute(self, conn: AsyncConnection[object]) -> int: + params: dict[str, object] = { + "released": self.released, + "id": self.id, + } + return await _execute_rows_affected(conn, self.SQL, params) + + def execute_sync(self, conn: Connection[object]) -> int: + params: dict[str, object] = { + "released": self.released, + "id": self.id, + } + return _execute_rows_affected_sync(conn, self.SQL, params) diff --git a/src/music_catalogue/sync/__init__.py b/src/music_catalogue/sync/__init__.py index 237544e..3f9fa03 100644 --- a/src/music_catalogue/sync/__init__.py +++ b/src/music_catalogue/sync/__init__.py @@ -8,65 +8,68 @@ from .._generated._core import ( NoRowError as NoRowError, ) +from .._generated._core import ( + Statement as Statement, +) from .._generated._register import ( register_types_sync as register_types, ) from .._generated.statements.insert_album import ( - InsertAlbumRow as InsertAlbumRow, + InsertAlbum as InsertAlbum, ) from .._generated.statements.insert_album import ( - insert_album_sync as insert_album, + InsertAlbumRow as InsertAlbumRow, ) from .._generated.statements.insert_multiple_albums import ( - InsertMultipleAlbumsRow as InsertMultipleAlbumsRow, + InsertMultipleAlbums as InsertMultipleAlbums, ) from .._generated.statements.insert_multiple_albums import ( - insert_multiple_albums_sync as insert_multiple_albums, + InsertMultipleAlbumsRow as InsertMultipleAlbumsRow, ) from .._generated.statements.select_album_by_format import ( - SelectAlbumByFormatRow as SelectAlbumByFormatRow, + SelectAlbumByFormat as SelectAlbumByFormat, ) from .._generated.statements.select_album_by_format import ( - select_album_by_format_sync as select_album_by_format, + SelectAlbumByFormatRow as SelectAlbumByFormatRow, ) from .._generated.statements.select_album_by_id import ( - SelectAlbumByIdRow as SelectAlbumByIdRow, + SelectAlbumById as SelectAlbumById, ) from .._generated.statements.select_album_by_id import ( - select_album_by_id_sync as select_album_by_id, + SelectAlbumByIdRow as SelectAlbumByIdRow, ) from .._generated.statements.select_album_by_name import ( - SelectAlbumByNameRow as SelectAlbumByNameRow, + SelectAlbumByName as SelectAlbumByName, ) from .._generated.statements.select_album_by_name import ( - select_album_by_name_sync as select_album_by_name, + SelectAlbumByNameRow as SelectAlbumByNameRow, ) from .._generated.statements.select_album_with_filters import ( - SelectAlbumWithFiltersRow as SelectAlbumWithFiltersRow, + SelectAlbumWithFilters as SelectAlbumWithFilters, ) from .._generated.statements.select_album_with_filters import ( - select_album_with_filters_sync as select_album_with_filters, + SelectAlbumWithFiltersRow as SelectAlbumWithFiltersRow, ) from .._generated.statements.select_album_with_tracks import ( - SelectAlbumWithTracksRow as SelectAlbumWithTracksRow, + SelectAlbumWithTracks as SelectAlbumWithTracks, ) from .._generated.statements.select_album_with_tracks import ( - select_album_with_tracks_sync as select_album_with_tracks, + SelectAlbumWithTracksRow as SelectAlbumWithTracksRow, ) from .._generated.statements.select_genre_by_artist import ( - SelectGenreByArtistRow as SelectGenreByArtistRow, + SelectGenreByArtist as SelectGenreByArtist, ) from .._generated.statements.select_genre_by_artist import ( - select_genre_by_artist_sync as select_genre_by_artist, + SelectGenreByArtistRow as SelectGenreByArtistRow, ) from .._generated.statements.update_album_recording_returning import ( - UpdateAlbumRecordingReturningRow as UpdateAlbumRecordingReturningRow, + UpdateAlbumRecordingReturning as UpdateAlbumRecordingReturning, ) from .._generated.statements.update_album_recording_returning import ( - update_album_recording_returning_sync as update_album_recording_returning, + UpdateAlbumRecordingReturningRow as UpdateAlbumRecordingReturningRow, ) from .._generated.statements.update_album_released import ( - update_album_released_sync as update_album_released, + UpdateAlbumReleased as UpdateAlbumReleased, ) from .._generated.types.album_format import ( AlbumFormat as AlbumFormat, @@ -84,6 +87,7 @@ __all__ = [ "JsonValue", "NoRowError", + "Statement", ] __all__ += [ "AlbumFormat", @@ -103,16 +107,16 @@ "UpdateAlbumRecordingReturningRow", ] __all__ += [ - "insert_album", - "insert_multiple_albums", - "select_album_by_format", - "select_album_by_id", - "select_album_by_name", - "select_album_with_filters", - "select_album_with_tracks", - "select_genre_by_artist", - "update_album_recording_returning", - "update_album_released", + "InsertAlbum", + "InsertMultipleAlbums", + "SelectAlbumByFormat", + "SelectAlbumById", + "SelectAlbumByName", + "SelectAlbumWithFilters", + "SelectAlbumWithTracks", + "SelectGenreByArtist", + "UpdateAlbumRecordingReturning", + "UpdateAlbumReleased", ] __all__ += [ "register_types",