From 5b475f197a81af569ffa983515d15e34e8ed8d59 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Thu, 6 Feb 2025 17:42:16 -0600 Subject: [PATCH] Umstellung auf PostgresDB & user Table & update drizzle --- api/src/app/drizzle.service.ts | 68 ++++---- api/src/db/schema.ts | 66 +++---- drizzle.config.ts | 6 +- drizzle/0000_ambitious_hercules.sql | 19 --- drizzle/0000_dapper_the_watchers.sql | 31 ++++ drizzle/0001_smooth_iron_lad.sql | 1 - drizzle/0002_aromatic_zodiak.sql | 2 - drizzle/0003_hard_cable.sql | 1 - drizzle/meta/0000_snapshot.json | 210 +++++++++++++++++------ drizzle/meta/0001_snapshot.json | 148 ---------------- drizzle/meta/0002_snapshot.json | 164 ------------------ drizzle/meta/0003_snapshot.json | 157 ----------------- drizzle/meta/_journal.json | 29 +--- package-lock.json | 246 ++++++++++++++++++++++++++- package.json | 8 +- 15 files changed, 513 insertions(+), 643 deletions(-) delete mode 100644 drizzle/0000_ambitious_hercules.sql create mode 100644 drizzle/0000_dapper_the_watchers.sql delete mode 100644 drizzle/0001_smooth_iron_lad.sql delete mode 100644 drizzle/0002_aromatic_zodiak.sql delete mode 100644 drizzle/0003_hard_cable.sql delete mode 100644 drizzle/meta/0001_snapshot.json delete mode 100644 drizzle/meta/0002_snapshot.json delete mode 100644 drizzle/meta/0003_snapshot.json diff --git a/api/src/app/drizzle.service.ts b/api/src/app/drizzle.service.ts index 07cfcf8..e091e87 100644 --- a/api/src/app/drizzle.service.ts +++ b/api/src/app/drizzle.service.ts @@ -1,8 +1,9 @@ // drizzle.service.ts import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { and, eq, sql } from 'drizzle-orm'; -import { drizzle } from 'drizzle-orm/libsql'; -import { Deck, SelectDeck, User } from '../db/schema'; +//import { drizzle } from 'drizzle-orm/libsql'; +import { drizzle } from 'drizzle-orm/node-postgres'; +import { deck, SelectDeck, User } from '../db/schema'; import { SqlLoggerService } from './sql-logger.service'; @Injectable() @@ -10,20 +11,27 @@ export class DrizzleService { // private readonly logger = new Logger(DrizzleService.name); private db: any; constructor(private sqlLogger: SqlLoggerService) { - this.db = drizzle('file:local.db', { + // this.db = drizzle('file:local.db', { + // logger: { + // logQuery: (query: string, params: any[]) => { + // this.sqlLogger.logQuery(query, params); + // }, + // }, + // }); + this.db = drizzle('postgresql://haiky:xieng7Seih@localhost:15432/haiky', { logger: { logQuery: (query: string, params: any[]) => { this.sqlLogger.logQuery(query, params); }, }, - }); + }); //drizzle(process.env.DATABASE_URL); } /** * Methode zum Abrufen aller Decks eines Benutzers */ async getDecks(user: User) { - return this.db.select().from(Deck).where(eq(Deck.user, user.email)); + return this.db.select().from(deck).where(eq(deck.user, user.email)); } /** @@ -32,7 +40,7 @@ export class DrizzleService { async createDeck(deckname: string, user: User) { // 'inserted' und 'updated' werden automatisch von der Datenbank gesetzt const result = await this.db - .insert(Deck) + .insert(deck) .values({ deckname, user: user.email, @@ -48,8 +56,8 @@ export class DrizzleService { async getDeckByName(deckname: string, user: User) { return this.db .select() - .from(Deck) - .where(and(eq(Deck.deckname, deckname), eq(Deck.user, user.email))); + .from(deck) + .where(and(eq(deck.deckname, deckname), eq(deck.user, user.email))); } /** @@ -61,7 +69,7 @@ export class DrizzleService { throw new HttpException('Deck not found', HttpStatus.NOT_FOUND); } - await this.db.delete(Deck).where(and(eq(Deck.deckname, deckname), eq(Deck.user, user.email))); + await this.db.delete(deck).where(and(eq(deck.deckname, deckname), eq(deck.user, user.email))); return { status: 'success' }; } @@ -80,12 +88,12 @@ export class DrizzleService { } await this.db - .update(Deck) + .update(deck) .set({ deckname: newDeckname, updated: sql`CURRENT_TIMESTAMP`, // Setze 'updated' auf CURRENT_TIMESTAMP }) - .where(and(eq(Deck.deckname, oldDeckname), eq(Deck.user, user.email))); + .where(and(eq(deck.deckname, oldDeckname), eq(deck.user, user.email))); return { status: 'success', message: 'Deck renamed successfully' }; } @@ -116,7 +124,7 @@ export class DrizzleService { for (let index = 0; index < newEntries.length; index++) { const box = newEntries[index]; const result = await this.db - .insert(Deck) + .insert(deck) .values({ deckname: data.deckname, bildname: data.bildname, @@ -138,7 +146,7 @@ export class DrizzleService { const existingDeck = existingDecks.find(d => d.id === box.id); if (existingDeck && (existingDeck.x1 !== box.x1 || existingDeck.x2 !== box.x2 || existingDeck.y1 !== box.y1 || existingDeck.y2 !== box.y2)) { const result = await this.db - .update(Deck) + .update(deck) .set({ x1: box.x1, x2: box.x2, @@ -146,7 +154,7 @@ export class DrizzleService { y2: box.y2, updated: sql`CURRENT_TIMESTAMP`, // Setze 'updated' auf CURRENT_TIMESTAMP }) - .where(and(eq(Deck.user, user.email), eq(Deck.bildid, data.bildid), eq(Deck.deckname, data.deckname), eq(Deck.id, box.id!!))); + .where(and(eq(deck.user, user.email), eq(deck.bildid, data.bildid), eq(deck.deckname, data.deckname), eq(deck.id, box.id!!))); if (result.rowsAffected === 0) { throw new HttpException(`Box with id ${box.id} not found`, HttpStatus.NOT_FOUND); } @@ -164,7 +172,7 @@ export class DrizzleService { const idsToDelete = existingIdsInDb.filter(id => !incomingIds.includes(id)); if (idsToDelete.length > 0) { - await this.db.delete(Deck).where(and(eq(Deck.deckname, data.deckname), eq(Deck.bildid, data.bildid), eq(Deck.user, user.email), sql`id in ${idsToDelete}`)); + await this.db.delete(deck).where(and(eq(deck.deckname, data.deckname), eq(deck.bildid, data.bildid), eq(deck.user, user.email), sql`id in ${idsToDelete}`)); } return { status: 'success', inserted_images: insertedImages }; @@ -175,16 +183,16 @@ export class DrizzleService { */ async deleteImagesByBildId(bildid: string, user: User) { const affectedDecks = await this.db - .select({ deckname: Deck.deckname }) - .from(Deck) - .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))) + .select({ deckname: deck.deckname }) + .from(deck) + .where(and(eq(deck.bildid, bildid), eq(deck.user, user.email))) .all(); if (affectedDecks.length === 0) { throw new HttpException('No entries found for the given image ID', HttpStatus.NOT_FOUND); } - await this.db.delete(Deck).where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))); + await this.db.delete(deck).where(and(eq(deck.bildid, bildid), eq(deck.user, user.email))); return { status: 'success', @@ -198,8 +206,8 @@ export class DrizzleService { async moveImage(bildid: string, targetDeckId: string, user: User) { const existingImages = await this.db .select() - .from(Deck) - .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))) + .from(deck) + .where(and(eq(deck.bildid, bildid), eq(deck.user, user.email))) .all(); if (existingImages.length === 0) { @@ -207,12 +215,12 @@ export class DrizzleService { } await this.db - .update(Deck) + .update(deck) .set({ deckname: targetDeckId, updated: sql`CURRENT_TIMESTAMP`, // Setze 'updated' auf CURRENT_TIMESTAMP }) - .where(and(eq(Deck.bildid, bildid), eq(Deck.user, user.email))); + .where(and(eq(deck.bildid, bildid), eq(deck.user, user.email))); return { status: 'success', moved_entries: existingImages.length }; } @@ -222,8 +230,8 @@ export class DrizzleService { async renameImage(bildId: string, newImagename: string, user: User) { const existingImages = this.db .select() - .from(Deck) - .where(and(eq(Deck.bildid, bildId), eq(Deck.user, user.email))); + .from(deck) + .where(and(eq(deck.bildid, bildId), eq(deck.user, user.email))); if (existingImages.length === 0) { throw new HttpException('Deck not found', HttpStatus.NOT_FOUND); } @@ -234,12 +242,12 @@ export class DrizzleService { // } await this.db - .update(Deck) + .update(deck) .set({ bildname: newImagename, updated: sql`CURRENT_TIMESTAMP`, // Setze 'updated' auf CURRENT_TIMESTAMP }) - .where(and(eq(Deck.bildid, bildId), eq(Deck.user, user.email))); + .where(and(eq(deck.bildid, bildId), eq(deck.user, user.email))); return { status: 'success', message: 'Image Entries renamed successfully' }; } /** @@ -264,9 +272,9 @@ export class DrizzleService { updateData.updated = sql`CURRENT_TIMESTAMP`; // Setze 'updated' auf CURRENT_TIMESTAMP const result = await this.db - .update(Deck) + .update(deck) .set(updateData) - .where(and(eq(Deck.id, id), eq(Deck.user, user.email))); + .where(and(eq(deck.id, id), eq(deck.user, user.email))); if (result.rowsAffected === 0) { throw new HttpException('Box not found', HttpStatus.NOT_FOUND); @@ -280,7 +288,7 @@ export class DrizzleService { */ async getDistinctBildIds(user: User): Promise { try { - const result = await this.db.selectDistinct([Deck.bildid]).from(Deck).all(); + const result = await this.db.selectDistinct([deck.bildid]).from(deck).all(); // Extrahiere die bildid Werte aus dem Ergebnis const usedIds = result.map((row: any) => row['0']).filter((id: string | null) => id !== null) as string[]; diff --git a/api/src/db/schema.ts b/api/src/db/schema.ts index d2ba352..ec8f615 100644 --- a/api/src/db/schema.ts +++ b/api/src/db/schema.ts @@ -1,37 +1,45 @@ import { sql } from 'drizzle-orm'; -import * as t from 'drizzle-orm/sqlite-core'; -import { integer, real, sqliteTable as table, text } from 'drizzle-orm/sqlite-core'; +import * as t from 'drizzle-orm/pg-core'; +import { pgEnum, pgTable as table } from 'drizzle-orm/pg-core'; -export const Deck = table( - 'Deck', +export const rolesEnum = pgEnum('roles', ['admin', 'guest', 'pro']); + +export const deck = table( + 'deck', { - id: integer('id').primaryKey({ autoIncrement: true }), - deckname: text('deckname').notNull(), - bildname: text('bildname'), - bildid: text('bildid'), - x1: real('x1'), - x2: real('x2'), - y1: real('y1'), - y2: real('y2'), - due: integer('due'), - ivl: real('ivl'), - factor: real('factor'), - reps: integer('reps'), - lapses: integer('lapses'), - isGraduated: integer('isGraduated'), - user: text('user').notNull(), - inserted: text().default(sql`(CURRENT_TIMESTAMP)`), // Neue Spalte - updated: text().default(sql`(CURRENT_TIMESTAMP)`), // Neue Spalte - }, - table => { - return { - index: t.uniqueIndex('email_idx').on(table.id), - }; + id: t.integer('id').primaryKey().generatedAlwaysAsIdentity(), + deckname: t.varchar('deckname').notNull(), + bildname: t.varchar('bildname'), + bildid: t.varchar('bildid'), + x1: t.real('x1'), + x2: t.real('x2'), + y1: t.real('y1'), + y2: t.real('y2'), + due: t.integer('due'), + ivl: t.real('ivl'), + factor: t.real('factor'), + reps: t.integer('reps'), + lapses: t.integer('lapses'), + isGraduated: t.integer('isgraduated'), + user: t.varchar('user').notNull(), + inserted: t.varchar().default(sql`(CURRENT_TIMESTAMP)`), // Neue Spalte + updated: t.varchar().default(sql`(CURRENT_TIMESTAMP)`), // Neue Spalte }, + table => [t.uniqueIndex('deck_idx').on(table.id)], ); - -export type InsertDeck = typeof Deck.$inferInsert; -export type SelectDeck = typeof Deck.$inferSelect; +export const users = table( + 'users', + { + id: t.integer().primaryKey().generatedAlwaysAsIdentity(), + name: t.varchar('name', { length: 256 }), + email: t.varchar().notNull(), + role: rolesEnum().default('guest'), + sign_in_provider: t.varchar('sign_in_provider', { length: 50 }), + }, + table => [t.uniqueIndex('users_idx').on(table.id)], +); +export type InsertDeck = typeof deck.$inferInsert; +export type SelectDeck = typeof deck.$inferSelect; export interface User { name: string; picture: string; diff --git a/drizzle.config.ts b/drizzle.config.ts index 33af16a..d05ce4c 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -3,8 +3,8 @@ import { defineConfig } from 'drizzle-kit'; export default defineConfig({ out: './drizzle', schema: './api/src/db/schema.ts', - dialect: 'sqlite', + dialect: 'postgresql', dbCredentials: { - url: 'file:local1.db', + url: process.env['DATABASE_URL'], }, -}); \ No newline at end of file +}); diff --git a/drizzle/0000_ambitious_hercules.sql b/drizzle/0000_ambitious_hercules.sql deleted file mode 100644 index 32d27b2..0000000 --- a/drizzle/0000_ambitious_hercules.sql +++ /dev/null @@ -1,19 +0,0 @@ -CREATE TABLE `Deck` ( - `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - `deckname` text NOT NULL, - `bildname` text, - `bildid` text, - `iconindex` integer, - `x1` real, - `x2` real, - `y1` real, - `y2` real, - `due` integer, - `ivl` real, - `factor` real, - `reps` integer, - `lapses` integer, - `isGraduated` integer -); ---> statement-breakpoint -CREATE UNIQUE INDEX `email_idx` ON `Deck` (`id`); \ No newline at end of file diff --git a/drizzle/0000_dapper_the_watchers.sql b/drizzle/0000_dapper_the_watchers.sql new file mode 100644 index 0000000..3907cc7 --- /dev/null +++ b/drizzle/0000_dapper_the_watchers.sql @@ -0,0 +1,31 @@ +CREATE TYPE "public"."roles" AS ENUM('admin', 'guest', 'pro');--> statement-breakpoint +CREATE TABLE "Deck" ( + "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "Deck_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1), + "deckname" varchar NOT NULL, + "bildname" varchar, + "bildid" varchar, + "x1" real, + "x2" real, + "y1" real, + "y2" real, + "due" integer, + "ivl" real, + "factor" real, + "reps" integer, + "lapses" integer, + "isGraduated" integer, + "user" varchar NOT NULL, + "inserted" varchar DEFAULT (CURRENT_TIMESTAMP), + "updated" varchar DEFAULT (CURRENT_TIMESTAMP) +); +--> statement-breakpoint +CREATE TABLE "users" ( + "id" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "users_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1), + "name" varchar(256), + "email" varchar NOT NULL, + "role" "roles" DEFAULT 'guest', + "sign_in_provider" varchar(50) +); +--> statement-breakpoint +CREATE UNIQUE INDEX "deck_idx" ON "Deck" USING btree ("id");--> statement-breakpoint +CREATE UNIQUE INDEX "users_idx" ON "users" USING btree ("id"); \ No newline at end of file diff --git a/drizzle/0001_smooth_iron_lad.sql b/drizzle/0001_smooth_iron_lad.sql deleted file mode 100644 index d5a492a..0000000 --- a/drizzle/0001_smooth_iron_lad.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `Deck` ADD `user` text NOT NULL; \ No newline at end of file diff --git a/drizzle/0002_aromatic_zodiak.sql b/drizzle/0002_aromatic_zodiak.sql deleted file mode 100644 index 1e3b53c..0000000 --- a/drizzle/0002_aromatic_zodiak.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE `Deck` ADD `inserted` text DEFAULT (CURRENT_TIMESTAMP);--> statement-breakpoint -ALTER TABLE `Deck` ADD `updated` text DEFAULT (CURRENT_TIMESTAMP); \ No newline at end of file diff --git a/drizzle/0003_hard_cable.sql b/drizzle/0003_hard_cable.sql deleted file mode 100644 index b27b927..0000000 --- a/drizzle/0003_hard_cable.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE `Deck` DROP COLUMN `iconindex`; \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index 5e9fc9f..3988ff1 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1,141 +1,245 @@ { - "version": "6", - "dialect": "sqlite", - "id": "3996df1c-a197-4842-869e-2e3b4f10064a", + "id": "ad8762e3-d7ad-4605-b2fc-b10a0de0f08a", "prevId": "00000000-0000-0000-0000-000000000000", + "version": "7", + "dialect": "postgresql", "tables": { - "Deck": { + "public.Deck": { "name": "Deck", + "schema": "", "columns": { "id": { "name": "id", "type": "integer", "primaryKey": true, "notNull": true, - "autoincrement": true + "identity": { + "type": "always", + "name": "Deck_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } }, "deckname": { "name": "deckname", - "type": "text", + "type": "varchar", "primaryKey": false, - "notNull": true, - "autoincrement": false + "notNull": true }, "bildname": { "name": "bildname", - "type": "text", + "type": "varchar", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "bildid": { "name": "bildid", - "type": "text", + "type": "varchar", "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "iconindex": { - "name": "iconindex", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "x1": { "name": "x1", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "x2": { "name": "x2", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "y1": { "name": "y1", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "y2": { "name": "y2", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "due": { "name": "due", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "ivl": { "name": "ivl", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "factor": { "name": "factor", "type": "real", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "reps": { "name": "reps", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "lapses": { "name": "lapses", "type": "integer", "primaryKey": false, - "notNull": false, - "autoincrement": false + "notNull": false }, "isGraduated": { "name": "isGraduated", "type": "integer", "primaryKey": false, + "notNull": false + }, + "user": { + "name": "user", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "inserted": { + "name": "inserted", + "type": "varchar", + "primaryKey": false, "notNull": false, - "autoincrement": false + "default": "(CURRENT_TIMESTAMP)" + }, + "updated": { + "name": "updated", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "(CURRENT_TIMESTAMP)" } }, "indexes": { - "email_idx": { - "name": "email_idx", + "deck_idx": { + "name": "deck_idx", "columns": [ - "id" + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } ], - "isUnique": true + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} } }, "foreignKeys": {}, "compositePrimaryKeys": {}, "uniqueConstraints": {}, - "checkConstraints": {} + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "identity": { + "type": "always", + "name": "users_id_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "roles", + "typeSchema": "public", + "primaryKey": false, + "notNull": false, + "default": "'guest'" + }, + "sign_in_provider": { + "name": "sign_in_provider", + "type": "varchar(50)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "users_idx": { + "name": "users_idx", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false } }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} + "enums": { + "public.roles": { + "name": "roles", + "schema": "public", + "values": [ + "admin", + "guest", + "pro" + ] + } }, - "internal": { - "indexes": {} + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} } } \ No newline at end of file diff --git a/drizzle/meta/0001_snapshot.json b/drizzle/meta/0001_snapshot.json deleted file mode 100644 index b36bce0..0000000 --- a/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,148 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "a3cf5e86-4f1b-4cdc-9688-cf9063ba6936", - "prevId": "3996df1c-a197-4842-869e-2e3b4f10064a", - "tables": { - "Deck": { - "name": "Deck", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "deckname": { - "name": "deckname", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "bildname": { - "name": "bildname", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "bildid": { - "name": "bildid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "iconindex": { - "name": "iconindex", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x1": { - "name": "x1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x2": { - "name": "x2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y1": { - "name": "y1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y2": { - "name": "y2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "due": { - "name": "due", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "ivl": { - "name": "ivl", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "factor": { - "name": "factor", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reps": { - "name": "reps", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "lapses": { - "name": "lapses", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "isGraduated": { - "name": "isGraduated", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user": { - "name": "user", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": { - "email_idx": { - "name": "email_idx", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/0002_snapshot.json b/drizzle/meta/0002_snapshot.json deleted file mode 100644 index 9c9abdd..0000000 --- a/drizzle/meta/0002_snapshot.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "1e5421d8-df58-434e-93c8-85dcbe6ec9ee", - "prevId": "a3cf5e86-4f1b-4cdc-9688-cf9063ba6936", - "tables": { - "Deck": { - "name": "Deck", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "deckname": { - "name": "deckname", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "bildname": { - "name": "bildname", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "bildid": { - "name": "bildid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "iconindex": { - "name": "iconindex", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x1": { - "name": "x1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x2": { - "name": "x2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y1": { - "name": "y1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y2": { - "name": "y2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "due": { - "name": "due", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "ivl": { - "name": "ivl", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "factor": { - "name": "factor", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reps": { - "name": "reps", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "lapses": { - "name": "lapses", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "isGraduated": { - "name": "isGraduated", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user": { - "name": "user", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "inserted": { - "name": "inserted", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(CURRENT_TIMESTAMP)" - }, - "updated": { - "name": "updated", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(CURRENT_TIMESTAMP)" - } - }, - "indexes": { - "email_idx": { - "name": "email_idx", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/0003_snapshot.json b/drizzle/meta/0003_snapshot.json deleted file mode 100644 index 00f971b..0000000 --- a/drizzle/meta/0003_snapshot.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "a0b561cf-8404-43ea-bc72-8b32671580bd", - "prevId": "1e5421d8-df58-434e-93c8-85dcbe6ec9ee", - "tables": { - "Deck": { - "name": "Deck", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "deckname": { - "name": "deckname", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "bildname": { - "name": "bildname", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "bildid": { - "name": "bildid", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x1": { - "name": "x1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "x2": { - "name": "x2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y1": { - "name": "y1", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "y2": { - "name": "y2", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "due": { - "name": "due", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "ivl": { - "name": "ivl", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "factor": { - "name": "factor", - "type": "real", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "reps": { - "name": "reps", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "lapses": { - "name": "lapses", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "isGraduated": { - "name": "isGraduated", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "user": { - "name": "user", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "inserted": { - "name": "inserted", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(CURRENT_TIMESTAMP)" - }, - "updated": { - "name": "updated", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false, - "default": "(CURRENT_TIMESTAMP)" - } - }, - "indexes": { - "email_idx": { - "name": "email_idx", - "columns": [ - "id" - ], - "isUnique": true - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index bda63fb..b16cde9 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -1,33 +1,12 @@ { "version": "7", - "dialect": "sqlite", + "dialect": "postgresql", "entries": [ { "idx": 0, - "version": "6", - "when": 1737229773082, - "tag": "0000_ambitious_hercules", - "breakpoints": true - }, - { - "idx": 1, - "version": "6", - "when": 1737229845910, - "tag": "0001_smooth_iron_lad", - "breakpoints": true - }, - { - "idx": 2, - "version": "6", - "when": 1738103858394, - "tag": "0002_aromatic_zodiak", - "breakpoints": true - }, - { - "idx": 3, - "version": "6", - "when": 1738235979220, - "tag": "0003_hard_cable", + "version": "7", + "when": 1738881267759, + "tag": "0000_dapper_the_watchers", "breakpoints": true } ] diff --git a/package-lock.json b/package-lock.json index f371e93..657117c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "firebase-admin": "^13.0.2", "flowbite": "^2.5.2", "http-server": "^14.1.1", + "pg": "^8.13.1", "reflect-metadata": "^0.1.13", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -54,10 +55,11 @@ "@swc/helpers": "~0.5.11", "@types/fabric": "^5.3.9", "@types/node": "~18.16.9", + "@types/pg": "^8.11.11", "chalk": "^5.4.1", "concurrently": "^9.1.2", - "drizzle-kit": "^0.30.2", - "drizzle-orm": "^0.38.4", + "drizzle-kit": "^0.30.4", + "drizzle-orm": "^0.39.2", "nx": "20.3.2", "prettier": "^2.6.2", "tailwindcss": "^3.4.15", @@ -10318,6 +10320,80 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/pg": { + "version": "8.11.11", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.11.tgz", + "integrity": "sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/pg/node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "dev": true, + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@types/pg/node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/pg/node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/@types/pg/node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/@types/qs": { "version": "6.9.17", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", @@ -13812,9 +13888,9 @@ } }, "node_modules/drizzle-kit": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.2.tgz", - "integrity": "sha512-vhdLrxWA32WNVF77NabpSnX7pQBornx64VDQDmKddRonOB2Xe/yY4glQ7rECoa+ogqcQNo7VblLUbeBK6Zn9Ow==", + "version": "0.30.4", + "resolved": "https://registry.npmjs.org/drizzle-kit/-/drizzle-kit-0.30.4.tgz", + "integrity": "sha512-B2oJN5UkvwwNHscPWXDG5KqAixu7AUzZ3qbe++KU9SsQ+cZWR4DXEPYcvWplyFAno0dhRJECNEhNxiDmFaPGyQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14258,9 +14334,9 @@ } }, "node_modules/drizzle-orm": { - "version": "0.38.4", - "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.38.4.tgz", - "integrity": "sha512-s7/5BpLKO+WJRHspvpqTydxFob8i1vo2rEx4pY6TGY7QSMuUfWUuzaY0DIpXCkgHOo37BaFC+SJQb99dDUXT3Q==", + "version": "0.39.2", + "resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.39.2.tgz", + "integrity": "sha512-cuopo+udkKEGGpSxCML9ZRQ43R01zYCTsbqCrb9kJkabx1QEwFlPIFoQfx6E6tuawtiX930Gwyrkwj4inlpzDg==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -22790,6 +22866,105 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pg": { + "version": "8.13.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.1.tgz", + "integrity": "sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.7.0", + "pg-pool": "^3.7.0", + "pg-protocol": "^1.7.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz", + "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.0.tgz", + "integrity": "sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.0.tgz", + "integrity": "sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -23680,6 +23855,52 @@ "dev": true, "license": "MIT" }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "dev": true, + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -25283,6 +25504,15 @@ "wbuf": "^1.7.3" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", diff --git a/package.json b/package.json index d6de842..068ea3a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "firebase-admin": "^13.0.2", "flowbite": "^2.5.2", "http-server": "^14.1.1", + "pg": "^8.13.1", "reflect-metadata": "^0.1.13", "rxjs": "~7.8.0", "tslib": "^2.3.0", @@ -56,10 +57,11 @@ "@swc/helpers": "~0.5.11", "@types/fabric": "^5.3.9", "@types/node": "~18.16.9", + "@types/pg": "^8.11.11", "chalk": "^5.4.1", "concurrently": "^9.1.2", - "drizzle-kit": "^0.30.2", - "drizzle-orm": "^0.38.4", + "drizzle-kit": "^0.30.4", + "drizzle-orm": "^0.39.2", "nx": "20.3.2", "prettier": "^2.6.2", "tailwindcss": "^3.4.15", @@ -67,4 +69,4 @@ "typescript": "~5.5.2", "webpack-cli": "^5.1.4" } -} +} \ No newline at end of file