Implement incremental sync and offline recovery
This commit is contained in:
+128
@@ -0,0 +1,128 @@
|
||||
ALTER TABLE "users"
|
||||
ADD COLUMN "library_cursor" BIGINT NOT NULL DEFAULT 0;
|
||||
|
||||
ALTER TABLE "library_events"
|
||||
ADD COLUMN "cursor" BIGINT,
|
||||
ADD COLUMN "payload" JSONB;
|
||||
|
||||
WITH ranked_events AS (
|
||||
SELECT
|
||||
"id",
|
||||
ROW_NUMBER() OVER (
|
||||
PARTITION BY "user_id"
|
||||
ORDER BY "created_at" ASC, "id" ASC
|
||||
)::BIGINT AS next_cursor
|
||||
FROM "library_events"
|
||||
)
|
||||
UPDATE "library_events" AS "event"
|
||||
SET "cursor" = ranked_events.next_cursor
|
||||
FROM ranked_events
|
||||
WHERE ranked_events."id" = "event"."id";
|
||||
|
||||
UPDATE "library_events" AS "event"
|
||||
SET "payload" = CASE
|
||||
WHEN track."status" = 'DELETED'::"TrackStatus" THEN jsonb_build_object(
|
||||
'deletedTrackId',
|
||||
track."id"
|
||||
)
|
||||
WHEN audio_asset."id" IS NOT NULL THEN jsonb_build_object(
|
||||
'track',
|
||||
jsonb_build_object(
|
||||
'trackId',
|
||||
track."id",
|
||||
'title',
|
||||
track."title",
|
||||
'artist',
|
||||
track."artist",
|
||||
'durationSeconds',
|
||||
GREATEST(
|
||||
0,
|
||||
ROUND(COALESCE(track."duration_ms", audio_asset."duration_ms", 0)::numeric / 1000.0)
|
||||
)::INTEGER,
|
||||
'sha256',
|
||||
audio_asset."sha256",
|
||||
'assetId',
|
||||
audio_asset."id",
|
||||
'createdAt',
|
||||
to_char(track."created_at" AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'),
|
||||
'updatedAt',
|
||||
to_char(track."updated_at" AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'),
|
||||
'artwork',
|
||||
CASE
|
||||
WHEN artwork_asset."id" IS NULL THEN NULL
|
||||
ELSE jsonb_build_object(
|
||||
'artworkId',
|
||||
artwork_asset."id",
|
||||
'sha256',
|
||||
artwork_asset."sha256",
|
||||
'mimeType',
|
||||
artwork_asset."mime_type",
|
||||
'width',
|
||||
artwork_asset."width",
|
||||
'height',
|
||||
artwork_asset."height"
|
||||
)
|
||||
END
|
||||
)
|
||||
)
|
||||
ELSE '{}'::jsonb
|
||||
END
|
||||
FROM "tracks" AS track
|
||||
LEFT JOIN "audio_assets" AS audio_asset
|
||||
ON audio_asset."id" = track."primary_audio_asset_id"
|
||||
LEFT JOIN "artwork_assets" AS artwork_asset
|
||||
ON artwork_asset."id" = track."artwork_asset_id"
|
||||
WHERE "event"."entity_type" = 'TRACK'::"EntityType"
|
||||
AND "event"."entity_id" = track."id";
|
||||
|
||||
UPDATE "library_events"
|
||||
SET "payload" = '{}'::jsonb
|
||||
WHERE "payload" IS NULL;
|
||||
|
||||
ALTER TABLE "library_events"
|
||||
ALTER COLUMN "cursor" SET NOT NULL,
|
||||
ALTER COLUMN "payload" SET NOT NULL;
|
||||
|
||||
CREATE UNIQUE INDEX "library_events_user_id_cursor_key"
|
||||
ON "library_events"("user_id", "cursor");
|
||||
|
||||
CREATE INDEX "library_events_user_id_cursor_idx"
|
||||
ON "library_events"("user_id", "cursor");
|
||||
|
||||
UPDATE "users" AS "user"
|
||||
SET "library_cursor" = COALESCE(cursor_summary."max_cursor", 0)
|
||||
FROM (
|
||||
SELECT
|
||||
"user_id",
|
||||
MAX("cursor") AS "max_cursor"
|
||||
FROM "library_events"
|
||||
GROUP BY "user_id"
|
||||
) AS cursor_summary
|
||||
WHERE cursor_summary."user_id" = "user"."id";
|
||||
|
||||
ALTER TABLE "device_sync_cursors"
|
||||
ADD COLUMN "user_id" UUID,
|
||||
ADD COLUMN "cursor" BIGINT NOT NULL DEFAULT 0;
|
||||
|
||||
UPDATE "device_sync_cursors" AS "sync_cursor"
|
||||
SET
|
||||
"user_id" = device."user_id",
|
||||
"cursor" = "sync_cursor"."last_event_id"
|
||||
FROM "devices" AS device
|
||||
WHERE device."id" = "sync_cursor"."device_id";
|
||||
|
||||
ALTER TABLE "device_sync_cursors"
|
||||
ALTER COLUMN "user_id" SET NOT NULL;
|
||||
|
||||
ALTER TABLE "device_sync_cursors"
|
||||
DROP COLUMN "last_event_id",
|
||||
DROP COLUMN "last_full_sync_at";
|
||||
|
||||
CREATE INDEX "device_sync_cursors_user_id_idx"
|
||||
ON "device_sync_cursors"("user_id");
|
||||
|
||||
ALTER TABLE "device_sync_cursors"
|
||||
ADD CONSTRAINT "device_sync_cursors_user_id_fkey"
|
||||
FOREIGN KEY ("user_id") REFERENCES "users"("id")
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE CASCADE;
|
||||
Reference in New Issue
Block a user