Skip to content

Commit

Permalink
split upsert
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrienPensart committed May 31, 2024
1 parent d0dde1b commit 4e2de64
Show file tree
Hide file tree
Showing 25 changed files with 417 additions and 91 deletions.
6 changes: 1 addition & 5 deletions Caddyfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
handle /artists {
method POST
request_body {
replace `{"query": "select artists {*}"}`
replace `{"query": "select Artist {*}"}`
}
request_header Content-Type application/json
# header_up Host {upstream_hostport}
Expand All @@ -21,8 +21,4 @@
}
}
}

# handle /artists {
# reverse_proxy http://localhost:8081
# }
}
4 changes: 1 addition & 3 deletions dbschema/default.esdl
Original file line number Diff line number Diff line change
Expand Up @@ -212,9 +212,7 @@ module default {
}
link artist := (select .album.artist);

required link genre: Genre {
on target delete delete source;
}
required link genre: Genre;

# youtube: str;
# spotify: str;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CREATE MIGRATION m1oy3zaoi4vykcutcfrianlcvpose52w7fdmesc6vcv3l73mlb5p4a
CREATE MIGRATION m14r34ka5fo7fpp3z7et6ib6dgb2hpkzepiekod4bt3waybknnylyq
ONTO initial
{
CREATE EXTENSION edgeql_http VERSION '1.0';
Expand Down Expand Up @@ -185,9 +185,7 @@ CREATE MIGRATION m1oy3zaoi4vykcutcfrianlcvpose52w7fdmesc6vcv3l73mlb5p4a
};
};
ALTER TYPE default::Music {
CREATE REQUIRED LINK genre: default::Genre {
ON TARGET DELETE DELETE SOURCE;
};
CREATE REQUIRED LINK genre: default::Genre;
};
ALTER TYPE default::Genre {
CREATE MULTI LINK musics := (.<genre[IS default::Music]);
Expand Down
10 changes: 5 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
services:
musicbot_db_prod:
container_name: musicbot-db-prod
musicbot_prod:
container_name: musicbot-prod
image: "edgedb/edgedb:5"
restart: always
ports:
Expand All @@ -19,14 +19,14 @@ services:
- ./dbschema:/dbschema
- ./credentials:/root/.config/edgedb/credentials
- musicbot-prod-data:/var/lib/edgedb/data
musicbot_db_test:
container_name: musicbot-db-test
musicbot_test:
container_name: musicbot-test
image: "edgedb/edgedb:5"
restart: always
ports:
- 5657:5656
environment:
EDGEDB_DOCKER_LOG_LEVEL: info
EDGEDB_DOCKER_LOG_LEVEL: debug
EDGEDB_SERVER_SECURITY: insecure_dev_mode
EDGEDB_SERVER_TLS_CERT_MODE: generate_self_signed
EDGEDB_SERVER_ADMIN_UI: enabled
Expand Down
7 changes: 3 additions & 4 deletions musicbot/commands/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ def pgcli(ctx: click.Context, musicdb: MusicDb, pgcli_args: tuple[str, ...]) ->
from pgcli.main import cli as pg_cli

dsn = musicdb.dsn.replace("edgedb://", "postgresql://")
dsn += "/main"
args = [dsn] + list(pgcli_args)
pgcli_logger = logging.getLogger("pgcli.main")
pgcli_logger.setLevel(logging.ERROR)
Expand Down Expand Up @@ -116,7 +115,7 @@ def ui(
@syncify
@beartype
async def clean(musicdb: MusicDb) -> None:
_ = await musicdb.clean_musics()
await musicdb.clean_musics()


@cli.command(help="Drop entire schema from DB")
Expand All @@ -125,12 +124,12 @@ async def clean(musicdb: MusicDb) -> None:
@syncify
@beartype
async def drop(musicdb: MusicDb) -> None:
_ = await musicdb.drop()
await musicdb.drop()


@cli.command(help="Clean entities without musics associated")
@musicdb_options
@syncify
@beartype
async def soft_clean(musicdb: MusicDb) -> None:
_ = await musicdb.soft_clean()
await musicdb.soft_clean()
15 changes: 6 additions & 9 deletions musicbot/commands/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ async def remove(
async def clean(
musicdb: MusicDb,
) -> None:
_ = await musicdb.clean_musics()
await musicdb.clean_musics()


@cli.command(help="Load musics")
Expand All @@ -129,11 +129,11 @@ async def scan(
output: str,
) -> None:
if clean:
_ = await musicdb.clean_musics()
await musicdb.clean_musics()

music_outputs = await scan_folders.scan(musicdb=musicdb)

_ = await musicdb.soft_clean()
await musicdb.soft_clean()

if output == "json":
MusicbotObject.print_json([asdict(mo) for mo in music_outputs])
Expand All @@ -160,8 +160,7 @@ async def soft_clean_periodically() -> None:
try:
while True:
try:
cleaned = await musicdb.soft_clean()
MusicbotObject.success(cleaned)
await musicdb.soft_clean()
MusicbotObject.success(f"DB cleaned, waiting {sleep} seconds.")
await asyncio.sleep(sleep)
except edgedb.ClientConnectionFailedTemporarilyError as error:
Expand Down Expand Up @@ -353,7 +352,7 @@ async def custom_playlists(
) -> None:
scan_folders = ScanFolders(directories=[scan_folder])
if not fast:
_ = await musicdb.clean_musics()
await musicdb.clean_musics()
_ = await scan_folders.scan(musicdb=musicdb)

musicdb.set_readonly()
Expand All @@ -373,9 +372,7 @@ async def custom_playlists(
playlist_options=playlist_options,
)

pike_keywords = await musicdb.query(
"for keyword in (select Keyword {name} filter contains(array_agg(.musics.keywords.name), 'pike') and .musics.rating >= 4.0 and .musics.album.artist.name = 'Buckethead') union (keyword.name) except {'pike'}"
)
pike_keywords = await musicdb.pike_keywords()

for pike_keyword in pike_keywords:
MusicbotObject.success(f"Generating pike playlists for keyword {pike_keyword}")
Expand Down
24 changes: 24 additions & 0 deletions musicbot/folder.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from dataclasses import asdict, dataclass
from pathlib import Path

import edgedb
from beartype import beartype
from beartype.typing import Self

from musicbot.object import MusicbotObject
from musicbot.playlist_options import PlaylistOptions
Expand Down Expand Up @@ -29,6 +31,28 @@ class Folder(MusicbotObject):
human_size: str = ""
human_duration: str = ""

@classmethod
def from_edgedb(
cls,
folder: edgedb.Object,
) -> Self:
return cls(
path=Path(folder.name),
name=folder.name,
ipv4=folder.ipv4,
username=folder.username,
n_artists=folder.n_artists,
all_artists=folder.all_artists,
n_albums=folder.n_albums,
n_musics=folder.n_musics,
n_keywords=folder.n_keywords,
all_keywords=folder.all_keywords,
n_genres=folder.n_genres,
all_genres=folder.all_genres,
human_size=folder.human_size,
human_duration=folder.human_duration,
)

def __repr__(self) -> str:
return f"{self.name} {self.ipv4} {self.username}"

Expand Down
104 changes: 57 additions & 47 deletions musicbot/musicdb.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logging
import os
from dataclasses import asdict, dataclass, field
from dataclasses import dataclass, field
from pathlib import Path
from urllib.parse import urlparse
from uuid import UUID
Expand All @@ -9,7 +9,7 @@
import httpx
from async_lru import alru_cache
from beartype import beartype
from beartype.typing import Any, Self
from beartype.typing import Self
from edgedb.asyncio_client import AsyncIOClient, create_async_client
from edgedb.options import RetryOptions, TransactionOptions

Expand All @@ -18,9 +18,14 @@
from musicbot.music_filter import MusicFilter
from musicbot.object import MusicbotObject
from musicbot.playlist import Playlist
from musicbot.queries.gen_bests_async_edgeql import GenBestsResult, gen_bests
from musicbot.queries.gen_playlist_async_edgeql import GenPlaylistResult, gen_playlist
from musicbot.queries.delete_musics_async_edgeql import delete_musics
from musicbot.queries.drop_schema_async_edgeql import drop_schema
from musicbot.queries.gen_bests_async_edgeql import gen_bests
from musicbot.queries.gen_playlist_async_edgeql import gen_playlist
from musicbot.queries.pike_keywords_async_edgeql import pike_keywords
from musicbot.queries.remove_async_edgeql import remove
from musicbot.queries.select_artists_async_edgeql import select_artists
from musicbot.queries.select_folder_async_edgeql import select_folder
from musicbot.queries.soft_clean_async_edgeql import soft_clean
from musicbot.queries.upsert_album_async_edgeql import upsert_album
from musicbot.queries.upsert_artist_async_edgeql import upsert_artist
Expand Down Expand Up @@ -90,9 +95,6 @@ def graphiql(self) -> str:
async def query_json(self, query: str) -> str:
return await self.client.query_json(query)

async def query(self, query: str) -> Any:
return await self.client.query(query)

async def graphql_query(self, query: str) -> httpx.Response | None:
operation = {"query": query}
try:
Expand All @@ -108,30 +110,15 @@ async def graphql_query(self, query: str) -> httpx.Response | None:

@alru_cache
async def folders(self) -> list[Folder]:
results = await self.client.query("select Folder {*} order by .name")
results = await select_folder(self.client)
folders = []
for result in results:
folder = Folder(
path=Path(result.name),
name=result.name,
ipv4=result.ipv4,
username=result.username,
n_artists=result.n_artists,
all_artists=result.all_artists,
n_albums=result.n_albums,
n_musics=result.n_musics,
n_keywords=result.n_keywords,
all_keywords=result.all_keywords,
n_genres=result.n_genres,
all_genres=result.all_genres,
human_size=result.human_size,
human_duration=result.human_duration,
)
folder = Folder.from_edgedb(folder=result)
folders.append(folder)
return folders

async def artists(self) -> list[edgedb.Object]:
return await self.client.query("select Artist {*} order by .name")
return await select_artists(self.client)

async def make_playlist(
self,
Expand All @@ -142,9 +129,21 @@ async def make_playlist(

results = set()
for music_filter in music_filters:
intermediate_results: list[GenPlaylistResult] = await gen_playlist(
intermediate_results = await gen_playlist(
self.client,
**asdict(music_filter),
min_length=music_filter.min_length,
max_length=music_filter.max_length,
min_size=music_filter.min_size,
max_size=music_filter.max_size,
min_rating=music_filter.min_rating,
max_rating=music_filter.max_rating,
artist=music_filter.artist,
album=music_filter.album,
genre=music_filter.genre,
title=music_filter.title,
keyword=music_filter.keyword,
pattern=music_filter.pattern,
limit=music_filter.limit,
)
results.update(intermediate_results)
name = " | ".join([music_filter.help_repr() for music_filter in music_filters])
Expand All @@ -153,26 +152,25 @@ async def make_playlist(
results=list(results),
)

async def clean_musics(self) -> None | list[edgedb.Object]:
query = """delete Artist;"""
if self.dry:
return None
return await self.client.query(query)
async def clean_musics(self) -> None:
if not self.dry:
_ = await delete_musics(self.client)

async def drop(self) -> None | list[edgedb.Object]:
query = """reset schema to initial;"""
if self.dry:
return None
return await self.client.query(query)
async def pike_keywords(self) -> list[str]:
return await pike_keywords(self.client)

async def soft_clean(self) -> None | edgedb.Object:
self.success("cleaning orphan musics, artists, albums, genres, keywords")
if self.dry:
return None
return await soft_clean(self.client)
async def drop(self) -> None:
if not self.dry:
await drop_schema(self.client)

async def ensure_connected(self) -> AsyncIOClient:
return await self.client.ensure_connected()
async def soft_clean(self) -> None:
if not self.dry:
cleaned = await soft_clean(self.client)
self.success(f"cleaned {cleaned.musics_deleted} musics")
self.success(f"cleaned {cleaned.artists_deleted} artists")
self.success(f"cleaned {cleaned.albums_deleted} albums")
self.success(f"cleaned {cleaned.genres_deleted} genres")
self.success(f"clceaned {cleaned.keywords_deleted} keywords")

async def remove_music_path(self, path: str) -> None | edgedb.Object:
logger.debug(f"{self} : removed {path}")
Expand Down Expand Up @@ -276,11 +274,23 @@ async def make_bests(
if not music_filters:
music_filters = frozenset([MusicFilter()])

results: list[GenBestsResult] = []
results = []
for music_filter in music_filters:
intermediate_result: GenBestsResult = await gen_bests(
intermediate_result = await gen_bests(
self.client,
**asdict(music_filter),
min_length=music_filter.min_length,
max_length=music_filter.max_length,
min_size=music_filter.min_size,
max_size=music_filter.max_size,
min_rating=music_filter.min_rating,
max_rating=music_filter.max_rating,
artist=music_filter.artist,
album=music_filter.album,
genre=music_filter.genre,
title=music_filter.title,
keyword=music_filter.keyword,
pattern=music_filter.pattern,
limit=music_filter.limit,
)
results.append(intermediate_result)

Expand Down
1 change: 1 addition & 0 deletions musicbot/queries/delete_musics.edgeql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
delete Artist;
Loading

0 comments on commit 4e2de64

Please sign in to comment.