mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-16 10:55:55 -07:00
chore: initial public commit
This commit is contained in:
commit
fc9054b78c
250 changed files with 32809 additions and 0 deletions
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue