Merge pull request #17 from BradNut/migrate-two-factor

Migrate two factor
This commit is contained in:
Bradley Shellnut 2024-07-12 02:11:56 +00:00 committed by GitHub
commit a45a24fdea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
204 changed files with 10417 additions and 21559 deletions

2
.nvmrc
View file

@ -1 +1 @@
v20
20

View file

@ -1,20 +1,21 @@
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
import env from './src/env';
export default defineConfig({
schema: './src/schema.ts',
out: './drizzle',
driver: 'pg',
dialect: 'postgresql',
schema: './src/db/schema/index.ts',
out: './src/db/migrations',
dbCredentials: {
host: process.env.DATABASE_HOST || 'localhost',
port: Number(process.env.DATABASE_PORT) || 5432,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE || 'boredgame',
ssl: process.env.DATABASE_HOST !== 'localhost'
host: env.DATABASE_HOST || 'localhost',
port: Number(env.DATABASE_PORT) || 5432,
user: env.DATABASE_USER,
password: env.DATABASE_PASSWORD,
database: env.DATABASE_DB || 'boredgame',
ssl: env.DATABASE_HOST !== 'localhost',
},
// Print all statements
verbose: true,
// Always as for confirmation
strict: true
strict: true,
});

View file

@ -1,6 +0,0 @@
ALTER TABLE "collection_items" ALTER COLUMN "collection_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "collection_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "expansions" ALTER COLUMN "base_game_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "expansions" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "wishlist_items" ALTER COLUMN "wishlist_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "wishlist_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;

View file

@ -1,5 +0,0 @@
ALTER TABLE "collections" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "password_reset_tokens" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "sessions" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "user_roles" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
ALTER TABLE "wishlists" ALTER COLUMN "user_id" SET DATA TYPE uuid;

View file

@ -1 +0,0 @@
ALTER TABLE "user_roles" ALTER COLUMN "role_id" SET DATA TYPE uuid;

View file

@ -1,13 +0,0 @@
ALTER TABLE "categories" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "collection_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "collections" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "expansions" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "external_ids" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "games" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "mechanics" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "publishers" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "user_roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "users" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "wishlist_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
ALTER TABLE "wishlists" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();

View file

@ -1,2 +0,0 @@
ALTER TABLE "roles" ALTER COLUMN "cuid" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "roles" ALTER COLUMN "name" SET NOT NULL;

View file

@ -1 +0,0 @@
ALTER TABLE "user_roles" ADD COLUMN "default" boolean DEFAULT false;

View file

@ -1 +0,0 @@
ALTER TABLE "user_roles" RENAME COLUMN "default" TO "primary";

View file

@ -1 +0,0 @@
ALTER TABLE "users" ADD COLUMN "two_factor_secret" text;

View file

@ -1,2 +0,0 @@
ALTER TABLE "users" ALTER COLUMN "two_factor_secret" SET DEFAULT '';--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "two_factor_enabled" boolean DEFAULT false;

View file

@ -1,14 +0,0 @@
CREATE TABLE IF NOT EXISTS "recovery_codes" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"user_id" uuid NOT NULL,
"code" text NOT NULL,
"used" boolean DEFAULT false,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "recovery_codes" ADD CONSTRAINT "recovery_codes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View file

@ -1,2 +0,0 @@
ALTER TABLE "collections" ADD COLUMN "name" text DEFAULT 'My Collection' NOT NULL;--> statement-breakpoint
ALTER TABLE "wishlists" ADD COLUMN "name" text DEFAULT 'My Wishlist' NOT NULL;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,90 +0,0 @@
{
"version": "5",
"dialect": "pg",
"entries": [
{
"idx": 0,
"version": "5",
"when": 1710268038944,
"tag": "0000_tricky_hitman",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1710268191378,
"tag": "0001_numerous_dragon_man",
"breakpoints": true
},
{
"idx": 2,
"version": "5",
"when": 1710268300740,
"tag": "0002_thick_lyja",
"breakpoints": true
},
{
"idx": 3,
"version": "5",
"when": 1710268371021,
"tag": "0003_mushy_madame_masque",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1710277583673,
"tag": "0004_glossy_enchantress",
"breakpoints": true
},
{
"idx": 5,
"version": "5",
"when": 1710366724519,
"tag": "0005_light_captain_marvel",
"breakpoints": true
},
{
"idx": 6,
"version": "5",
"when": 1710905422967,
"tag": "0006_wild_stone_men",
"breakpoints": true
},
{
"idx": 7,
"version": "5",
"when": 1710905572670,
"tag": "0007_large_miss_america",
"breakpoints": true
},
{
"idx": 8,
"version": "5",
"when": 1711757183163,
"tag": "0008_amusing_franklin_richards",
"breakpoints": true
},
{
"idx": 9,
"version": "5",
"when": 1711868447607,
"tag": "0009_gray_carlie_cooper",
"breakpoints": true
},
{
"idx": 10,
"version": "5",
"when": 1712271520175,
"tag": "0010_wakeful_metal_master",
"breakpoints": true
},
{
"idx": 11,
"version": "5",
"when": 1713311328819,
"tag": "0011_charming_bucky",
"breakpoints": true
}
]
}

View file

@ -15,59 +15,58 @@
"lint": "prettier --plugin-search-dir . --check . && eslint .",
"format": "prettier --plugin-search-dir . --write .",
"site:update": "pnpm update -i -L",
"generate": "drizzle-kit generate:pg",
"migrate": "tsx ./src/migrate.ts",
"seed": "tsx ./src/seed.ts",
"push": "drizzle-kit push:pg"
"generate": "drizzle-kit generate",
"migrate": "tsx src/db/migrate.ts",
"seed": "tsx src/db/seed.ts",
"push": "drizzle-kit push"
},
"devDependencies": {
"@melt-ui/pp": "^0.3.0",
"@melt-ui/svelte": "^0.76.3",
"@playwright/test": "^1.43.1",
"@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.83.0",
"@playwright/test": "^1.45.1",
"@resvg/resvg-js": "^2.6.2",
"@sveltejs/adapter-auto": "^3.2.0",
"@sveltejs/enhanced-img": "^0.2.0",
"@sveltejs/kit": "^2.5.6",
"@sveltejs/vite-plugin-svelte": "^3.1.0",
"@sveltejs/adapter-auto": "^3.2.2",
"@sveltejs/enhanced-img": "^0.3.0",
"@sveltejs/kit": "^2.5.18",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@types/cookie": "^0.6.0",
"@types/node": "^20.12.6",
"@types/pg": "^8.11.5",
"@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"@types/node": "^20.14.10",
"@types/pg": "^8.11.6",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"autoprefixer": "^10.4.19",
"dotenv": "^16.4.5",
"drizzle-kit": "^0.20.14",
"drizzle-kit": "^0.23.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
"eslint-plugin-svelte": "^2.41.0",
"just-clone": "^6.2.0",
"just-debounce-it": "^3.2.0",
"postcss": "^8.4.38",
"postcss": "^8.4.39",
"postcss-import": "^16.1.0",
"postcss-load-config": "^5.0.3",
"postcss-preset-env": "^9.5.4",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3",
"sass": "^1.74.1",
"postcss-load-config": "^5.1.0",
"postcss-preset-env": "^9.6.0",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.5",
"sass": "^1.77.8",
"satori": "^0.10.13",
"satori-html": "^0.3.2",
"svelte": "^4.2.14",
"svelte-check": "^3.6.9",
"svelte": "5.0.0-next.175",
"svelte-check": "^3.8.4",
"svelte-headless-table": "^0.18.2",
"svelte-meta-tags": "^3.1.2",
"svelte-preprocess": "^5.1.3",
"svelte-preprocess": "^6.0.2",
"svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.4.4",
"sveltekit-rate-limiter": "^0.5.1",
"sveltekit-superforms": "^2.12.4",
"tailwindcss": "^3.4.3",
"sveltekit-superforms": "^2.16.0",
"tailwindcss": "^3.4.4",
"ts-node": "^10.9.2",
"tslib": "^2.6.1",
"tsx": "^4.7.2",
"typescript": "^5.4.4",
"vite": "^5.2.8",
"vitest": "^1.4.0",
"zod": "^3.22.4"
"tslib": "^2.6.3",
"tsx": "^4.16.2",
"typescript": "^5.5.3",
"vite": "^5.3.3",
"vitest": "^1.6.0",
"zod": "^3.23.8"
},
"type": "module",
"engines": {
@ -75,42 +74,44 @@
"pnpm": ">=8"
},
"dependencies": {
"@fontsource/fira-mono": "^5.0.12",
"@iconify-icons/line-md": "^1.2.26",
"@iconify-icons/mdi": "^1.2.47",
"@fontsource/fira-mono": "^5.0.13",
"@iconify-icons/line-md": "^1.2.30",
"@iconify-icons/mdi": "^1.2.48",
"@lucia-auth/adapter-drizzle": "^1.0.7",
"@lukeed/uuid": "^2.0.1",
"@neondatabase/serverless": "^0.9.1",
"@neondatabase/serverless": "^0.9.4",
"@paralleldrive/cuid2": "^2.2.2",
"@sveltejs/adapter-vercel": "^5.2.0",
"@sveltejs/adapter-vercel": "^5.4.1",
"@types/feather-icons": "^4.29.4",
"@vercel/og": "^0.5.20",
"bits-ui": "^0.21.3",
"bits-ui": "^0.21.12",
"boardgamegeekclient": "^1.9.1",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"clsx": "^2.1.1",
"cookie": "^0.6.0",
"drizzle-orm": "^0.30.7",
"feather-icons": "^4.29.1",
"formsnap": "^1.0.0",
"dotenv": "^16.4.5",
"dotenv-expand": "^11.0.6",
"drizzle-orm": "^0.32.0",
"feather-icons": "^4.29.2",
"formsnap": "^1.0.1",
"html-entities": "^2.5.2",
"iconify-icon": "^2.1.0",
"just-capitalize": "^3.2.0",
"just-kebab-case": "^4.2.0",
"loader": "^2.1.1",
"lucia": "3.1.1",
"lucide-svelte": "^0.368.0",
"open-props": "^1.7.2",
"oslo": "^1.2.0",
"pg": "^8.11.5",
"lucia": "3.2.0",
"lucide-svelte": "^0.407.0",
"open-props": "^1.7.5",
"oslo": "^1.2.1",
"pg": "^8.12.0",
"postgres": "^3.4.4",
"qrcode": "^1.5.3",
"radix-svelte": "^0.9.0",
"svelte-french-toast": "^1.2.0",
"svelte-lazy-loader": "^1.0.0",
"tailwind-merge": "^2.2.2",
"tailwind-merge": "^2.4.0",
"tailwind-variants": "^0.2.1",
"tailwindcss-animate": "^1.0.6",
"zod-to-json-schema": "^3.22.5"
"tailwindcss-animate": "^1.0.7",
"zod-to-json-schema": "^3.23.1"
}
}

