From d67c7a0faada861b3fabdb22162717dc51fb9b28 Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Mon, 6 Oct 2025 11:07:31 +0300 Subject: [PATCH] Refactor data synchronization logic and repository structure - Updated the album, artist, track, user, playlist, loved track, and scrobble repositories to include asynchronous data fetching and insertion methods. - Implemented batch processing for syncing albums, artists, tracks, users, playlists, loved tracks, and scrobbles from a source PostgreSQL database to a destination PostgreSQL database. - Enhanced error handling during data insertion to log failures without interrupting the sync process. - Removed unique constraints on albumUri and artistUri fields in the tracks schema to allow for non-unique entries. - Modified user schema to make displayName optional. - Updated journal metadata for versioning. --- ..._sinister.sql => 0000_greedy_vanisher.sql} | 75 +- apps/api/drizzle/0001_woozy_saracen.sql | 1 - apps/api/drizzle/meta/0000_snapshot.json | 24 +- apps/api/drizzle/meta/0001_snapshot.json | 3146 ----------------- apps/api/drizzle/meta/_journal.json | 11 +- apps/api/src/schema/tracks.ts | 4 +- apps/api/src/schema/users.ts | 2 +- crates/pgpull/src/lib.rs | 283 +- crates/pgpull/src/repo/album.rs | 57 + crates/pgpull/src/repo/artist.rs | 58 + crates/pgpull/src/repo/loved_track.rs | 40 + crates/pgpull/src/repo/mod.rs | 1 + crates/pgpull/src/repo/playlist.rs | 50 + crates/pgpull/src/repo/scrobble.rs | 44 + crates/pgpull/src/repo/track.rs | 77 + crates/pgpull/src/repo/user.rs | 36 + 16 files changed, 693 insertions(+), 3216 deletions(-) rename apps/api/drizzle/{0000_quiet_mister_sinister.sql => 0000_greedy_vanisher.sql} (92%) delete mode 100644 apps/api/drizzle/0001_woozy_saracen.sql delete mode 100644 apps/api/drizzle/meta/0001_snapshot.json create mode 100644 crates/pgpull/src/repo/loved_track.rs diff --git a/apps/api/drizzle/0000_quiet_mister_sinister.sql b/apps/api/drizzle/0000_greedy_vanisher.sql similarity index 92% rename from apps/api/drizzle/0000_quiet_mister_sinister.sql rename to apps/api/drizzle/0000_greedy_vanisher.sql index 483b5d88..ad2fd994 100644 --- a/apps/api/drizzle/0000_quiet_mister_sinister.sql +++ b/apps/api/drizzle/0000_greedy_vanisher.sql @@ -1,5 +1,5 @@ CREATE TABLE "album_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "album_id" text NOT NULL, "track_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -8,7 +8,7 @@ CREATE TABLE "album_tracks" ( ); --> statement-breakpoint CREATE TABLE "albums" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "title" text NOT NULL, "artist" text NOT NULL, "release_date" text, @@ -33,7 +33,7 @@ CREATE TABLE "albums" ( ); --> statement-breakpoint CREATE TABLE "api_keys" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "api_key" text NOT NULL, "shared_secret" text NOT NULL, @@ -45,7 +45,7 @@ CREATE TABLE "api_keys" ( ); --> statement-breakpoint CREATE TABLE "artist_albums" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "artist_id" text NOT NULL, "album_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -54,7 +54,7 @@ CREATE TABLE "artist_albums" ( ); --> statement-breakpoint CREATE TABLE "artist_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "artist_id" text NOT NULL, "track_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -63,7 +63,7 @@ CREATE TABLE "artist_tracks" ( ); --> statement-breakpoint CREATE TABLE "artists" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "biography" text, "born" timestamp, @@ -76,6 +76,7 @@ CREATE TABLE "artists" ( "spotify_link" text, "tidal_link" text, "youtube_link" text, + "genres" text[], "xata_createdat" timestamp DEFAULT now() NOT NULL, "xata_updatedat" timestamp DEFAULT now() NOT NULL, "xata_version" integer, @@ -84,7 +85,7 @@ CREATE TABLE "artists" ( ); --> statement-breakpoint CREATE TABLE "dropbox_accounts" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "email" text NOT NULL, "is_beta_user" boolean DEFAULT false NOT NULL, "user_id" text NOT NULL, @@ -95,7 +96,7 @@ CREATE TABLE "dropbox_accounts" ( ); --> statement-breakpoint CREATE TABLE "dropbox_directories" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "path" text NOT NULL, "parent_id" text, @@ -108,7 +109,7 @@ CREATE TABLE "dropbox_directories" ( ); --> statement-breakpoint CREATE TABLE "dropbox_paths" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "path" text NOT NULL, "name" text NOT NULL, "dropbox_id" text NOT NULL, @@ -122,14 +123,14 @@ CREATE TABLE "dropbox_paths" ( ); --> statement-breakpoint CREATE TABLE "dropbox_tokens" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "refresh_token" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, "xata_updatedat" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "dropbox" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "dropbox_token_id" text NOT NULL, "xata_version" text NOT NULL, @@ -138,7 +139,7 @@ CREATE TABLE "dropbox" ( ); --> statement-breakpoint CREATE TABLE "google_drive_accounts" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "email" text NOT NULL, "is_beta_user" boolean DEFAULT false NOT NULL, "user_id" text NOT NULL, @@ -149,7 +150,7 @@ CREATE TABLE "google_drive_accounts" ( ); --> statement-breakpoint CREATE TABLE "google_drive_directories" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "path" text NOT NULL, "parent_id" text, @@ -162,7 +163,7 @@ CREATE TABLE "google_drive_directories" ( ); --> statement-breakpoint CREATE TABLE "google_drive_paths" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "google_drive_id" text NOT NULL, "track_id" text NOT NULL, "name" text NOT NULL, @@ -175,14 +176,14 @@ CREATE TABLE "google_drive_paths" ( ); --> statement-breakpoint CREATE TABLE "google_drive_tokens" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "refresh_token" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, "xata_updatedat" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "google_drive" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "google_drive_token_id" text NOT NULL, "user_id" text NOT NULL, "xata_version" text NOT NULL, @@ -191,7 +192,7 @@ CREATE TABLE "google_drive" ( ); --> statement-breakpoint CREATE TABLE "loved_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "track_id" text NOT NULL, "uri" text, @@ -200,14 +201,14 @@ CREATE TABLE "loved_tracks" ( ); --> statement-breakpoint CREATE TABLE "playlist_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "playlist_id" text NOT NULL, "track_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "playlists" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "picture" text, "description" text, @@ -222,14 +223,14 @@ CREATE TABLE "playlists" ( ); --> statement-breakpoint CREATE TABLE "profile_shouts" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "shout_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "queue_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "track_id" text NOT NULL, "position" integer NOT NULL, @@ -240,7 +241,7 @@ CREATE TABLE "queue_tracks" ( ); --> statement-breakpoint CREATE TABLE "scrobbles" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text, "track_id" text, "album_id" text, @@ -254,7 +255,7 @@ CREATE TABLE "scrobbles" ( ); --> statement-breakpoint CREATE TABLE "shout_likes" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "shout_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -263,14 +264,14 @@ CREATE TABLE "shout_likes" ( ); --> statement-breakpoint CREATE TABLE "shout_reports" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "shout_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL ); --> statement-breakpoint CREATE TABLE "shouts" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "content" text NOT NULL, "track_id" text, "artist_id" text, @@ -285,7 +286,7 @@ CREATE TABLE "shouts" ( ); --> statement-breakpoint CREATE TABLE "spotify_accounts" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "xata_version" integer NOT NULL, "email" text NOT NULL, "user_id" text NOT NULL, @@ -295,7 +296,7 @@ CREATE TABLE "spotify_accounts" ( ); --> statement-breakpoint CREATE TABLE "spotify_tokens" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "xata_version" integer NOT NULL, "access_token" text NOT NULL, "refresh_token" text NOT NULL, @@ -305,7 +306,7 @@ CREATE TABLE "spotify_tokens" ( ); --> statement-breakpoint CREATE TABLE "tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "title" text NOT NULL, "artist" text NOT NULL, "album_artist" text NOT NULL, @@ -337,13 +338,11 @@ CREATE TABLE "tracks" ( CONSTRAINT "tracks_apple_music_link_unique" UNIQUE("apple_music_link"), CONSTRAINT "tracks_tidal_link_unique" UNIQUE("tidal_link"), CONSTRAINT "tracks_sha256_unique" UNIQUE("sha256"), - CONSTRAINT "tracks_uri_unique" UNIQUE("uri"), - CONSTRAINT "tracks_album_uri_unique" UNIQUE("album_uri"), - CONSTRAINT "tracks_artist_uri_unique" UNIQUE("artist_uri") + CONSTRAINT "tracks_uri_unique" UNIQUE("uri") ); --> statement-breakpoint CREATE TABLE "user_albums" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "album_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -355,7 +354,7 @@ CREATE TABLE "user_albums" ( ); --> statement-breakpoint CREATE TABLE "user_artists" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "artist_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -367,7 +366,7 @@ CREATE TABLE "user_artists" ( ); --> statement-breakpoint CREATE TABLE "user_playlists" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "playlist_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -376,7 +375,7 @@ CREATE TABLE "user_playlists" ( ); --> statement-breakpoint CREATE TABLE "user_tracks" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "user_id" text NOT NULL, "track_id" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -388,9 +387,9 @@ CREATE TABLE "user_tracks" ( ); --> statement-breakpoint CREATE TABLE "users" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "did" text NOT NULL, - "display_name" text NOT NULL, + "display_name" text, "handle" text NOT NULL, "avatar" text NOT NULL, "xata_createdat" timestamp DEFAULT now() NOT NULL, @@ -401,7 +400,7 @@ CREATE TABLE "users" ( ); --> statement-breakpoint CREATE TABLE "webscrobblers" ( - "xata_id" text PRIMARY KEY DEFAULT xata_id(), + "xata_id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "uuid" text NOT NULL, "description" text, diff --git a/apps/api/drizzle/0001_woozy_saracen.sql b/apps/api/drizzle/0001_woozy_saracen.sql deleted file mode 100644 index efc652b1..00000000 --- a/apps/api/drizzle/0001_woozy_saracen.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE "artists" ADD COLUMN "genres" text[]; \ No newline at end of file diff --git a/apps/api/drizzle/meta/0000_snapshot.json b/apps/api/drizzle/meta/0000_snapshot.json index cfb7d870..01d8080d 100644 --- a/apps/api/drizzle/meta/0000_snapshot.json +++ b/apps/api/drizzle/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "49adc24b-83c8-4065-8e13-80045e7f0f27", + "id": "97b0b357-40d7-42b5-ab53-2738bd804a2c", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -558,6 +558,12 @@ "primaryKey": false, "notNull": false }, + "genres": { + "name": "genres", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, "xata_createdat": { "name": "xata_createdat", "type": "timestamp", @@ -2576,20 +2582,6 @@ "columns": [ "uri" ] - }, - "tracks_album_uri_unique": { - "name": "tracks_album_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "album_uri" - ] - }, - "tracks_artist_uri_unique": { - "name": "tracks_artist_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "artist_uri" - ] } }, "policies": {}, @@ -2989,7 +2981,7 @@ "name": "display_name", "type": "text", "primaryKey": false, - "notNull": true + "notNull": false }, "handle": { "name": "handle", diff --git a/apps/api/drizzle/meta/0001_snapshot.json b/apps/api/drizzle/meta/0001_snapshot.json deleted file mode 100644 index 00bc9abd..00000000 --- a/apps/api/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,3146 +0,0 @@ -{ - "id": "aeb183b0-c260-41fa-959b-2cde9fced54e", - "prevId": "49adc24b-83c8-4065-8e13-80045e7f0f27", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.album_tracks": { - "name": "album_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "album_id": { - "name": "album_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "album_tracks_album_id_albums_xata_id_fk": { - "name": "album_tracks_album_id_albums_xata_id_fk", - "tableFrom": "album_tracks", - "tableTo": "albums", - "columnsFrom": [ - "album_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "album_tracks_track_id_tracks_xata_id_fk": { - "name": "album_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "album_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.albums": { - "name": "albums", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artist": { - "name": "artist", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "release_date": { - "name": "release_date", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "year": { - "name": "year", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "album_art": { - "name": "album_art", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artist_uri": { - "name": "artist_uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "apple_music_link": { - "name": "apple_music_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "spotify_link": { - "name": "spotify_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tidal_link": { - "name": "tidal_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "youtube_link": { - "name": "youtube_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sha256": { - "name": "sha256", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "albums_uri_unique": { - "name": "albums_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - }, - "albums_apple_music_link_unique": { - "name": "albums_apple_music_link_unique", - "nullsNotDistinct": false, - "columns": [ - "apple_music_link" - ] - }, - "albums_spotify_link_unique": { - "name": "albums_spotify_link_unique", - "nullsNotDistinct": false, - "columns": [ - "spotify_link" - ] - }, - "albums_tidal_link_unique": { - "name": "albums_tidal_link_unique", - "nullsNotDistinct": false, - "columns": [ - "tidal_link" - ] - }, - "albums_youtube_link_unique": { - "name": "albums_youtube_link_unique", - "nullsNotDistinct": false, - "columns": [ - "youtube_link" - ] - }, - "albums_sha256_unique": { - "name": "albums_sha256_unique", - "nullsNotDistinct": false, - "columns": [ - "sha256" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.api_keys": { - "name": "api_keys", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "api_key": { - "name": "api_key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "shared_secret": { - "name": "shared_secret", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "api_keys_user_id_users_xata_id_fk": { - "name": "api_keys_user_id_users_xata_id_fk", - "tableFrom": "api_keys", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.artist_albums": { - "name": "artist_albums", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "artist_id": { - "name": "artist_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "album_id": { - "name": "album_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "artist_albums_artist_id_artists_xata_id_fk": { - "name": "artist_albums_artist_id_artists_xata_id_fk", - "tableFrom": "artist_albums", - "tableTo": "artists", - "columnsFrom": [ - "artist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "artist_albums_album_id_albums_xata_id_fk": { - "name": "artist_albums_album_id_albums_xata_id_fk", - "tableFrom": "artist_albums", - "tableTo": "albums", - "columnsFrom": [ - "album_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.artist_tracks": { - "name": "artist_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "artist_id": { - "name": "artist_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "artist_tracks_artist_id_artists_xata_id_fk": { - "name": "artist_tracks_artist_id_artists_xata_id_fk", - "tableFrom": "artist_tracks", - "tableTo": "artists", - "columnsFrom": [ - "artist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "artist_tracks_track_id_tracks_xata_id_fk": { - "name": "artist_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "artist_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.artists": { - "name": "artists", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "biography": { - "name": "biography", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "born": { - "name": "born", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "born_in": { - "name": "born_in", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "died": { - "name": "died", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "picture": { - "name": "picture", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sha256": { - "name": "sha256", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "apple_music_link": { - "name": "apple_music_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "spotify_link": { - "name": "spotify_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tidal_link": { - "name": "tidal_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "youtube_link": { - "name": "youtube_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "genres": { - "name": "genres", - "type": "text[]", - "primaryKey": false, - "notNull": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "artists_sha256_unique": { - "name": "artists_sha256_unique", - "nullsNotDistinct": false, - "columns": [ - "sha256" - ] - }, - "artists_uri_unique": { - "name": "artists_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dropbox_accounts": { - "name": "dropbox_accounts", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_beta_user": { - "name": "is_beta_user", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "dropbox_accounts_user_id_users_xata_id_fk": { - "name": "dropbox_accounts_user_id_users_xata_id_fk", - "tableFrom": "dropbox_accounts", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "dropbox_accounts_email_unique": { - "name": "dropbox_accounts_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dropbox_directories": { - "name": "dropbox_directories", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "dropbox_id": { - "name": "dropbox_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "file_id": { - "name": "file_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "dropbox_directories_parent_id_dropbox_directories_xata_id_fk": { - "name": "dropbox_directories_parent_id_dropbox_directories_xata_id_fk", - "tableFrom": "dropbox_directories", - "tableTo": "dropbox_directories", - "columnsFrom": [ - "parent_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "dropbox_directories_file_id_unique": { - "name": "dropbox_directories_file_id_unique", - "nullsNotDistinct": false, - "columns": [ - "file_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dropbox_paths": { - "name": "dropbox_paths", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dropbox_id": { - "name": "dropbox_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "directory_id": { - "name": "directory_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "file_id": { - "name": "file_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "dropbox_paths_directory_id_dropbox_directories_xata_id_fk": { - "name": "dropbox_paths_directory_id_dropbox_directories_xata_id_fk", - "tableFrom": "dropbox_paths", - "tableTo": "dropbox_directories", - "columnsFrom": [ - "directory_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "dropbox_paths_file_id_unique": { - "name": "dropbox_paths_file_id_unique", - "nullsNotDistinct": false, - "columns": [ - "file_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dropbox_tokens": { - "name": "dropbox_tokens", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.dropbox": { - "name": "dropbox", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "dropbox_token_id": { - "name": "dropbox_token_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "dropbox_user_id_users_xata_id_fk": { - "name": "dropbox_user_id_users_xata_id_fk", - "tableFrom": "dropbox", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "dropbox_dropbox_token_id_dropbox_tokens_xata_id_fk": { - "name": "dropbox_dropbox_token_id_dropbox_tokens_xata_id_fk", - "tableFrom": "dropbox", - "tableTo": "dropbox_tokens", - "columnsFrom": [ - "dropbox_token_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.google_drive_accounts": { - "name": "google_drive_accounts", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_beta_user": { - "name": "is_beta_user", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "google_drive_accounts_user_id_users_xata_id_fk": { - "name": "google_drive_accounts_user_id_users_xata_id_fk", - "tableFrom": "google_drive_accounts", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "google_drive_accounts_email_unique": { - "name": "google_drive_accounts_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.google_drive_directories": { - "name": "google_drive_directories", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "google_drive_id": { - "name": "google_drive_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "file_id": { - "name": "file_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "google_drive_directories_parent_id_google_drive_directories_xata_id_fk": { - "name": "google_drive_directories_parent_id_google_drive_directories_xata_id_fk", - "tableFrom": "google_drive_directories", - "tableTo": "google_drive_directories", - "columnsFrom": [ - "parent_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "google_drive_directories_file_id_unique": { - "name": "google_drive_directories_file_id_unique", - "nullsNotDistinct": false, - "columns": [ - "file_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.google_drive_paths": { - "name": "google_drive_paths", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "google_drive_id": { - "name": "google_drive_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "directory_id": { - "name": "directory_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "file_id": { - "name": "file_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "google_drive_paths_directory_id_google_drive_directories_xata_id_fk": { - "name": "google_drive_paths_directory_id_google_drive_directories_xata_id_fk", - "tableFrom": "google_drive_paths", - "tableTo": "google_drive_directories", - "columnsFrom": [ - "directory_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "google_drive_paths_file_id_unique": { - "name": "google_drive_paths_file_id_unique", - "nullsNotDistinct": false, - "columns": [ - "file_id" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.google_drive_tokens": { - "name": "google_drive_tokens", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.google_drive": { - "name": "google_drive", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "google_drive_token_id": { - "name": "google_drive_token_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "google_drive_google_drive_token_id_google_drive_tokens_xata_id_fk": { - "name": "google_drive_google_drive_token_id_google_drive_tokens_xata_id_fk", - "tableFrom": "google_drive", - "tableTo": "google_drive_tokens", - "columnsFrom": [ - "google_drive_token_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "google_drive_user_id_users_xata_id_fk": { - "name": "google_drive_user_id_users_xata_id_fk", - "tableFrom": "google_drive", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.loved_tracks": { - "name": "loved_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "loved_tracks_user_id_users_xata_id_fk": { - "name": "loved_tracks_user_id_users_xata_id_fk", - "tableFrom": "loved_tracks", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "loved_tracks_track_id_tracks_xata_id_fk": { - "name": "loved_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "loved_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "loved_tracks_uri_unique": { - "name": "loved_tracks_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.playlist_tracks": { - "name": "playlist_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "playlist_id": { - "name": "playlist_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "playlist_tracks_playlist_id_playlists_xata_id_fk": { - "name": "playlist_tracks_playlist_id_playlists_xata_id_fk", - "tableFrom": "playlist_tracks", - "tableTo": "playlists", - "columnsFrom": [ - "playlist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "playlist_tracks_track_id_tracks_xata_id_fk": { - "name": "playlist_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "playlist_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.playlists": { - "name": "playlists", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "picture": { - "name": "picture", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "spotify_link": { - "name": "spotify_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tidal_link": { - "name": "tidal_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "apple_music_link": { - "name": "apple_music_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_by": { - "name": "created_by", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "playlists_created_by_users_xata_id_fk": { - "name": "playlists_created_by_users_xata_id_fk", - "tableFrom": "playlists", - "tableTo": "users", - "columnsFrom": [ - "created_by" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "playlists_uri_unique": { - "name": "playlists_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.profile_shouts": { - "name": "profile_shouts", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "shout_id": { - "name": "shout_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "profile_shouts_user_id_users_xata_id_fk": { - "name": "profile_shouts_user_id_users_xata_id_fk", - "tableFrom": "profile_shouts", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "profile_shouts_shout_id_shouts_xata_id_fk": { - "name": "profile_shouts_shout_id_shouts_xata_id_fk", - "tableFrom": "profile_shouts", - "tableTo": "shouts", - "columnsFrom": [ - "shout_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.queue_tracks": { - "name": "queue_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "position": { - "name": "position", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "file_uri": { - "name": "file_uri", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "queue_tracks_user_id_users_xata_id_fk": { - "name": "queue_tracks_user_id_users_xata_id_fk", - "tableFrom": "queue_tracks", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "queue_tracks_track_id_tracks_xata_id_fk": { - "name": "queue_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "queue_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.scrobbles": { - "name": "scrobbles", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "album_id": { - "name": "album_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artist_id": { - "name": "artist_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "timestamp": { - "name": "timestamp", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "scrobbles_user_id_users_xata_id_fk": { - "name": "scrobbles_user_id_users_xata_id_fk", - "tableFrom": "scrobbles", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "scrobbles_track_id_tracks_xata_id_fk": { - "name": "scrobbles_track_id_tracks_xata_id_fk", - "tableFrom": "scrobbles", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "scrobbles_album_id_albums_xata_id_fk": { - "name": "scrobbles_album_id_albums_xata_id_fk", - "tableFrom": "scrobbles", - "tableTo": "albums", - "columnsFrom": [ - "album_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "scrobbles_artist_id_artists_xata_id_fk": { - "name": "scrobbles_artist_id_artists_xata_id_fk", - "tableFrom": "scrobbles", - "tableTo": "artists", - "columnsFrom": [ - "artist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "scrobbles_uri_unique": { - "name": "scrobbles_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.shout_likes": { - "name": "shout_likes", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "shout_id": { - "name": "shout_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "shout_likes_user_id_users_xata_id_fk": { - "name": "shout_likes_user_id_users_xata_id_fk", - "tableFrom": "shout_likes", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shout_likes_shout_id_shouts_xata_id_fk": { - "name": "shout_likes_shout_id_shouts_xata_id_fk", - "tableFrom": "shout_likes", - "tableTo": "shouts", - "columnsFrom": [ - "shout_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "shout_likes_uri_unique": { - "name": "shout_likes_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.shout_reports": { - "name": "shout_reports", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "shout_id": { - "name": "shout_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "shout_reports_user_id_users_xata_id_fk": { - "name": "shout_reports_user_id_users_xata_id_fk", - "tableFrom": "shout_reports", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shout_reports_shout_id_shouts_xata_id_fk": { - "name": "shout_reports_shout_id_shouts_xata_id_fk", - "tableFrom": "shout_reports", - "tableTo": "shouts", - "columnsFrom": [ - "shout_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.shouts": { - "name": "shouts", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "content": { - "name": "content", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artist_id": { - "name": "artist_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "album_id": { - "name": "album_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "scrobble_id": { - "name": "scrobble_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "author_id": { - "name": "author_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "parent_id": { - "name": "parent_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "shouts_track_id_tracks_xata_id_fk": { - "name": "shouts_track_id_tracks_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shouts_artist_id_users_xata_id_fk": { - "name": "shouts_artist_id_users_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "users", - "columnsFrom": [ - "artist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shouts_album_id_albums_xata_id_fk": { - "name": "shouts_album_id_albums_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "albums", - "columnsFrom": [ - "album_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shouts_scrobble_id_scrobbles_xata_id_fk": { - "name": "shouts_scrobble_id_scrobbles_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "scrobbles", - "columnsFrom": [ - "scrobble_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shouts_author_id_users_xata_id_fk": { - "name": "shouts_author_id_users_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "users", - "columnsFrom": [ - "author_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "shouts_parent_id_shouts_xata_id_fk": { - "name": "shouts_parent_id_shouts_xata_id_fk", - "tableFrom": "shouts", - "tableTo": "shouts", - "columnsFrom": [ - "parent_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "shouts_uri_unique": { - "name": "shouts_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.spotify_accounts": { - "name": "spotify_accounts", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "is_beta_user": { - "name": "is_beta_user", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "spotify_accounts_user_id_users_xata_id_fk": { - "name": "spotify_accounts_user_id_users_xata_id_fk", - "tableFrom": "spotify_accounts", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.spotify_tokens": { - "name": "spotify_tokens", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "spotify_tokens_user_id_users_xata_id_fk": { - "name": "spotify_tokens_user_id_users_xata_id_fk", - "tableFrom": "spotify_tokens", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.tracks": { - "name": "tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "title": { - "name": "title", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artist": { - "name": "artist", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "album_artist": { - "name": "album_artist", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "album_art": { - "name": "album_art", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "album": { - "name": "album", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_number": { - "name": "track_number", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "duration": { - "name": "duration", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "mb_id": { - "name": "mb_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "youtube_link": { - "name": "youtube_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "spotify_link": { - "name": "spotify_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "apple_music_link": { - "name": "apple_music_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "tidal_link": { - "name": "tidal_link", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "sha256": { - "name": "sha256", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "disc_number": { - "name": "disc_number", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "lyrics": { - "name": "lyrics", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "composer": { - "name": "composer", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "genre": { - "name": "genre", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "label": { - "name": "label", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "copyright_message": { - "name": "copyright_message", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "album_uri": { - "name": "album_uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "artist_uri": { - "name": "artist_uri", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "tracks_mb_id_unique": { - "name": "tracks_mb_id_unique", - "nullsNotDistinct": false, - "columns": [ - "mb_id" - ] - }, - "tracks_youtube_link_unique": { - "name": "tracks_youtube_link_unique", - "nullsNotDistinct": false, - "columns": [ - "youtube_link" - ] - }, - "tracks_spotify_link_unique": { - "name": "tracks_spotify_link_unique", - "nullsNotDistinct": false, - "columns": [ - "spotify_link" - ] - }, - "tracks_apple_music_link_unique": { - "name": "tracks_apple_music_link_unique", - "nullsNotDistinct": false, - "columns": [ - "apple_music_link" - ] - }, - "tracks_tidal_link_unique": { - "name": "tracks_tidal_link_unique", - "nullsNotDistinct": false, - "columns": [ - "tidal_link" - ] - }, - "tracks_sha256_unique": { - "name": "tracks_sha256_unique", - "nullsNotDistinct": false, - "columns": [ - "sha256" - ] - }, - "tracks_uri_unique": { - "name": "tracks_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - }, - "tracks_album_uri_unique": { - "name": "tracks_album_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "album_uri" - ] - }, - "tracks_artist_uri_unique": { - "name": "tracks_artist_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "artist_uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_albums": { - "name": "user_albums", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "album_id": { - "name": "album_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "scrobbles": { - "name": "scrobbles", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_albums_user_id_users_xata_id_fk": { - "name": "user_albums_user_id_users_xata_id_fk", - "tableFrom": "user_albums", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "user_albums_album_id_albums_xata_id_fk": { - "name": "user_albums_album_id_albums_xata_id_fk", - "tableFrom": "user_albums", - "tableTo": "albums", - "columnsFrom": [ - "album_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_albums_uri_unique": { - "name": "user_albums_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_artists": { - "name": "user_artists", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "artist_id": { - "name": "artist_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "scrobbles": { - "name": "scrobbles", - "type": "integer", - "primaryKey": false, - "notNull": false - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_artists_user_id_users_xata_id_fk": { - "name": "user_artists_user_id_users_xata_id_fk", - "tableFrom": "user_artists", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "user_artists_artist_id_artists_xata_id_fk": { - "name": "user_artists_artist_id_artists_xata_id_fk", - "tableFrom": "user_artists", - "tableTo": "artists", - "columnsFrom": [ - "artist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_artists_uri_unique": { - "name": "user_artists_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_playlists": { - "name": "user_playlists", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "playlist_id": { - "name": "playlist_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "user_playlists_user_id_users_xata_id_fk": { - "name": "user_playlists_user_id_users_xata_id_fk", - "tableFrom": "user_playlists", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "user_playlists_playlist_id_tracks_xata_id_fk": { - "name": "user_playlists_playlist_id_tracks_xata_id_fk", - "tableFrom": "user_playlists", - "tableTo": "tracks", - "columnsFrom": [ - "playlist_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_playlists_uri_unique": { - "name": "user_playlists_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.user_tracks": { - "name": "user_tracks", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "track_id": { - "name": "track_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "uri": { - "name": "uri", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "scrobbles": { - "name": "scrobbles", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "user_tracks_user_id_users_xata_id_fk": { - "name": "user_tracks_user_id_users_xata_id_fk", - "tableFrom": "user_tracks", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "user_tracks_track_id_tracks_xata_id_fk": { - "name": "user_tracks_track_id_tracks_xata_id_fk", - "tableFrom": "user_tracks", - "tableTo": "tracks", - "columnsFrom": [ - "track_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_tracks_uri_unique": { - "name": "user_tracks_uri_unique", - "nullsNotDistinct": false, - "columns": [ - "uri" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.users": { - "name": "users", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "did": { - "name": "did", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "display_name": { - "name": "display_name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "handle": { - "name": "handle", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "avatar": { - "name": "avatar", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_version": { - "name": "xata_version", - "type": "integer", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "users_did_unique": { - "name": "users_did_unique", - "nullsNotDistinct": false, - "columns": [ - "did" - ] - }, - "users_handle_unique": { - "name": "users_handle_unique", - "nullsNotDistinct": false, - "columns": [ - "handle" - ] - } - }, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - }, - "public.webscrobblers": { - "name": "webscrobblers", - "schema": "", - "columns": { - "xata_id": { - "name": "xata_id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "uuid": { - "name": "uuid", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "enabled": { - "name": "enabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "xata_createdat": { - "name": "xata_createdat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "xata_updatedat": { - "name": "xata_updatedat", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "webscrobblers_user_id_users_xata_id_fk": { - "name": "webscrobblers_user_id_users_xata_id_fk", - "tableFrom": "webscrobblers", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "xata_id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "policies": {}, - "checkConstraints": {}, - "isRLSEnabled": false - } - }, - "enums": {}, - "schemas": {}, - "sequences": {}, - "roles": {}, - "policies": {}, - "views": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/apps/api/drizzle/meta/_journal.json b/apps/api/drizzle/meta/_journal.json index 33f335e0..9ebc989b 100644 --- a/apps/api/drizzle/meta/_journal.json +++ b/apps/api/drizzle/meta/_journal.json @@ -5,15 +5,8 @@ { "idx": 0, "version": "7", - "when": 1753405608015, - "tag": "0000_quiet_mister_sinister", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1759657577245, - "tag": "0001_woozy_saracen", + "when": 1759736561936, + "tag": "0000_greedy_vanisher", "breakpoints": true } ] diff --git a/apps/api/src/schema/tracks.ts b/apps/api/src/schema/tracks.ts index 3d83371c..e371d4cc 100644 --- a/apps/api/src/schema/tracks.ts +++ b/apps/api/src/schema/tracks.ts @@ -23,8 +23,8 @@ const tracks = pgTable("tracks", { label: text("label"), copyrightMessage: text("copyright_message"), uri: text("uri").unique(), - albumUri: text("album_uri").unique(), - artistUri: text("artist_uri").unique(), + albumUri: text("album_uri"), + artistUri: text("artist_uri"), createdAt: timestamp("xata_createdat").defaultNow().notNull(), updatedAt: timestamp("xata_updatedat").defaultNow().notNull(), xataVersion: integer("xata_version"), diff --git a/apps/api/src/schema/users.ts b/apps/api/src/schema/users.ts index 7d13c3a5..ee7358c0 100644 --- a/apps/api/src/schema/users.ts +++ b/apps/api/src/schema/users.ts @@ -4,7 +4,7 @@ import { integer, pgTable, text, timestamp } from "drizzle-orm/pg-core"; const users = pgTable("users", { id: text("xata_id").primaryKey(), did: text("did").unique().notNull(), - displayName: text("display_name").notNull(), + displayName: text("display_name"), handle: text("handle").unique().notNull(), avatar: text("avatar").notNull(), createdAt: timestamp("xata_createdat").defaultNow().notNull(), diff --git a/crates/pgpull/src/lib.rs b/crates/pgpull/src/lib.rs index 902ea8a9..6884df5e 100644 --- a/crates/pgpull/src/lib.rs +++ b/crates/pgpull/src/lib.rs @@ -3,7 +3,9 @@ use std::env; mod repo; mod xata; -use anyhow::Error; +use anyhow::{Context, Error}; +use owo_colors::OwoColorize; +use sqlx::postgres::PgPoolOptions; pub async fn pull_data() -> Result<(), Error> { if env::var("SOURCE_POSTGRES_URL").is_err() { @@ -13,7 +15,282 @@ pub async fn pull_data() -> Result<(), Error> { std::process::exit(1); } - // Placeholder for the actual data pulling logic from PostgreSQL - println!("Pulling data from PostgreSQL..."); + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&env::var("SOURCE_POSTGRES_URL")?) + .await?; + + let dest_pool = PgPoolOptions::new() + .max_connections(5) + .connect(&env::var("XATA_POSTGRES_URL")?) + .await?; + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let album_sync = tokio::spawn(async move { + let total_albums: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM albums") + .fetch_one(&pool_clone) + .await?; + let total_albums = total_albums.0; + tracing::info!(total = %total_albums.magenta(), "Total albums to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_albums).step_by(BATCH_SIZE) { + let albums = + repo::album::get_albums(&pool_clone, offset as i64, BATCH_SIZE as i64).await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + albums.len() as i64).min(total_albums)).magenta(), + total = %total_albums.magenta(), + "Fetched albums" + ); + for album in &albums { + tracing::info!(title = %album.title.cyan(), i = %i.magenta(), total = %total_albums.magenta(), "Inserting album"); + repo::album::insert_album(&dest_pool_clone, album).await?; + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let artist_sync = tokio::spawn(async move { + let total_artists: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM artists") + .fetch_one(&pool_clone) + .await?; + let total_artists = total_artists.0; + tracing::info!(total = %total_artists.magenta(), "Total artists to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_artists).step_by(BATCH_SIZE) { + let artists = + repo::artist::get_artists(&pool_clone, offset as i64, BATCH_SIZE as i64).await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + artists.len() as i64).min(total_artists)).magenta(), + total = %total_artists.magenta(), + "Fetched artists" + ); + for artist in &artists { + tracing::info!(name = %artist.name.cyan(), i = %i.magenta(), total = %total_artists.magenta(), "Inserting artist"); + repo::artist::insert_artist(&dest_pool_clone, artist).await?; + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let track_sync = tokio::spawn(async move { + let total_tracks: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM tracks") + .fetch_one(&pool_clone) + .await?; + let total_tracks = total_tracks.0; + tracing::info!(total = %total_tracks.magenta(), "Total tracks to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_tracks).step_by(BATCH_SIZE) { + let tracks = + repo::track::get_tracks(&pool_clone, offset as i64, BATCH_SIZE as i64).await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + tracks.len() as i64).min(total_tracks)).magenta(), + total = %total_tracks.magenta(), + "Fetched tracks" + ); + + for track in &tracks { + tracing::info!(title = %track.title.cyan(), i = %i.magenta(), total = %total_tracks.magenta(), "Inserting track"); + match repo::track::insert_track(&dest_pool_clone, track).await { + Ok(_) => {} + Err(e) => { + tracing::error!(error = %e, "Failed to insert track"); + } + } + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let user_sync = tokio::spawn(async move { + let total_users: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM users") + .fetch_one(&pool_clone) + .await?; + let total_users = total_users.0; + tracing::info!(total = %total_users.magenta(), "Total users to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_users).step_by(BATCH_SIZE) { + let users = + repo::user::get_users(&pool_clone, offset as i64, BATCH_SIZE as i64).await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + users.len() as i64).min(total_users)).magenta(), + total = %total_users.magenta(), + "Fetched users" + ); + + for user in &users { + tracing::info!(handle = %user.handle.cyan(), i = %i.magenta(), total = %total_users.magenta(), "Inserting user"); + match repo::user::insert_user(&dest_pool_clone, user).await { + Ok(_) => {} + Err(e) => { + tracing::error!(error = %e, "Failed to insert user"); + } + } + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let (album_sync, artist_sync, track_sync, user_sync) = + tokio::join!(album_sync, artist_sync, track_sync, user_sync); + + album_sync.context("Album sync task failed")??; + artist_sync.context("Artist sync task failed")??; + track_sync.context("Track sync task failed")??; + user_sync.context("User sync task failed")??; + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let playlist_sync = tokio::spawn(async move { + let total_playlists: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM playlists") + .fetch_one(&pool_clone) + .await?; + let total_playlists = total_playlists.0; + tracing::info!(total = %total_playlists.magenta(), "Total playlists to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_playlists).step_by(BATCH_SIZE) { + let playlists = + repo::playlist::get_playlists(&pool_clone, offset as i64, BATCH_SIZE as i64) + .await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + playlists.len() as i64).min(total_playlists)).magenta(), + total = %total_playlists.magenta(), + "Fetched playlists" + ); + + for playlist in &playlists { + tracing::info!(name = %playlist.name.cyan(), i = %i.magenta(), total = %total_playlists.magenta(), "Inserting playlist"); + match repo::playlist::insert_playlist(&dest_pool_clone, playlist).await { + Ok(_) => {} + Err(e) => { + tracing::error!(error = %e, "Failed to insert playlist"); + } + } + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + let loved_track_sync = tokio::spawn(async move { + let total_loved_tracks: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM loved_tracks") + .fetch_one(&pool_clone) + .await?; + let total_loved_tracks = total_loved_tracks.0; + tracing::info!(total = %total_loved_tracks.magenta(), "Total loved tracks to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_loved_tracks).step_by(BATCH_SIZE) { + let loved_tracks = + repo::loved_track::get_loved_tracks(&pool_clone, offset as i64, BATCH_SIZE as i64) + .await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + loved_tracks.len() as i64).min(total_loved_tracks)).magenta(), + total = %total_loved_tracks.magenta(), + "Fetched loved tracks" + ); + + for loved_track in &loved_tracks { + tracing::info!(user_id = %loved_track.user_id.cyan(), track_id = %loved_track.track_id.magenta(), i = %i.magenta(), total = %total_loved_tracks.magenta(), "Inserting loved track"); + repo::loved_track::insert_loved_track(&dest_pool_clone, loved_track).await?; + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let pool_clone = pool.clone(); + let dest_pool_clone = dest_pool.clone(); + + let scrobble_sync = tokio::spawn(async move { + let total_scrobbles: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM scrobbles") + .fetch_one(&pool_clone) + .await?; + let total_scrobbles = total_scrobbles.0; + tracing::info!(total = %total_scrobbles.magenta(), "Total scrobbles to sync"); + + const BATCH_SIZE: usize = 1000; + + let start = 0; + let mut i = 1; + + for offset in (start..total_scrobbles).step_by(BATCH_SIZE) { + let scrobbles = + repo::scrobble::get_scrobbles(&pool_clone, offset as i64, BATCH_SIZE as i64) + .await?; + tracing::info!( + offset = %offset.magenta(), + end = %((offset + scrobbles.len() as i64).min(total_scrobbles)).magenta(), + total = %total_scrobbles.magenta(), + "Fetched scrobbles" + ); + + for scrobble in &scrobbles { + tracing::info!(user_id = %scrobble.user_id.cyan(), track_id = %scrobble.track_id.magenta(), i = %i.magenta(), total = %total_scrobbles.magenta(), "Inserting scrobble"); + match repo::scrobble::insert_scrobble(&dest_pool_clone, scrobble).await { + Ok(_) => {} + Err(e) => { + tracing::error!(error = %e, "Failed to insert scrobble"); + } + } + i += 1; + } + } + Ok::<(), Error>(()) + }); + + let (loved_track_sync, playlist_sync, scrobble_sync) = + tokio::join!(loved_track_sync, playlist_sync, scrobble_sync); + loved_track_sync.context("Loved track sync task failed")??; + playlist_sync.context("Playlist sync task failed")??; + scrobble_sync.context("Scrobble sync task failed")??; + Ok(()) } diff --git a/crates/pgpull/src/repo/album.rs b/crates/pgpull/src/repo/album.rs index e69de29b..1fd53219 100644 --- a/crates/pgpull/src/repo/album.rs +++ b/crates/pgpull/src/repo/album.rs @@ -0,0 +1,57 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::album::Album; + +pub async fn get_albums( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let albums: Vec = sqlx::query_as("SELECT * FROM albums OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(albums) +} + +pub async fn insert_album(pool: &Pool, album: &Album) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO albums ( + xata_id, + title, + artist, + release_date, + album_art, + year, + spotify_link, + tidal_link, + youtube_link, + apple_music_link, + sha256, + uri, + artist_uri, + xata_createdat + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&album.xata_id) + .bind(&album.title) + .bind(&album.artist) + .bind(&album.release_date) + .bind(&album.album_art) + .bind(album.year) + .bind(&album.spotify_link) + .bind(&album.tidal_link) + .bind(&album.youtube_link) + .bind(&album.apple_music_link) + .bind(&album.sha256) + .bind(&album.uri) + .bind(&album.artist_uri) + .bind(album.xata_createdat) + .execute(pool) + .await?; + + Ok(()) +} diff --git a/crates/pgpull/src/repo/artist.rs b/crates/pgpull/src/repo/artist.rs index e69de29b..24b4e223 100644 --- a/crates/pgpull/src/repo/artist.rs +++ b/crates/pgpull/src/repo/artist.rs @@ -0,0 +1,58 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::artist::Artist; + +pub async fn get_artists( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let artists = sqlx::query_as::<_, Artist>("SELECT * FROM artists OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(artists) +} + +pub async fn insert_artist(pool: &Pool, artist: &Artist) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO artists ( + xata_id, + name, + biography, + born, + born_in, + died, + picture, + sha256, + spotify_link, + tidal_link, + youtube_link, + apple_music_link, + uri, + genres, + xata_createdat + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&artist.xata_id) + .bind(&artist.name) + .bind(&artist.biography) + .bind(&artist.born) + .bind(&artist.born_in) + .bind(&artist.died) + .bind(&artist.picture) + .bind(&artist.sha256) + .bind(&artist.spotify_link) + .bind(&artist.tidal_link) + .bind(&artist.youtube_link) + .bind(&artist.apple_music_link) + .bind(&artist.uri) + .bind(&artist.genres) + .bind(artist.xata_createdat) + .execute(pool) + .await?; + Ok(()) +} diff --git a/crates/pgpull/src/repo/loved_track.rs b/crates/pgpull/src/repo/loved_track.rs new file mode 100644 index 00000000..387d80d4 --- /dev/null +++ b/crates/pgpull/src/repo/loved_track.rs @@ -0,0 +1,40 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::loved_track::LovedTrack; + +pub async fn get_loved_tracks( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let loved_tracks = + sqlx::query_as::<_, LovedTrack>("SELECT * FROM loved_tracks OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(loved_tracks) +} + +pub async fn insert_loved_track( + pool: &Pool, + loved_track: &LovedTrack, +) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO loved_tracks ( + xata_id, + user_id, + track_id, + xata_createdat + ) VALUES ($1, $2, $3, $4) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&loved_track.xata_id) + .bind(&loved_track.user_id) + .bind(&loved_track.track_id) + .bind(loved_track.xata_createdat) + .execute(pool) + .await?; + Ok(()) +} diff --git a/crates/pgpull/src/repo/mod.rs b/crates/pgpull/src/repo/mod.rs index 627ee2f7..f5c5c7e0 100644 --- a/crates/pgpull/src/repo/mod.rs +++ b/crates/pgpull/src/repo/mod.rs @@ -1,5 +1,6 @@ pub mod album; pub mod artist; +pub mod loved_track; pub mod playlist; pub mod scrobble; pub mod track; diff --git a/crates/pgpull/src/repo/playlist.rs b/crates/pgpull/src/repo/playlist.rs index e69de29b..b467e644 100644 --- a/crates/pgpull/src/repo/playlist.rs +++ b/crates/pgpull/src/repo/playlist.rs @@ -0,0 +1,50 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::playlist::Playlist; + +pub async fn get_playlists( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let playlists: Vec = sqlx::query_as("SELECT * FROM playlists OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(playlists) +} + +pub async fn insert_playlist(pool: &Pool, playlist: &Playlist) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO playlists ( + xata_id, + name, + description, + picture, + spotify_link, + tidal_link, + apple_music_link, + xata_createdat, + xata_updatedat, + uri, + created_by + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&playlist.xata_id) + .bind(&playlist.name) + .bind(&playlist.description) + .bind(&playlist.picture) + .bind(&playlist.spotify_link) + .bind(&playlist.tidal_link) + .bind(&playlist.apple_music_link) + .bind(playlist.xata_createdat) + .bind(playlist.xata_updatedat) + .bind(&playlist.uri) + .bind(&playlist.created_by) + .execute(pool) + .await?; + Ok(()) +} diff --git a/crates/pgpull/src/repo/scrobble.rs b/crates/pgpull/src/repo/scrobble.rs index e69de29b..0e070b52 100644 --- a/crates/pgpull/src/repo/scrobble.rs +++ b/crates/pgpull/src/repo/scrobble.rs @@ -0,0 +1,44 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::scrobble::Scrobble; + +pub async fn get_scrobbles( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let scrobbles = sqlx::query_as::<_, Scrobble>("SELECT * FROM scrobbles OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(scrobbles) +} + +pub async fn insert_scrobble(pool: &Pool, scrobble: &Scrobble) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO scrobbles ( + xata_id, + user_id, + track_id, + album_id, + artist_id, + uri, + xata_createdat, + timestamp + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&scrobble.xata_id) + .bind(&scrobble.user_id) + .bind(&scrobble.track_id) + .bind(&scrobble.album_id) + .bind(&scrobble.artist_id) + .bind(&scrobble.uri) + .bind(scrobble.xata_createdat) + .bind(scrobble.timestamp) + .execute(pool) + .await?; + Ok(()) +} diff --git a/crates/pgpull/src/repo/track.rs b/crates/pgpull/src/repo/track.rs index e69de29b..27d6575e 100644 --- a/crates/pgpull/src/repo/track.rs +++ b/crates/pgpull/src/repo/track.rs @@ -0,0 +1,77 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::track::Track; + +pub async fn get_tracks( + pool: &Pool, + offset: i64, + limit: i64, +) -> Result, Error> { + let tracks: Vec = sqlx::query_as("SELECT * FROM tracks OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(tracks) +} + +pub async fn insert_track(pool: &Pool, track: &Track) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO tracks ( + xata_id, + title, + artist, + album_artist, + album_art, + album, + track_number, + duration, + mb_id, + youtube_link, + spotify_link, + tidal_link, + apple_music_link, + sha256, + lyrics, + composer, + genre, + disc_number, + copyright_message, + label, + uri, + artist_uri, + album_uri, + xata_createdat + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24) + ON CONFLICT (xata_id) DO NOTHING + "#, + ) + .bind(&track.xata_id) + .bind(&track.title) + .bind(&track.artist) + .bind(&track.album_artist) + .bind(&track.album_art) + .bind(&track.album) + .bind(track.track_number) + .bind(track.duration) + .bind(&track.mb_id) + .bind(&track.youtube_link) + .bind(&track.spotify_link) + .bind(&track.tidal_link) + .bind(&track.apple_music_link) + .bind(&track.sha256) + .bind(&track.lyrics) + .bind(&track.composer) + .bind(&track.genre) + .bind(track.disc_number) + .bind(&track.copyright_message) + .bind(&track.label) + .bind(&track.uri) + .bind(&track.artist_uri) + .bind(&track.album_uri) + .bind(track.xata_createdat) + .execute(pool) + .await?; + Ok(()) +} diff --git a/crates/pgpull/src/repo/user.rs b/crates/pgpull/src/repo/user.rs index e69de29b..37f448f4 100644 --- a/crates/pgpull/src/repo/user.rs +++ b/crates/pgpull/src/repo/user.rs @@ -0,0 +1,36 @@ +use anyhow::Error; +use sqlx::{Pool, Postgres}; + +use crate::xata::user::User; + +pub async fn get_users(pool: &Pool, offset: i64, limit: i64) -> Result, Error> { + let users = sqlx::query_as::<_, User>("SELECT * FROM users OFFSET $1 LIMIT $2") + .bind(offset) + .bind(limit) + .fetch_all(pool) + .await?; + Ok(users) +} + +pub async fn insert_user(pool: &Pool, user: &User) -> Result<(), Error> { + sqlx::query( + r#"INSERT INTO users ( + xata_id, + display_name, + did, + handle, + avatar, + xata_createdat + ) VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (xata_id) DO NOTHING"#, + ) + .bind(&user.xata_id) + .bind(&user.display_name) + .bind(&user.did) + .bind(&user.handle) + .bind(&user.avatar) + .bind(user.xata_createdat) + .execute(pool) + .await?; + Ok(()) +} -- 2.51.2