mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-07 13:38:15 -08:00
chore: initial public commit
This commit is contained in:
commit
fc9054b78c
250 changed files with 32809 additions and 0 deletions
282
db/migrations/000001_initial_schema.sql
Normal file
282
db/migrations/000001_initial_schema.sql
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
SELECT 'up SQL query';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- Extensions
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||
|
||||
-- Types
|
||||
CREATE TYPE role AS ENUM (
|
||||
'admin',
|
||||
'user'
|
||||
);
|
||||
|
||||
-- Functions
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE FUNCTION delete_orphan_releases() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM artist_releases
|
||||
WHERE release_id = OLD.release_id
|
||||
) THEN
|
||||
DELETE FROM releases WHERE id = OLD.release_id;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- Tables
|
||||
CREATE TABLE artists (
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME artists_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
image UUID,
|
||||
image_source text,
|
||||
CONSTRAINT artists_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE artist_aliases (
|
||||
artist_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
source text NOT NULL,
|
||||
is_primary boolean NOT NULL,
|
||||
CONSTRAINT artist_aliases_pkey PRIMARY KEY (artist_id, alias)
|
||||
);
|
||||
|
||||
CREATE TABLE releases (
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME releases_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
image UUID,
|
||||
various_artists boolean DEFAULT false NOT NULL,
|
||||
image_source text,
|
||||
CONSTRAINT releases_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE artist_releases (
|
||||
artist_id integer NOT NULL,
|
||||
release_id integer NOT NULL,
|
||||
CONSTRAINT artist_releases_pkey PRIMARY KEY (artist_id, release_id)
|
||||
);
|
||||
|
||||
CREATE TABLE tracks (
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME tracks_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
duration integer DEFAULT 0 NOT NULL,
|
||||
release_id integer NOT NULL,
|
||||
CONSTRAINT tracks_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE artist_tracks (
|
||||
artist_id integer NOT NULL,
|
||||
track_id integer NOT NULL,
|
||||
CONSTRAINT artist_tracks_pkey PRIMARY KEY (artist_id, track_id)
|
||||
);
|
||||
|
||||
CREATE TABLE users (
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME users_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
),
|
||||
username text UNIQUE NOT NULL,
|
||||
role role DEFAULT 'user'::role NOT NULL,
|
||||
password bytea NOT NULL,
|
||||
CONSTRAINT users_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE api_keys (
|
||||
id integer NOT NULL GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME api_keys_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
),
|
||||
key text UNIQUE NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
created_at timestamp without time zone DEFAULT now() NOT NULL,
|
||||
label text NOT NULL,
|
||||
CONSTRAINT api_keys_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE release_aliases (
|
||||
release_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
source text NOT NULL,
|
||||
is_primary boolean NOT NULL,
|
||||
CONSTRAINT release_aliases_pkey PRIMARY KEY (release_id, alias)
|
||||
);
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id UUID NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
created_at timestamp without time zone DEFAULT now() NOT NULL,
|
||||
expires_at timestamp without time zone NOT NULL,
|
||||
persistent boolean DEFAULT false NOT NULL,
|
||||
CONSTRAINT sessions_pkey PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE track_aliases (
|
||||
track_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
is_primary boolean NOT NULL,
|
||||
source text NOT NULL,
|
||||
CONSTRAINT track_aliases_pkey PRIMARY KEY (track_id, alias)
|
||||
);
|
||||
|
||||
CREATE TABLE listens (
|
||||
track_id integer NOT NULL,
|
||||
listened_at timestamptz NOT NULL,
|
||||
client text,
|
||||
user_id integer NOT NULL,
|
||||
CONSTRAINT listens_pkey PRIMARY KEY (track_id, listened_at)
|
||||
);
|
||||
|
||||
|
||||
-- Views
|
||||
CREATE VIEW artists_with_name AS
|
||||
SELECT a.id,
|
||||
a.musicbrainz_id,
|
||||
a.image,
|
||||
a.image_source,
|
||||
aa.alias AS name
|
||||
FROM (artists a
|
||||
JOIN artist_aliases aa ON ((aa.artist_id = a.id)))
|
||||
WHERE (aa.is_primary = true);
|
||||
|
||||
CREATE VIEW releases_with_title AS
|
||||
SELECT r.id,
|
||||
r.musicbrainz_id,
|
||||
r.image,
|
||||
r.various_artists,
|
||||
r.image_source,
|
||||
ra.alias AS title
|
||||
FROM (releases r
|
||||
JOIN release_aliases ra ON ((ra.release_id = r.id)))
|
||||
WHERE (ra.is_primary = true);
|
||||
|
||||
CREATE VIEW tracks_with_title AS
|
||||
SELECT t.id,
|
||||
t.musicbrainz_id,
|
||||
t.duration,
|
||||
t.release_id,
|
||||
ta.alias AS title
|
||||
FROM (tracks t
|
||||
JOIN track_aliases ta ON ((ta.track_id = t.id)))
|
||||
WHERE (ta.is_primary = true);
|
||||
|
||||
-- Foreign Key Constraints
|
||||
ALTER TABLE ONLY api_keys
|
||||
ADD CONSTRAINT api_keys_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY artist_aliases
|
||||
ADD CONSTRAINT artist_aliases_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES artists(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY artist_releases
|
||||
ADD CONSTRAINT artist_releases_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES artists(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY artist_releases
|
||||
ADD CONSTRAINT artist_releases_release_id_fkey FOREIGN KEY (release_id) REFERENCES releases(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY artist_tracks
|
||||
ADD CONSTRAINT artist_tracks_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES artists(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY artist_tracks
|
||||
ADD CONSTRAINT artist_tracks_track_id_fkey FOREIGN KEY (track_id) REFERENCES tracks(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY listens
|
||||
ADD CONSTRAINT listens_track_id_fkey FOREIGN KEY (track_id) REFERENCES tracks(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY listens
|
||||
ADD CONSTRAINT listens_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY release_aliases
|
||||
ADD CONSTRAINT release_aliases_release_id_fkey FOREIGN KEY (release_id) REFERENCES releases(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY sessions
|
||||
ADD CONSTRAINT sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY track_aliases
|
||||
ADD CONSTRAINT track_aliases_track_id_fkey FOREIGN KEY (track_id) REFERENCES tracks(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY tracks
|
||||
ADD CONSTRAINT track_release_id_fkey FOREIGN KEY (release_id) REFERENCES releases(id) ON DELETE CASCADE;
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX idx_artist_aliases_alias_trgm ON artist_aliases USING gin (alias gin_trgm_ops);
|
||||
CREATE INDEX idx_artist_aliases_artist_id ON artist_aliases USING btree (artist_id);
|
||||
CREATE INDEX idx_artist_releases ON artist_releases USING btree (artist_id, release_id);
|
||||
CREATE INDEX idx_release_aliases_alias_trgm ON release_aliases USING gin (alias gin_trgm_ops);
|
||||
CREATE INDEX idx_tracks_release_id ON tracks USING btree (release_id);
|
||||
CREATE INDEX listens_listened_at_idx ON listens USING btree (listened_at);
|
||||
CREATE INDEX listens_track_id_listened_at_idx ON listens USING btree (track_id, listened_at);
|
||||
CREATE INDEX release_aliases_release_id_idx ON release_aliases USING btree (release_id) WHERE (is_primary = true);
|
||||
CREATE INDEX track_aliases_track_id_idx ON track_aliases USING btree (track_id) WHERE (is_primary = true);
|
||||
CREATE INDEX idx_track_aliases_alias_trgm ON track_aliases USING gin (alias gin_trgm_ops);
|
||||
|
||||
-- Triggers
|
||||
CREATE TRIGGER trg_delete_orphan_releases AFTER DELETE ON artist_releases FOR EACH ROW EXECUTE FUNCTION delete_orphan_releases();
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
SELECT 'down SQL query';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- Drop Triggers
|
||||
DROP TRIGGER IF EXISTS trg_delete_orphan_releases ON artist_releases;
|
||||
|
||||
-- Drop Views
|
||||
DROP VIEW IF EXISTS artists_with_name;
|
||||
DROP VIEW IF EXISTS releases_with_title;
|
||||
DROP VIEW IF EXISTS tracks_with_title;
|
||||
|
||||
-- Drop Tables (in reverse dependency order)
|
||||
DROP TABLE IF EXISTS listens CASCADE;
|
||||
DROP TABLE IF EXISTS api_keys CASCADE;
|
||||
DROP TABLE IF EXISTS artist_tracks CASCADE;
|
||||
DROP TABLE IF EXISTS artist_releases CASCADE;
|
||||
DROP TABLE IF EXISTS release_aliases CASCADE;
|
||||
DROP TABLE IF EXISTS track_aliases CASCADE;
|
||||
DROP TABLE IF EXISTS sessions CASCADE;
|
||||
DROP TABLE IF EXISTS tracks CASCADE;
|
||||
DROP TABLE IF EXISTS artists CASCADE;
|
||||
DROP TABLE IF EXISTS users CASCADE;
|
||||
DROP TABLE IF EXISTS artist_aliases CASCADE;
|
||||
|
||||
-- Drop Functions
|
||||
DROP FUNCTION IF EXISTS delete_orphan_releases();
|
||||
|
||||
-- Drop Types
|
||||
DROP TYPE IF EXISTS role;
|
||||
|
||||
-- Drop Extensions
|
||||
DROP EXTENSION IF EXISTS pg_trgm;
|
||||
3
db/migrations/000002_fix_api_key_fkey.sql
Normal file
3
db/migrations/000002_fix_api_key_fkey.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
-- +goose Up
|
||||
ALTER TABLE api_keys DROP CONSTRAINT api_keys_user_id_fkey;
|
||||
ALTER TABLE api_keys ADD CONSTRAINT api_keys_user_id_fkey FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
772
db/migrations/etc/dump.sql
Normal file
772
db/migrations/etc/dump.sql
Normal file
|
|
@ -0,0 +1,772 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
-- Dumped from database version 16.9 (Debian 16.9-1.pgdg120+1)
|
||||
-- Dumped by pg_dump version 16.4 (Debian 16.4-1.pgdg120+1)
|
||||
|
||||
-- Started on 2025-06-11 14:30:57 UTC
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
--
|
||||
-- TOC entry 2 (class 3079 OID 16511)
|
||||
-- Name: pg_trgm; Type: EXTENSION; Schema: -; Owner: -
|
||||
--
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3536 (class 0 OID 0)
|
||||
-- Dependencies: 2
|
||||
-- Name: EXTENSION pg_trgm; Type: COMMENT; Schema: -; Owner:
|
||||
--
|
||||
|
||||
COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams';
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 921 (class 1247 OID 16885)
|
||||
-- Name: role; Type: TYPE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TYPE public.role AS ENUM (
|
||||
'admin',
|
||||
'user'
|
||||
);
|
||||
|
||||
|
||||
ALTER TYPE public.role OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 269 (class 1255 OID 16963)
|
||||
-- Name: delete_orphan_releases(); Type: FUNCTION; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE FUNCTION public.delete_orphan_releases() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM artist_releases
|
||||
WHERE release_id = OLD.release_id
|
||||
) THEN
|
||||
DELETE FROM releases WHERE id = OLD.release_id;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
ALTER FUNCTION public.delete_orphan_releases() OWNER TO postgres;
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = heap;
|
||||
|
||||
--
|
||||
-- TOC entry 231 (class 1259 OID 16901)
|
||||
-- Name: api_keys; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.api_keys (
|
||||
id integer NOT NULL,
|
||||
key text NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
label text
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.api_keys OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 230 (class 1259 OID 16900)
|
||||
-- Name: api_keys_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.api_keys ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME public.api_keys_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 220 (class 1259 OID 16402)
|
||||
-- Name: artist_aliases; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.artist_aliases (
|
||||
artist_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
source text NOT NULL,
|
||||
is_primary boolean NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.artist_aliases OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 227 (class 1259 OID 16839)
|
||||
-- Name: artist_releases; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.artist_releases (
|
||||
artist_id integer NOT NULL,
|
||||
release_id integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.artist_releases OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 223 (class 1259 OID 16469)
|
||||
-- Name: artist_tracks; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.artist_tracks (
|
||||
artist_id integer NOT NULL,
|
||||
track_id integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.artist_tracks OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 219 (class 1259 OID 16393)
|
||||
-- Name: artists; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.artists (
|
||||
id integer NOT NULL,
|
||||
musicbrainz_id uuid,
|
||||
image text,
|
||||
image_source text
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.artists OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 218 (class 1259 OID 16392)
|
||||
-- Name: artists_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.artists ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME public.artists_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 235 (class 1259 OID 16980)
|
||||
-- Name: artists_with_name; Type: VIEW; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE VIEW public.artists_with_name AS
|
||||
SELECT a.id,
|
||||
a.musicbrainz_id,
|
||||
a.image,
|
||||
a.image_source,
|
||||
aa.alias AS name
|
||||
FROM (public.artists a
|
||||
JOIN public.artist_aliases aa ON ((aa.artist_id = a.id)))
|
||||
WHERE (aa.is_primary = true);
|
||||
|
||||
|
||||
ALTER VIEW public.artists_with_name OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 217 (class 1259 OID 16386)
|
||||
-- Name: goose_db_version; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.goose_db_version (
|
||||
id integer NOT NULL,
|
||||
version_id bigint NOT NULL,
|
||||
is_applied boolean NOT NULL,
|
||||
tstamp timestamp without time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.goose_db_version OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 216 (class 1259 OID 16385)
|
||||
-- Name: goose_db_version_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.goose_db_version ALTER COLUMN id ADD GENERATED BY DEFAULT AS IDENTITY (
|
||||
SEQUENCE NAME public.goose_db_version_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 224 (class 1259 OID 16485)
|
||||
-- Name: listens; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.listens (
|
||||
track_id integer NOT NULL,
|
||||
listened_at timestamp with time zone NOT NULL,
|
||||
client text,
|
||||
user_id integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.listens OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 232 (class 1259 OID 16916)
|
||||
-- Name: release_aliases; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.release_aliases (
|
||||
release_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
source text NOT NULL,
|
||||
is_primary boolean NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.release_aliases OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 226 (class 1259 OID 16825)
|
||||
-- Name: releases; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.releases (
|
||||
id integer NOT NULL,
|
||||
musicbrainz_id uuid,
|
||||
image uuid,
|
||||
various_artists boolean DEFAULT false NOT NULL,
|
||||
image_source text
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.releases OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 225 (class 1259 OID 16824)
|
||||
-- Name: releases_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.releases ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME public.releases_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 236 (class 1259 OID 16984)
|
||||
-- Name: releases_with_title; Type: VIEW; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE VIEW public.releases_with_title AS
|
||||
SELECT r.id,
|
||||
r.musicbrainz_id,
|
||||
r.image,
|
||||
r.various_artists,
|
||||
r.image_source,
|
||||
ra.alias AS title
|
||||
FROM (public.releases r
|
||||
JOIN public.release_aliases ra ON ((ra.release_id = r.id)))
|
||||
WHERE (ra.is_primary = true);
|
||||
|
||||
|
||||
ALTER VIEW public.releases_with_title OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 233 (class 1259 OID 16940)
|
||||
-- Name: sessions; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.sessions (
|
||||
id uuid NOT NULL,
|
||||
user_id integer NOT NULL,
|
||||
created_at timestamp without time zone DEFAULT now() NOT NULL,
|
||||
expires_at timestamp without time zone NOT NULL,
|
||||
persistent boolean DEFAULT false NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.sessions OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 234 (class 1259 OID 16967)
|
||||
-- Name: track_aliases; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.track_aliases (
|
||||
track_id integer NOT NULL,
|
||||
alias text NOT NULL,
|
||||
is_primary boolean NOT NULL,
|
||||
source text NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.track_aliases OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 222 (class 1259 OID 16455)
|
||||
-- Name: tracks; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.tracks (
|
||||
id integer NOT NULL,
|
||||
musicbrainz_id uuid,
|
||||
duration integer DEFAULT 0 NOT NULL,
|
||||
release_id integer NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.tracks OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 221 (class 1259 OID 16454)
|
||||
-- Name: tracks_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.tracks ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME public.tracks_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 237 (class 1259 OID 16988)
|
||||
-- Name: tracks_with_title; Type: VIEW; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE VIEW public.tracks_with_title AS
|
||||
SELECT t.id,
|
||||
t.musicbrainz_id,
|
||||
t.duration,
|
||||
t.release_id,
|
||||
ta.alias AS title
|
||||
FROM (public.tracks t
|
||||
JOIN public.track_aliases ta ON ((ta.track_id = t.id)))
|
||||
WHERE (ta.is_primary = true);
|
||||
|
||||
|
||||
ALTER VIEW public.tracks_with_title OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 229 (class 1259 OID 16890)
|
||||
-- Name: users; Type: TABLE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TABLE public.users (
|
||||
id integer NOT NULL,
|
||||
username text NOT NULL,
|
||||
role public.role DEFAULT 'user'::public.role NOT NULL,
|
||||
password bytea NOT NULL
|
||||
);
|
||||
|
||||
|
||||
ALTER TABLE public.users OWNER TO postgres;
|
||||
|
||||
--
|
||||
-- TOC entry 228 (class 1259 OID 16889)
|
||||
-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE public.users ALTER COLUMN id ADD GENERATED ALWAYS AS IDENTITY (
|
||||
SEQUENCE NAME public.users_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3361 (class 2606 OID 16910)
|
||||
-- Name: api_keys api_keys_key_key; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.api_keys
|
||||
ADD CONSTRAINT api_keys_key_key UNIQUE (key);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3363 (class 2606 OID 16908)
|
||||
-- Name: api_keys api_keys_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.api_keys
|
||||
ADD CONSTRAINT api_keys_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3335 (class 2606 OID 16408)
|
||||
-- Name: artist_aliases artist_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_aliases
|
||||
ADD CONSTRAINT artist_aliases_pkey PRIMARY KEY (artist_id, alias);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3354 (class 2606 OID 16843)
|
||||
-- Name: artist_releases artist_releases_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_releases
|
||||
ADD CONSTRAINT artist_releases_pkey PRIMARY KEY (artist_id, release_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3344 (class 2606 OID 16473)
|
||||
-- Name: artist_tracks artist_tracks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_tracks
|
||||
ADD CONSTRAINT artist_tracks_pkey PRIMARY KEY (artist_id, track_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3331 (class 2606 OID 16401)
|
||||
-- Name: artists artists_musicbrainz_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artists
|
||||
ADD CONSTRAINT artists_musicbrainz_id_key UNIQUE (musicbrainz_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3333 (class 2606 OID 16399)
|
||||
-- Name: artists artists_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artists
|
||||
ADD CONSTRAINT artists_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3329 (class 2606 OID 16391)
|
||||
-- Name: goose_db_version goose_db_version_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.goose_db_version
|
||||
ADD CONSTRAINT goose_db_version_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3347 (class 2606 OID 16622)
|
||||
-- Name: listens listens_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.listens
|
||||
ADD CONSTRAINT listens_pkey PRIMARY KEY (track_id, listened_at);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3366 (class 2606 OID 16922)
|
||||
-- Name: release_aliases release_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.release_aliases
|
||||
ADD CONSTRAINT release_aliases_pkey PRIMARY KEY (release_id, alias);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3350 (class 2606 OID 16833)
|
||||
-- Name: releases releases_musicbrainz_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.releases
|
||||
ADD CONSTRAINT releases_musicbrainz_id_key UNIQUE (musicbrainz_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3352 (class 2606 OID 16831)
|
||||
-- Name: releases releases_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.releases
|
||||
ADD CONSTRAINT releases_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3369 (class 2606 OID 16946)
|
||||
-- Name: sessions sessions_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.sessions
|
||||
ADD CONSTRAINT sessions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3371 (class 2606 OID 16973)
|
||||
-- Name: track_aliases track_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.track_aliases
|
||||
ADD CONSTRAINT track_aliases_pkey PRIMARY KEY (track_id, alias);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3340 (class 2606 OID 16463)
|
||||
-- Name: tracks tracks_musicbrainz_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.tracks
|
||||
ADD CONSTRAINT tracks_musicbrainz_id_key UNIQUE (musicbrainz_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3342 (class 2606 OID 16461)
|
||||
-- Name: tracks tracks_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.tracks
|
||||
ADD CONSTRAINT tracks_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3357 (class 2606 OID 16897)
|
||||
-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.users
|
||||
ADD CONSTRAINT users_pkey PRIMARY KEY (id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3359 (class 2606 OID 16899)
|
||||
-- Name: users users_username_key; Type: CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.users
|
||||
ADD CONSTRAINT users_username_key UNIQUE (username);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3336 (class 1259 OID 16936)
|
||||
-- Name: idx_artist_aliases_alias_trgm; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX idx_artist_aliases_alias_trgm ON public.artist_aliases USING gin (alias public.gin_trgm_ops);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3337 (class 1259 OID 16495)
|
||||
-- Name: idx_artist_aliases_artist_id; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX idx_artist_aliases_artist_id ON public.artist_aliases USING btree (artist_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3355 (class 1259 OID 16855)
|
||||
-- Name: idx_artist_releases; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX idx_artist_releases ON public.artist_releases USING btree (artist_id, release_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3364 (class 1259 OID 16937)
|
||||
-- Name: idx_release_aliases_alias_trgm; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX idx_release_aliases_alias_trgm ON public.release_aliases USING gin (alias public.gin_trgm_ops);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3338 (class 1259 OID 16854)
|
||||
-- Name: idx_tracks_release_id; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX idx_tracks_release_id ON public.tracks USING btree (release_id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3345 (class 1259 OID 16498)
|
||||
-- Name: listens_listened_at_idx; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX listens_listened_at_idx ON public.listens USING btree (listened_at);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3348 (class 1259 OID 16499)
|
||||
-- Name: listens_track_id_listened_at_idx; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX listens_track_id_listened_at_idx ON public.listens USING btree (track_id, listened_at);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3367 (class 1259 OID 16992)
|
||||
-- Name: release_aliases_release_id_idx; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX release_aliases_release_id_idx ON public.release_aliases USING btree (release_id) WHERE (is_primary = true);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3372 (class 1259 OID 16993)
|
||||
-- Name: track_aliases_track_id_idx; Type: INDEX; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE INDEX track_aliases_track_id_idx ON public.track_aliases USING btree (track_id) WHERE (is_primary = true);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3384 (class 2620 OID 16964)
|
||||
-- Name: artist_releases trg_delete_orphan_releases; Type: TRIGGER; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
CREATE TRIGGER trg_delete_orphan_releases AFTER DELETE ON public.artist_releases FOR EACH ROW EXECUTE FUNCTION public.delete_orphan_releases();
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3380 (class 2606 OID 16957)
|
||||
-- Name: api_keys api_keys_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.api_keys
|
||||
ADD CONSTRAINT api_keys_user_id_fkey FOREIGN KEY (id) REFERENCES public.users(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3373 (class 2606 OID 16409)
|
||||
-- Name: artist_aliases artist_aliases_artist_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_aliases
|
||||
ADD CONSTRAINT artist_aliases_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES public.artists(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3378 (class 2606 OID 16844)
|
||||
-- Name: artist_releases artist_releases_artist_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_releases
|
||||
ADD CONSTRAINT artist_releases_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES public.artists(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3379 (class 2606 OID 16849)
|
||||
-- Name: artist_releases artist_releases_release_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_releases
|
||||
ADD CONSTRAINT artist_releases_release_id_fkey FOREIGN KEY (release_id) REFERENCES public.releases(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3374 (class 2606 OID 16474)
|
||||
-- Name: artist_tracks artist_tracks_artist_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_tracks
|
||||
ADD CONSTRAINT artist_tracks_artist_id_fkey FOREIGN KEY (artist_id) REFERENCES public.artists(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3375 (class 2606 OID 16479)
|
||||
-- Name: artist_tracks artist_tracks_track_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.artist_tracks
|
||||
ADD CONSTRAINT artist_tracks_track_id_fkey FOREIGN KEY (track_id) REFERENCES public.tracks(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3376 (class 2606 OID 16490)
|
||||
-- Name: listens listens_track_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.listens
|
||||
ADD CONSTRAINT listens_track_id_fkey FOREIGN KEY (track_id) REFERENCES public.tracks(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3377 (class 2606 OID 16952)
|
||||
-- Name: listens listens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.listens
|
||||
ADD CONSTRAINT listens_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3381 (class 2606 OID 16923)
|
||||
-- Name: release_aliases release_aliases_release_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.release_aliases
|
||||
ADD CONSTRAINT release_aliases_release_id_fkey FOREIGN KEY (release_id) REFERENCES public.releases(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3382 (class 2606 OID 16947)
|
||||
-- Name: sessions sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.sessions
|
||||
ADD CONSTRAINT sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id);
|
||||
|
||||
|
||||
--
|
||||
-- TOC entry 3383 (class 2606 OID 16974)
|
||||
-- Name: track_aliases track_aliases_track_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public.track_aliases
|
||||
ADD CONSTRAINT track_aliases_track_id_fkey FOREIGN KEY (track_id) REFERENCES public.tracks(id) ON DELETE CASCADE;
|
||||
|
||||
|
||||
-- Completed on 2025-06-11 14:30:58 UTC
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
|
||||
-- +goose StatementEnd
|
||||
106
db/migrations/old/000001_initial_schema.sql
Normal file
106
db/migrations/old/000001_initial_schema.sql
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
SELECT 'up SQL query';
|
||||
-- +goose StatementEnd
|
||||
|
||||
CREATE TABLE IF NOT EXISTS artists (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY,
|
||||
PRIMARY KEY(id),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
image UUID,
|
||||
image_source TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS artist_aliases (
|
||||
artist_id INT NOT NULL REFERENCES artists(id) ON DELETE CASCADE,
|
||||
alias TEXT NOT NULL,
|
||||
PRIMARY KEY (artist_id, alias),
|
||||
source TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- CREATE TABLE IF NOT EXISTS release_groups (
|
||||
-- id INT NOT NULL GENERATED ALWAYS AS IDENTITY,
|
||||
-- PRIMARY KEY(id),
|
||||
-- musicbrainz_id UUID UNIQUE,
|
||||
-- title TEXT NOT NULL,
|
||||
-- various_artists BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
-- image TEXT
|
||||
-- );
|
||||
|
||||
CREATE TABLE IF NOT EXISTS releases (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY,
|
||||
PRIMARY KEY(id),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
-- release_group_id INT REFERENCES release_groups(id) ON DELETE SET NULL,
|
||||
image UUID,
|
||||
image_source TEXT,
|
||||
various_artists BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
title TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS release_aliases (
|
||||
release_id INT NOT NULL REFERENCES releases(id) ON DELETE CASCADE,
|
||||
alias TEXT NOT NULL,
|
||||
PRIMARY KEY (release_id, alias),
|
||||
source TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS artist_releases (
|
||||
artist_id INT REFERENCES artists(id) ON DELETE CASCADE,
|
||||
release_id INT REFERENCES releases(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (artist_id, release_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS tracks (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY,
|
||||
PRIMARY KEY(id),
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
title TEXT NOT NULL,
|
||||
duration INT NOT NULL DEFAULT 0,
|
||||
release_id INT NOT NULL REFERENCES releases(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS artist_tracks (
|
||||
artist_id INT REFERENCES artists(id) ON DELETE CASCADE,
|
||||
track_id INT REFERENCES tracks(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (artist_id, track_id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS listens (
|
||||
track_id INT NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
|
||||
listened_at TIMESTAMPTZ NOT NULL,
|
||||
PRIMARY KEY(track_id, listened_at)
|
||||
);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX idx_artist_aliases_artist_id ON artist_aliases(artist_id);
|
||||
CREATE INDEX idx_artist_releases ON artist_releases(artist_id, release_id);
|
||||
CREATE INDEX idx_tracks_release_id ON tracks(release_id);
|
||||
CREATE INDEX listens_listened_at_idx ON listens(listened_at);
|
||||
CREATE INDEX listens_track_id_listened_at_idx ON listens(track_id, listened_at);
|
||||
|
||||
-- Trigram search support
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
CREATE INDEX idx_tracks_title_trgm ON tracks USING gin (title gin_trgm_ops);
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
SELECT 'down SQL query';
|
||||
-- +goose StatementEnd
|
||||
|
||||
DROP INDEX idx_artist_aliases_artist_id;
|
||||
DROP INDEX idx_artist_releases;
|
||||
DROP INDEX idx_tracks_release_id;
|
||||
DROP INDEX listens_listened_at_idx;
|
||||
DROP INDEX listens_track_id_listened_at_idx;
|
||||
DROP INDEX idx_tracks_title_trgm;
|
||||
|
||||
DROP TABLE listens;
|
||||
DROP TABLE artist_aliases;
|
||||
DROP TABLE artist_releases;
|
||||
DROP TABLE artist_tracks;
|
||||
DROP TABLE tracks;
|
||||
DROP TABLE releases;
|
||||
DROP TABLE release_groups;
|
||||
DROP TABLE artists;
|
||||
87
db/migrations/old/20250603_switch_to_release_ids.sql
Normal file
87
db/migrations/old/20250603_switch_to_release_ids.sql
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
-- Step 1: Create new releases table with surrogate ID
|
||||
DROP TABLE releases;
|
||||
CREATE TABLE releases (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
musicbrainz_id UUID UNIQUE,
|
||||
release_group_id INT REFERENCES release_groups(id) ON DELETE SET NULL,
|
||||
title TEXT NOT NULL
|
||||
);
|
||||
|
||||
-- Step 2: Create artist_releases (replaces artist_release_groups)
|
||||
CREATE TABLE artist_releases (
|
||||
artist_id INT REFERENCES artists(id) ON DELETE CASCADE,
|
||||
release_id INT REFERENCES releases(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (artist_id, release_id)
|
||||
);
|
||||
|
||||
-- Step 3: Populate releases with one release per release_group
|
||||
INSERT INTO releases (musicbrainz_id, release_group_id, title)
|
||||
SELECT musicbrainz_id, id AS release_group_id, title
|
||||
FROM release_groups;
|
||||
|
||||
-- Step 4: Add release_id to tracks temporarily
|
||||
ALTER TABLE tracks ADD COLUMN release_id INT;
|
||||
|
||||
-- Step 5: Fill release_id in tracks from the newly inserted releases
|
||||
UPDATE tracks
|
||||
SET release_id = releases.id
|
||||
FROM releases
|
||||
WHERE tracks.release_group_id = releases.release_group_id;
|
||||
|
||||
-- Step 6: Set release_id to NOT NULL now that it's populated
|
||||
ALTER TABLE tracks ALTER COLUMN release_id SET NOT NULL;
|
||||
|
||||
-- Step 7: Drop old FK and column for release_group_id
|
||||
ALTER TABLE tracks DROP CONSTRAINT tracks_release_group_id_fkey;
|
||||
ALTER TABLE tracks DROP COLUMN release_group_id;
|
||||
|
||||
-- Step 8: Drop old artist_release_groups and migrate to artist_releases
|
||||
INSERT INTO artist_releases (artist_id, release_id)
|
||||
SELECT arg.artist_id, r.id
|
||||
FROM artist_release_groups arg
|
||||
JOIN releases r ON arg.release_group_id = r.release_group_id;
|
||||
|
||||
DROP TABLE artist_release_groups;
|
||||
|
||||
-- Step 9: Add indexes for new relations
|
||||
CREATE INDEX idx_tracks_release_id ON tracks(release_id);
|
||||
CREATE INDEX idx_artist_releases ON artist_releases(artist_id, release_id);
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
-- Rollback: Recreate artist_release_groups
|
||||
CREATE TABLE artist_release_groups (
|
||||
artist_id INT REFERENCES artists(id) ON DELETE CASCADE,
|
||||
release_group_id INT REFERENCES release_groups(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY (artist_id, release_group_id)
|
||||
);
|
||||
|
||||
-- Recreate release_group_id in tracks
|
||||
ALTER TABLE tracks ADD COLUMN release_group_id INT;
|
||||
|
||||
-- Restore release_group_id values
|
||||
UPDATE tracks
|
||||
SET release_group_id = r.release_group_id
|
||||
FROM releases r
|
||||
WHERE tracks.release_id = r.id;
|
||||
|
||||
-- Restore artist_release_groups values
|
||||
INSERT INTO artist_release_groups (artist_id, release_group_id)
|
||||
SELECT ar.artist_id, r.release_group_id
|
||||
FROM artist_releases ar
|
||||
JOIN releases r ON ar.release_id = r.id;
|
||||
|
||||
-- Drop new tables and columns
|
||||
ALTER TABLE tracks DROP COLUMN release_id;
|
||||
DROP INDEX IF EXISTS idx_tracks_release_id;
|
||||
DROP INDEX IF EXISTS idx_artist_releases;
|
||||
DROP TABLE artist_releases;
|
||||
DROP TABLE releases;
|
||||
|
||||
-- +goose StatementEnd
|
||||
52
db/migrations/old/20250606_users_and_source_tracking.sql
Normal file
52
db/migrations/old/20250606_users_and_source_tracking.sql
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
CREATE TYPE role AS ENUM ('admin', 'user');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY,
|
||||
PRIMARY KEY(id),
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password TEXT NOT NULL,
|
||||
role role NOT NULL DEFAULT 'user'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
id INT NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
user_id INT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
label TEXT
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS release_aliases (
|
||||
release_id INT NOT NULL REFERENCES releases(id) ON DELETE CASCADE,
|
||||
alias TEXT NOT NULL,
|
||||
PRIMARY KEY (release_id, alias),
|
||||
source TEXT NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE listens
|
||||
ADD user_id INT NOT NULL REFERENCES users(id);
|
||||
ALTER TABLE listens
|
||||
ADD client TEXT;
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
ALTER TABLE listens
|
||||
DROP COLUMN client;
|
||||
ALTER TABLE listens
|
||||
DROP COLUMN user_id;
|
||||
|
||||
DROP TABLE IF EXISTS release_aliases;
|
||||
|
||||
DROP TABLE IF EXISTS api_keys;
|
||||
|
||||
DROP TABLE IF EXISTS users;
|
||||
|
||||
DROP TYPE IF EXISTS role;
|
||||
|
||||
-- +goose StatementEnd
|
||||
8
db/migrations/old/20250607_populate_release_aliases.sql
Normal file
8
db/migrations/old/20250607_populate_release_aliases.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
INSERT INTO release_aliases (release_id, alias, source)
|
||||
SELECT id, title, 'Canonical'
|
||||
FROM releases;
|
||||
|
||||
-- +goose StatementEnd
|
||||
7
db/migrations/old/20250608_add_indexes_for_search.sql
Normal file
7
db/migrations/old/20250608_add_indexes_for_search.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
CREATE INDEX idx_artist_aliases_alias_trgm ON artist_aliases USING GIN (alias gin_trgm_ops);
|
||||
CREATE INDEX idx_release_aliases_alias_trgm ON release_aliases USING GIN (alias gin_trgm_ops);
|
||||
|
||||
-- +goose StatementEnd
|
||||
7
db/migrations/old/20250609_default_user.sql
Normal file
7
db/migrations/old/20250609_default_user.sql
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
ALTER TABLE users DROP COLUMN password;
|
||||
ALTER TABLE users ADD password BYTEA NOT NULL;
|
||||
|
||||
-- +goose StatementEnd
|
||||
19
db/migrations/old/20250610_sessions.sql
Normal file
19
db/migrations/old/20250610_sessions.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
CREATE TABLE sessions (
|
||||
id UUID PRIMARY KEY,
|
||||
user_id INT NOT NULL REFERENCES users(id),
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
expires_at TIMESTAMP NOT NULL,
|
||||
persistent BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
DROP TABLE IF EXISTS sessions;
|
||||
|
||||
-- +goose StatementEnd
|
||||
30
db/migrations/old/20250611_release_delete_trigger.sql
Normal file
30
db/migrations/old/20250611_release_delete_trigger.sql
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
CREATE OR REPLACE FUNCTION delete_orphan_releases()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM artist_releases
|
||||
WHERE release_id = OLD.release_id
|
||||
) THEN
|
||||
DELETE FROM releases WHERE id = OLD.release_id;
|
||||
END IF;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER trg_delete_orphan_releases
|
||||
AFTER DELETE ON artist_releases
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION delete_orphan_releases();
|
||||
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
-- +goose StatementBegin
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_delete_orphan_releases ON artist_releases;
|
||||
DROP FUNCTION IF EXISTS delete_orphan_releases;
|
||||
|
||||
-- +goose StatementEnd
|
||||
81
db/migrations/old/20250612_refactor_alias.sql
Normal file
81
db/migrations/old/20250612_refactor_alias.sql
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
|
||||
-- Step 1: Add the column as nullable initially
|
||||
ALTER TABLE artist_aliases
|
||||
ADD COLUMN is_primary boolean;
|
||||
|
||||
-- Step 2: Set it to true if alias matches artist name, false otherwise
|
||||
UPDATE artist_aliases aa
|
||||
SET is_primary = (aa.alias = a.name)
|
||||
FROM artists a
|
||||
WHERE aa.artist_id = a.id;
|
||||
|
||||
-- Step 3: Make the column NOT NULL
|
||||
ALTER TABLE artist_aliases
|
||||
ALTER COLUMN is_primary SET NOT NULL;
|
||||
|
||||
-- Step 1: Add the column as nullable initially
|
||||
ALTER TABLE release_aliases
|
||||
ADD COLUMN is_primary boolean;
|
||||
|
||||
-- Step 2: Set is_primary to true if alias matches release title, false otherwise
|
||||
UPDATE release_aliases ra
|
||||
SET is_primary = (ra.alias = r.title)
|
||||
FROM releases r
|
||||
WHERE ra.release_id = r.id;
|
||||
|
||||
-- Step 3: Make the column NOT NULL
|
||||
ALTER TABLE release_aliases
|
||||
ALTER COLUMN is_primary SET NOT NULL;
|
||||
|
||||
-- Step 1: Create the table
|
||||
CREATE TABLE track_aliases (
|
||||
track_id INTEGER NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
|
||||
alias TEXT NOT NULL,
|
||||
is_primary BOOLEAN NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
PRIMARY KEY (track_id, alias)
|
||||
);
|
||||
|
||||
-- Step 2: Insert canonical titles from the tracks table
|
||||
INSERT INTO track_aliases (track_id, alias, is_primary, source)
|
||||
SELECT
|
||||
id,
|
||||
title,
|
||||
TRUE,
|
||||
'Canonical'
|
||||
FROM tracks;
|
||||
|
||||
ALTER TABLE artists DROP COLUMN IF EXISTS name;
|
||||
ALTER TABLE tracks DROP COLUMN IF EXISTS title;
|
||||
ALTER TABLE releases DROP COLUMN IF EXISTS title;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS artists_with_name AS
|
||||
SELECT
|
||||
a.*,
|
||||
aa.alias AS name
|
||||
FROM artists a
|
||||
JOIN artist_aliases aa ON aa.artist_id = a.id
|
||||
WHERE aa.is_primary = TRUE;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS releases_with_title AS
|
||||
SELECT
|
||||
r.*,
|
||||
ra.alias AS title
|
||||
FROM releases r
|
||||
JOIN release_aliases ra ON ra.release_id = r.id
|
||||
WHERE ra.is_primary = TRUE;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS tracks_with_title AS
|
||||
SELECT
|
||||
t.*,
|
||||
ta.alias AS title
|
||||
FROM tracks t
|
||||
JOIN track_aliases ta ON ta.track_id = t.id
|
||||
WHERE ta.is_primary = TRUE;
|
||||
|
||||
CREATE INDEX ON release_aliases (release_id) WHERE is_primary = TRUE;
|
||||
CREATE INDEX ON track_aliases (track_id) WHERE is_primary = TRUE;
|
||||
|
||||
-- +goose StatementEnd
|
||||
65
db/queries/alias.sql
Normal file
65
db/queries/alias.sql
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
-- name: InsertArtistAlias :exec
|
||||
INSERT INTO artist_aliases (artist_id, alias, source, is_primary)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetAllArtistAliases :many
|
||||
SELECT * FROM artist_aliases
|
||||
WHERE artist_id = $1 ORDER BY is_primary DESC;
|
||||
|
||||
-- name: GetArtistAlias :one
|
||||
SELECT * FROM artist_aliases
|
||||
WHERE alias = $1 LIMIT 1;
|
||||
|
||||
-- name: SetArtistAliasPrimaryStatus :exec
|
||||
UPDATE artist_aliases SET is_primary = $1 WHERE artist_id = $2 AND alias = $3;
|
||||
|
||||
-- name: DeleteArtistAlias :exec
|
||||
DELETE FROM artist_aliases
|
||||
WHERE artist_id = $1
|
||||
AND alias = $2
|
||||
AND is_primary = false;
|
||||
|
||||
-- name: InsertReleaseAlias :exec
|
||||
INSERT INTO release_aliases (release_id, alias, source, is_primary)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetAllReleaseAliases :many
|
||||
SELECT * FROM release_aliases
|
||||
WHERE release_id = $1 ORDER BY is_primary DESC;
|
||||
|
||||
-- name: GetReleaseAlias :one
|
||||
SELECT * FROM release_aliases
|
||||
WHERE alias = $1 LIMIT 1;
|
||||
|
||||
-- name: SetReleaseAliasPrimaryStatus :exec
|
||||
UPDATE release_aliases SET is_primary = $1 WHERE release_id = $2 AND alias = $3;
|
||||
|
||||
-- name: DeleteReleaseAlias :exec
|
||||
DELETE FROM release_aliases
|
||||
WHERE release_id = $1
|
||||
AND alias = $2
|
||||
AND is_primary = false;
|
||||
|
||||
-- name: InsertTrackAlias :exec
|
||||
INSERT INTO track_aliases (track_id, alias, source, is_primary)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetAllTrackAliases :many
|
||||
SELECT * FROM track_aliases
|
||||
WHERE track_id = $1 ORDER BY is_primary DESC;
|
||||
|
||||
-- name: GetTrackAlias :one
|
||||
SELECT * FROM track_aliases
|
||||
WHERE alias = $1 LIMIT 1;
|
||||
|
||||
-- name: SetTrackAliasPrimaryStatus :exec
|
||||
UPDATE track_aliases SET is_primary = $1 WHERE track_id = $2 AND alias = $3;
|
||||
|
||||
-- name: DeleteTrackAlias :exec
|
||||
DELETE FROM track_aliases
|
||||
WHERE track_id = $1
|
||||
AND alias = $2
|
||||
AND is_primary = false;
|
||||
112
db/queries/artist.sql
Normal file
112
db/queries/artist.sql
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
-- name: InsertArtist :one
|
||||
INSERT INTO artists (musicbrainz_id, image, image_source)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetArtist :one
|
||||
SELECT
|
||||
a.*,
|
||||
array_agg(aa.alias)::text[] AS aliases
|
||||
FROM artists_with_name a
|
||||
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
||||
WHERE a.id = $1
|
||||
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name;
|
||||
|
||||
-- name: GetTrackArtists :many
|
||||
SELECT
|
||||
a.*
|
||||
FROM artists_with_name a
|
||||
LEFT JOIN artist_tracks at ON a.id = at.artist_id
|
||||
WHERE at.track_id = $1
|
||||
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name;
|
||||
|
||||
-- name: GetArtistByImage :one
|
||||
SELECT * FROM artists WHERE image = $1 LIMIT 1;
|
||||
|
||||
-- name: GetReleaseArtists :many
|
||||
SELECT
|
||||
a.*
|
||||
FROM artists_with_name a
|
||||
LEFT JOIN artist_releases ar ON a.id = ar.artist_id
|
||||
WHERE ar.release_id = $1
|
||||
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name;
|
||||
|
||||
-- name: GetArtistByName :one
|
||||
WITH artist_with_aliases AS (
|
||||
SELECT
|
||||
a.*,
|
||||
COALESCE(array_agg(aa.alias), '{}')::text[] AS aliases
|
||||
FROM artists_with_name a
|
||||
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
||||
WHERE a.id IN (
|
||||
SELECT aa2.artist_id FROM artist_aliases aa2 WHERE aa2.alias = $1
|
||||
)
|
||||
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name
|
||||
)
|
||||
SELECT * FROM artist_with_aliases;
|
||||
|
||||
-- name: GetArtistByMbzID :one
|
||||
SELECT
|
||||
a.*,
|
||||
array_agg(aa.alias)::text[] AS aliases
|
||||
FROM artists_with_name a
|
||||
LEFT JOIN artist_aliases aa ON a.id = aa.artist_id
|
||||
WHERE a.musicbrainz_id = $1
|
||||
GROUP BY a.id, a.musicbrainz_id, a.image, a.image_source, a.name;
|
||||
|
||||
-- name: GetTopArtistsPaginated :many
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.musicbrainz_id,
|
||||
a.image,
|
||||
COUNT(*) AS listen_count
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
JOIN artist_tracks at ON at.track_id = t.id
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
GROUP BY a.id, a.name, a.musicbrainz_id, a.image, a.image_source, a.name
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: CountTopArtists :one
|
||||
SELECT COUNT(DISTINCT at.artist_id) AS total_count
|
||||
FROM listens l
|
||||
JOIN artist_tracks at ON l.track_id = at.track_id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2;
|
||||
|
||||
-- name: UpdateArtistMbzID :exec
|
||||
UPDATE artists SET musicbrainz_id = $2
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: UpdateArtistImage :exec
|
||||
UPDATE artists SET image = $2, image_source = $3
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: DeleteConflictingArtistTracks :exec
|
||||
DELETE FROM artist_tracks at
|
||||
WHERE at.artist_id = $1
|
||||
AND track_id IN (
|
||||
SELECT at.track_id FROM artist_tracks at WHERE at.artist_id = $2
|
||||
);
|
||||
|
||||
-- name: UpdateArtistTracks :exec
|
||||
UPDATE artist_tracks
|
||||
SET artist_id = $2
|
||||
WHERE artist_id = $1;
|
||||
|
||||
-- name: DeleteConflictingArtistReleases :exec
|
||||
DELETE FROM artist_releases ar
|
||||
WHERE ar.artist_id = $1
|
||||
AND release_id IN (
|
||||
SELECT ar.release_id FROM artist_releases ar WHERE ar.artist_id = $2
|
||||
);
|
||||
|
||||
-- name: UpdateArtistReleases :exec
|
||||
UPDATE artist_releases
|
||||
SET artist_id = $2
|
||||
WHERE artist_id = $1;
|
||||
|
||||
-- name: DeleteArtist :exec
|
||||
DELETE FROM artists WHERE id = $1;
|
||||
9
db/queries/etc.sql
Normal file
9
db/queries/etc.sql
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
-- name: CleanOrphanedEntries :exec
|
||||
DO $$
|
||||
BEGIN
|
||||
DELETE FROM tracks WHERE id NOT IN (SELECT l.track_id FROM listens l);
|
||||
DELETE FROM releases WHERE id NOT IN (SELECT t.release_id FROM tracks t);
|
||||
-- DELETE FROM releases WHERE release_group_id NOT IN (SELECT t.release_group_id FROM tracks t);
|
||||
-- DELETE FROM releases WHERE release_group_id NOT IN (SELECT rg.id FROM release_groups rg);
|
||||
DELETE FROM artists WHERE id NOT IN (SELECT at.artist_id FROM artist_tracks at);
|
||||
END $$;
|
||||
222
db/queries/listen.sql
Normal file
222
db/queries/listen.sql
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
-- name: InsertListen :exec
|
||||
INSERT INTO listens (track_id, listened_at, user_id, client)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetLastListensPaginated :many
|
||||
SELECT
|
||||
l.*,
|
||||
t.title AS track_title,
|
||||
t.release_id AS release_id,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
ORDER BY l.listened_at DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetLastListensFromArtistPaginated :many
|
||||
SELECT
|
||||
l.*,
|
||||
t.title AS track_title,
|
||||
t.release_id AS release_id,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
JOIN artist_tracks at ON t.id = at.track_id
|
||||
WHERE at.artist_id = $5
|
||||
AND l.listened_at BETWEEN $1 AND $2
|
||||
ORDER BY l.listened_at DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetLastListensFromReleasePaginated :many
|
||||
SELECT
|
||||
l.*,
|
||||
t.title AS track_title,
|
||||
t.release_id AS release_id,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.release_id = $5
|
||||
ORDER BY l.listened_at DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetLastListensFromTrackPaginated :many
|
||||
SELECT
|
||||
l.*,
|
||||
t.title AS track_title,
|
||||
t.release_id AS release_id,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.id = $5
|
||||
ORDER BY l.listened_at DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: CountListens :one
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM listens l
|
||||
WHERE l.listened_at BETWEEN $1 AND $2;
|
||||
|
||||
-- name: CountListensFromTrack :one
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM listens l
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND l.track_id = $3;
|
||||
|
||||
-- name: CountListensFromArtist :one
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM listens l
|
||||
JOIN artist_tracks at ON l.track_id = at.track_id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND at.artist_id = $3;
|
||||
|
||||
-- name: CountListensFromRelease :one
|
||||
SELECT COUNT(*) AS total_count
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.release_id = $3;
|
||||
|
||||
-- name: CountTimeListened :one
|
||||
SELECT COALESCE(SUM(t.duration), 0)::BIGINT AS seconds_listened
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2;
|
||||
|
||||
-- name: CountTimeListenedToArtist :one
|
||||
SELECT COALESCE(SUM(t.duration), 0)::BIGINT AS seconds_listened
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
JOIN artist_tracks at ON t.id = at.track_id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND at.artist_id = $3;
|
||||
|
||||
-- name: CountTimeListenedToRelease :one
|
||||
SELECT COALESCE(SUM(t.duration), 0)::BIGINT AS seconds_listened
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.release_id = $3;
|
||||
|
||||
-- name: CountTimeListenedToTrack :one
|
||||
SELECT COALESCE(SUM(t.duration), 0)::BIGINT AS seconds_listened
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.id = $3;
|
||||
|
||||
-- name: ListenActivity :many
|
||||
WITH buckets AS (
|
||||
SELECT generate_series($1::timestamptz, $2::timestamptz, $3::interval) AS bucket_start
|
||||
),
|
||||
bucketed_listens AS (
|
||||
SELECT
|
||||
b.bucket_start,
|
||||
COUNT(l.listened_at) AS listen_count
|
||||
FROM buckets b
|
||||
LEFT JOIN listens l
|
||||
ON l.listened_at >= b.bucket_start
|
||||
AND l.listened_at < b.bucket_start + $3::interval
|
||||
GROUP BY b.bucket_start
|
||||
ORDER BY b.bucket_start
|
||||
)
|
||||
SELECT * FROM bucketed_listens;
|
||||
|
||||
-- name: ListenActivityForArtist :many
|
||||
WITH buckets AS (
|
||||
SELECT generate_series($1::timestamptz, $2::timestamptz, $3::interval) AS bucket_start
|
||||
),
|
||||
filtered_listens AS (
|
||||
SELECT l.*
|
||||
FROM listens l
|
||||
JOIN artist_tracks t ON l.track_id = t.track_id
|
||||
WHERE t.artist_id = $4
|
||||
),
|
||||
bucketed_listens AS (
|
||||
SELECT
|
||||
b.bucket_start,
|
||||
COUNT(l.listened_at) AS listen_count
|
||||
FROM buckets b
|
||||
LEFT JOIN filtered_listens l
|
||||
ON l.listened_at >= b.bucket_start
|
||||
AND l.listened_at < b.bucket_start + $3::interval
|
||||
GROUP BY b.bucket_start
|
||||
ORDER BY b.bucket_start
|
||||
)
|
||||
SELECT * FROM bucketed_listens;
|
||||
|
||||
-- name: ListenActivityForRelease :many
|
||||
WITH buckets AS (
|
||||
SELECT generate_series($1::timestamptz, $2::timestamptz, $3::interval) AS bucket_start
|
||||
),
|
||||
filtered_listens AS (
|
||||
SELECT l.*
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE t.release_id = $4
|
||||
),
|
||||
bucketed_listens AS (
|
||||
SELECT
|
||||
b.bucket_start,
|
||||
COUNT(l.listened_at) AS listen_count
|
||||
FROM buckets b
|
||||
LEFT JOIN filtered_listens l
|
||||
ON l.listened_at >= b.bucket_start
|
||||
AND l.listened_at < b.bucket_start + $3::interval
|
||||
GROUP BY b.bucket_start
|
||||
ORDER BY b.bucket_start
|
||||
)
|
||||
SELECT * FROM bucketed_listens;
|
||||
|
||||
-- name: ListenActivityForTrack :many
|
||||
WITH buckets AS (
|
||||
SELECT generate_series($1::timestamptz, $2::timestamptz, $3::interval) AS bucket_start
|
||||
),
|
||||
filtered_listens AS (
|
||||
SELECT l.*
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE t.id = $4
|
||||
),
|
||||
bucketed_listens AS (
|
||||
SELECT
|
||||
b.bucket_start,
|
||||
COUNT(l.listened_at) AS listen_count
|
||||
FROM buckets b
|
||||
LEFT JOIN filtered_listens l
|
||||
ON l.listened_at >= b.bucket_start
|
||||
AND l.listened_at < b.bucket_start + $3::interval
|
||||
GROUP BY b.bucket_start
|
||||
ORDER BY b.bucket_start
|
||||
)
|
||||
SELECT * FROM bucketed_listens;
|
||||
|
||||
-- name: UpdateTrackIdForListens :exec
|
||||
UPDATE listens SET track_id = $2
|
||||
WHERE track_id = $1;
|
||||
|
||||
-- name: DeleteListen :exec
|
||||
DELETE FROM listens WHERE track_id = $1 AND listened_at = $2;
|
||||
118
db/queries/release.sql
Normal file
118
db/queries/release.sql
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
-- name: InsertRelease :one
|
||||
INSERT INTO releases (musicbrainz_id, various_artists, image, image_source)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetRelease :one
|
||||
SELECT * FROM releases_with_title
|
||||
WHERE id = $1 LIMIT 1;
|
||||
|
||||
-- name: GetReleaseByMbzID :one
|
||||
SELECT * FROM releases_with_title
|
||||
WHERE musicbrainz_id = $1 LIMIT 1;
|
||||
|
||||
-- name: GetReleaseByImageID :one
|
||||
SELECT * FROM releases
|
||||
WHERE image = $1 LIMIT 1;
|
||||
|
||||
-- name: GetReleaseByArtistAndTitle :one
|
||||
SELECT r.*
|
||||
FROM releases_with_title r
|
||||
JOIN artist_releases ar ON r.id = ar.release_id
|
||||
WHERE r.title = $1 AND ar.artist_id = $2
|
||||
LIMIT 1;
|
||||
|
||||
-- name: GetReleaseByArtistAndTitles :one
|
||||
SELECT r.*
|
||||
FROM releases_with_title r
|
||||
JOIN artist_releases ar ON r.id = ar.release_id
|
||||
WHERE r.title = ANY ($1::TEXT[]) AND ar.artist_id = $2
|
||||
LIMIT 1;
|
||||
|
||||
-- name: GetTopReleasesFromArtist :many
|
||||
SELECT
|
||||
r.*,
|
||||
COUNT(*) AS listen_count,
|
||||
(
|
||||
SELECT json_agg(DISTINCT jsonb_build_object('id', a.id, 'name', a.name))
|
||||
FROM artists_with_name a
|
||||
JOIN artist_releases ar ON ar.artist_id = a.id
|
||||
WHERE ar.release_id = r.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
JOIN releases_with_title r ON t.release_id = r.id
|
||||
JOIN artist_releases ar ON r.id = ar.release_id
|
||||
WHERE ar.artist_id = $5
|
||||
AND l.listened_at BETWEEN $1 AND $2
|
||||
GROUP BY r.id, r.title, r.musicbrainz_id, r.various_artists, r.image, r.image_source
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetTopReleasesPaginated :many
|
||||
SELECT
|
||||
r.*,
|
||||
COUNT(*) AS listen_count,
|
||||
(
|
||||
SELECT json_agg(DISTINCT jsonb_build_object('id', a.id, 'name', a.name))
|
||||
FROM artists_with_name a
|
||||
JOIN artist_releases ar ON ar.artist_id = a.id
|
||||
WHERE ar.release_id = r.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
JOIN releases_with_title r ON t.release_id = r.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
GROUP BY r.id, r.title, r.musicbrainz_id, r.various_artists, r.image, r.image_source
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: CountTopReleases :one
|
||||
SELECT COUNT(DISTINCT r.id) AS total_count
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2;
|
||||
|
||||
-- name: CountReleasesFromArtist :one
|
||||
SELECT COUNT(*)
|
||||
FROM releases r
|
||||
JOIN artist_releases ar ON r.id = ar.release_id
|
||||
WHERE ar.artist_id = $1;
|
||||
|
||||
-- name: AssociateArtistToRelease :exec
|
||||
INSERT INTO artist_releases (artist_id, release_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetReleasesWithoutImages :many
|
||||
SELECT
|
||||
r.*,
|
||||
(
|
||||
SELECT json_agg(DISTINCT jsonb_build_object('id', a.id, 'name', a.name))
|
||||
FROM artists_with_name a
|
||||
JOIN artist_releases ar ON a.id = ar.artist_id
|
||||
WHERE ar.release_id = r.id
|
||||
) AS artists
|
||||
FROM releases_with_title r
|
||||
WHERE r.image IS NULL
|
||||
AND r.id > $2
|
||||
ORDER BY r.id ASC
|
||||
LIMIT $1;
|
||||
|
||||
-- name: UpdateReleaseMbzID :exec
|
||||
UPDATE releases SET musicbrainz_id = $2
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: UpdateReleaseImage :exec
|
||||
UPDATE releases SET image = $2, image_source = $3
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: DeleteRelease :exec
|
||||
DELETE FROM releases WHERE id = $1;
|
||||
|
||||
-- name: DeleteReleasesFromArtist :exec
|
||||
DELETE FROM releases r
|
||||
USING artist_releases ar
|
||||
WHERE ar.release_id = r.id
|
||||
AND ar.artist_id = $1;
|
||||
161
db/queries/search.sql
Normal file
161
db/queries/search.sql
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
-- name: SearchArtists :many
|
||||
SELECT id, name, musicbrainz_id, image, score
|
||||
FROM (
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.musicbrainz_id,
|
||||
a.image,
|
||||
similarity(aa.alias, $1) AS score,
|
||||
ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY similarity(aa.alias, $1) DESC) AS rn
|
||||
FROM artist_aliases aa
|
||||
JOIN artists_with_name a ON aa.artist_id = a.id
|
||||
WHERE similarity(aa.alias, $1) > 0.28
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC
|
||||
LIMIT $2;
|
||||
|
||||
-- name: SearchArtistsBySubstring :many
|
||||
SELECT id, name, musicbrainz_id, image, score
|
||||
FROM (
|
||||
SELECT
|
||||
a.id,
|
||||
a.name,
|
||||
a.musicbrainz_id,
|
||||
a.image,
|
||||
1.0 AS score, -- why
|
||||
ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY aa.alias) AS rn
|
||||
FROM artist_aliases aa
|
||||
JOIN artists_with_name a ON aa.artist_id = a.id
|
||||
WHERE aa.alias ILIKE $1 || '%'
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC
|
||||
LIMIT $2;
|
||||
|
||||
-- name: SearchTracks :many
|
||||
SELECT
|
||||
ranked.id,
|
||||
ranked.title,
|
||||
ranked.musicbrainz_id,
|
||||
ranked.release_id,
|
||||
ranked.image,
|
||||
ranked.score,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = ranked.id
|
||||
) AS artists
|
||||
FROM (
|
||||
SELECT
|
||||
t.id,
|
||||
t.title,
|
||||
t.musicbrainz_id,
|
||||
t.release_id,
|
||||
r.image,
|
||||
similarity(ta.alias, $1) AS score,
|
||||
ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY similarity(ta.alias, $1) DESC) AS rn
|
||||
FROM track_aliases ta
|
||||
JOIN tracks_with_title t ON ta.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE similarity(ta.alias, $1) > 0.28
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC, title
|
||||
LIMIT $2;
|
||||
|
||||
-- name: SearchTracksBySubstring :many
|
||||
SELECT
|
||||
ranked.id,
|
||||
ranked.title,
|
||||
ranked.musicbrainz_id,
|
||||
ranked.release_id,
|
||||
ranked.image,
|
||||
ranked.score,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = ranked.id
|
||||
) AS artists
|
||||
FROM (
|
||||
SELECT
|
||||
t.id,
|
||||
t.title,
|
||||
t.musicbrainz_id,
|
||||
t.release_id,
|
||||
r.image,
|
||||
1.0 AS score,
|
||||
ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY ta.alias) AS rn
|
||||
FROM track_aliases ta
|
||||
JOIN tracks_with_title t ON ta.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE ta.alias ILIKE $1 || '%'
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC, title
|
||||
LIMIT $2;
|
||||
|
||||
-- name: SearchReleases :many
|
||||
SELECT
|
||||
ranked.id,
|
||||
ranked.title,
|
||||
ranked.musicbrainz_id,
|
||||
ranked.image,
|
||||
ranked.various_artists,
|
||||
ranked.score,
|
||||
(
|
||||
SELECT json_agg(DISTINCT jsonb_build_object('id', a.id, 'name', a.name))
|
||||
FROM artists_with_name a
|
||||
JOIN artist_releases ar ON ar.artist_id = a.id
|
||||
WHERE ar.release_id = ranked.id
|
||||
) AS artists
|
||||
FROM (
|
||||
SELECT
|
||||
r.id,
|
||||
r.title,
|
||||
r.musicbrainz_id,
|
||||
r.image,
|
||||
r.various_artists,
|
||||
similarity(ra.alias, $1) AS score,
|
||||
ROW_NUMBER() OVER (PARTITION BY r.id ORDER BY similarity(ra.alias, $1) DESC) AS rn
|
||||
FROM release_aliases ra
|
||||
JOIN releases_with_title r ON ra.release_id = r.id
|
||||
WHERE similarity(ra.alias, $1) > 0.28
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC, title
|
||||
LIMIT $2;
|
||||
|
||||
-- name: SearchReleasesBySubstring :many
|
||||
SELECT
|
||||
ranked.id,
|
||||
ranked.title,
|
||||
ranked.musicbrainz_id,
|
||||
ranked.image,
|
||||
ranked.various_artists,
|
||||
ranked.score,
|
||||
(
|
||||
SELECT json_agg(DISTINCT jsonb_build_object('id', a.id, 'name', a.name))
|
||||
FROM artists_with_name a
|
||||
JOIN artist_releases ar ON ar.artist_id = a.id
|
||||
WHERE ar.release_id = ranked.id
|
||||
) AS artists
|
||||
FROM (
|
||||
SELECT
|
||||
r.id,
|
||||
r.title,
|
||||
r.musicbrainz_id,
|
||||
r.image,
|
||||
r.various_artists,
|
||||
1.0 AS score, -- idk why
|
||||
ROW_NUMBER() OVER (PARTITION BY r.id ORDER BY ra.alias) AS rn
|
||||
FROM release_aliases ra
|
||||
JOIN releases_with_title r ON ra.release_id = r.id
|
||||
WHERE ra.alias ILIKE $1 || '%'
|
||||
) ranked
|
||||
WHERE rn = 1
|
||||
ORDER BY score DESC, title
|
||||
LIMIT $2;
|
||||
19
db/queries/sessions.sql
Normal file
19
db/queries/sessions.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
-- name: InsertSession :one
|
||||
INSERT INTO sessions (id, user_id, expires_at, persistent)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetSession :one
|
||||
SELECT * FROM sessions WHERE id = $1 AND expires_at > NOW();
|
||||
|
||||
-- name: UpdateSessionExpiry :exec
|
||||
UPDATE sessions SET expires_at = $2 WHERE id = $1;
|
||||
|
||||
-- name: DeleteSession :exec
|
||||
DELETE FROM sessions WHERE id = $1;
|
||||
|
||||
-- name: GetUserBySession :one
|
||||
SELECT *
|
||||
FROM users u
|
||||
JOIN sessions s ON u.id = s.user_id
|
||||
WHERE s.id = $1;
|
||||
139
db/queries/track.sql
Normal file
139
db/queries/track.sql
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
-- name: InsertTrack :one
|
||||
INSERT INTO tracks (musicbrainz_id, release_id, duration)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
|
||||
-- name: AssociateArtistToTrack :exec
|
||||
INSERT INTO artist_tracks (artist_id, track_id)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: GetTrack :one
|
||||
SELECT
|
||||
t.*,
|
||||
r.image
|
||||
FROM tracks_with_title t
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE t.id = $1 LIMIT 1;
|
||||
|
||||
-- name: GetTrackByMbzID :one
|
||||
SELECT * FROM tracks_with_title
|
||||
WHERE musicbrainz_id = $1 LIMIT 1;
|
||||
|
||||
-- name: GetAllTracksFromArtist :many
|
||||
SELECT t.*
|
||||
FROM tracks_with_title t
|
||||
JOIN artist_tracks at ON t.id = at.track_id
|
||||
WHERE at.artist_id = $1;
|
||||
|
||||
-- name: GetTrackByTitleAndArtists :one
|
||||
SELECT t.*
|
||||
FROM tracks_with_title t
|
||||
JOIN artist_tracks at ON at.track_id = t.id
|
||||
WHERE t.title = $1
|
||||
AND at.artist_id = ANY($2::int[])
|
||||
GROUP BY t.id, t.title, t.musicbrainz_id, t.duration, t.release_id
|
||||
HAVING COUNT(DISTINCT at.artist_id) = cardinality($2::int[]);
|
||||
|
||||
-- name: GetTopTracksPaginated :many
|
||||
SELECT
|
||||
t.id,
|
||||
t.title,
|
||||
t.musicbrainz_id,
|
||||
t.release_id,
|
||||
r.image,
|
||||
COUNT(*) AS listen_count,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at
|
||||
JOIN artists_with_name a ON a.id = at.artist_id
|
||||
WHERE at.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
GROUP BY t.id, t.title, t.musicbrainz_id, t.release_id, r.image
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetTopTracksByArtistPaginated :many
|
||||
SELECT
|
||||
t.id,
|
||||
t.title,
|
||||
t.musicbrainz_id,
|
||||
t.release_id,
|
||||
r.image,
|
||||
COUNT(*) AS listen_count,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at2
|
||||
JOIN artists_with_name a ON a.id = at2.artist_id
|
||||
WHERE at2.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
JOIN artist_tracks at ON at.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND at.artist_id = $5
|
||||
GROUP BY t.id, t.title, t.musicbrainz_id, t.release_id, r.image
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: GetTopTracksInReleasePaginated :many
|
||||
SELECT
|
||||
t.id,
|
||||
t.title,
|
||||
t.musicbrainz_id,
|
||||
t.release_id,
|
||||
r.image,
|
||||
COUNT(*) AS listen_count,
|
||||
(
|
||||
SELECT json_agg(json_build_object('id', a.id, 'name', a.name))
|
||||
FROM artist_tracks at2
|
||||
JOIN artists_with_name a ON a.id = at2.artist_id
|
||||
WHERE at2.track_id = t.id
|
||||
) AS artists
|
||||
FROM listens l
|
||||
JOIN tracks_with_title t ON l.track_id = t.id
|
||||
JOIN releases r ON t.release_id = r.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.release_id = $5
|
||||
GROUP BY t.id, t.title, t.musicbrainz_id, t.release_id, r.image
|
||||
ORDER BY listen_count DESC
|
||||
LIMIT $3 OFFSET $4;
|
||||
|
||||
-- name: CountTopTracks :one
|
||||
SELECT COUNT(DISTINCT l.track_id) AS total_count
|
||||
FROM listens l
|
||||
WHERE l.listened_at BETWEEN $1 AND $2;
|
||||
|
||||
-- name: CountTopTracksByArtist :one
|
||||
SELECT COUNT(DISTINCT l.track_id) AS total_count
|
||||
FROM listens l
|
||||
JOIN artist_tracks at ON l.track_id = at.track_id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND at.artist_id = $3;
|
||||
|
||||
-- name: CountTopTracksByRelease :one
|
||||
SELECT COUNT(DISTINCT l.track_id) AS total_count
|
||||
FROM listens l
|
||||
JOIN tracks t ON l.track_id = t.id
|
||||
WHERE l.listened_at BETWEEN $1 AND $2
|
||||
AND t.release_id = $3;
|
||||
|
||||
-- name: UpdateTrackMbzID :exec
|
||||
UPDATE tracks SET musicbrainz_id = $2
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: UpdateTrackDuration :exec
|
||||
UPDATE tracks SET duration = $2
|
||||
WHERE id = $1;
|
||||
|
||||
-- name: UpdateReleaseForAll :exec
|
||||
UPDATE tracks SET release_id = $2
|
||||
WHERE release_id = $1;
|
||||
|
||||
-- name: DeleteTrack :exec
|
||||
DELETE FROM tracks WHERE id = $1;
|
||||
45
db/queries/users.sql
Normal file
45
db/queries/users.sql
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
-- name: InsertUser :one
|
||||
INSERT INTO users (username, password, role)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteUser :exec
|
||||
DELETE FROM users WHERE id = $1;
|
||||
|
||||
-- name: GetUserByUsername :one
|
||||
SELECT * FROM users WHERE username = $1;
|
||||
|
||||
-- name: CountUsers :one
|
||||
SELECT COUNT(*) FROM users;
|
||||
|
||||
-- name: InsertApiKey :one
|
||||
INSERT INTO api_keys (user_id, key, label)
|
||||
VALUES ($1, $2, $3)
|
||||
RETURNING *;
|
||||
|
||||
-- name: DeleteApiKey :exec
|
||||
DELETE FROM api_keys WHERE id = $1;
|
||||
|
||||
-- name: CountApiKeys :one
|
||||
SELECT COUNT(*) FROM api_keys WHERE user_id = $1;
|
||||
|
||||
-- name: GetUserByApiKey :one
|
||||
SELECT u.*
|
||||
FROM users u
|
||||
JOIN api_keys ak ON u.id = ak.user_id
|
||||
WHERE ak.key = $1;
|
||||
|
||||
-- name: GetAllApiKeysByUserID :many
|
||||
SELECT ak.*
|
||||
FROM api_keys ak
|
||||
JOIN users u ON ak.user_id = u.id
|
||||
WHERE u.id = $1;
|
||||
|
||||
-- name: UpdateUserUsername :exec
|
||||
UPDATE users SET username = $2 WHERE id = $1;
|
||||
|
||||
-- name: UpdateUserPassword :exec
|
||||
UPDATE users SET password = $2 WHERE id = $1;
|
||||
|
||||
-- name: UpdateApiKeyLabel :exec
|
||||
UPDATE api_keys SET label = $3 WHERE id = $1 AND user_id = $2;
|
||||
Loading…
Add table
Add a link
Reference in a new issue