diff --git a/website/drizzle/0000_loose_abomination.sql b/website/drizzle/0000_loose_abomination.sql new file mode 100644 index 0000000..c1ec40d --- /dev/null +++ b/website/drizzle/0000_loose_abomination.sql @@ -0,0 +1,150 @@ +DO $$ BEGIN + CREATE TYPE "public"."transaction_type" AS ENUM('BUY', 'SELL'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "account" ( + "id" text PRIMARY KEY NOT NULL, + "account_id" text NOT NULL, + "provider_id" text NOT NULL, + "user_id" serial NOT NULL, + "access_token" text, + "refresh_token" text, + "id_token" text, + "access_token_expires_at" timestamp with time zone, + "refresh_token_expires_at" timestamp with time zone, + "scope" text, + "password" text, + "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 "coin" ( + "id" serial PRIMARY KEY NOT NULL, + "name" varchar(255) NOT NULL, + "symbol" varchar(10) NOT NULL, + "creator_id" serial NOT NULL, + "initial_supply" numeric(28, 8) NOT NULL, + "circulating_supply" numeric(28, 8) NOT NULL, + "current_price" numeric(19, 8) NOT NULL, + "market_cap" numeric(28, 4) NOT NULL, + "volume_24h" numeric(28, 4) DEFAULT '0.0000', + "change_24h" numeric(8, 4) DEFAULT '0.0000', + "pool_coin_amount" numeric(28, 8) DEFAULT '0.00000000' NOT NULL, + "pool_base_currency_amount" numeric(28, 4) DEFAULT '0.0000' NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_listed" boolean DEFAULT true NOT NULL, + CONSTRAINT "coin_symbol_unique" UNIQUE("symbol") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "price_history" ( + "id" serial PRIMARY KEY NOT NULL, + "coin_id" integer NOT NULL, + "price" numeric(19, 8) NOT NULL, + "timestamp" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "session" ( + "id" text PRIMARY KEY NOT NULL, + "expires_at" timestamp with time zone NOT NULL, + "token" text NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "ip_address" text, + "user_agent" text, + "user_id" serial NOT NULL, + CONSTRAINT "session_token_unique" UNIQUE("token") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "transaction" ( + "id" serial PRIMARY KEY NOT NULL, + "user_id" serial NOT NULL, + "coin_id" integer NOT NULL, + "type" "transaction_type" NOT NULL, + "quantity" numeric(28, 8) NOT NULL, + "price_per_coin" numeric(19, 8) NOT NULL, + "total_base_currency_amount" numeric(28, 4) NOT NULL, + "timestamp" timestamp with time zone DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" serial PRIMARY KEY NOT NULL, + "name" text NOT NULL, + "email" text NOT NULL, + "email_verified" boolean DEFAULT false NOT NULL, + "image" text, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + "is_admin" boolean DEFAULT false, + "is_banned" boolean DEFAULT false, + "ban_reason" text, + "base_currency_balance" numeric(19, 4) DEFAULT '10000.0000' NOT NULL, + CONSTRAINT "user_email_unique" UNIQUE("email") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user_portfolio" ( + "user_id" serial NOT NULL, + "coin_id" integer NOT NULL, + "quantity" numeric(28, 8) NOT NULL, + "updated_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "user_portfolio_user_id_coin_id_pk" PRIMARY KEY("user_id","coin_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "verification" ( + "id" text PRIMARY KEY NOT NULL, + "identifier" text NOT NULL, + "value" text NOT NULL, + "expires_at" timestamp with time zone NOT NULL, + "created_at" timestamp with time zone DEFAULT now(), + "updated_at" timestamp with time zone DEFAULT now() +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "coin" ADD CONSTRAINT "coin_creator_id_user_id_fk" FOREIGN KEY ("creator_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "price_history" ADD CONSTRAINT "price_history_coin_id_coin_id_fk" FOREIGN KEY ("coin_id") REFERENCES "public"."coin"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "transaction" ADD CONSTRAINT "transaction_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "transaction" ADD CONSTRAINT "transaction_coin_id_coin_id_fk" FOREIGN KEY ("coin_id") REFERENCES "public"."coin"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "user_portfolio" ADD CONSTRAINT "user_portfolio_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "user_portfolio" ADD CONSTRAINT "user_portfolio_coin_id_coin_id_fk" FOREIGN KEY ("coin_id") REFERENCES "public"."coin"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/website/drizzle/0000_wonderful_mephistopheles.sql b/website/drizzle/0000_wonderful_mephistopheles.sql deleted file mode 100644 index 6b21c95..0000000 --- a/website/drizzle/0000_wonderful_mephistopheles.sql +++ /dev/null @@ -1,62 +0,0 @@ -CREATE TABLE IF NOT EXISTS "account" ( - "id" text PRIMARY KEY NOT NULL, - "account_id" text NOT NULL, - "provider_id" text NOT NULL, - "user_id" text NOT NULL, - "access_token" text, - "refresh_token" text, - "id_token" text, - "access_token_expires_at" timestamp, - "refresh_token_expires_at" timestamp, - "scope" text, - "password" text, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "session" ( - "id" text PRIMARY KEY NOT NULL, - "expires_at" timestamp NOT NULL, - "token" text NOT NULL, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "ip_address" text, - "user_agent" text, - "user_id" text NOT NULL, - CONSTRAINT "session_token_unique" UNIQUE("token") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "user" ( - "id" text PRIMARY KEY NOT NULL, - "name" text NOT NULL, - "email" text NOT NULL, - "email_verified" boolean NOT NULL, - "image" text, - "created_at" timestamp NOT NULL, - "updated_at" timestamp NOT NULL, - "is_admin" boolean NOT NULL, - "is_banned" boolean NOT NULL, - "ban_reason" text, - CONSTRAINT "user_email_unique" UNIQUE("email") -); ---> statement-breakpoint -CREATE TABLE IF NOT EXISTS "verification" ( - "id" text PRIMARY KEY NOT NULL, - "identifier" text NOT NULL, - "value" text NOT NULL, - "expires_at" timestamp NOT NULL, - "created_at" timestamp, - "updated_at" timestamp -); ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; diff --git a/website/drizzle/0001_sleepy_queen_noir.sql b/website/drizzle/0001_sleepy_queen_noir.sql deleted file mode 100644 index 79afaf3..0000000 --- a/website/drizzle/0001_sleepy_queen_noir.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE "user" ALTER COLUMN "is_admin" DROP NOT NULL;--> statement-breakpoint -ALTER TABLE "user" ALTER COLUMN "is_banned" DROP NOT NULL; \ No newline at end of file diff --git a/website/drizzle/meta/0000_snapshot.json b/website/drizzle/meta/0000_snapshot.json index 340e33a..e79e706 100644 --- a/website/drizzle/meta/0000_snapshot.json +++ b/website/drizzle/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "d7c4426d-0ef2-49ad-b93a-54e25e216fc3", + "id": "c69a25a2-291e-48c8-847d-6d39c4251cab", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", @@ -28,7 +28,7 @@ }, "user_id": { "name": "user_id", - "type": "text", + "type": "serial", "primaryKey": false, "notNull": true }, @@ -52,13 +52,13 @@ }, "access_token_expires_at": { "name": "access_token_expires_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, "notNull": false }, "refresh_token_expires_at": { "name": "refresh_token_expires_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, "notNull": false }, @@ -76,15 +76,17 @@ }, "created_at": { "name": "created_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" }, "updated_at": { "name": "updated_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" } }, "indexes": {}, @@ -99,7 +101,185 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.coin": { + "name": "coin", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "symbol": { + "name": "symbol", + "type": "varchar(10)", + "primaryKey": false, + "notNull": true + }, + "creator_id": { + "name": "creator_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "initial_supply": { + "name": "initial_supply", + "type": "numeric(28, 8)", + "primaryKey": false, + "notNull": true + }, + "circulating_supply": { + "name": "circulating_supply", + "type": "numeric(28, 8)", + "primaryKey": false, + "notNull": true + }, + "current_price": { + "name": "current_price", + "type": "numeric(19, 8)", + "primaryKey": false, + "notNull": true + }, + "market_cap": { + "name": "market_cap", + "type": "numeric(28, 4)", + "primaryKey": false, + "notNull": true + }, + "volume_24h": { + "name": "volume_24h", + "type": "numeric(28, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "change_24h": { + "name": "change_24h", + "type": "numeric(8, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "pool_coin_amount": { + "name": "pool_coin_amount", + "type": "numeric(28, 8)", + "primaryKey": false, + "notNull": true, + "default": "'0.00000000'" + }, + "pool_base_currency_amount": { + "name": "pool_base_currency_amount", + "type": "numeric(28, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "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()" + }, + "is_listed": { + "name": "is_listed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": {}, + "foreignKeys": { + "coin_creator_id_user_id_fk": { + "name": "coin_creator_id_user_id_fk", + "tableFrom": "coin", + "tableTo": "user", + "columnsFrom": [ + "creator_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "coin_symbol_unique": { + "name": "coin_symbol_unique", + "nullsNotDistinct": false, + "columns": [ + "symbol" + ] + } + } + }, + "public.price_history": { + "name": "price_history", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "coin_id": { + "name": "coin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "price": { + "name": "price", + "type": "numeric(19, 8)", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "price_history_coin_id_coin_id_fk": { + "name": "price_history_coin_id_coin_id_fk", + "tableFrom": "price_history", + "tableTo": "coin", + "columnsFrom": [ + "coin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", "onUpdate": "no action" } }, @@ -118,7 +298,7 @@ }, "expires_at": { "name": "expires_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, "notNull": true }, @@ -130,15 +310,17 @@ }, "created_at": { "name": "created_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" }, "updated_at": { "name": "updated_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" }, "ip_address": { "name": "ip_address", @@ -154,7 +336,7 @@ }, "user_id": { "name": "user_id", - "type": "text", + "type": "serial", "primaryKey": false, "notNull": true } @@ -171,7 +353,7 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", "onUpdate": "no action" } }, @@ -186,13 +368,100 @@ } } }, + "public.transaction": { + "name": "transaction", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "coin_id": { + "name": "coin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "transaction_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "numeric(28, 8)", + "primaryKey": false, + "notNull": true + }, + "price_per_coin": { + "name": "price_per_coin", + "type": "numeric(19, 8)", + "primaryKey": false, + "notNull": true + }, + "total_base_currency_amount": { + "name": "total_base_currency_amount", + "type": "numeric(28, 4)", + "primaryKey": false, + "notNull": true + }, + "timestamp": { + "name": "timestamp", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "transaction_user_id_user_id_fk": { + "name": "transaction_user_id_user_id_fk", + "tableFrom": "transaction", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "transaction_coin_id_coin_id_fk": { + "name": "transaction_coin_id_coin_id_fk", + "tableFrom": "transaction", + "tableTo": "coin", + "columnsFrom": [ + "coin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, "public.user": { "name": "user", "schema": "", "columns": { "id": { "name": "id", - "type": "text", + "type": "serial", "primaryKey": true, "notNull": true }, @@ -212,7 +481,8 @@ "name": "email_verified", "type": "boolean", "primaryKey": false, - "notNull": true + "notNull": true, + "default": false }, "image": { "name": "image", @@ -222,33 +492,44 @@ }, "created_at": { "name": "created_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" }, "updated_at": { "name": "updated_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": true + "notNull": true, + "default": "now()" }, "is_admin": { "name": "is_admin", "type": "boolean", "primaryKey": false, - "notNull": true + "notNull": false, + "default": false }, "is_banned": { "name": "is_banned", "type": "boolean", "primaryKey": false, - "notNull": true + "notNull": false, + "default": false }, "ban_reason": { "name": "ban_reason", "type": "text", "primaryKey": false, "notNull": false + }, + "base_currency_balance": { + "name": "base_currency_balance", + "type": "numeric(19, 4)", + "primaryKey": false, + "notNull": true, + "default": "'10000.0000'" } }, "indexes": {}, @@ -264,6 +545,76 @@ } } }, + "public.user_portfolio": { + "name": "user_portfolio", + "schema": "", + "columns": { + "user_id": { + "name": "user_id", + "type": "serial", + "primaryKey": false, + "notNull": true + }, + "coin_id": { + "name": "coin_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "quantity": { + "name": "quantity", + "type": "numeric(28, 8)", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_portfolio_user_id_user_id_fk": { + "name": "user_portfolio_user_id_user_id_fk", + "tableFrom": "user_portfolio", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_portfolio_coin_id_coin_id_fk": { + "name": "user_portfolio_coin_id_coin_id_fk", + "tableFrom": "user_portfolio", + "tableTo": "coin", + "columnsFrom": [ + "coin_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_portfolio_user_id_coin_id_pk": { + "name": "user_portfolio_user_id_coin_id_pk", + "columns": [ + "user_id", + "coin_id" + ] + } + }, + "uniqueConstraints": {} + }, "public.verification": { "name": "verification", "schema": "", @@ -288,21 +639,23 @@ }, "expires_at": { "name": "expires_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, "notNull": true }, "created_at": { "name": "created_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": false + "notNull": false, + "default": "now()" }, "updated_at": { "name": "updated_at", - "type": "timestamp", + "type": "timestamp with time zone", "primaryKey": false, - "notNull": false + "notNull": false, + "default": "now()" } }, "indexes": {}, @@ -311,7 +664,16 @@ "uniqueConstraints": {} } }, - "enums": {}, + "enums": { + "public.transaction_type": { + "name": "transaction_type", + "schema": "public", + "values": [ + "BUY", + "SELL" + ] + } + }, "schemas": {}, "_meta": { "columns": {}, diff --git a/website/drizzle/meta/0001_snapshot.json b/website/drizzle/meta/0001_snapshot.json deleted file mode 100644 index 69dbebf..0000000 --- a/website/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,321 +0,0 @@ -{ - "id": "dec93290-a459-4102-b9d8-0095bf72a576", - "prevId": "d7c4426d-0ef2-49ad-b93a-54e25e216fc3", - "version": "7", - "dialect": "postgresql", - "tables": { - "public.account": { - "name": "account", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "account_id": { - "name": "account_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "provider_id": { - "name": "provider_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "access_token": { - "name": "access_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "refresh_token": { - "name": "refresh_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "id_token": { - "name": "id_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "access_token_expires_at": { - "name": "access_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "refresh_token_expires_at": { - "name": "refresh_token_expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "scope": { - "name": "scope", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "password": { - "name": "password", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "account_user_id_user_id_fk": { - "name": "account_user_id_user_id_fk", - "tableFrom": "account", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "public.session": { - "name": "session", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "ip_address": { - "name": "ip_address", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_agent": { - "name": "user_agent", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - } - }, - "indexes": {}, - "foreignKeys": { - "session_user_id_user_id_fk": { - "name": "session_user_id_user_id_fk", - "tableFrom": "session", - "tableTo": "user", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "session_token_unique": { - "name": "session_token_unique", - "nullsNotDistinct": false, - "columns": [ - "token" - ] - } - } - }, - "public.user": { - "name": "user", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "email_verified": { - "name": "email_verified", - "type": "boolean", - "primaryKey": false, - "notNull": true - }, - "image": { - "name": "image", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "is_admin": { - "name": "is_admin", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "is_banned": { - "name": "is_banned", - "type": "boolean", - "primaryKey": false, - "notNull": false - }, - "ban_reason": { - "name": "ban_reason", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "user_email_unique": { - "name": "user_email_unique", - "nullsNotDistinct": false, - "columns": [ - "email" - ] - } - } - }, - "public.verification": { - "name": "verification", - "schema": "", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "identifier": { - "name": "identifier", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "expires_at": { - "name": "expires_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "schemas": {}, - "_meta": { - "columns": {}, - "schemas": {}, - "tables": {} - } -} \ No newline at end of file diff --git a/website/drizzle/meta/_journal.json b/website/drizzle/meta/_journal.json index 23fb218..c5ca0c7 100644 --- a/website/drizzle/meta/_journal.json +++ b/website/drizzle/meta/_journal.json @@ -5,15 +5,8 @@ { "idx": 0, "version": "7", - "when": 1747905045049, - "tag": "0000_wonderful_mephistopheles", - "breakpoints": true - }, - { - "idx": 1, - "version": "7", - "when": 1747908527252, - "tag": "0001_sleepy_queen_noir", + "when": 1747913144586, + "tag": "0000_loose_abomination", "breakpoints": true } ] diff --git a/website/src/lib/server/db/schema.ts b/website/src/lib/server/db/schema.ts index 07e4737..10524d6 100644 --- a/website/src/lib/server/db/schema.ts +++ b/website/src/lib/server/db/schema.ts @@ -1,50 +1,105 @@ -import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core"; +import { pgTable, text, timestamp, boolean, decimal, serial, varchar, integer, primaryKey, pgEnum } from "drizzle-orm/pg-core"; + +export const transactionTypeEnum = pgEnum('transaction_type', ['BUY', 'SELL']); export const user = pgTable("user", { - id: text("id").primaryKey(), - name: text('name').notNull(), - email: text('email').notNull().unique(), - emailVerified: boolean('email_verified').notNull(), - image: text('image'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull(), - isAdmin: boolean('is_admin'), - isBanned: boolean('is_banned'), - banReason: text('ban_reason') + id: serial("id").primaryKey(), + name: text("name").notNull(), + email: text("email").notNull().unique(), + emailVerified: boolean("email_verified").notNull().default(false), + image: text("image"), + createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), + isAdmin: boolean("is_admin").default(false), + isBanned: boolean("is_banned").default(false), + banReason: text("ban_reason"), + baseCurrencyBalance: decimal("base_currency_balance", { + precision: 19, + scale: 4, + }).notNull().default("10000.0000"), // 10,000 *BUSS }); export const session = pgTable("session", { id: text("id").primaryKey(), - expiresAt: timestamp('expires_at').notNull(), - token: text('token').notNull().unique(), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull(), - ipAddress: text('ip_address'), - userAgent: text('user_agent'), - userId: text('user_id').notNull().references(() => user.id) + expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(), + token: text("token").notNull().unique(), + createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), + ipAddress: text("ip_address"), + userAgent: text("user_agent"), + userId: serial("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), }); export const account = pgTable("account", { id: text("id").primaryKey(), - accountId: text('account_id').notNull(), - providerId: text('provider_id').notNull(), - userId: text('user_id').notNull().references(() => user.id), - accessToken: text('access_token'), - refreshToken: text('refresh_token'), - idToken: text('id_token'), - accessTokenExpiresAt: timestamp('access_token_expires_at'), - refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), - scope: text('scope'), - password: text('password'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull() + accountId: text("account_id").notNull(), + providerId: text("provider_id").notNull(), + userId: serial("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), + accessToken: text("access_token"), + refreshToken: text("refresh_token"), + idToken: text("id_token"), + accessTokenExpiresAt: timestamp("access_token_expires_at", { withTimezone: true, }), + refreshTokenExpiresAt: timestamp("refresh_token_expires_at", { withTimezone: true, }), + scope: text("scope"), + password: text("password"), + createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), }); export const verification = pgTable("verification", { id: text("id").primaryKey(), - identifier: text('identifier').notNull(), - value: text('value').notNull(), - expiresAt: timestamp('expires_at').notNull(), - createdAt: timestamp('created_at'), - updatedAt: timestamp('updated_at') + identifier: text("identifier").notNull(), + value: text("value").notNull(), + expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(), + createdAt: timestamp("created_at", { withTimezone: true }).defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow(), +}); + +export const coin = pgTable("coin", { + id: serial("id").primaryKey(), + name: varchar("name", { length: 255 }).notNull(), + symbol: varchar("symbol", { length: 10 }).notNull().unique(), + creatorId: serial("creator_id").references(() => user.id, { onDelete: "set null", }), // Coin can exist even if creator is deleted + initialSupply: decimal("initial_supply", { precision: 28, scale: 8 }).notNull(), + circulatingSupply: decimal("circulating_supply", { precision: 28, scale: 8 }).notNull(), + currentPrice: decimal("current_price", { precision: 19, scale: 8 }).notNull(), // Price in base currency + marketCap: decimal("market_cap", { precision: 28, scale: 4 }).notNull(), + volume24h: decimal("volume_24h", { precision: 28, scale: 4 }).default("0.0000"), + change24h: decimal("change_24h", { precision: 8, scale: 4 }).default("0.0000"), // Percentage + poolCoinAmount: decimal("pool_coin_amount", { precision: 28, scale: 8 }).notNull().default("0.00000000"), + poolBaseCurrencyAmount: decimal("pool_base_currency_amount", { precision: 28, scale: 4, }).notNull().default("0.0000"), + createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(), + updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), + isListed: boolean("is_listed").default(true).notNull(), +}); + +export const userPortfolio = pgTable("user_portfolio", { + userId: serial("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), + coinId: integer("coin_id").notNull().references(() => coin.id, { onDelete: "cascade" }), + quantity: decimal("quantity", { precision: 28, scale: 8 }).notNull(), + updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(), +}, + (table) => { + return { + pk: primaryKey({ columns: [table.userId, table.coinId] }), + }; + }, +); + +export const transaction = pgTable("transaction", { + id: serial("id").primaryKey(), + userId: serial("user_id").notNull().references(() => user.id, { onDelete: "cascade" }), + coinId: integer("coin_id").notNull().references(() => coin.id, { onDelete: "cascade" }), + type: transactionTypeEnum("type").notNull(), + quantity: decimal("quantity", { precision: 28, scale: 8 }).notNull(), + pricePerCoin: decimal("price_per_coin", { precision: 19, scale: 8 }).notNull(), + totalBaseCurrencyAmount: decimal("total_base_currency_amount", { precision: 28, scale: 4 }).notNull(), + timestamp: timestamp("timestamp", { withTimezone: true }).notNull().defaultNow(), +}); + +export const priceHistory = pgTable("price_history", { + id: serial("id").primaryKey(), + coinId: integer("coin_id").notNull().references(() => coin.id, { onDelete: "cascade" }), + price: decimal("price", { precision: 19, scale: 8 }).notNull(), + timestamp: timestamp("timestamp", { withTimezone: true }).notNull().defaultNow(), });