diff --git a/.gitignore b/.gitignore index 0f264b2..bd707d9 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,4 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts +.krud/ diff --git a/bun.lockb b/bun.lockb index f180b5a..367c336 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/drizzle/0000_brainy_marvel_apes.sql b/drizzle/0000_thankful_sasquatch.sql similarity index 64% rename from drizzle/0000_brainy_marvel_apes.sql rename to drizzle/0000_thankful_sasquatch.sql index 95eba0f..04b27b7 100644 --- a/drizzle/0000_brainy_marvel_apes.sql +++ b/drizzle/0000_thankful_sasquatch.sql @@ -10,33 +10,30 @@ CREATE TABLE IF NOT EXISTS "account" ( "scope" text, "id_token" text, "session_state" text, - CONSTRAINT account_provider_providerAccountId_pk PRIMARY KEY("provider","providerAccountId") + CONSTRAINT "account_provider_providerAccountId_pk" PRIMARY KEY("provider","providerAccountId") ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS "child" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid - () NOT NULL, - "parent_id" uuid NOT NULL, + "id" uuid PRIMARY KEY NOT NULL, "name" varchar(256), "phone" varchar(256), - "key" varchar(256) + "key" varchar(256), + "parent_id" uuid ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS "device" ( - "device_id" varchar NOT NULL, - "child_id" uuid NOT NULL, + "id" uuid PRIMARY KEY NOT NULL, + "child_id" uuid, "api_key" varchar NOT NULL, "pin" integer NOT NULL, "expires" timestamp DEFAULT now () + interval '1 hour', - CONSTRAINT device_device_id_child_id_pk PRIMARY KEY("device_id","child_id"), - CONSTRAINT "device_device_id_unique" UNIQUE("device_id"), CONSTRAINT "device_api_key_unique" UNIQUE("api_key") ); --> statement-breakpoint CREATE TABLE IF NOT EXISTS "ping" ( - "device_id" varchar NOT NULL, + "device_id" uuid NOT NULL, "latitude" double precision NOT NULL, "longitude" double precision NOT NULL, "timestamp" timestamp NOT NULL @@ -60,7 +57,7 @@ CREATE TABLE IF NOT EXISTS "verification_token" ( "identifier" text NOT NULL, "token" text NOT NULL, "expires" timestamp NOT NULL, - CONSTRAINT verification_token_identifier_token_pk PRIMARY KEY("identifier","token") + CONSTRAINT "verification_token_identifier_token_pk" PRIMARY KEY("identifier","token") ); --> statement-breakpoint DO $$ BEGIN @@ -69,18 +66,6 @@ EXCEPTION WHEN duplicate_object THEN null; END $$; --> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "child" ADD CONSTRAINT "child_parent_id_user_id_fk" FOREIGN KEY ("parent_id") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "device" ADD CONSTRAINT "device_child_id_child_id_fk" FOREIGN KEY ("child_id") REFERENCES "child"("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_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE cascade ON UPDATE no action; EXCEPTION diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index 5caf859..9dfc748 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1,5 +1,5 @@ { - "id": "cbc2e341-c3c0-4b72-b8ee-bcb6e11b7b34", + "id": "876770f8-cae4-4913-b299-855783c0b37c", "prevId": "00000000-0000-0000-0000-000000000000", "version": "5", "dialect": "pg", @@ -110,13 +110,6 @@ "name": "id", "type": "uuid", "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid\n ()" - }, - "parent_id": { - "name": "parent_id", - "type": "uuid", - "primaryKey": false, "notNull": true }, "name": { @@ -136,24 +129,16 @@ "type": "varchar(256)", "primaryKey": false, "notNull": false + }, + "parent_id": { + "name": "parent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false } }, "indexes": {}, - "foreignKeys": { - "child_parent_id_user_id_fk": { - "name": "child_parent_id_user_id_fk", - "tableFrom": "child", - "tableTo": "user", - "columnsFrom": [ - "parent_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, + "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": {} }, @@ -161,17 +146,17 @@ "name": "device", "schema": "", "columns": { - "device_id": { - "name": "device_id", - "type": "varchar", - "primaryKey": false, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, "notNull": true }, "child_id": { "name": "child_id", "type": "uuid", "primaryKey": false, - "notNull": true + "notNull": false }, "api_key": { "name": "api_key", @@ -194,38 +179,9 @@ } }, "indexes": {}, - "foreignKeys": { - "device_child_id_child_id_fk": { - "name": "device_child_id_child_id_fk", - "tableFrom": "device", - "tableTo": "child", - "columnsFrom": [ - "child_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": { - "device_device_id_child_id_pk": { - "name": "device_device_id_child_id_pk", - "columns": [ - "device_id", - "child_id" - ] - } - }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, "uniqueConstraints": { - "device_device_id_unique": { - "name": "device_device_id_unique", - "nullsNotDistinct": false, - "columns": [ - "device_id" - ] - }, "device_api_key_unique": { "name": "device_api_key_unique", "nullsNotDistinct": false, @@ -241,7 +197,7 @@ "columns": { "device_id": { "name": "device_id", - "type": "varchar", + "type": "uuid", "primaryKey": false, "notNull": true }, diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 65c5f56..195b37c 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1702675078550, - "tag": "0000_brainy_marvel_apes", + "when": 1703070994335, + "tag": "0000_thankful_sasquatch", "breakpoints": true } ] diff --git a/package.json b/package.json index f602c26..30f28d5 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,13 @@ "scripts": { "dev2": "next dev", "dev": "NODE_ENV=development next dev -p 3002 & local-ssl-proxy --key /etc/letsencrypt/live/dev.fergl.ie/privkey.pem --cert /etc/letsencrypt/live/dev.fergl.ie/fullchain.pem --source 3000 --target 3002", + "drizzle:seed": "node --loader esbuild-register/loader -r esbuild-register ./src/db/seed.ts", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { - "@auth/drizzle-adapter": "^0.3.9", + "@auth/drizzle-adapter": "^0.3.11", "@hookform/resolvers": "^3.3.2", "@microsoft/signalr": "^8.0.0", "@radix-ui/react-accordion": "^1.1.2", @@ -41,21 +42,21 @@ "@radix-ui/react-tooltip": "^1.0.7", "@t3-oss/env-core": "^0.7.1", "@t3-oss/env-nextjs": "^0.7.1", - "@tanstack/react-query": "^5.12.2", - "@tanstack/react-query-devtools": "^5.13.3", + "@tanstack/react-query": "^5.14.1", + "@tanstack/react-query-devtools": "^5.14.1", "axios": "^1.6.2", "class-variance-authority": "^0.7.0", "clsx": "^2.0.0", "cmdk": "^0.2.0", - "date-fns": "^2.30.0", + "date-fns": "^3.0.0", "dotenv": "^16.3.1", "drizzle-orm": "^0.29.1", "generate-api-key": "^1.0.2", "http-status-codes": "^2.3.0", "leaflet": "^1.9.4", "local-ssl-proxy": "^2.0.5", - "lucide-react": "^0.294.0", - "next": "14.0.3", + "lucide-react": "^0.298.0", + "next": "14.0.4", "next-auth": "^4.24.5", "next-themes": "^0.2.1", "pg": "^8.11.3", @@ -63,7 +64,7 @@ "react": "^18", "react-day-picker": "^8.9.1", "react-dom": "^18", - "react-hook-form": "^7.48.2", + "react-hook-form": "^7.49.2", "react-leaflet": "^4.2.1", "react-qr-code": "^2.0.12", "socket.io": "^4.7.2", @@ -79,11 +80,11 @@ "@types/react": "^18", "@types/react-dom": "^18", "autoprefixer": "^10", - "drizzle-kit": "^0.20.6", + "drizzle-kit": "^0.20.7", "eslint": "^8", - "eslint-config-next": "14.0.3", + "eslint-config-next": "14.0.4", "postcss": "^8", - "prettier": "3.1.0", + "prettier": "3.1.1", "tailwindcss": "^3", "typescript": "^5" } diff --git a/scripts/reset.sh b/scripts/reset.sh index 8b6f28c..c07a717 100755 --- a/scripts/reset.sh +++ b/scripts/reset.sh @@ -11,6 +11,9 @@ echo "Dropping db" dropdb -f --if-exists parentgrine echo "Creating db" createdb parentgrine +echo "Exiting" +exit -npx drizzle-kit generate:pg --config=./drizzle.config.ts -npx drizzle-kit push:pg --config=./drizzle.config.ts +bunx drizzle-kit generate:pg --config=./drizzle.config.ts +bunx drizzle-kit push:pg --config=./drizzle.config.ts +bunx tsx src/db/migrate.ts diff --git a/src/app/api/child/route.ts b/src/app/api/child/route.ts index 13e8304..cb0f4c8 100644 --- a/src/app/api/child/route.ts +++ b/src/app/api/child/route.ts @@ -5,7 +5,6 @@ import { NextResponse } from 'next/server'; import { getServerAuthSession } from '@/lib/services/auth/config'; import { eq } from 'drizzle-orm'; -//TODO: create-t3-app supports app router now export async function GET(request: Request) { const session = await getServerAuthSession(); if (!session || !session.user) diff --git a/src/db/index.ts b/src/db/index.ts index 9395f0b..4ecbf71 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -7,7 +7,7 @@ import { migrate } from 'drizzle-orm/postgres-js/migrator'; const client = postgres(env.DATABASE_URL as string); const db = drizzle(client, { schema }); -console.log('DRIZZLE', 'migrating'); -migrate(db, { migrationsFolder: 'drizzle' }) - .then(() => console.log('DRIZZLE', 'migrated')); +// console.log('DRIZZLE', 'migrating'); +// migrate(db, { migrationsFolder: 'drizzle' }) +// .then(() => console.log('DRIZZLE', 'migrated')); export default db; diff --git a/src/db/migrate.ts b/src/db/migrate.ts new file mode 100644 index 0000000..19a901d --- /dev/null +++ b/src/db/migrate.ts @@ -0,0 +1,8 @@ +import 'dotenv/config'; +import db from '.'; +import { migrate } from 'drizzle-orm/postgres-js/migrator'; + +// This will run migrations on the database, skipping the ones already applied +// migrate(db, { migrationsFolder: './drizzle' }).then(() => +// console.log('DRIZZLE', 'migrated') +// ); diff --git a/src/db/schema.ts b/src/db/schema.ts index 4f5286c..fdd38fd 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -68,57 +68,56 @@ export const verificationTokens = pgTable( ); //#endregion auth +export const userRelations = relations(users, ({ many }) => ({ + children: many(child), +})); + //#region child export const child = pgTable('child', { - id: uuid('id') - .default(sql`gen_random_uuid()`) - .primaryKey(), - parentId: uuid('parent_id') - .notNull() - .references(() => users.id, { onDelete: 'cascade' }), + id: uuid('id').primaryKey(), name: varchar('name', { length: 256 }), phone: varchar('phone', { length: 256 }), apiKey: varchar('key', { length: 256 }), + parentId: uuid('parent_id'), }); - -export const childDevices = relations(child, ({ many }) => ({ +export const childRelations = relations(child, ({ one, many }) => ({ + parent: one(users, { + fields: [child.parentId], + references: [users.id], + }), devices: many(device), })); -//#endregion child -//#region device + export const device = pgTable( 'device', { - deviceId: varchar('device_id').notNull().unique(), - childId: uuid('child_id') - .notNull() - .references(() => child.id, { onDelete: 'cascade' }), + id: uuid('id').primaryKey(), + childId: uuid('child_id'), apiKey: varchar('api_key').notNull().unique(), //TODO: make the device request/pin a separate table and enforce the expiry pin: integer('pin').notNull(), expires: timestamp('expires').default(sql`now () + interval '1 hour'`), - }, - (device) => ({ - composePk: primaryKey({ columns: [device.deviceId, device.childId] }), - }) + } ); -const deviceRelations = relations(device, ({ one }) => ({ +export const deviceRelations = relations(device, ({ one, many }) => ({ child: one(child, { fields: [device.childId], references: [child.id], }), + pings: many(ping), })); export const ping = pgTable('ping', { - deviceId: varchar('device_id').notNull(), + deviceId: uuid('device_id').notNull(), latitude: doublePrecision('latitude').notNull(), longitude: doublePrecision('longitude').notNull(), timestamp: timestamp('timestamp').notNull(), }); -export const devicePings = relations(device, ({ many }) => ({ - pings: many(ping), +export const pingRelations = relations(ping, ({ one, many }) => ({ + child: one(device, { + fields: [ping.deviceId], + references: [device.id], + }), })); - -//#endregion device diff --git a/src/db/seed.ts b/src/db/seed.ts new file mode 100644 index 0000000..b672832 --- /dev/null +++ b/src/db/seed.ts @@ -0,0 +1,5 @@ +import * as dotenv from 'dotenv'; +dotenv.config({ path: './.env' }); + +if (!('DATABASE_URL' in process.env)) + throw new Error('DATABASE_URL not found on .env.development');