Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
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
Esempio n. 4
0
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,
    )
Esempio n. 5
0
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,
    )
Esempio n. 6
0
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)
Esempio n. 7
0
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)
Esempio n. 8
0
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)
Esempio n. 9
0
    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 = ?
Esempio n. 10
0
        """
        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 = ?
        """,
Esempio n. 11
0
        """
        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 = ?
        """,