From 37d6d6703ff1d0b5bc1b6010cf60f6aa42541823 Mon Sep 17 00:00:00 2001 From: gunshiz Date: Sun, 6 Sep 2026 13:59:32 +0700 Subject: [PATCH] feat : add metrial fetcher --- db/schema.ts | 21 +- drizzle/0031_watery_sumo.sql | 13 + drizzle/meta/0031_snapshot.json | 3643 +++++++++++++++++++++++++++++++ drizzle/meta/_journal.json | 7 + lib/catalog/lunaris.test.ts | 21 + lib/catalog/lunaris.ts | 35 + lib/catalog/sync.ts | 55 +- lib/guides/queries.ts | 40 +- 8 files changed, 3827 insertions(+), 8 deletions(-) create mode 100644 drizzle/0031_watery_sumo.sql create mode 100644 drizzle/meta/0031_snapshot.json diff --git a/db/schema.ts b/db/schema.ts index 7c73061..9c15181 100644 --- a/db/schema.ts +++ b/db/schema.ts @@ -16,7 +16,11 @@ import { varchar, } from "drizzle-orm/pg-core"; -import type { CatalogConstellation, CatalogTalent } from "@/lib/catalog/lunaris"; +import type { + CatalogAscensionGroup, + CatalogConstellation, + CatalogTalent, +} from "@/lib/catalog/lunaris"; import type { ExtraSheet } from "@/lib/guides/extra-sheet"; const authSchema = pgSchema("auth"); @@ -451,6 +455,7 @@ export const catalogCharacters = catalogSchema.table( nameCardImageKey: text("name_card_image_key"), constellations: jsonb("constellations").$type().default([]).notNull(), talents: jsonb("talents").$type().default([]).notNull(), + ascension: jsonb("ascension").$type().default([]).notNull(), }, (table) => [ primaryKey({ columns: [table.key] }), @@ -458,6 +463,20 @@ export const catalogCharacters = catalogSchema.table( ], ); +export const catalogMaterials = catalogSchema.table( + "material", + { + key: varchar("key", { length: 64 }).primaryKey(), + name: text("name").notNull(), + description: text("description"), + rarity: integer("rarity"), + type: varchar("type", { length: 64 }), + imageKey: text("image_key").notNull(), + ...timestamps, + }, + (table) => [index("catalog_material_name_idx").on(table.name)], +); + export const catalogWeapons = catalogSchema.table( "weapon", { diff --git a/drizzle/0031_watery_sumo.sql b/drizzle/0031_watery_sumo.sql new file mode 100644 index 0000000..2666fe0 --- /dev/null +++ b/drizzle/0031_watery_sumo.sql @@ -0,0 +1,13 @@ +CREATE TABLE "catalog"."material" ( + "key" varchar(64) PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "description" text, + "rarity" integer, + "type" varchar(64), + "image_key" text NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "catalog"."character" ADD COLUMN "ascension" jsonb DEFAULT '[]'::jsonb NOT NULL;--> statement-breakpoint +CREATE INDEX "catalog_material_name_idx" ON "catalog"."material" USING btree ("name"); \ No newline at end of file diff --git a/drizzle/meta/0031_snapshot.json b/drizzle/meta/0031_snapshot.json new file mode 100644 index 0000000..4e13b0f --- /dev/null +++ b/drizzle/meta/0031_snapshot.json @@ -0,0 +1,3643 @@ +{ + "id": "988c292e-03b4-410e-891d-df1bb34702ca", + "prevId": "3bdbf94f-82ef-448e-b19a-3d1634d288e8", + "version": "7", + "dialect": "postgresql", + "tables": { + "auth.account": { + "name": "account", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "account_issuer_unique": { + "name": "account_issuer_unique", + "columns": [ + { + "expression": "issuer", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.artifact_group": { + "name": "artifact_group", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "artifact_group_order_idx": { + "name": "artifact_group_order_idx", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "artifact_group_guide_id_guide_id_fk": { + "name": "artifact_group_guide_id_guide_id_fk", + "tableFrom": "artifact_group", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.artifact_profile": { + "name": "artifact_profile", + "schema": "guides", + "columns": { + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "sands": { + "name": "sands", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "goblet": { + "name": "goblet", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "circlet": { + "name": "circlet", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "substats": { + "name": "substats", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "targets": { + "name": "targets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "talents": { + "name": "talents", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "artifact_profile_guide_id_guide_id_fk": { + "name": "artifact_profile_guide_id_guide_id_fk", + "tableFrom": "artifact_profile", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.artifact_recommendation": { + "name": "artifact_recommendation", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "first_artifact_key": { + "name": "first_artifact_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "second_artifact_key": { + "name": "second_artifact_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "percent": { + "name": "percent", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "artifact_recommendation_order_idx": { + "name": "artifact_recommendation_order_idx", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "artifact_recommendation_group_id_artifact_group_id_fk": { + "name": "artifact_recommendation_group_id_artifact_group_id_fk", + "tableFrom": "artifact_recommendation", + "tableTo": "artifact_group", + "schemaTo": "guides", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.block": { + "name": "block", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "schema_version": { + "name": "schema_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "responsive_layout": { + "name": "responsive_layout", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "block_page_order_idx": { + "name": "block_page_order_idx", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "block_page_id_page_id_fk": { + "name": "block_page_id_page_id_fk", + "tableFrom": "block", + "tableTo": "page", + "schemaTo": "editor", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "catalog.artifact": { + "name": "artifact", + "schema": "catalog", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rarity": { + "name": "rarity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image_key": { + "name": "image_key", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "catalog_artifact_name_idx": { + "name": "catalog_artifact_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "artifact_key_pk": { + "name": "artifact_key_pk", + "columns": [ + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "catalog.character": { + "name": "character", + "schema": "catalog", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "element": { + "name": "element", + "type": "varchar(48)", + "primaryKey": false, + "notNull": false + }, + "rarity": { + "name": "rarity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "weapon_type": { + "name": "weapon_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "image_key": { + "name": "image_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "element_icon_key": { + "name": "element_icon_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "coop_image_key": { + "name": "coop_image_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name_card_image_key": { + "name": "name_card_image_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "constellations": { + "name": "constellations", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "talents": { + "name": "talents", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "ascension": { + "name": "ascension", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + } + }, + "indexes": { + "catalog_character_name_idx": { + "name": "catalog_character_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "character_key_pk": { + "name": "character_key_pk", + "columns": [ + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "catalog.material": { + "name": "material", + "schema": "catalog", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rarity": { + "name": "rarity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "image_key": { + "name": "image_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "catalog_material_name_idx": { + "name": "catalog_material_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "catalog.weapon": { + "name": "weapon", + "schema": "catalog", + "columns": { + "key": { + "name": "key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rarity": { + "name": "rarity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "weapon_type": { + "name": "weapon_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "image_key": { + "name": "image_key", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "catalog_weapon_name_idx": { + "name": "catalog_weapon_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": { + "weapon_key_pk": { + "name": "weapon_key_pk", + "columns": [ + "key" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.character": { + "name": "character", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "name_th": { + "name": "name_th", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name_en": { + "name": "name_en", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "portrait_media_id": { + "name": "portrait_media_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "element": { + "name": "element", + "type": "varchar(48)", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "varchar(80)", + "primaryKey": false, + "notNull": false + }, + "rarity": { + "name": "rarity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "visible": { + "name": "visible", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "character_slug_unique": { + "name": "character_slug_unique", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "character_directory_idx": { + "name": "character_directory_idx", + "columns": [ + { + "expression": "visible", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "character_portrait_media_id_media_id_fk": { + "name": "character_portrait_media_id_media_id_fk", + "tableFrom": "character", + "tableTo": "media", + "schemaTo": "media", + "columnsFrom": [ + "portrait_media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.constellation_condition": { + "name": "constellation_condition", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "constellation_condition_order_idx": { + "name": "constellation_condition_order_idx", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "constellation_condition_guide_id_guide_id_fk": { + "name": "constellation_condition_guide_id_guide_id_fk", + "tableFrom": "constellation_condition", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.constellation_recommendation": { + "name": "constellation_recommendation", + "schema": "guides", + "columns": { + "condition_id": { + "name": "condition_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "detail": { + "name": "detail", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cumulative_percent": { + "name": "cumulative_percent", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": true + }, + "is_great": { + "name": "is_great", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": { + "constellation_recommendation_condition_id_constellation_condition_id_fk": { + "name": "constellation_recommendation_condition_id_constellation_condition_id_fk", + "tableFrom": "constellation_recommendation", + "tableTo": "constellation_condition", + "schemaTo": "guides", + "columnsFrom": [ + "condition_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "constellation_recommendation_condition_id_level_pk": { + "name": "constellation_recommendation_condition_id_level_pk", + "columns": [ + "condition_id", + "level" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.data_source_version": { + "name": "data_source_version", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "rows": { + "name": "rows", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "evaluation": { + "name": "evaluation", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_by_id": { + "name": "created_by_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "data_source_version_unique": { + "name": "data_source_version_unique", + "columns": [ + { + "expression": "data_source_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_source_version_data_source_id_data_source_id_fk": { + "name": "data_source_version_data_source_id_data_source_id_fk", + "tableFrom": "data_source_version", + "tableTo": "data_source", + "schemaTo": "editor", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "data_source_version_created_by_id_user_id_fk": { + "name": "data_source_version_created_by_id_user_id_fk", + "tableFrom": "data_source_version", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.data_source": { + "name": "data_source", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fields": { + "name": "fields", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "current_version": { + "name": "current_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "data_source_name_idx": { + "name": "data_source_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.extra_section_row": { + "name": "extra_section_row", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "media_id": { + "name": "media_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "heading": { + "name": "heading", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "percent": { + "name": "percent", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": false + }, + "background_color": { + "name": "background_color", + "type": "varchar(7)", + "primaryKey": false, + "notNull": false + }, + "text_color": { + "name": "text_color", + "type": "varchar(7)", + "primaryKey": false, + "notNull": false + }, + "highlights": { + "name": "highlights", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "catalog_items": { + "name": "catalog_items", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "sheet": { + "name": "sheet", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "extra_section_row_order_idx": { + "name": "extra_section_row_order_idx", + "columns": [ + { + "expression": "section_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "extra_section_row_section_id_extra_section_section_id_fk": { + "name": "extra_section_row_section_id_extra_section_section_id_fk", + "tableFrom": "extra_section_row", + "tableTo": "extra_section", + "schemaTo": "guides", + "columnsFrom": [ + "section_id" + ], + "columnsTo": [ + "section_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "extra_section_row_media_id_media_id_fk": { + "name": "extra_section_row_media_id_media_id_fk", + "tableFrom": "extra_section_row", + "tableTo": "media", + "schemaTo": "media", + "columnsFrom": [ + "media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.extra_section": { + "name": "extra_section", + "schema": "guides", + "columns": { + "section_id": { + "name": "section_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "extra_section_section_id_guide_section_id_fk": { + "name": "extra_section_section_id_guide_section_id_fk", + "tableFrom": "extra_section", + "tableTo": "guide_section", + "schemaTo": "guides", + "columnsFrom": [ + "section_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.glossary_alias": { + "name": "glossary_alias", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "kind": { + "name": "kind", + "type": "varchar(16)", + "primaryKey": false, + "notNull": true + }, + "catalog_key": { + "name": "catalog_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "alias": { + "name": "alias", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "normalized_alias": { + "name": "normalized_alias", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "glossary_alias_kind_normalized_unique": { + "name": "glossary_alias_kind_normalized_unique", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "normalized_alias", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "glossary_alias_item_idx": { + "name": "glossary_alias_item_idx", + "columns": [ + { + "expression": "kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "catalog_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.guide_section": { + "name": "guide_section", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(32)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "guide_section_slug_unique": { + "name": "guide_section_slug_unique", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "guide_section_order_idx": { + "name": "guide_section_order_idx", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "guide_section_guide_id_guide_id_fk": { + "name": "guide_section_guide_id_guide_id_fk", + "tableFrom": "guide_section", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.guide": { + "name": "guide", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "character_key": { + "name": "character_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "overview": { + "name": "overview", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "youtube_url": { + "name": "youtube_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cover_media_id": { + "name": "cover_media_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "trashed_at": { + "name": "trashed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "guide_character_key_unique": { + "name": "guide_character_key_unique", + "columns": [ + { + "expression": "character_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "guide_slug_unique": { + "name": "guide_slug_unique", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "guide_directory_idx": { + "name": "guide_directory_idx", + "columns": [ + { + "expression": "trashed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "guide_cover_media_id_media_id_fk": { + "name": "guide_cover_media_id_media_id_fk", + "tableFrom": "guide", + "tableTo": "media", + "schemaTo": "media", + "columnsFrom": [ + "cover_media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "media.media": { + "name": "media", + "schema": "media", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "object_key": { + "name": "object_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "byte_size": { + "name": "byte_size", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "checksum": { + "name": "checksum", + "type": "varchar(128)", + "primaryKey": false, + "notNull": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "current_reference_count": { + "name": "current_reference_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "revision_reference_count": { + "name": "revision_reference_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_by_id": { + "name": "created_by_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "media_object_key_unique": { + "name": "media_object_key_unique", + "columns": [ + { + "expression": "object_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "media_visibility_idx": { + "name": "media_visibility_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "current_reference_count", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "media_created_by_id_user_id_fk": { + "name": "media_created_by_id_user_id_fk", + "tableFrom": "media", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "created_by_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "media.media_reference": { + "name": "media_reference", + "schema": "media", + "columns": { + "media_id": { + "name": "media_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_type": { + "name": "owner_type", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true + }, + "owner_id": { + "name": "owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "reference_kind": { + "name": "reference_kind", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "media_reference_owner_idx": { + "name": "media_reference_owner_idx", + "columns": [ + { + "expression": "owner_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "media_reference_media_id_media_id_fk": { + "name": "media_reference_media_id_media_id_fk", + "tableFrom": "media_reference", + "tableTo": "media", + "schemaTo": "media", + "columnsFrom": [ + "media_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "media_reference_media_id_owner_type_owner_id_reference_kind_pk": { + "name": "media_reference_media_id_owner_type_owner_id_reference_kind_pk", + "columns": [ + "media_id", + "owner_type", + "owner_id", + "reference_kind" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.outbox_event": { + "name": "outbox_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "outbox_event_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "9223372036854775807", + "cache": "1", + "cycle": false + } + }, + "topic": { + "name": "topic", + "type": "varchar(160)", + "primaryKey": false, + "notNull": true + }, + "aggregate_id": { + "name": "aggregate_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "available_at": { + "name": "available_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "outbox_pending_idx": { + "name": "outbox_pending_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.page_data_source": { + "name": "page_data_source", + "schema": "editor", + "columns": { + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data_source_id": { + "name": "data_source_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pinned_version": { + "name": "pinned_version", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "page_data_source_dependency_idx": { + "name": "page_data_source_dependency_idx", + "columns": [ + { + "expression": "data_source_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "page_data_source_page_id_page_id_fk": { + "name": "page_data_source_page_id_page_id_fk", + "tableFrom": "page_data_source", + "tableTo": "page", + "schemaTo": "editor", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "page_data_source_data_source_id_data_source_id_fk": { + "name": "page_data_source_data_source_id_data_source_id_fk", + "tableFrom": "page_data_source", + "tableTo": "data_source", + "schemaTo": "editor", + "columnsFrom": [ + "data_source_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "page_data_source_page_id_data_source_id_pk": { + "name": "page_data_source_page_id_data_source_id_pk", + "columns": [ + "page_id", + "data_source_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.page": { + "name": "page", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nav_order": { + "name": "nav_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "visible": { + "name": "visible", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "public_note": { + "name": "public_note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "page_character_slug_unique": { + "name": "page_character_slug_unique", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "page_navigation_idx": { + "name": "page_navigation_idx", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "visible", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "nav_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "page_character_id_character_id_fk": { + "name": "page_character_id_character_id_fk", + "tableFrom": "page", + "tableTo": "character", + "schemaTo": "editor", + "columnsFrom": [ + "character_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.public_snapshot": { + "name": "public_snapshot", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "page_version": { + "name": "page_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "version_vector": { + "name": "version_vector", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "vector_hash": { + "name": "vector_hash", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "dto": { + "name": "dto", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "visible": { + "name": "visible", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "public_snapshot_version_unique": { + "name": "public_snapshot_version_unique", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "page_version", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "vector_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_snapshot_lookup_idx": { + "name": "public_snapshot_lookup_idx", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "visible", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "public_snapshot_page_id_page_id_fk": { + "name": "public_snapshot_page_id_page_id_fk", + "tableFrom": "public_snapshot", + "tableTo": "page", + "schemaTo": "editor", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.revision": { + "name": "revision", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "page_id": { + "name": "page_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "page_version": { + "name": "page_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "author_id": { + "name": "author_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_revision_id": { + "name": "source_revision_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "checkpoint_hour": { + "name": "checkpoint_hour", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "data_source_versions": { + "name": "data_source_versions", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "media_ids": { + "name": "media_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "revision_page_created_idx": { + "name": "revision_page_created_idx", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "revision_checkpoint_hour_unique": { + "name": "revision_checkpoint_hour_unique", + "columns": [ + { + "expression": "page_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "checkpoint_hour", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"editor\".\"revision\".\"kind\" = 'checkpoint'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "revision_page_id_page_id_fk": { + "name": "revision_page_id_page_id_fk", + "tableFrom": "revision", + "tableTo": "page", + "schemaTo": "editor", + "columnsFrom": [ + "page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "revision_author_id_user_id_fk": { + "name": "revision_author_id_user_id_fk", + "tableFrom": "revision", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "author_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.session": { + "name": "session", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.slug_alias": { + "name": "slug_alias", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "kind": { + "name": "kind", + "type": "varchar(24)", + "primaryKey": false, + "notNull": true + }, + "old_character_slug": { + "name": "old_character_slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "old_page_slug": { + "name": "old_page_slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": false + }, + "target_character_id": { + "name": "target_character_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "target_page_id": { + "name": "target_page_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slug_alias_path_unique": { + "name": "slug_alias_path_unique", + "columns": [ + { + "expression": "old_character_slug", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "old_page_slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slug_alias_target_character_id_character_id_fk": { + "name": "slug_alias_target_character_id_character_id_fk", + "tableFrom": "slug_alias", + "tableTo": "character", + "schemaTo": "editor", + "columnsFrom": [ + "target_character_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slug_alias_target_page_id_page_id_fk": { + "name": "slug_alias_target_page_id_page_id_fk", + "tableFrom": "slug_alias", + "tableTo": "page", + "schemaTo": "editor", + "columnsFrom": [ + "target_page_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.team_composition": { + "name": "team_composition", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rotation_seconds": { + "name": "rotation_seconds", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": true + }, + "combo": { + "name": "combo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "team_composition_order_idx": { + "name": "team_composition_order_idx", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "team_composition_guide_id_guide_id_fk": { + "name": "team_composition_guide_id_guide_id_fk", + "tableFrom": "team_composition", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.team_member": { + "name": "team_member", + "schema": "guides", + "columns": { + "team_id": { + "name": "team_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "character_key": { + "name": "character_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "weapon_key": { + "name": "weapon_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "artifact_key": { + "name": "artifact_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "second_artifact_key": { + "name": "second_artifact_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": false + }, + "constellation": { + "name": "constellation", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "refinement": { + "name": "refinement", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "damage": { + "name": "damage", + "type": "numeric(18, 2)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "team_member_team_id_team_composition_id_fk": { + "name": "team_member_team_id_team_composition_id_fk", + "tableFrom": "team_member", + "tableTo": "team_composition", + "schemaTo": "guides", + "columnsFrom": [ + "team_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "team_member_team_id_position_pk": { + "name": "team_member_team_id_position_pk", + "columns": [ + "team_id", + "position" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "editor.template": { + "name": "template", + "schema": "editor", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "varchar(120)", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "structure": { + "name": "structure", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "built_in": { + "name": "built_in", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "template_slug_unique": { + "name": "template_slug_unique", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.user": { + "name": "user", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'admin'" + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "auth.verification": { + "name": "verification", + "schema": "auth", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.weapon_condition": { + "name": "weapon_condition", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "guide_id": { + "name": "guide_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "weapon_condition_order_idx": { + "name": "weapon_condition_order_idx", + "columns": [ + { + "expression": "guide_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "weapon_condition_guide_id_guide_id_fk": { + "name": "weapon_condition_guide_id_guide_id_fk", + "tableFrom": "weapon_condition", + "tableTo": "guide", + "schemaTo": "guides", + "columnsFrom": [ + "guide_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "guides.weapon_recommendation": { + "name": "weapon_recommendation", + "schema": "guides", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "condition_id": { + "name": "condition_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "weapon_key": { + "name": "weapon_key", + "type": "varchar(64)", + "primaryKey": false, + "notNull": true + }, + "refinement": { + "name": "refinement", + "type": "varchar(8)", + "primaryKey": false, + "notNull": true + }, + "overall_percent": { + "name": "overall_percent", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": false + }, + "personal_percent": { + "name": "personal_percent", + "type": "numeric(8, 2)", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "weapon_recommendation_order_idx": { + "name": "weapon_recommendation_order_idx", + "columns": [ + { + "expression": "condition_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "weapon_recommendation_condition_id_weapon_condition_id_fk": { + "name": "weapon_recommendation_condition_id_weapon_condition_id_fk", + "tableFrom": "weapon_recommendation", + "tableTo": "weapon_condition", + "schemaTo": "guides", + "columnsFrom": [ + "condition_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "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/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 62b8cd1..1a3e9d4 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -218,6 +218,13 @@ "when": 1788605973095, "tag": "0030_third_maddog", "breakpoints": true + }, + { + "idx": 31, + "version": "7", + "when": 1788673251760, + "tag": "0031_watery_sumo", + "breakpoints": true } ] } \ No newline at end of file diff --git a/lib/catalog/lunaris.test.ts b/lib/catalog/lunaris.test.ts index ccc2eb8..b9c5468 100644 --- a/lib/catalog/lunaris.test.ts +++ b/lib/catalog/lunaris.test.ts @@ -2,6 +2,7 @@ import { describe, expect, it } from "vitest"; import { avatarIconName, + ascensionSnapshot, characterDetailSchema, cleanLunarisText, constellationSnapshot, @@ -58,6 +59,26 @@ describe("Lunaris character data", () => { expect(constellationSnapshot(detail, (icon) => icon)).toEqual([]); }); + it("normalizes scalar and grouped ascension materials", () => { + const detail = characterDetailSchema.parse({ + ascension: { + "202": 7049900, + exp: { "104001": 2, "104003": 418 }, + }, + }); + + expect(ascensionSnapshot(detail)).toEqual([ + { type: "202", items: [{ key: "202", amount: 7049900 }] }, + { + type: "exp", + items: [ + { key: "104001", amount: 2 }, + { key: "104003", amount: 418 }, + ], + }, + ]); + }); + it("reads the supported weapon type from character details", () => { const detail = characterDetailSchema.parse({ info: { element: "Cryo", weapon: "WEAPON_SWORD_ONE_HAND" }, diff --git a/lib/catalog/lunaris.ts b/lib/catalog/lunaris.ts index 1defd89..a98889b 100644 --- a/lib/catalog/lunaris.ts +++ b/lib/catalog/lunaris.ts @@ -14,6 +14,25 @@ export interface CatalogTalent { iconKey: string | null; } +export interface CatalogAscensionMaterial { + key: string; + amount: number; +} + +export interface CatalogAscensionGroup { + type: string; + items: CatalogAscensionMaterial[]; +} + +export interface CatalogMaterial { + key: string; + name: string; + description: string | null; + rarity: number | null; + type: string | null; + imageKey: string; +} + const constellationSchema = z.object({ name: z.string(), description: z.string(), @@ -37,6 +56,10 @@ export const characterDetailSchema = z.object({ elementalskill: skillSchema.optional(), elementalburst: skillSchema.optional(), }).nullish(), + ascension: z.record( + z.string(), + z.union([z.number().int(), z.record(z.string(), z.number().int())]), + ).nullish(), }); export function cleanLunarisText(value: string): string { @@ -106,3 +129,15 @@ export function talentSnapshot( iconKey: iconKey(talent.icon), }] : []); } + +export function ascensionSnapshot( + value: z.infer, +): CatalogAscensionGroup[] { + return Object.entries(value.ascension ?? {}).map(([type, entries]) => ({ + type, + items: + typeof entries === "number" + ? [{ key: type, amount: entries }] + : Object.entries(entries).map(([key, amount]) => ({ key, amount })), + })); +} diff --git a/lib/catalog/sync.ts b/lib/catalog/sync.ts index 0982a6d..25753bf 100644 --- a/lib/catalog/sync.ts +++ b/lib/catalog/sync.ts @@ -6,9 +6,11 @@ import { getDb } from "@/db/client"; import { catalogArtifacts, catalogCharacters, + catalogMaterials, catalogWeapons, } from "@/db/schema"; import { + ascensionSnapshot, avatarIconName, characterDetailSchema, constellationSnapshot, @@ -17,7 +19,9 @@ import { talentSnapshot, } from "@/lib/catalog/lunaris"; import type { + CatalogAscensionGroup, CatalogConstellation, + CatalogMaterial, CatalogTalent, } from "@/lib/catalog/lunaris"; import { customTravelers, isUpstreamTraveler } from "@/lib/catalog/travelers"; @@ -63,6 +67,16 @@ const artifactSchema = z.record( qualityType: z.string().optional(), }), ); +const materialSchema = z.record( + z.string(), + z.object({ + enName: z.string(), + enDescription: z.string().optional(), + icon: z.string(), + qualityType: z.string().optional(), + type: z.string().optional(), + }), +); interface SyncedCharacter { key: string; @@ -80,6 +94,7 @@ interface SyncedCharacter { localImage: string | null; constellations: CatalogConstellation[]; talents: CatalogTalent[]; + ascension: CatalogAscensionGroup[]; } async function getJson(url: string): Promise { @@ -107,6 +122,10 @@ function webpName(value: string): string { return value.endsWith(".webp") ? value : `${value}.webp`; } +function pngName(value: string): string { + return value.endsWith(".png") ? value : `${value}.png`; +} + function rarity(value: string | undefined): number | null { if (!value) return null; return ( @@ -186,14 +205,26 @@ async function uploadAssets( } async function syncCatalogVersion(version: string): Promise { - const [charactersRaw, weaponsRaw, artifactsRaw] = await Promise.all([ + const [charactersRaw, weaponsRaw, artifactsRaw, materialsRaw] = await Promise.all([ getJson(`${API_ROOT}/${version}/charlist.json`), getJson(`${API_ROOT}/${version}/weaponlist.json`), getJson(`${API_ROOT}/${version}/artifactlist.json`), + getJson(`${API_ROOT}/${version}/materiallist.json`), ]); const characterData = characterSchema.parse(charactersRaw); const weaponData = weaponSchema.parse(weaponsRaw); const artifactData = artifactSchema.parse(artifactsRaw); + const materialData = materialSchema.parse(materialsRaw); + const materials: CatalogMaterial[] = Object.entries(materialData).map( + ([key, value]) => ({ + key, + name: value.enName, + description: value.enDescription ?? null, + rarity: rarity(value.qualityType), + type: value.type ?? null, + imageKey: `catalog/materials/${pngName(value.icon)}`, + }), + ); const remoteCharacters: SyncedCharacter[] = await mapConcurrent( Object.entries(characterData).filter( @@ -207,7 +238,7 @@ async function syncCatalogVersion(version: string): Promise { const detailRaw = await getOptionalJson( `${API_ROOT}/${version}/en/char/${encodeURIComponent(key)}.json`, ); - const detail = detailRaw + const detail = detailRaw ? characterDetailSchema.parse(detailRaw) : null; const avatarIcon = webpName(avatarIconName(value.CardImg)); @@ -242,6 +273,7 @@ async function syncCatalogVersion(version: string): Promise { (icon) => `catalog/characters/talents/${webpName(icon)}`, ) : [], + ascension: detail ? ascensionSnapshot(detail) : [], }; }, ); @@ -275,6 +307,7 @@ async function syncCatalogVersion(version: string): Promise { detail, (icon) => `catalog/characters/talents/${webpName(icon)}`, ), + ascension: ascensionSnapshot(detail), }; }, ); @@ -339,6 +372,14 @@ async function syncCatalogVersion(version: string): Promise { source: item.sourceImage, target: item.imageKey, }); + for (const material of materials) { + const source = materialData[material.key].icon; + uniqueAssets.set(material.imageKey, { + source: `${API_ROOT}/assets/items/${encodeURIComponent(pngName(source))}`, + target: material.imageKey, + type: "image/png", + }); + } for (const character of characters) { if (character.elementIconKey && character.element) uniqueAssets.set(character.elementIconKey, { @@ -414,6 +455,7 @@ async function syncCatalogVersion(version: string): Promise { nameCardImageKey: item.nameCardImageKey, constellations: item.constellations, talents: item.talents, + ascension: item.ascension, })), ), { type: "application/json", acl: "public-read" }, @@ -443,10 +485,16 @@ async function syncCatalogVersion(version: string): Promise { ), { type: "application/json", acl: "public-read" }, ), + storage.write( + "catalog/materials.json", + JSON.stringify(materials), + { type: "application/json", acl: "public-read" }, + ), ]); await getDb().transaction(async (tx) => { await tx.delete(catalogCharacters); + await tx.delete(catalogMaterials); await tx.delete(catalogWeapons); await tx.delete(catalogArtifacts); if (characters.length) @@ -465,8 +513,11 @@ async function syncCatalogVersion(version: string): Promise { nameCardImageKey: item.nameCardImageKey, constellations: item.constellations, talents: item.talents, + ascension: item.ascension, })), ); + if (materials.length) + await tx.insert(catalogMaterials).values(materials); if (weapons.length) await tx .insert(catalogWeapons) diff --git a/lib/guides/queries.ts b/lib/guides/queries.ts index b76644c..bd6590b 100644 --- a/lib/guides/queries.ts +++ b/lib/guides/queries.ts @@ -10,6 +10,7 @@ import { artifactRecommendations, catalogArtifacts, catalogCharacters, + catalogMaterials, catalogWeapons, constellationConditions, constellationRecommendations, @@ -28,7 +29,10 @@ import { aliasesByItem } from "@/lib/glossary"; const catalogVersionSchema = z.object({ version: z.string() }); -function catalogCharacterWithUrls(item: typeof catalogCharacters.$inferSelect) { +function catalogCharacterWithUrls( + item: typeof catalogCharacters.$inferSelect, + materialByKey = new Map(), +) { return { ...item, imageUrl: publicMediaUrl(item.imageKey), @@ -43,28 +47,47 @@ function catalogCharacterWithUrls(item: typeof catalogCharacters.$inferSelect) { ...talent, iconUrl: talent.iconKey ? publicMediaUrl(talent.iconKey) : null, })), + ascension: item.ascension.map((group) => ({ + ...group, + items: group.items.map((entry) => { + const material = materialByKey.get(entry.key); + return { + ...entry, + name: material?.name ?? entry.key, + description: material?.description ?? null, + rarity: material?.rarity ?? null, + type: material?.type ?? null, + imageUrl: material ? publicMediaUrl(material.imageKey) : null, + lunarisUrl: `https://lunaris.moe/material/${encodeURIComponent(entry.key)}`, + available: Boolean(material), + }; + }), + })), }; } export async function getActiveCatalog() { const db = getDb(); - const [characters, weapons, artifacts, aliases] = await Promise.all([ + const [characters, weapons, artifacts, materials, aliases] = await Promise.all([ db.select().from(catalogCharacters).orderBy(asc(catalogCharacters.name)), db.select().from(catalogWeapons).orderBy(asc(catalogWeapons.name)), db.select().from(catalogArtifacts).orderBy(asc(catalogArtifacts.name)), + db.select().from(catalogMaterials).orderBy(asc(catalogMaterials.name)), db.select().from(glossaryAliases), ]); if (!characters.length) return null; const groupedAliases = aliasesByItem(aliases); + const materialByKey = new Map(materials.map((item) => [item.key, item])); const storage = await getMediaStorage(); const { version } = catalogVersionSchema.parse( await storage.file("catalog/current.json").json(), ); return { version, - characters: characters.map((item) => ({ ...catalogCharacterWithUrls(item), aliases: groupedAliases.character.get(item.key) ?? [] })), + characters: characters.map((item) => ({ ...catalogCharacterWithUrls(item, materialByKey), aliases: groupedAliases.character.get(item.key) ?? [] })), weapons: weapons.map((item) => ({ ...item, aliases: groupedAliases.weapon.get(item.key) ?? [], imageUrl: publicMediaUrl(item.imageKey) })), artifacts: artifacts.map((item) => ({ ...item, aliases: groupedAliases.artifact.get(item.key) ?? [], imageUrl: publicMediaUrl(item.imageKey) })), + materials: materials.map((item) => ({ ...item, imageUrl: publicMediaUrl(item.imageKey), lunarisUrl: `https://lunaris.moe/material/${encodeURIComponent(item.key)}` })), }; } @@ -114,7 +137,10 @@ async function getGuideContent(slug: string, publicOnly: boolean) { )) .limit(1); if (!row) return null; - const [sections, weaponConditionsRows, groups, profile, constellationGroups, teams, aliases] = await Promise.all([ + const materialKeys = [...new Set( + row.character.ascension.flatMap((group) => group.items.map((item) => item.key)), + )]; + const [sections, weaponConditionsRows, groups, profile, constellationGroups, teams, aliases, materials] = await Promise.all([ getDb().select().from(guideSections).where(and(eq(guideSections.guideId, row.guide.id), eq(guideSections.enabled, true))).orderBy(asc(guideSections.sortOrder)), getDb().select().from(weaponConditions).where(eq(weaponConditions.guideId, row.guide.id)).orderBy(asc(weaponConditions.sortOrder)), getDb().select().from(artifactGroups).where(eq(artifactGroups.guideId, row.guide.id)).orderBy(asc(artifactGroups.sortOrder)), @@ -122,8 +148,12 @@ async function getGuideContent(slug: string, publicOnly: boolean) { getDb().select().from(constellationConditions).where(eq(constellationConditions.guideId, row.guide.id)).orderBy(asc(constellationConditions.sortOrder)), getDb().select().from(teamCompositions).where(eq(teamCompositions.guideId, row.guide.id)).orderBy(asc(teamCompositions.sortOrder)), getDb().select().from(glossaryAliases), + materialKeys.length + ? getDb().select().from(catalogMaterials).where(inArray(catalogMaterials.key, materialKeys)) + : [], ]); const groupedAliases = aliasesByItem(aliases); + const materialByKey = new Map(materials.map((item) => [item.key, item])); const elementIconUrls = Object.fromEntries( (await getDb() @@ -168,7 +198,7 @@ async function getGuideContent(slug: string, publicOnly: boolean) { return { ...row.guide, coverUrl: publicMediaUrl(row.cover.objectKey), - character: { ...catalogCharacterWithUrls(row.character), aliases: groupedAliases.character.get(row.character.key) ?? [] }, + character: { ...catalogCharacterWithUrls(row.character, materialByKey), aliases: groupedAliases.character.get(row.character.key) ?? [] }, elementIconUrls, sections, weapons: weaponRows.map(({ recommendation, weapon }) => ({ ...recommendation, weapon: { ...weapon, aliases: groupedAliases.weapon.get(weapon.key) ?? [], imageUrl: publicMediaUrl(weapon.imageKey) } })),