File diff suppressed because it is too large Load diff

24
src/db/index.ts Normal file
View file

@ -0,0 +1,24 @@
import { drizzle } from 'drizzle-orm/node-postgres';
import pg from 'pg';
import env from '../env';
import * as schema from './schema';
// create the connection
export const pool = new pg.Pool({
user: env.DATABASE_USER,
password: env.DATABASE_PASSWORD,
host: env.DATABASE_HOST,
port: Number(env.DATABASE_PORT).valueOf(),
database: env.DATABASE_DB,
ssl: env.DATABASE_HOST !== 'localhost',
max: env.DB_MIGRATING || env.DB_SEEDING ? 1 : undefined,
});
export const db = drizzle(pool, {
schema,
logger: env.NODE_ENV === 'development',
});
export type db = typeof db;
export default db;

26
src/db/migrate.ts Normal file
View file

@ -0,0 +1,26 @@
import 'dotenv/config';
import postgres from 'postgres';
import { drizzle } from 'drizzle-orm/postgres-js';
import { migrate } from 'drizzle-orm/postgres-js/migrator';
import env from '../env';
import config from '../../drizzle.config';
const connection = postgres({
host: env.DATABASE_HOST || 'localhost',
port: env.DATABASE_PORT,
user: env.DATABASE_USER || 'root',
password: env.DATABASE_PASSWORD || '',
database: env.DATABASE_DB || 'boredgame',
ssl: env.NODE_ENV === 'development' ? false : 'require',
max: 1,
});
const db = drizzle(connection);
try {
await migrate(db, { migrationsFolder: config.out! });
console.log('Migrations complete');
} catch (e) {
console.error(e);
}
process.exit();

View file

