def update(usr: T, conn: Connection, **changes) -> T: """ Update a user and persist changes to the database. To update a value, pass it in as a keyword argument. To keep the original value, do not pass in a keyword argument. :param usr: The user to update. :param conn: A connection to the database. :param nickname: New user nickname. :type nickname: :py:obj:`str` :return: The updated user. """ if changes.get("nickname", None) and not _validate_nickname(changes["nickname"]): raise InvalidNickname conn.execute( """ UPDATE system__users SET nickname = ? WHERE id = ? """, (changes.get("nickname", usr.nickname), usr.id), ) logger.info(f"Updated user {usr.id} with {changes}.") return update_dataclass(usr, **changes)
def update(inv: T, conn: Connection, **changes) -> T: """ Update an invite and persist changes to the database. To update a value, pass it in as a keyword argument. To keep the original value, do not pass in a keyword argument. :param inv: The invite to update. :param conn: A connection to the database. :param used_by: The user that used the invite. :type used_by: :py:obj:`src.library.user.T` :return: The updated invite. """ if changes.get("used_by"): changes["used_by"] = changes["used_by"].id conn.execute( """ UPDATE system__invites SET used_by = ? WHERE id = ? """, (changes.get("used_by", inv.used_by), inv.id), ) logger.info(f"Updated invite {inv.id} with {changes}.") return update_dataclass(inv, **changes)
def test_update_dataclass(): @dataclass(frozen=True) class Example: a: int d1 = Example(a=1) d2 = update_dataclass(d1, a=2) assert d1.a == 1 assert d2.a == 2
def del_release(col: T, release_id: int, conn: Connection) -> T: """ Remove the provided release from the provided collection. :param col: The collection to remove the release from. :param release_id: The release to remove. :param conn: A connection to the database. :return: The collection with the number of tracks (if present) updated. :raises NotFound: If no release has the given release ID. :raises DoesNotExist: If the release is not in the collection. """ if not release.exists(release_id, conn): logger.debug(f"Release {release_id} does not exist.") raise NotFound(f"Release {release_id} does not exist.") cursor = conn.execute( """ SELECT 1 FROM music__collections_releases WHERE collection_id = ? AND release_id = ? """, (col.id, release_id), ) if not cursor.fetchone(): logger.debug(f"Release {release_id} not in collection {col.id}.") raise DoesNotExist("Release is not in collection.") conn.execute( """ DELETE FROM music__collections_releases WHERE collection_id = ? AND release_id = ? """, (col.id, release_id), ) now = datetime.utcnow() conn.execute( """ UPDATE music__collections SET last_updated_on = ? WHERE id = ? """, ( now, col.id, ), ) logger.info(f"Deleted release {release_id} from collection {col.id}.") return update_dataclass( col, num_releases=(col.num_releases - 1 if col.num_releases is not None else col.num_releases), last_updated_on=now, )
def add_release(col: T, release_id: int, conn: Connection) -> T: """ Add the provided release to the provided collection. :param col: The collection to add the release to. :param release_id: The ID of the release to add. :param conn: A connection to the database. :return: The collection with the number of tracks (if present) updated. :raises NotFound: If no release has the given release ID. :raises AlreadyExists: If the release is already in the collection. """ if not release.exists(release_id, conn): logger.debug(f"Release {release_id} does not exist.") raise NotFound(f"Release {release_id} does not exist.") cursor = conn.execute( """ SELECT 1 FROM music__collections_releases WHERE collection_id = ? AND release_id = ? """, (col.id, release_id), ) if cursor.fetchone(): logger.debug(f"Release {release_id} already in collection {col.id}.") raise AlreadyExists("Release is already in collection.") conn.execute( """ INSERT INTO music__collections_releases (collection_id, release_id) VALUES (?, ?) """, (col.id, release_id), ) now = datetime.now() conn.execute( """ UPDATE music__collections SET last_updated_on = ? WHERE id = ? """, ( col.id, now, ), ) logger.info(f"Added release {release_id} to collection {col.id}.") return update_dataclass( col, num_releases=(col.num_releases + 1 if col.num_releases is not None else col.num_releases), last_updated_on=now, )
def update(rls: T, conn: Connection, **changes) -> T: """ Update a release and persist changes to the database. To update a value, pass it in as a keyword argument. To keep the original value, do not pass in a keyword argument. :param rls: The release to update. :param conn: A connection to the database. :param title: New release title. :type title: :py:obj:`str` :param release_type: New release type. :type release_type: :py:obj:`src.enums.ReleaseType` :param release_year: New release year. :type release_year: :py:obj:`int` :param release_date: New release date. :type release_date: :py:obj:`datetime.date` :param rating: New release rating. Pass in 0 to delete existing rating. Passing in ``None`` does not change the existing rating. :type rating: :py:obj:`int` :return: The updated release. """ if changes.get("rating", rls.rating) == 0: changes["rating"] = None conn.execute( """ UPDATE music__releases SET title = ?, release_type = ?, release_year = ?, release_date = ?, rating = ? WHERE id = ? """, ( changes.get("title", rls.title), changes.get("release_type", rls.release_type).value, changes.get("release_year", rls.release_year), changes.get("release_date", rls.release_date), changes.get("rating", rls.rating), rls.id, ), ) logger.info(f"Updated release {rls.id} with {changes}.") return update_dataclass(rls, **changes)
def update(trk: T, conn: Connection, **changes) -> T: """ Update a track and persist changes to the database. To update a value, pass it in as a keyword argument. To keep the original value, do not pass in a keyword argument. :param trk: The track to update. :param conn: A connection to the database. :param title: New track title. :type title: :py:obj:`str` :param release_id: ID of the new release. :type release_id: :py:obj:`int` :param track_number: New track number. :type track_number: :py:obj:`str` :param disc_number: New disc number. :type disc_number: :py:obj:`str` :return: The updated track. :raise NotFound: If the new release ID does not exist. """ if "release_id" in changes and not librelease.exists( changes["release_id"], conn): logger.debug(f"Release {changes['release_id']} does not exist.") raise NotFound(f"Release {changes['release_id']} does not exist.") conn.execute( """ UPDATE music__tracks SET title = ?, release_id = ?, track_number = ?, disc_number = ? WHERE id = ? """, ( changes.get("title", trk.title), changes.get("release_id", trk.release_id), changes.get("track_number", trk.track_number), changes.get("disc_number", trk.disc_number), trk.id, ), ) logger.info(f"Updated track {trk.id} with {changes}.") return update_dataclass(trk, **changes)
def update(ety: T, position: int, conn: Connection) -> T: """ Update the index of an entry in a playlist. Shift all other entries accordingly. :param ety: The playlist entry to update. :param position: The intended new index of the entry. :param conn: A connection to the database. :return: The updated entry. :raises IndexError: If the entry is out of bounds. """ max_ = _highest_position(ety.playlist_id, conn) if position < 1 or position > max_: raise IndexError(f"Position {position} out of bounds.") # Nothing to do here... if position == ety.position: return ety # I believe Python surrounds these with an implicit transaction. if position > ety.position: conn.execute( """ UPDATE music__playlists_tracks SET position = position - 1 WHERE playlist_id = ? AND position > ? AND position <= ? """, (ety.playlist_id, ety.position, position), ) conn.execute( """ UPDATE music__playlists_tracks SET position = ? WHERE id = ? """, (position, ety.id), ) else: conn.execute( """ UPDATE music__playlists_tracks SET position = position + 1 WHERE playlist_id = ? AND position < ? AND position >= ? """, (ety.playlist_id, ety.position, position), ) conn.execute( """ UPDATE music__playlists_tracks SET position = ? WHERE id = ? """, (position, ety.id), ) conn.execute( """ UPDATE music__playlists SET last_updated_on = CURRENT_TIMESTAMP WHERE id = ? """, (ety.playlist_id,), ) logger.info(f"Updated position of entry {id} to {position}.") return update_dataclass(ety, position=position)
conn.execute( """ UPDATE music__artists SET name = ? WHERE id = ? """, ( changes.get("name", art.name), art.id, ), ) logger.info(f"Updated artist {art.id} with {changes}.") return update_dataclass(art, **changes) def starred(art: T, user_id: int, conn: Connection) -> bool: """ Return whether this artist is starred by the passed-in user. :param art: The provided artist. :param user_id: The passed-in user's ID. :param conn: A connection to the database. :return: Whether the artist is starred by the user. """ cursor = conn.execute( """ SELECT 1 FROM music__artists_starred WHERE user_id = ? AND artist_id = ?
""" UPDATE music__playlists SET name = ?, last_updated_on = ? WHERE id = ? """, ( changes.get("name", ply.name), changes["last_updated_on"], ply.id, ), ) logger.info(f"Updated playlist {ply.id} with {changes}.") return update_dataclass(ply, **changes) def starred(ply: T, user_id: int, conn: Connection) -> bool: """ Return whether this playlist is starred by the passed-in user. :param ply: The provided playlist. :param user_id: The passed-in user's ID. :param conn: A connection to the database. :return: Whether the playlist is starred by the user. """ cursor = conn.execute( """ SELECT 1 FROM music__playlists_starred WHERE user_id = ? AND playlist_id = ? """,
""" UPDATE music__collections SET name = ?, last_updated_on = ? WHERE id = ? """, ( changes.get("name", col.name), changes["last_updated_on"], col.id, ), ) logger.info(f"Updated collection {col.id} with {changes}.") return update_dataclass(col, **changes) def starred(col: T, user_id: int, conn: Connection) -> bool: """ Return whether this collection is starred by the passed-in user. :param col: The provided collection. :param user_id: The passed-in user's ID. :param conn: A connection to the database. :return: Whether the collection is starred by the user. """ cursor = conn.execute( """ SELECT 1 FROM music__collections_starred WHERE user_id = ? AND collection_id = ? """,