mirror of
https://github.com/fergalmoran/kidarr-server.git
synced 2025-12-26 19:38:39 +00:00
Relations working (I think???
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,3 +33,4 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
.krud/
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "5",
|
||||
"when": 1702675078550,
|
||||
"tag": "0000_brainy_marvel_apes",
|
||||
"when": 1703070994335,
|
||||
"tag": "0000_thankful_sasquatch",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
21
package.json
21
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"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
8
src/db/migrate.ts
Normal file
8
src/db/migrate.ts
Normal file
@@ -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')
|
||||
// );
|
||||
@@ -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
|
||||
|
||||
5
src/db/seed.ts
Normal file
5
src/db/seed.ts
Normal file
@@ -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');
|
||||
Reference in New Issue
Block a user