@ -1,16 +1,16 @@
DO $$ BEGIN
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
CREATE TYPE "public"."external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "categories" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"name" text,
"slug" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "categories_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
@ -27,48 +27,49 @@ CREATE TABLE IF NOT EXISTS "categories_to_games" (
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "collection_items" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"collection_id" text NOT NULL,
"game_id" text NOT NULL,
"collection_id" uuid NOT NULL,
"game_id" uuid NOT NULL,
"times_played" integer DEFAULT 0,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "collection_items_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "collections" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"user_id" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"user_id" uuid NOT NULL,
"name" text DEFAULT 'My Collection' NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "expansions" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"base_game_id" text NOT NULL,
"game_id" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"base_game_id" uuid NOT NULL,
"game_id" uuid NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "expansions_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "external_ids" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"type" "external_id_type" NOT NULL,
"type" "external_id_type",
"external_id" text NOT NULL,
CONSTRAINT "external_ids_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "games" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"name" text,
"slug" text,
"name" text NOT NULL,
"slug" text NOT NULL,
"description" text,
"year_published" integer,
"min_players" integer,
@ -80,10 +81,9 @@ CREATE TABLE IF NOT EXISTS "games" (
"image_url" text,
"thumb_url" text,
"url" text,
"text_searchable_index" "tsvector",
"last_sync_at" timestamp (6) with time zone,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"last_sync_at" timestamp,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
@ -94,12 +94,12 @@ CREATE TABLE IF NOT EXISTS "games_to_external_ids" (
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "mechanics" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"name" text,
"slug" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "mechanics_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
@ -117,18 +117,19 @@ CREATE TABLE IF NOT EXISTS "mechanics_to_games" (
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"expires_at" timestamp (6) with time zone,
"created_at" timestamp DEFAULT now() NOT NULL
"user_id" uuid NOT NULL,
"expires_at" timestamp,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "publishers" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"name" text,
"slug" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "publishers_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
@ -144,34 +145,61 @@ CREATE TABLE IF NOT EXISTS "publishers_to_games" (
CONSTRAINT "publishers_to_games_publisher_id_game_id_pk" PRIMARY KEY("publisher_id","game_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "recovery_codes" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"user_id" uuid NOT NULL,
"code" text NOT NULL,
"used" boolean DEFAULT false,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "roles" (
"id" uuid PRIMARY KEY NOT NULL,
"cuid" text,
"name" text,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text NOT NULL,
"name" text NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
CONSTRAINT "roles_name_unique" UNIQUE("name")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "sessions" (
"id" text PRIMARY KEY NOT NULL,
"user_id" text NOT NULL,
"user_id" uuid NOT NULL,
"expires_at" timestamp with time zone NOT NULL,
"ip_country" text,
"ip_address" text
"ip_address" text,
"two_factor_auth_enabled" boolean DEFAULT false,
"is_two_factor_authenticated" boolean DEFAULT false
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "two_factor" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"two_factor_secret" text NOT NULL,
"two_factor_enabled" boolean DEFAULT false NOT NULL,
"initiated_time" timestamp with time zone NOT NULL,
"user_id" uuid NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "two_factor_cuid_unique" UNIQUE("cuid"),
CONSTRAINT "two_factor_user_id_unique" UNIQUE("user_id")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "user_roles" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"user_id" text NOT NULL,
"role_id" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"user_id" uuid NOT NULL,
"role_id" uuid NOT NULL,
"primary" boolean DEFAULT false,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "users" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"username" text,
"hashed_password" text,
@ -181,185 +209,202 @@ CREATE TABLE IF NOT EXISTS "users" (
"verified" boolean DEFAULT false,
"receive_email" boolean DEFAULT false,
"theme" text DEFAULT 'system',
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
CONSTRAINT "users_username_unique" UNIQUE("username"),
CONSTRAINT "users_email_unique" UNIQUE("email")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "wishlist_items" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"wishlist_id" text NOT NULL,
"game_id" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"wishlist_id" uuid NOT NULL,
"game_id" uuid NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "wishlists" (
"id" uuid PRIMARY KEY NOT NULL,
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"cuid" text,
"user_id" text NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL,
"user_id" uuid NOT NULL,
"name" text DEFAULT 'My Wishlist' NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
);
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "text_searchable_idx" ON "games" ("text_searchable_index");--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_base_game_id_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_base_game_id_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "public"."mechanics"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "public"."mechanics"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "public"."publishers"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "public"."publishers"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
ALTER TABLE "recovery_codes" ADD CONSTRAINT "recovery_codes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_wishlist_id_wishlists_id_fk" FOREIGN KEY ("wishlist_id") REFERENCES "wishlists"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "public"."roles"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "wishlists" ADD CONSTRAINT "wishlists_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_wishlist_id_wishlists_id_fk" FOREIGN KEY ("wishlist_id") REFERENCES "public"."wishlists"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "wishlists" ADD CONSTRAINT "wishlists_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "search_index" ON "games" USING gin ((
setweight(to_tsvector('english', "name"), 'A') ||
setweight(to_tsvector('english', "slug"), 'B')
));

View file

@ -0,0 +1,2 @@
ALTER TABLE "two_factor" RENAME COLUMN "two_factor_secret" TO "secret";--> statement-breakpoint
ALTER TABLE "two_factor" RENAME COLUMN "two_factor_enabled" TO "enabled";

View file

@ -0,0 +1 @@
ALTER TABLE "two_factor" ALTER COLUMN "initiated_time" DROP NOT NULL;

View file

@ -1,10 +1,10 @@
{
"id": "176e5b1f-d146-4604-ab17-b16052da13c0",
"id": "e120d11a-bf28-4c96-9f2f-96e23e23c7e2",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "5",
"dialect": "pg",
"version": "7",
"dialect": "postgresql",
"tables": {
"categories": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
@ -12,7 +12,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -34,14 +35,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -60,7 +61,7 @@
}
}
},
"categories_to_external_ids": {
"public.categories_to_external_ids": {
"name": "categories_to_external_ids",
"schema": "",
"columns": {
@ -117,7 +118,7 @@
},
"uniqueConstraints": {}
},
"categories_to_games": {
"public.categories_to_games": {
"name": "categories_to_games",
"schema": "",
"columns": {
@ -174,7 +175,7 @@
},
"uniqueConstraints": {}
},
"collection_items": {
"public.collection_items": {
"name": "collection_items",
"schema": "",
"columns": {
@ -182,7 +183,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -192,13 +194,13 @@
},
"collection_id": {
"name": "collection_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"game_id": {
"name": "game_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
@ -211,14 +213,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -264,7 +266,7 @@
}
}
},
"collections": {
"public.collections": {
"name": "collections",
"schema": "",
"columns": {
@ -272,7 +274,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -282,20 +285,27 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Collection'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -328,7 +338,7 @@
}
}
},
"expansions": {
"public.expansions": {
"name": "expansions",
"schema": "",
"columns": {
@ -336,7 +346,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -346,26 +357,26 @@
},
"base_game_id": {
"name": "base_game_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"game_id": {
"name": "game_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -411,7 +422,7 @@
}
}
},
"external_ids": {
"public.external_ids": {
"name": "external_ids",
"schema": "",
"columns": {
@ -419,7 +430,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -430,8 +442,9 @@
"type": {
"name": "type",
"type": "external_id_type",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
"notNull": false
},
"external_id": {
"name": "external_id",
@ -453,7 +466,7 @@
}
}
},
"games": {
"public.games": {
"name": "games",
"schema": "",
"columns": {
@ -461,7 +474,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -473,13 +487,13 @@
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"description": {
"name": "description",
@ -547,40 +561,42 @@
"primaryKey": false,
"notNull": false
},
"text_searchable_index": {
"name": "text_searchable_index",
"type": "tsvector",
"primaryKey": false,
"notNull": false
},
"last_sync_at": {
"name": "last_sync_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"text_searchable_idx": {
"name": "text_searchable_idx",
"search_index": {
"name": "search_index",
"columns": [
"text_searchable_index"
{
"expression": "(\n\t\t\t\tsetweight(to_tsvector('english', \"name\"), 'A') ||\n setweight(to_tsvector('english', \"slug\"), 'B')\n )",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
}
},
"foreignKeys": {},
@ -595,7 +611,7 @@
}
}
},
"games_to_external_ids": {
"public.games_to_external_ids": {
"name": "games_to_external_ids",
"schema": "",
"columns": {
@ -652,7 +668,7 @@
},
"uniqueConstraints": {}
},
"mechanics": {
"public.mechanics": {
"name": "mechanics",
"schema": "",
"columns": {
@ -660,7 +676,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -682,14 +699,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -708,7 +725,7 @@
}
}
},
"mechanics_to_external_ids": {
"public.mechanics_to_external_ids": {
"name": "mechanics_to_external_ids",
"schema": "",
"columns": {
@ -765,7 +782,7 @@
},
"uniqueConstraints": {}
},
"mechanics_to_games": {
"public.mechanics_to_games": {
"name": "mechanics_to_games",
"schema": "",
"columns": {
@ -822,7 +839,7 @@
},
"uniqueConstraints": {}
},
"password_reset_tokens": {
"public.password_reset_tokens": {
"name": "password_reset_tokens",
"schema": "",
"columns": {
@ -834,19 +851,26 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"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()"
@ -871,7 +895,7 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"publishers": {
"public.publishers": {
"name": "publishers",
"schema": "",
"columns": {
@ -879,7 +903,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -901,14 +926,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -927,7 +952,7 @@
}
}
},
"publishers_to_external_ids": {
"public.publishers_to_external_ids": {
"name": "publishers_to_external_ids",
"schema": "",
"columns": {
@ -984,7 +1009,7 @@
},
"uniqueConstraints": {}
},
"publishers_to_games": {
"public.publishers_to_games": {
"name": "publishers_to_games",
"schema": "",
"columns": {
@ -1041,7 +1066,71 @@
},
"uniqueConstraints": {}
},
"roles": {
"public.recovery_codes": {
"name": "recovery_codes",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"code": {
"name": "code",
"type": "text",
"primaryKey": false,
"notNull": true
},
"used": {
"name": "used",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"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": {},
"foreignKeys": {
"recovery_codes_user_id_users_id_fk": {
"name": "recovery_codes_user_id_users_id_fk",
"tableFrom": "recovery_codes",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.roles": {
"name": "roles",
"schema": "",
"columns": {
@ -1049,19 +1138,34 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": 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": {},
@ -1084,7 +1188,7 @@
}
}
},
"sessions": {
"public.sessions": {
"name": "sessions",
"schema": "",
"columns": {
@ -1096,7 +1200,7 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
@ -1117,6 +1221,20 @@
"type": "text",
"primaryKey": false,
"notNull": false
},
"two_factor_auth_enabled": {
"name": "two_factor_auth_enabled",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"is_two_factor_authenticated": {
"name": "is_two_factor_authenticated",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
}
},
"indexes": {},
@ -1138,7 +1256,98 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_roles": {
"public.two_factor": {
"name": "two_factor",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
},
"two_factor_secret": {
"name": "two_factor_secret",
"type": "text",
"primaryKey": false,
"notNull": true
},
"two_factor_enabled": {
"name": "two_factor_enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"initiated_time": {
"name": "initiated_time",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "uuid",
"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": {},
"foreignKeys": {
"two_factor_user_id_users_id_fk": {
"name": "two_factor_user_id_users_id_fk",
"tableFrom": "two_factor",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"two_factor_cuid_unique": {
"name": "two_factor_cuid_unique",
"nullsNotDistinct": false,
"columns": [
"cuid"
]
},
"two_factor_user_id_unique": {
"name": "two_factor_user_id_unique",
"nullsNotDistinct": false,
"columns": [
"user_id"
]
}
}
},
"public.user_roles": {
"name": "user_roles",
"schema": "",
"columns": {
@ -1146,7 +1355,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1156,26 +1366,33 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role_id": {
"name": "role_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"primary": {
"name": "primary",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1221,7 +1438,7 @@
}
}
},
"users": {
"public.users": {
"name": "users",
"schema": "",
"columns": {
@ -1229,7 +1446,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1290,14 +1508,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1330,7 +1548,7 @@
}
}
},
"wishlist_items": {
"public.wishlist_items": {
"name": "wishlist_items",
"schema": "",
"columns": {
@ -1338,7 +1556,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1348,26 +1567,26 @@
},
"wishlist_id": {
"name": "wishlist_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"game_id": {
"name": "game_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1413,7 +1632,7 @@
}
}
},
"wishlists": {
"public.wishlists": {
"name": "wishlists",
"schema": "",
"columns": {
@ -1421,7 +1640,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1431,20 +1651,27 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Wishlist'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1479,16 +1706,17 @@
}
},
"enums": {
"external_id_type": {
"public.external_id_type": {
"name": "external_id_type",
"values": {
"game": "game",
"category": "category",
"mechanic": "mechanic",
"publisher": "publisher",
"designer": "designer",
"artist": "artist"
}
"schema": "public",
"values": [
"game",
"category",
"mechanic",
"publisher",
"designer",
"artist"
]
}
},
"schemas": {},

View file

@ -1,10 +1,10 @@
{
"id": "7fd9b34f-059f-41a9-9a4c-f9769825233d",
"prevId": "176e5b1f-d146-4604-ab17-b16052da13c0",
"version": "5",
"dialect": "pg",
"id": "52e7c416-89cb-4c6a-9118-68a03cfc2920",
"prevId": "e120d11a-bf28-4c96-9f2f-96e23e23c7e2",
"version": "7",
"dialect": "postgresql",
"tables": {
"categories": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
@ -12,7 +12,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -34,14 +35,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -60,7 +61,7 @@
}
}
},
"categories_to_external_ids": {
"public.categories_to_external_ids": {
"name": "categories_to_external_ids",
"schema": "",
"columns": {
@ -117,7 +118,7 @@
},
"uniqueConstraints": {}
},
"categories_to_games": {
"public.categories_to_games": {
"name": "categories_to_games",
"schema": "",
"columns": {
@ -174,7 +175,7 @@
},
"uniqueConstraints": {}
},
"collection_items": {
"public.collection_items": {
"name": "collection_items",
"schema": "",
"columns": {
@ -182,7 +183,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -211,14 +213,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -264,7 +266,7 @@
}
}
},
"collections": {
"public.collections": {
"name": "collections",
"schema": "",
"columns": {
@ -272,7 +274,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -282,20 +285,27 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Collection'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -328,7 +338,7 @@
}
}
},
"expansions": {
"public.expansions": {
"name": "expansions",
"schema": "",
"columns": {
@ -336,7 +346,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -358,14 +369,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -411,7 +422,7 @@
}
}
},
"external_ids": {
"public.external_ids": {
"name": "external_ids",
"schema": "",
"columns": {
@ -419,7 +430,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -430,8 +442,9 @@
"type": {
"name": "type",
"type": "external_id_type",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
"notNull": false
},
"external_id": {
"name": "external_id",
@ -453,7 +466,7 @@
}
}
},
"games": {
"public.games": {
"name": "games",
"schema": "",
"columns": {
@ -461,7 +474,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -473,13 +487,13 @@
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"description": {
"name": "description",
@ -547,40 +561,42 @@
"primaryKey": false,
"notNull": false
},
"text_searchable_index": {
"name": "text_searchable_index",
"type": "tsvector",
"primaryKey": false,
"notNull": false
},
"last_sync_at": {
"name": "last_sync_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"text_searchable_idx": {
"name": "text_searchable_idx",
"search_index": {
"name": "search_index",
"columns": [
"text_searchable_index"
{
"expression": "(\n\t\t\t\tsetweight(to_tsvector('english', \"name\"), 'A') ||\n setweight(to_tsvector('english', \"slug\"), 'B')\n )",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
}
},
"foreignKeys": {},
@ -595,7 +611,7 @@
}
}
},
"games_to_external_ids": {
"public.games_to_external_ids": {
"name": "games_to_external_ids",
"schema": "",
"columns": {
@ -652,7 +668,7 @@
},
"uniqueConstraints": {}
},
"mechanics": {
"public.mechanics": {
"name": "mechanics",
"schema": "",
"columns": {
@ -660,7 +676,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -682,14 +699,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -708,7 +725,7 @@
}
}
},
"mechanics_to_external_ids": {
"public.mechanics_to_external_ids": {
"name": "mechanics_to_external_ids",
"schema": "",
"columns": {
@ -765,7 +782,7 @@
},
"uniqueConstraints": {}
},
"mechanics_to_games": {
"public.mechanics_to_games": {
"name": "mechanics_to_games",
"schema": "",
"columns": {
@ -822,7 +839,7 @@
},
"uniqueConstraints": {}
},
"password_reset_tokens": {
"public.password_reset_tokens": {
"name": "password_reset_tokens",
"schema": "",
"columns": {
@ -834,19 +851,26 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"expires_at": {
"name": "expires_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"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()"
@ -871,7 +895,7 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"publishers": {
"public.publishers": {
"name": "publishers",
"schema": "",
"columns": {
@ -879,7 +903,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -901,14 +926,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -927,7 +952,7 @@
}
}
},
"publishers_to_external_ids": {
"public.publishers_to_external_ids": {
"name": "publishers_to_external_ids",
"schema": "",
"columns": {
@ -984,7 +1009,7 @@
},
"uniqueConstraints": {}
},
"publishers_to_games": {
"public.publishers_to_games": {
"name": "publishers_to_games",
"schema": "",
"columns": {
@ -1041,7 +1066,71 @@
},
"uniqueConstraints": {}
},
"roles": {
"public.recovery_codes": {
"name": "recovery_codes",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"code": {
"name": "code",
"type": "text",
"primaryKey": false,
"notNull": true
},
"used": {
"name": "used",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"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": {},
"foreignKeys": {
"recovery_codes_user_id_users_id_fk": {
"name": "recovery_codes_user_id_users_id_fk",
"tableFrom": "recovery_codes",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.roles": {
"name": "roles",
"schema": "",
"columns": {
@ -1049,19 +1138,34 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": 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": {},
@ -1084,7 +1188,7 @@
}
}
},
"sessions": {
"public.sessions": {
"name": "sessions",
"schema": "",
"columns": {
@ -1096,7 +1200,7 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
@ -1117,6 +1221,20 @@
"type": "text",
"primaryKey": false,
"notNull": false
},
"two_factor_auth_enabled": {
"name": "two_factor_auth_enabled",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"is_two_factor_authenticated": {
"name": "is_two_factor_authenticated",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
}
},
"indexes": {},
@ -1138,7 +1256,98 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_roles": {
"public.two_factor": {
"name": "two_factor",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
},
"secret": {
"name": "secret",
"type": "text",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"initiated_time": {
"name": "initiated_time",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "uuid",
"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": {},
"foreignKeys": {
"two_factor_user_id_users_id_fk": {
"name": "two_factor_user_id_users_id_fk",
"tableFrom": "two_factor",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"two_factor_cuid_unique": {
"name": "two_factor_cuid_unique",
"nullsNotDistinct": false,
"columns": [
"cuid"
]
},
"two_factor_user_id_unique": {
"name": "two_factor_user_id_unique",
"nullsNotDistinct": false,
"columns": [
"user_id"
]
}
}
},
"public.user_roles": {
"name": "user_roles",
"schema": "",
"columns": {
@ -1146,7 +1355,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1156,26 +1366,33 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"role_id": {
"name": "role_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"primary": {
"name": "primary",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1221,7 +1438,7 @@
}
}
},
"users": {
"public.users": {
"name": "users",
"schema": "",
"columns": {
@ -1229,7 +1446,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1290,14 +1508,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1330,7 +1548,7 @@
}
}
},
"wishlist_items": {
"public.wishlist_items": {
"name": "wishlist_items",
"schema": "",
"columns": {
@ -1338,7 +1556,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1360,14 +1579,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1413,7 +1632,7 @@
}
}
},
"wishlists": {
"public.wishlists": {
"name": "wishlists",
"schema": "",
"columns": {
@ -1421,7 +1640,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1431,20 +1651,27 @@
},
"user_id": {
"name": "user_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Wishlist'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1479,16 +1706,17 @@
}
},
"enums": {
"external_id_type": {
"public.external_id_type": {
"name": "external_id_type",
"values": {
"game": "game",
"category": "category",
"mechanic": "mechanic",
"publisher": "publisher",
"designer": "designer",
"artist": "artist"
}
"schema": "public",
"values": [
"game",
"category",
"mechanic",
"publisher",
"designer",
"artist"
]
}
},
"schemas": {},

View file

@ -1,10 +1,10 @@
{
"id": "e088433f-589d-4c15-953e-3b32e85e658f",
"prevId": "7fd9b34f-059f-41a9-9a4c-f9769825233d",
"version": "5",
"dialect": "pg",
"id": "79adee85-e57c-4a9f-87df-835457b68129",
"prevId": "52e7c416-89cb-4c6a-9118-68a03cfc2920",
"version": "7",
"dialect": "postgresql",
"tables": {
"categories": {
"public.categories": {
"name": "categories",
"schema": "",
"columns": {
@ -12,7 +12,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -34,14 +35,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -60,7 +61,7 @@
}
}
},
"categories_to_external_ids": {
"public.categories_to_external_ids": {
"name": "categories_to_external_ids",
"schema": "",
"columns": {
@ -117,7 +118,7 @@
},
"uniqueConstraints": {}
},
"categories_to_games": {
"public.categories_to_games": {
"name": "categories_to_games",
"schema": "",
"columns": {
@ -174,7 +175,7 @@
},
"uniqueConstraints": {}
},
"collection_items": {
"public.collection_items": {
"name": "collection_items",
"schema": "",
"columns": {
@ -182,7 +183,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -211,14 +213,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -264,7 +266,7 @@
}
}
},
"collections": {
"public.collections": {
"name": "collections",
"schema": "",
"columns": {
@ -272,7 +274,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -286,16 +289,23 @@
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Collection'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -328,7 +338,7 @@
}
}
},
"expansions": {
"public.expansions": {
"name": "expansions",
"schema": "",
"columns": {
@ -336,7 +346,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -358,14 +369,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -411,7 +422,7 @@
}
}
},
"external_ids": {
"public.external_ids": {
"name": "external_ids",
"schema": "",
"columns": {
@ -419,7 +430,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -430,8 +442,9 @@
"type": {
"name": "type",
"type": "external_id_type",
"typeSchema": "public",
"primaryKey": false,
"notNull": true
"notNull": false
},
"external_id": {
"name": "external_id",
@ -453,7 +466,7 @@
}
}
},
"games": {
"public.games": {
"name": "games",
"schema": "",
"columns": {
@ -461,7 +474,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -473,13 +487,13 @@
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"slug": {
"name": "slug",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"description": {
"name": "description",
@ -547,40 +561,42 @@
"primaryKey": false,
"notNull": false
},
"text_searchable_index": {
"name": "text_searchable_index",
"type": "tsvector",
"primaryKey": false,
"notNull": false
},
"last_sync_at": {
"name": "last_sync_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {
"text_searchable_idx": {
"name": "text_searchable_idx",
"search_index": {
"name": "search_index",
"columns": [
"text_searchable_index"
{
"expression": "(\n\t\t\t\tsetweight(to_tsvector('english', \"name\"), 'A') ||\n setweight(to_tsvector('english', \"slug\"), 'B')\n )",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
}
},
"foreignKeys": {},
@ -595,7 +611,7 @@
}
}
},
"games_to_external_ids": {
"public.games_to_external_ids": {
"name": "games_to_external_ids",
"schema": "",
"columns": {
@ -652,7 +668,7 @@
},
"uniqueConstraints": {}
},
"mechanics": {
"public.mechanics": {
"name": "mechanics",
"schema": "",
"columns": {
@ -660,7 +676,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -682,14 +699,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -708,7 +725,7 @@
}
}
},
"mechanics_to_external_ids": {
"public.mechanics_to_external_ids": {
"name": "mechanics_to_external_ids",
"schema": "",
"columns": {
@ -765,7 +782,7 @@
},
"uniqueConstraints": {}
},
"mechanics_to_games": {
"public.mechanics_to_games": {
"name": "mechanics_to_games",
"schema": "",
"columns": {
@ -822,7 +839,7 @@
},
"uniqueConstraints": {}
},
"password_reset_tokens": {
"public.password_reset_tokens": {
"name": "password_reset_tokens",
"schema": "",
"columns": {
@ -840,13 +857,20 @@
},
"expires_at": {
"name": "expires_at",
"type": "timestamp (6) with time zone",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"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()"
@ -871,7 +895,7 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"publishers": {
"public.publishers": {
"name": "publishers",
"schema": "",
"columns": {
@ -879,7 +903,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -901,14 +926,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -927,7 +952,7 @@
}
}
},
"publishers_to_external_ids": {
"public.publishers_to_external_ids": {
"name": "publishers_to_external_ids",
"schema": "",
"columns": {
@ -984,7 +1009,7 @@
},
"uniqueConstraints": {}
},
"publishers_to_games": {
"public.publishers_to_games": {
"name": "publishers_to_games",
"schema": "",
"columns": {
@ -1041,7 +1066,71 @@
},
"uniqueConstraints": {}
},
"roles": {
"public.recovery_codes": {
"name": "recovery_codes",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"code": {
"name": "code",
"type": "text",
"primaryKey": false,
"notNull": true
},
"used": {
"name": "used",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"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": {},
"foreignKeys": {
"recovery_codes_user_id_users_id_fk": {
"name": "recovery_codes_user_id_users_id_fk",
"tableFrom": "recovery_codes",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"public.roles": {
"name": "roles",
"schema": "",
"columns": {
@ -1049,19 +1138,34 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": 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": {},
@ -1084,7 +1188,7 @@
}
}
},
"sessions": {
"public.sessions": {
"name": "sessions",
"schema": "",
"columns": {
@ -1117,6 +1221,20 @@
"type": "text",
"primaryKey": false,
"notNull": false
},
"two_factor_auth_enabled": {
"name": "two_factor_auth_enabled",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"is_two_factor_authenticated": {
"name": "is_two_factor_authenticated",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
}
},
"indexes": {},
@ -1138,7 +1256,98 @@
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_roles": {
"public.two_factor": {
"name": "two_factor",
"schema": "",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
"type": "text",
"primaryKey": false,
"notNull": false
},
"secret": {
"name": "secret",
"type": "text",
"primaryKey": false,
"notNull": true
},
"enabled": {
"name": "enabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"initiated_time": {
"name": "initiated_time",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "uuid",
"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": {},
"foreignKeys": {
"two_factor_user_id_users_id_fk": {
"name": "two_factor_user_id_users_id_fk",
"tableFrom": "two_factor",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"two_factor_cuid_unique": {
"name": "two_factor_cuid_unique",
"nullsNotDistinct": false,
"columns": [
"cuid"
]
},
"two_factor_user_id_unique": {
"name": "two_factor_user_id_unique",
"nullsNotDistinct": false,
"columns": [
"user_id"
]
}
}
},
"public.user_roles": {
"name": "user_roles",
"schema": "",
"columns": {
@ -1146,7 +1355,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1162,20 +1372,27 @@
},
"role_id": {
"name": "role_id",
"type": "text",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"primary": {
"name": "primary",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1221,7 +1438,7 @@
}
}
},
"users": {
"public.users": {
"name": "users",
"schema": "",
"columns": {
@ -1229,7 +1446,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1290,14 +1508,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1330,7 +1548,7 @@
}
}
},
"wishlist_items": {
"public.wishlist_items": {
"name": "wishlist_items",
"schema": "",
"columns": {
@ -1338,7 +1556,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1360,14 +1579,14 @@
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1413,7 +1632,7 @@
}
}
},
"wishlists": {
"public.wishlists": {
"name": "wishlists",
"schema": "",
"columns": {
@ -1421,7 +1640,8 @@
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true
"notNull": true,
"default": "gen_random_uuid()"
},
"cuid": {
"name": "cuid",
@ -1435,16 +1655,23 @@
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"default": "'My Wishlist'"
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
@ -1479,16 +1706,17 @@
}
},
"enums": {
"external_id_type": {
"public.external_id_type": {
"name": "external_id_type",
"values": {
"game": "game",
"category": "category",
"mechanic": "mechanic",
"publisher": "publisher",
"designer": "designer",
"artist": "artist"
}
"schema": "public",
"values": [
"game",
"category",
"mechanic",
"publisher",
"designer",
"artist"
]
}
},
"schemas": {},

View file

@ -0,0 +1,27 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1720625651245,
"tag": "0000_dazzling_stick",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1720625948784,
"tag": "0001_noisy_sally_floyd",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1720626020902,
"tag": "0002_fancy_valkyrie",
"breakpoints": true
}
]
}

View file

@ -0,0 +1,25 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import categoriesToExternalIds from './categoriesToExternalIds';
import categories_to_games from './categoriesToGames';
import { timestamps } from '../utils';
const categories = pgTable('categories', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
name: text('name'),
slug: text('slug'),
...timestamps,
});
export type Categories = InferSelectModel<typeof categories>;
export const categories_relations = relations(categories, ({ many }) => ({
categories_to_games: many(categories_to_games),
categoriesToExternalIds: many(categoriesToExternalIds),
}));
export default categories;

View file

@ -0,0 +1,24 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import categories from './categories';
import externalIds from './externalIds';
const categoriesToExternalIds = pgTable(
'categories_to_external_ids',
{
categoryId: uuid('category_id')
.notNull()
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
categoriesToExternalIdsPkey: primaryKey({
columns: [table.categoryId, table.externalId],
}),
};
},
);
export default categoriesToExternalIds;

View file

@ -0,0 +1,36 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import categories from './categories';
import games from './games';
const categories_to_games = pgTable(
'categories_to_games',
{
category_id: uuid('category_id')
.notNull()
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
categoriesToGamesPkey: primaryKey({
columns: [table.category_id, table.game_id],
}),
};
},
);
export const categories_to_games_relations = relations(categories_to_games, ({ one }) => ({
category: one(categories, {
fields: [categories_to_games.category_id],
references: [categories.id],
}),
game: one(games, {
fields: [categories_to_games.game_id],
references: [games.id],
}),
}));
export default categories_to_games;

View file

@ -0,0 +1,36 @@
import { integer, pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import collections from './collections';
import games from './games';
import { timestamps } from '../utils';
const collection_items = pgTable('collection_items', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
collection_id: uuid('collection_id')
.notNull()
.references(() => collections.id, { onDelete: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'cascade' }),
times_played: integer('times_played').default(0),
...timestamps,
});
export type CollectionItems = InferSelectModel<typeof collection_items>;
export const collection_item_relations = relations(collection_items, ({ one }) => ({
collection: one(collections, {
fields: [collection_items.collection_id],
references: [collections.id],
}),
game: one(games, {
fields: [collection_items.game_id],
references: [games.id],
}),
}));
export default collection_items;

View file

@ -0,0 +1,28 @@
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import users from './users';
import { timestamps } from '../utils';
const collections = pgTable('collections', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
user_id: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
name: text('name').notNull().default('My Collection'),
...timestamps,
});
export const collection_relations = relations(collections, ({ one }) => ({
user: one(users, {
fields: [collections.user_id],
references: [users.id],
}),
}));
export type Collections = InferSelectModel<typeof collections>;
export default collections;

View file

@ -0,0 +1,34 @@
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import games from './games';
import { timestamps } from '../utils';
export const expansions = pgTable('expansions', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
base_game_id: uuid('base_game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
...timestamps,
});
export type Expansions = InferSelectModel<typeof expansions>;
export const expansion_relations = relations(expansions, ({ one }) => ({
baseGame: one(games, {
fields: [expansions.base_game_id],
references: [games.id],
}),
game: one(games, {
fields: [expansions.game_id],
references: [games.id],
}),
}));
export default expansions;

View file

@ -0,0 +1,25 @@
import { pgEnum, pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import type { InferSelectModel } from 'drizzle-orm';
export const externalIdType = pgEnum('external_id_type', [
'game',
'category',
'mechanic',
'publisher',
'designer',
'artist',
]);
const externalIds = pgTable('external_ids', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
type: externalIdType('type'),
externalId: text('external_id').notNull(),
});
export type ExternalIds = InferSelectModel<typeof externalIds>;
export default externalIds;

53
src/db/schema/games.ts Normal file
View file

@ -0,0 +1,53 @@
import { index, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations, sql } from 'drizzle-orm';
import categoriesToGames from './categoriesToGames';
import gamesToExternalIds from './gamesToExternalIds';
import mechanicsToGames from './mechanicsToGames';
import publishersToGames from './publishersToGames';
import { timestamps } from '../utils';
const games = pgTable(
'games',
{
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
name: text('name').notNull(),
slug: text('slug').notNull(),
description: text('description'),
year_published: integer('year_published'),
min_players: integer('min_players'),
max_players: integer('max_players'),
playtime: integer('playtime'),
min_playtime: integer('min_playtime'),
max_playtime: integer('max_playtime'),
min_age: integer('min_age'),
image_url: text('image_url'),
thumb_url: text('thumb_url'),
url: text('url'),
last_sync_at: timestamp('last_sync_at'),
...timestamps,
},
(table) => ({
searchIndex: index('search_index').using(
'gin',
sql`(
setweight(to_tsvector('english', ${table.name}), 'A') ||
setweight(to_tsvector('english', ${table.slug}), 'B')
)`,
),
}),
);
export const gameRelations = relations(games, ({ many }) => ({
categories_to_games: many(categoriesToGames),
mechanics_to_games: many(mechanicsToGames),
publishers_to_games: many(publishersToGames),
gamesToExternalIds: many(gamesToExternalIds),
}));
export type Games = InferSelectModel<typeof games>;
export default games;

View file

@ -0,0 +1,24 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import games from './games';
import externalIds from './externalIds';
const gamesToExternalIds = pgTable(
'games_to_external_ids',
{
gameId: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
gamesToExternalIdsPkey: primaryKey({
columns: [table.gameId, table.externalId],
}),
};
},
);
export default gamesToExternalIds;

36
src/db/schema/index.ts Normal file
View file

@ -0,0 +1,36 @@
export { default as users, user_relations, type Users } from './users';
export { default as recoveryCodes, type RecoveryCodes } from './recoveryCodes';
export {
default as password_reset_tokens,
password_reset_token_relations,
type PasswordResetTokens,
} from './passwordResetTokens';
export { default as sessions, type Sessions } from './sessions';
export { default as roles, role_relations, type Roles } from './roles';
export { default as userRoles, user_role_relations, type UserRoles } from './userRoles';
export { default as collections, collection_relations, type Collections } from './collections';
export {
default as collection_items,
collection_item_relations,
type CollectionItems,
} from './collectionItems';
export { default as wishlists, wishlists_relations, type Wishlists } from './wishlists';
export {
default as wishlist_items,
wishlist_item_relations,
type WishlistItems,
} from './wishlistItems';
export { default as externalIds, type ExternalIds, externalIdType } from './externalIds';
export { default as games, gameRelations, type Games } from './games';
export { default as gamesToExternalIds } from './gamesToExternalIds';
export { default as expansions, expansion_relations, type Expansions } from './expansions';
export { default as publishers, publishers_relations, type Publishers } from './publishers';
export { default as publishers_to_games, publishers_to_games_relations } from './publishersToGames';
export { default as publishersToExternalIds } from './publishersToExternalIds';
export { default as categories, categories_relations, type Categories } from './categories';
export { default as categoriesToExternalIds } from './categoriesToExternalIds';
export { default as categories_to_games, categories_to_games_relations } from './categoriesToGames';
export { default as mechanics, mechanics_relations, type Mechanics } from './mechanics';
export { default as mechanicsToExternalIds } from './mechanicsToExternalIds';
export { default as mechanics_to_games, mechanics_to_games_relations } from './mechanicsToGames';
export { default as twoFactor } from './two-factor.table';

View file

@ -0,0 +1,25 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import mechanicsToGames from './mechanicsToGames';
import mechanicsToExternalIds from './mechanicsToExternalIds';
import { timestamps } from '../utils';
const mechanics = pgTable('mechanics', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
name: text('name'),
slug: text('slug'),
...timestamps,
});
export type Mechanics = InferSelectModel<typeof mechanics>;
export const mechanics_relations = relations(mechanics, ({ many }) => ({
mechanics_to_games: many(mechanicsToGames),
mechanicsToExternalIds: many(mechanicsToExternalIds),
}));
export default mechanics;

View file

@ -0,0 +1,24 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import mechanics from './mechanics';
import externalIds from './externalIds';
const mechanicsToExternalIds = pgTable(
'mechanics_to_external_ids',
{
mechanicId: uuid('mechanic_id')
.notNull()
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
mechanicsToExternalIdsPkey: primaryKey({
columns: [table.mechanicId, table.externalId],
}),
};
},
);
export default mechanicsToExternalIds;

View file

@ -0,0 +1,36 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import mechanics from './mechanics';
import games from './games';
const mechanics_to_games = pgTable(
'mechanics_to_games',
{
mechanic_id: uuid('mechanic_id')
.notNull()
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
mechanicsToGamesPkey: primaryKey({
columns: [table.mechanic_id, table.game_id],
}),
};
},
);
export const mechanics_to_games_relations = relations(mechanics_to_games, ({ one }) => ({
mechanic: one(mechanics, {
fields: [mechanics_to_games.mechanic_id],
references: [mechanics.id],
}),
game: one(games, {
fields: [mechanics_to_games.game_id],
references: [games.id],
}),
}));
export default mechanics_to_games;

View file

@ -0,0 +1,27 @@
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import users from './users';
import { timestamps } from '../utils';
const password_reset_tokens = pgTable('password_reset_tokens', {
id: text('id')
.primaryKey()
.$defaultFn(() => cuid2()),
user_id: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
expires_at: timestamp('expires_at'),
...timestamps,
});
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
export const password_reset_token_relations = relations(password_reset_tokens, ({ one }) => ({
user: one(users, {
fields: [password_reset_tokens.user_id],
references: [users.id],
}),
}));
export default password_reset_tokens;

View file

@ -0,0 +1,25 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import publishers_to_games from './publishersToGames';
import publishersToExternalIds from './publishersToExternalIds';
import { timestamps } from '../utils';
const publishers = pgTable('publishers', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
name: text('name'),
slug: text('slug'),
...timestamps,
});
export type Publishers = InferSelectModel<typeof publishers>;
export const publishers_relations = relations(publishers, ({ many }) => ({
publishers_to_games: many(publishers_to_games),
publishersToExternalIds: many(publishersToExternalIds),
}));
export default publishers;

View file

@ -0,0 +1,24 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import publishers from './publishers';
import externalIds from './externalIds';
const publishersToExternalIds = pgTable(
'publishers_to_external_ids',
{
publisherId: uuid('publisher_id')
.notNull()
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
publishersToExternalIdsPkey: primaryKey({
columns: [table.publisherId, table.externalId],
}),
};
},
);
export default publishersToExternalIds;

View file

@ -0,0 +1,36 @@
import { pgTable, primaryKey, uuid } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import publishers from './publishers';
import games from './games';
const publishers_to_games = pgTable(
'publishers_to_games',
{
publisher_id: uuid('publisher_id')
.notNull()
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
publishersToGamesPkey: primaryKey({
columns: [table.publisher_id, table.game_id],
}),
};
},
);
export const publishers_to_games_relations = relations(publishers_to_games, ({ one }) => ({
publisher: one(publishers, {
fields: [publishers_to_games.publisher_id],
references: [publishers.id],
}),
game: one(games, {
fields: [publishers_to_games.game_id],
references: [games.id],
}),
}));
export default publishers_to_games;

View file

@ -0,0 +1,18 @@
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
import type { InferSelectModel } from 'drizzle-orm';
import users from './users';
import { timestamps } from '../utils';
const recovery_codes = pgTable('recovery_codes', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id')
.notNull()
.references(() => users.id),
code: text('code').notNull(),
used: boolean('used').default(false),
...timestamps,
});
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
export default recovery_codes;

23
src/db/schema/roles.ts Normal file
View file

@ -0,0 +1,23 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import user_roles from './userRoles';
import { timestamps } from '../utils';
const roles = pgTable('roles', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2())
.notNull(),
name: text('name').unique().notNull(),
...timestamps,
});
export type Roles = InferSelectModel<typeof roles>;
export const role_relations = relations(roles, ({ many }) => ({
user_roles: many(user_roles),
}));
export default roles;

22
src/db/schema/sessions.ts Normal file
View file

@ -0,0 +1,22 @@
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { type InferSelectModel } from 'drizzle-orm';
import users from './users';
const sessions = pgTable('sessions', {
id: text('id').primaryKey(),
userId: uuid('user_id')
.notNull()
.references(() => users.id),
expiresAt: timestamp('expires_at', {
withTimezone: true,
mode: 'date',
}).notNull(),
ipCountry: text('ip_country'),
ipAddress: text('ip_address'),
twoFactorAuthEnabled: boolean('two_factor_auth_enabled').default(false),
isTwoFactorAuthenticated: boolean('is_two_factor_authenticated').default(false),
});
export type Sessions = InferSelectModel<typeof sessions>;
export default sessions;

View file

@ -0,0 +1,34 @@
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
import { timestamps } from '../utils';
import users from './users';
const twoFactorTable = pgTable('two_factor', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
secret: text('secret').notNull(),
enabled: boolean('enabled').notNull().default(false),
initiatedTime: timestamp('initiated_time', {
mode: 'date',
withTimezone: true,
}),
userId: uuid('user_id')
.notNull()
.references(() => users.id)
.unique(),
...timestamps,
});
export const emailVerificationsRelations = relations(twoFactorTable, ({ one }) => ({
user: one(users, {
fields: [twoFactorTable.userId],
references: [users.id],
}),
}));
export type TwoFactor = InferSelectModel<typeof twoFactorTable>;
export default twoFactorTable;

View file

@ -0,0 +1,36 @@
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import users from './users';
import roles from './roles';
import { timestamps } from '../utils';
const user_roles = pgTable('user_roles', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
user_id: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
role_id: uuid('role_id')
.notNull()
.references(() => roles.id, { onDelete: 'cascade' }),
primary: boolean('primary').default(false),
...timestamps,
});
export const user_role_relations = relations(user_roles, ({ one }) => ({
role: one(roles, {
fields: [user_roles.role_id],
references: [roles.id],
}),
user: one(users, {
fields: [user_roles.user_id],
references: [users.id],
}),
}));
export type UserRoles = InferSelectModel<typeof user_roles>;
export default user_roles;

29
src/db/schema/users.ts Normal file
View file

@ -0,0 +1,29 @@
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import { timestamps } from '../utils';
import user_roles from './userRoles';
const users = pgTable('users', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
username: text('username').unique(),
hashed_password: text('hashed_password'),
email: text('email').unique(),
first_name: text('first_name'),
last_name: text('last_name'),
verified: boolean('verified').default(false),
receive_email: boolean('receive_email').default(false),
theme: text('theme').default('system'),
...timestamps,
});
export const user_relations = relations(users, ({ many }) => ({
user_roles: many(user_roles),
}));
export type Users = InferSelectModel<typeof users>;
export default users;

View file

@ -0,0 +1,35 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import wishlists from './wishlists';
import games from './games';
import { timestamps } from '../utils';
const wishlist_items = pgTable('wishlist_items', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
wishlist_id: uuid('wishlist_id')
.notNull()
.references(() => wishlists.id, { onDelete: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'cascade' }),
...timestamps,
});
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
wishlist: one(wishlists, {
fields: [wishlist_items.wishlist_id],
references: [wishlists.id],
}),
game: one(games, {
fields: [wishlist_items.game_id],
references: [games.id],
}),
}));
export default wishlist_items;

View file

@ -0,0 +1,28 @@
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { type InferSelectModel, relations } from 'drizzle-orm';
import users from './users';
import { timestamps } from '../utils';
const wishlists = pgTable('wishlists', {
id: uuid('id').primaryKey().defaultRandom(),
cuid: text('cuid')
.unique()
.$defaultFn(() => cuid2()),
user_id: uuid('user_id')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
name: text('name').notNull().default('My Wishlist'),
...timestamps,
});
export type Wishlists = InferSelectModel<typeof wishlists>;
export const wishlists_relations = relations(wishlists, ({ one }) => ({
user: one(users, {
fields: [wishlists.user_id],
references: [users.id],
}),
}));
export default wishlists;

48
src/db/seed.ts Normal file
View file

@ -0,0 +1,48 @@
import { Table, getTableName, sql } from 'drizzle-orm';
import env from '../env';
import { db, pool } from '$db';
import * as schema from './schema';
import * as seeds from './seeds';
if (!env.DB_SEEDING) {
throw new Error('You must set DB_SEEDING to "true" when running seeds');
}
async function resetTable(db: db, table: Table) {
return db.execute(sql.raw(`TRUNCATE TABLE ${getTableName(table)} RESTART IDENTITY CASCADE`));
}
for (const table of [
schema.categories,
schema.categoriesToExternalIds,
schema.categories_to_games,
schema.collection_items,
schema.collections,
schema.expansions,
schema.externalIds,
schema.games,
schema.gamesToExternalIds,
schema.mechanics,
schema.mechanicsToExternalIds,
schema.mechanics_to_games,
schema.password_reset_tokens,
schema.publishers,
schema.publishersToExternalIds,
schema.publishers_to_games,
schema.recoveryCodes,
schema.roles,
schema.sessions,
schema.userRoles,
schema.users,
schema.wishlists,
schema.wishlist_items,
]) {
// await db.delete(table); // clear tables without truncating / resetting ids
await resetTable(db, table);
}
await seeds.roles(db);
await seeds.users(db);
await pool.end();
process.exit();

View file

@ -0,0 +1,14 @@
[
{
"name": "admin"
},
{
"name": "user"
},
{
"name": "editor"
},
{
"name": "moderator"
}
]

View file

@ -0,0 +1,62 @@
[
{
"first_name": "John",
"last_name": "Smith",
"username": "john.smith",
"email": "john.smith@example.com",
"password": "password",
"roles": [
{
"name": "user",
"primary": true
}
]
},
{
"first_name": "Jane",
"last_name": "Doe",
"username": "jane.doe",
"email": "jane.doe@example.com",
"password": "password",
"roles": [
{
"name": "user",
"primary": true
}
]
},
{
"first_name": "Michael",
"last_name": "Editor",
"username": "michael.editor",
"email": "michael.editor@example.com",
"password": "password",
"roles": [
{
"name": "editor",
"primary": true
},
{
"name": "user",
"primary": false
}
]
},
{
"first_name": "Jane",
"last_name": "Moderator",
"username": "jane.moderator",
"email": "jane.moderator@example.com",
"password": "password",
"roles": [
{
"name": "moderator",
"primary": true
},
{
"name": "user",
"primary": false
}
]
}
]

2
src/db/seeds/index.ts Normal file
View file

@ -0,0 +1,2 @@
export { default as users } from './users';
export { default as roles } from './roles';

12
src/db/seeds/roles.ts Normal file
View file

@ -0,0 +1,12 @@
import { eq } from 'drizzle-orm';
import { type db } from '$db';
import * as schema from '$db/schema';
import roles from './data/roles.json';
export default async function seed(db: db) {
console.log('Creating roles ...');
for (const role of roles) {
await db.insert(schema.roles).values(role).onConflictDoNothing();
}
console.log('Roles created.');
}

98
src/db/seeds/users.ts Normal file
View file

@ -0,0 +1,98 @@
import { eq } from 'drizzle-orm';
import { Argon2id } from 'oslo/password';
import { type db } from '$db';
import * as schema from '$db/schema';
import users from './data/users.json';
import env from '../../env';
type JsonUser = {
id: string;
username: string;
email: string;
password: string;
roles: {
name: string;
primary: boolean;
}[];
};
type JsonRole = {
name: string;
primary: boolean;
};
export default async function seed(db: db) {
const adminRole = await db.select().from(schema.roles).where(eq(schema.roles.name, 'admin'));
const userRole = await db.select().from(schema.roles).where(eq(schema.roles.name, 'user'));
console.log('Admin Role: ', adminRole);
const adminUser = await db
.insert(schema.users)
.values({
username: `${env.ADMIN_USERNAME}`,
email: '',
hashed_password: await new Argon2id().hash(`${env.ADMIN_PASSWORD}`),
first_name: 'Brad',
last_name: 'S',
verified: true,
})
.returning()
.onConflictDoNothing();
console.log('Admin user created.', adminUser);
await db
.insert(schema.collections)
.values({ user_id: adminUser[0].id })
.onConflictDoNothing();
await db
.insert(schema.wishlists)
.values({ user_id: adminUser[0].id })
.onConflictDoNothing();
await db
.insert(schema.userRoles)
.values({
user_id: adminUser[0].id,
role_id: adminRole[0].id,
})
.onConflictDoNothing();
console.log('Admin user given admin role.');
await db
.insert(schema.userRoles)
.values({
user_id: adminUser[0].id,
role_id: userRole[0].id,
})
.onConflictDoNothing();
console.log('Admin user given user role.');
await Promise.all(
users.map(async (user) => {
const [insertedUser] = await db
.insert(schema.users)
.values({
...user,
hashed_password: await new Argon2id().hash(user.password),
})
.returning();
await db.insert(schema.collections).values({ user_id: insertedUser?.id });
await db.insert(schema.wishlists).values({ user_id: insertedUser?.id });
await Promise.all(
user.roles.map(async (role: JsonRole) => {
const foundRole = await db.query.roles.findFirst({
where: eq(schema.roles.name, role.name),
});
await db.insert(schema.userRoles).values({
user_id: insertedUser?.id,
role_id: foundRole?.id,
primary: role?.primary,
});
}),
);
}),
);
}

43
src/db/utils.ts Normal file
View file

@ -0,0 +1,43 @@
// import { HTTPException } from 'hono/http-exception';
import { timestamp } from 'drizzle-orm/pg-core';
import { customType } from 'drizzle-orm/pg-core';
export const citext = customType<{ data: string }>({
dataType() {
return 'citext';
},
});
export const cuid2 = customType<{ data: string }>({
dataType() {
return 'text';
},
});
export const takeFirst = <T>(values: T[]): T | null => {
if (values.length === 0) return null;
return values[0]!;
};
export const takeFirstOrThrow = <T>(values: T[]): T => {
if (values.length === 0)
// throw new HTTPException(404, {
// message: 'Resource not found',
// });
return values[0]!;
};
export const timestamps = {
createdAt: timestamp('created_at', {
mode: 'date',
withTimezone: true,
})
.notNull()
.defaultNow(),
updatedAt: timestamp('updated_at', {
mode: 'date',
withTimezone: true,
})
.notNull()
.defaultNow(),
};

52
src/env.ts Normal file
View file

@ -0,0 +1,52 @@
import { config } from 'dotenv';
import { expand } from 'dotenv-expand';
import { ZodError, z } from 'zod';
const stringBoolean = z.coerce
.string()
.transform((val) => {
return val === 'true';
})
.default('false');
const EnvSchema = z.object({
NODE_ENV: z.string().default('development'),
DATABASE_USER: z.string(),
DATABASE_PASSWORD: z.string(),
DATABASE_HOST: z.string(),
DATABASE_PORT: z.coerce.number(),
DATABASE_DB: z.string(),
DATABASE_URL: z.string(),
PUBLIC_SITE_NAME: z.string(),
PUBLIC_SITE_URL: z.string(),
PUBLIC_UMAMI_DO_NOT_TRACK: z.string(),
PUBLIC_UMAMI_ID: z.string(),
PUBLIC_UMAMI_URL: z.string(),
DB_MIGRATING: stringBoolean,
DB_SEEDING: stringBoolean,
ADMIN_USERNAME: z.string(),
ADMIN_PASSWORD: z.string(),
TWO_FACTOR_TIMEOUT: z.coerce.number().default(300000),
});
export type EnvSchema = z.infer<typeof EnvSchema>;
expand(config());
try {
EnvSchema.parse(process.env);
} catch (error) {
if (error instanceof ZodError) {
let message = 'Missing required values in .env:\n';
error.issues.forEach((issue) => {
message += issue.path[0] + '\n';
});
const e = new Error(message);
e.stack = '';
throw e;
} else {
console.error(error);
}
}
export default EnvSchema.parse(process.env);

View file

@ -32,11 +32,10 @@ export const authentication: Handle = async function ({ event, resolve }) {
if (session && session.fresh) {
const sessionCookie = lucia.createSessionCookie(session.id);
console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2));
// sveltekit types deviates from the de-facto standard
// you can use 'as any' too
// sveltekit types deviates from the de-facto standard, you can use 'as any' too
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
...sessionCookie.attributes,
});
}
console.log('session from hooks', JSON.stringify(session, null, 2));
@ -45,7 +44,7 @@ export const authentication: Handle = async function ({ event, resolve }) {
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
...sessionCookie.attributes,
});
}
event.locals.user = user;
@ -56,6 +55,6 @@ export const authentication: Handle = async function ({ event, resolve }) {
export const handle: Handle = sequence(
// Sentry.sentryHandle(),
authentication
authentication,
);
// export const handleError = Sentry.handleErrorWithSentry();

View file

@ -1,4 +1,6 @@
<script lang="ts">
const { children } = $props();
function portal(node: HTMLElement) {
let target;
@ -25,5 +27,5 @@
</script>
<div use:portal hidden>
<slot />
{@render children()}
</div>

View file

@ -2,7 +2,7 @@
import { enhance } from "$app/forms";
import { MinusCircle, PlusCircle } from "lucide-svelte";
import { Button } from '$components/ui/button';
import type { CollectionItems, Wishlists } from "../../schema";
import type { CollectionItems, Wishlists } from "$db/schema";
export let game_id: string;
export let collection: CollectionItems;

View file

@ -1,112 +1,112 @@
<script>
/**
* @event {boolean} check
*/
/**
* @event {boolean} check
*/
/**
* Specify the value of the checkbox
* @type {any}
*/
export let value = '';
/**
* Specify the value of the checkbox
* @type {any}
*/
export let value = '';
/** Specify whether the checkbox is checked */
export let checked = false;
/** Specify whether the checkbox is checked */
export let checked = false;
/**
* Specify the bound group
* @type {any[]}
*/
export let group = undefined;
/**
* Specify the bound group
* @type {any[]}
*/
export let group = undefined;
/** Specify whether the checkbox is indeterminate */
export let indeterminate = false;
/** Specify whether the checkbox is indeterminate */
export let indeterminate = false;
/** Set to `true` to display the skeleton state */
export let skeleton = false;
/** Set to `true` to display the skeleton state */
export let skeleton = false;
/** Set to `true` to mark the field as required */
export let required = false;
/** Set to `true` to mark the field as required */
export let required = false;
/** Set to `true` for the checkbox to be read-only */
export let readonly = false;
/** Set to `true` for the checkbox to be read-only */
export let readonly = false;
/** Set to `true` to disable the checkbox */
export let disabled = false;
/** Set to `true` to disable the checkbox */
export let disabled = false;
/** Specify the label text */
export let labelText = '';
/** Specify the label text */
export let labelText = '';
/** Set to `true` to visually hide the label text */
export let hideLabel = false;
/** Set to `true` to visually hide the label text */
export let hideLabel = false;
/** Set a name for the input element */
export let name = '';
/** Set a name for the input element */
export let name = '';
/**
* Specify the title attribute for the label element
* @type {string}
*/
export let title = undefined;
/**
* Specify the title attribute for the label element
* @type {string}
*/
export let title = undefined;
/** Set an id for the input label */
export let id = 'ccs-' + Math.random().toString(36);
/** Set an id for the input label */
export let id = 'ccs-' + Math.random().toString(36);
/** Obtain a reference to the input HTML element */
export let ref = null;
/** Obtain a reference to the input HTML element */
export let ref = null;
import { createEventDispatcher } from 'svelte';
import CheckboxSkeleton from './CheckboxSkeleton.svelte';
import { createEventDispatcher } from 'svelte';
import CheckboxSkeleton from './CheckboxSkeleton.svelte';
const dispatch = createEventDispatcher();
const dispatch = createEventDispatcher();
$: useGroup = Array.isArray(group);
$: checked = useGroup ? group.includes(value) : checked;
$: dispatch('check', checked);
$: useGroup = Array.isArray(group);
$: checked = useGroup ? group.includes(value) : checked;
$: dispatch('check', checked);
</script>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
{#if skeleton}
<CheckboxSkeleton {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave />
<CheckboxSkeleton {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave />
{:else}
<div
class:bx--form-item={true}
class:bx--checkbox-wrapper={true}
{...$$restProps}
on:click
on:mouseover
on:mouseenter
on:mouseleave
>
<input
bind:this={ref}
type="checkbox"
{value}
{checked}
{disabled}
{id}
{indeterminate}
{name}
{required}
{readonly}
class:bx--checkbox={true}
on:change={() => {
if (useGroup) {
group = group.includes(value)
? group.filter((_value) => _value !== value)
: [...group, value];
} else {
checked = !checked;
}
}}
on:change
on:blur
/>
<label for={id} {title} class:bx--checkbox-label={true}>
<span class:bx--checkbox-label-text={true} class:bx--visually-hidden={hideLabel}>
<slot name="labelText">
{labelText}
</slot>
</span>
</label>
</div>
<div
class:bx--form-item={true}
class:bx--checkbox-wrapper={true}
{...$$restProps}
on:click
on:mouseover
on:mouseenter
on:mouseleave
>
<input
bind:this={ref}
type="checkbox"
{value}
{checked}
{disabled}
{id}
{indeterminate}
{name}
{required}
{readonly}
class:bx--checkbox={true}
on:change={() => {
if (useGroup) {
group = group.includes(value)
? group.filter((_value) => _value !== value)
: [...group, value];
} else {
checked = !checked;
}
}}
on:change
on:blur
/>
<label for={id} {title} class:bx--checkbox-label={true}>
<span class:bx--checkbox-label-text={true} class:bx--visually-hidden={hideLabel}>
<slot name="labelText">
{labelText}
</slot>
</span>
</label>
</div>
{/if}

View file

@ -1,10 +1,9 @@
<script lang="ts">
import type { GameType, SavedGameType } from '$lib/types';
import * as Card from "$lib/components/ui/card";
import type { CollectionItems } from '../../schema';
import type { CollectionItems } from '$db/schema';
export let game: GameType | CollectionItems;
export let detailed: boolean = false;
export let variant: 'default' | 'compact' = 'default';
// Naive and assumes description is only on our GameType at the moment

View file

@ -2,21 +2,19 @@
import { applyAction, enhance } from '$app/forms';
import toast from 'svelte-french-toast';
import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte';
import * as DropdownMenu from "$components/ui/dropdown-menu";
import * as Avatar from "$components/ui/avatar";
import * as DropdownMenu from '$components/ui/dropdown-menu';
import * as Avatar from '$components/ui/avatar';
import { invalidateAll } from '$app/navigation';
import Logo from '$components/logo.svelte';
import type { Users } from "../../schema";
import type { Users } from '$db/schema';
export let user: Users | null = null;
type HeaderProps = {
user: Users | null;
};
console.log('header user', user);
let { user = null }: HeaderProps = $props();
let avatar: string;
$: if (user) {
avatar = user.username?.slice(0, 1).toUpperCase() || ':)';
}
let avatar: string = $derived(user?.username?.slice(0, 1).toUpperCase() || ':)');
</script>
<header>
@ -28,7 +26,6 @@
<span class="logo-text">Bored Game</span>
</a>
</div>
<!-- <TextSearch /> -->
<nav>
{#if user}
<DropdownMenu.Root>
@ -41,7 +38,7 @@
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Group>
<DropdownMenu.Label>My Account</DropdownMenu.Label>
<DropdownMenu.Label>Account</DropdownMenu.Label>
<DropdownMenu.Separator />
<a href="/profile">
<DropdownMenu.Item>
@ -49,57 +46,53 @@
<span>Profile</span>
</DropdownMenu.Item>
</a>
<a href="/collection">
<a href="/collections">
<DropdownMenu.Item>
<ListChecks class="mr-2 h-4 w-4" />
<span>Collection</span>
<span>Collections</span>
</DropdownMenu.Item>
</a>
<a href="/wishlist">
<a href="/wishlists">
<DropdownMenu.Item>
<ListTodo class="mr-2 h-4 w-4" />
<span>Wishlist</span>
<span>Wishlists</span>
</DropdownMenu.Item>
</a>
<form
use:enhance={() => {
return async ({ result }) => {
console.log(result);
if (result.type === 'success' || result.type === 'redirect') {
toast.success('Logged Out');
} else if (result.type === 'error') {
<DropdownMenu.Item>
<form
use:enhance={() => {
return async ({ result }) => {
console.log(result);
toast.error(`Error: ${result.error.message}`);
} else {
toast.error(`Something went wrong.`);
console.log(result);
}
await invalidateAll();
await applyAction(result);
};
}}
action="/logout"
method="POST"
>
<button type="submit" class="">
<DropdownMenu.Item>
<div class="flex items-center gap-1">
<LogOut class="mr-2 h-4 w-4"/>
<span>Sign out</span>
</div>
</DropdownMenu.Item>
</button>
</form>
if (result.type === 'success' || result.type === 'redirect') {
toast.success('Logged Out');
} else if (result.type === 'error') {
console.log(result);
toast.error(`Error: ${result.error.message}`);
} else {
toast.error(`Something went wrong.`);
console.log(result);
}
await invalidateAll();
await applyAction(result);
};
}}
action="/logout"
method="POST"
>
<button type="submit">
<div class="flex items-center gap-1">
<LogOut class="mr-2 h-4 w-4" />
<span>Sign out</span>
</div>
</button>
</form>
</DropdownMenu.Item>
</DropdownMenu.Group>
</DropdownMenu.Content>
</DropdownMenu.Root>
{:else}
<a href="/login">
<span class="flex-auto">Login</span></a
>
<a href="/sign-up">
<span class="flex-auto">Sign Up</span></a
>
<a href="/login"> <span class="flex-auto">Login</span></a>
<a href="/sign-up"> <span class="flex-auto">Sign Up</span></a>
{/if}
</nav>
</header>

View file

@ -1,7 +1,5 @@
<script lang="ts">
export let url: string;
export let ariaLabel = `Link to ${url}`;
export let external = false;
const { url, ariaLabel = `Link to ${url}`, external = false, children }: { url: string; ariaLabel?: string; external?: boolean; children: any } = $props();
</script>
<a
@ -10,7 +8,7 @@
rel="noreferrer"
aria-label={`Board Game Atlas Link for ${ariaLabel}`}
>
<slot />
{@render children()}
</a>
<style>

View file

@ -0,0 +1,15 @@
<script lang="ts">
import type { HTMLAttributes } from 'svelte/elements';
import { cn } from '$lib/utils/ui';
import type { Snippet } from 'svelte';
interface Props extends HTMLAttributes<HTMLDivElement> {
children: Snippet;
}
let { class: classNames, children, ...restProps }: Props = $props();
</script>
<div {...restProps} class={cn('mx-auto w-full max-w-6xl px-0 md:px-6', classNames)}>
{@render children()}
</div>

View file

@ -1,11 +1,5 @@
<script lang="ts">
import { fade } from 'svelte/transition';
// import {
// Dialog,
// DialogDescription,
// DialogOverlay,
// DialogTitle
// } from '@rgossiaux/svelte-headlessui';
import { boredState } from '$lib/stores/boredState';
import { collectionStore } from '$lib/stores/collectionStore';
import { browser } from '$app/environment';

View file

@ -0,0 +1,32 @@
<script lang="ts">
import { cn } from '$lib/utils/ui';
import { PinInput, type PinInputProps } from 'bits-ui';
interface Props extends Omit<PinInputProps, 'value'> {
value: string;
inputCount?: number;
}
let { value = $bindable(), inputCount = 6, ...rest }: Props = $props();
let pin = $state<string[] | undefined>(value?.split('') ?? []);
let inputs = $derived(Array(inputCount).fill(null));
$effect(() => {
value = pin?.join('') ?? '';
});
</script>
<PinInput.Root
{...rest}
bind:value={pin}
class={cn('flex items-center gap-2', rest.class)}
type="text"
placeholder=""
>
{#each inputs as _}
<PinInput.Input
class="flex h-14 w-10 rounded-md border border-input bg-background px-3 py-2 text-center text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
/>
{/each}
<PinInput.HiddenInput />
</PinInput.Root>

View file

@ -1,8 +1,8 @@
<script lang="ts">
import { superForm, type Infer, type SuperValidated } from 'sveltekit-superforms';
import { search_schema, type SearchSchema } from '$lib/zodValidation';
import * as Form from "$lib/components/ui/form";
import { zodClient } from 'sveltekit-superforms/adapters';
import { search_schema, type SearchSchema } from '$lib/zodValidation';
import * as Form from "$lib/components/ui/form";
import Input from '$components/ui/input/input.svelte';
import Checkbox from '$components/ui/checkbox/checkbox.svelte';

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = AvatarPrimitive.FallbackProps;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = AvatarPrimitive.ImageProps;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { Avatar as AvatarPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = AvatarPrimitive.Props;

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { Button as ButtonPrimitive } from "bits-ui";
import { type Events, type Props, buttonVariants } from "./index.js";
import { cn } from "$lib/utils.js";
import { buttonVariants, type Props, type Events } from "./index.js";
type $$Props = Props;
type $$Events = Events;

View file

@ -1,9 +1,9 @@
import Root from "./button.svelte";
import { tv, type VariantProps } from "tailwind-variants";
import { type VariantProps, tv } from "tailwind-variants";
import type { Button as ButtonPrimitive } from "bits-ui";
import Root from "./button.svelte";
const buttonVariants = tv({
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLParagraphElement>;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;

View file

@ -1,7 +1,7 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import type { HeadingLevel } from ".";
import type { HeadingLevel } from "./index.js";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
tag?: HeadingLevel;

View file

@ -1,6 +1,6 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;

View file

@ -1,7 +1,8 @@
<script lang="ts">
import { Checkbox as CheckboxPrimitive } from "bits-ui";
import { Check, Minus } from "lucide-svelte";
import { cn } from "$lib/utils";
import Check from "lucide-svelte/icons/check";
import Minus from "lucide-svelte/icons/minus";
import { cn } from "$lib/utils.js";
type $$Props = CheckboxPrimitive.Props;
type $$Events = CheckboxPrimitive.Events;
@ -13,7 +14,7 @@
<CheckboxPrimitive.Root
class={cn(
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
"peer box-content h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:opacity-50",
className
)}
bind:checked
@ -21,7 +22,7 @@
on:click
>
<CheckboxPrimitive.Indicator
class={cn("flex items-center justify-center text-current h-4 w-4")}
class={cn("flex h-4 w-4 items-center justify-center text-current")}
let:isChecked
let:isIndeterminate
>

View file

@ -2,5 +2,5 @@ import Root from "./checkbox.svelte";
export {
Root,
//
Root as Checkbox
Root as Checkbox,
};

View file

@ -0,0 +1,36 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import X from "lucide-svelte/icons/x";
import * as Dialog from "./index.js";
import { cn, flyAndScale } from "$lib/utils.js";
type $$Props = DialogPrimitive.ContentProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = flyAndScale;
export let transitionConfig: $$Props["transitionConfig"] = {
duration: 200,
};
export { className as class };
</script>
<Dialog.Portal>
<Dialog.Overlay />
<DialogPrimitive.Content
{transition}
{transitionConfig}
class={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg sm:rounded-lg md:w-full",
className
)}
{...$$restProps}
>
<slot />
<DialogPrimitive.Close
class="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"
>
<X class="h-4 w-4" />
<span class="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</Dialog.Portal>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
type $$Props = DialogPrimitive.DescriptionProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<DialogPrimitive.Description
class={cn("text-sm text-muted-foreground", className)}
{...$$restProps}
>
<slot />
</DialogPrimitive.Description>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div
class={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
{...$$restProps}
>
<slot />
</div>

View file

@ -0,0 +1,13 @@
<script lang="ts">
import type { HTMLAttributes } from "svelte/elements";
import { cn } from "$lib/utils.js";
type $$Props = HTMLAttributes<HTMLDivElement>;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<div class={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...$$restProps}>
<slot />
</div>

View file

@ -0,0 +1,21 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { fade } from "svelte/transition";
import { cn } from "$lib/utils.js";
type $$Props = DialogPrimitive.OverlayProps;
let className: $$Props["class"] = undefined;
export let transition: $$Props["transition"] = fade;
export let transitionConfig: $$Props["transitionConfig"] = {
duration: 150,
};
export { className as class };
</script>
<DialogPrimitive.Overlay
{transition}
{transitionConfig}
class={cn("fixed inset-0 z-50 bg-background/80 backdrop-blur-sm", className)}
{...$$restProps}
/>

View file

@ -0,0 +1,8 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
type $$Props = DialogPrimitive.PortalProps;
</script>
<DialogPrimitive.Portal {...$$restProps}>
<slot />
</DialogPrimitive.Portal>

View file

@ -0,0 +1,16 @@
<script lang="ts">
import { Dialog as DialogPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
type $$Props = DialogPrimitive.TitleProps;
let className: $$Props["class"] = undefined;
export { className as class };
</script>
<DialogPrimitive.Title
class={cn("text-lg font-semibold leading-none tracking-tight", className)}
{...$$restProps}
>
<slot />
</DialogPrimitive.Title>

View file

@ -1,12 +1,37 @@
import { Dialog as DialogPrimitive } from "radix-svelte";
import { Dialog as DialogPrimitive } from "bits-ui";
export const Dialog = DialogPrimitive.Root;
export const DialogTrigger = DialogPrimitive.Trigger;
import Title from "./dialog-title.svelte";
import Portal from "./dialog-portal.svelte";
import Footer from "./dialog-footer.svelte";
import Header from "./dialog-header.svelte";
import Overlay from "./dialog-overlay.svelte";
import Content from "./dialog-content.svelte";
import Description from "./dialog-description.svelte";
export { default as DialogContent } from "./DialogContent.svelte";
export { default as DialogDescription } from "./DialogDescription.svelte";
export { default as DialogFooter } from "./DialogFooter.svelte";
export { default as DialogHeader } from "./DialogHeader.svelte";
export { default as DialogOverlay } from "./DialogOverlay.svelte";
export { default as DialogPortal } from "./DialogPortal.svelte";
export { default as DialogTitle } from "./DialogTitle.svelte";
const Root = DialogPrimitive.Root;
const Trigger = DialogPrimitive.Trigger;
const Close = DialogPrimitive.Close;
export {
Root,
Title,
Portal,
Footer,
Header,
Trigger,
Overlay,
Content,
Description,
Close,
//
Root as Dialog,
Title as DialogTitle,
Portal as DialogPortal,
Footer as DialogFooter,
Header as DialogHeader,
Trigger as DialogTrigger,
Overlay as DialogOverlay,
Content as DialogContent,
Description as DialogDescription,
Close as DialogClose,
};

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
import Check from "lucide-svelte/icons/check";
import { cn } from "$lib/utils";
import { cn } from "$lib/utils.js";
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;

Some files were not shown because too many files have changed in this diff Show more