From 55c9445fc596ff9001e996dab2525655969d2cfd Mon Sep 17 00:00:00 2001 From: TZGyn Date: Sat, 11 Nov 2023 05:02:41 +0800 Subject: [PATCH] added drizzle --- .env.example | 3 +- bun.lockb | Bin 77218 -> 118474 bytes drizzle.config.ts | 15 +++ drizzle/0000_bored_eddie_brock.sql | 23 ++++ drizzle/0001_sudden_nightmare.sql | 7 ++ drizzle/meta/0000_snapshot.json | 138 +++++++++++++++++++++++ drizzle/meta/0001_snapshot.json | 174 +++++++++++++++++++++++++++++ drizzle/meta/_journal.json | 20 ++++ package.json | 75 +++++++------ src/lib/db/index.ts | 9 ++ src/lib/db/schema.ts | 47 ++++++++ 11 files changed, 474 insertions(+), 37 deletions(-) create mode 100644 drizzle.config.ts create mode 100644 drizzle/0000_bored_eddie_brock.sql create mode 100644 drizzle/0001_sudden_nightmare.sql create mode 100644 drizzle/meta/0000_snapshot.json create mode 100644 drizzle/meta/0001_snapshot.json create mode 100644 drizzle/meta/_journal.json create mode 100644 src/lib/db/index.ts create mode 100644 src/lib/db/schema.ts diff --git a/.env.example b/.env.example index 7e795bb..1540ef0 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ PORT=3000 PROTOCOL_HEADER=x-forwarded-proto -HOST_HEADER=x-forwarded-host \ No newline at end of file +HOST_HEADER=x-forwarded-host +DATABASE_URL=postgres://postgres:password@127.0.0.1:5432/link-shortener \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 08a94da18b8bb5c1df8db5094f15e4cb77641be8..ea5762aed9b91535384435eb6c2c1bcf281d84a5 100755 GIT binary patch delta 37360 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 diff --git a/drizzle.config.ts b/drizzle.config.ts new file mode 100644 index 0000000..bd01fe9 --- /dev/null +++ b/drizzle.config.ts @@ -0,0 +1,15 @@ +// drizzle.config.ts +import type { Config } from 'drizzle-kit'; + +export default { + schema: './src/lib/db/schema.ts', + out: './drizzle', + driver: 'pg', + dbCredentials: { + user: 'postgres', + password: 'password', + host: '0.0.0.0', + port: 5432, + database: 'link-shortener', + }, +} satisfies Config; diff --git a/drizzle/0000_bored_eddie_brock.sql b/drizzle/0000_bored_eddie_brock.sql new file mode 100644 index 0000000..41f9e58 --- /dev/null +++ b/drizzle/0000_bored_eddie_brock.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS "shortener" ( + "id" serial PRIMARY KEY NOT NULL, + "link" varchar(255) NOT NULL, + "code" varchar(255) NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user" ( + "id" serial PRIMARY KEY NOT NULL, + "uuid" text NOT NULL, + "email" varchar(255) NOT NULL, + "username" varchar(255) NOT NULL, + "password" varchar(255) NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "visitor" ( + "id" serial PRIMARY KEY NOT NULL, + "shortener_id" integer NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "country_code" varchar(255) NOT NULL, + "country" varchar(255) NOT NULL +); diff --git a/drizzle/0001_sudden_nightmare.sql b/drizzle/0001_sudden_nightmare.sql new file mode 100644 index 0000000..a3ad0df --- /dev/null +++ b/drizzle/0001_sudden_nightmare.sql @@ -0,0 +1,7 @@ +CREATE TABLE IF NOT EXISTS "session" ( + "token" varchar(255) NOT NULL, + "user_id" integer NOT NULL, + "expires" timestamp NOT NULL +); +--> statement-breakpoint +ALTER TABLE "user" ADD CONSTRAINT "user_email_unique" UNIQUE("email"); \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json new file mode 100644 index 0000000..2915846 --- /dev/null +++ b/drizzle/meta/0000_snapshot.json @@ -0,0 +1,138 @@ +{ + "id": "1098bf22-b657-4c36-b85c-51f1a8f6e36d", + "prevId": "00000000-0000-0000-0000-000000000000", + "version": "5", + "dialect": "pg", + "tables": { + "shortener": { + "name": "shortener", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "link": { + "name": "link", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uuid": { + "name": "uuid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "visitor": { + "name": "visitor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "shortener_id": { + "name": "shortener_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "country_code": { + "name": "country_code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "country": { + "name": "country", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json new file mode 100644 index 0000000..ea5252d --- /dev/null +++ b/drizzle/meta/0001_snapshot.json @@ -0,0 +1,174 @@ +{ + "id": "7c7bf598-99e4-405b-a089-065b8e8226fa", + "prevId": "1098bf22-b657-4c36-b85c-51f1a8f6e36d", + "version": "5", + "dialect": "pg", + "tables": { + "session": { + "name": "session", + "schema": "", + "columns": { + "token": { + "name": "token", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "expires": { + "name": "expires", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "shortener": { + "name": "shortener", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "link": { + "name": "link", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "uuid": { + "name": "uuid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "visitor": { + "name": "visitor", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "shortener_id": { + "name": "shortener_id", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "country_code": { + "name": "country_code", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + }, + "country": { + "name": "country", + "type": "varchar(255)", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json new file mode 100644 index 0000000..996435a --- /dev/null +++ b/drizzle/meta/_journal.json @@ -0,0 +1,20 @@ +{ + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1699648628603, + "tag": "0000_bored_eddie_brock", + "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1699649369484, + "tag": "0001_sudden_nightmare", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 5da5c26..9729ade 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,41 @@ { - "name": "link-shortener-svelte", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview", - "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", - "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", - "lint": "prettier --plugin-search-dir . --check .", - "format": "prettier --plugin-search-dir . --write ." - }, - "devDependencies": { - "@sveltejs/kit": "^1.20.4", - "autoprefixer": "^10.4.14", - "postcss": "^8.4.24", - "postcss-load-config": "^4.0.1", - "prettier": "^2.8.0", - "prettier-plugin-svelte": "^2.10.1", - "svelte": "^4.0.5", - "svelte-adapter-bun": "^0.5.1", - "svelte-check": "^3.4.3", - "tailwindcss": "^3.3.2", - "tslib": "^2.4.1", - "typescript": "^5.0.0", - "vite": "^4.4.2" - }, - "type": "module", - "dependencies": { - "bits-ui": "^0.9.1", - "clsx": "^2.0.0", - "lucide-svelte": "^0.292.0", - "mode-watcher": "^0.0.7", - "tailwind-merge": "^2.0.0", - "tailwind-variants": "^0.1.18" - } + "name": "link-shortener-svelte", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --plugin-search-dir . --check .", + "format": "prettier --plugin-search-dir . --write ." + }, + "devDependencies": { + "@sveltejs/kit": "^1.20.4", + "autoprefixer": "^10.4.14", + "drizzle-kit": "^0.20.1", + "postcss": "^8.4.24", + "postcss-load-config": "^4.0.1", + "prettier": "^2.8.0", + "prettier-plugin-svelte": "^2.10.1", + "svelte": "^4.0.5", + "svelte-adapter-bun": "^0.5.1", + "svelte-check": "^3.4.3", + "tailwindcss": "^3.3.2", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^4.4.2" + }, + "type": "module", + "dependencies": { + "bits-ui": "^0.9.1", + "clsx": "^2.0.0", + "drizzle-orm": "^0.29.0", + "lucide-svelte": "^0.292.0", + "mode-watcher": "^0.0.7", + "postgres": "^3.4.3", + "tailwind-merge": "^2.0.0", + "tailwind-variants": "^0.1.18" + } } diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts new file mode 100644 index 0000000..64d4ed2 --- /dev/null +++ b/src/lib/db/index.ts @@ -0,0 +1,9 @@ +import { drizzle } from 'drizzle-orm/postgres-js'; +import postgres from 'postgres'; +import * as schema from './schema'; + +const client = postgres( + process.env.DATABASE_URL ?? + 'postgres://postgres:password@127.0.0.1:5432/link-shortener', +); +export const db = drizzle(client, { schema }); diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts new file mode 100644 index 0000000..80f18f8 --- /dev/null +++ b/src/lib/db/schema.ts @@ -0,0 +1,47 @@ +import { + pgTable, + serial, + varchar, + timestamp, + text, + integer, +} from 'drizzle-orm/pg-core'; + +import { relations } from 'drizzle-orm'; + +export const shortener = pgTable('shortener', { + id: serial('id').primaryKey().notNull(), + link: varchar('link', { length: 255 }).notNull(), + code: varchar('code', { length: 255 }).notNull(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), +}); + +export const user = pgTable('user', { + id: serial('id').primaryKey().notNull(), + uuid: text('uuid').notNull(), + email: varchar('email', { length: 255 }).notNull().unique(), + username: varchar('username', { length: 255 }).notNull(), + password: varchar('password', { length: 255 }).notNull(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), +}); + +export const visitor = pgTable('visitor', { + id: serial('id').primaryKey().notNull(), + shortenerId: integer('shortener_id').notNull(), + createdAt: timestamp('created_at', { mode: 'string' }).defaultNow().notNull(), + countryCode: varchar('country_code', { length: 255 }).notNull(), + country: varchar('country', { length: 255 }).notNull(), +}); + +export const session = pgTable('session', { + token: varchar('token', { length: 255 }).notNull(), + userId: integer('user_id').notNull(), + expiresAt: timestamp('expires', { mode: 'date' }).notNull(), +}); + +export const sessionRelations = relations(session, ({ one }) => ({ + user: one(user, { + fields: [session.userId], + references: [user.id], + }), +}));