diff --git a/dbal/ts/src/adapters/prisma-adapter.ts b/dbal/ts/src/adapters/prisma-adapter.ts deleted file mode 100644 index 26c78243f..000000000 --- a/dbal/ts/src/adapters/prisma-adapter.ts +++ /dev/null @@ -1,304 +0,0 @@ -import { PrismaClient } from '@prisma/client' -import type { DBALAdapter, AdapterCapabilities } from './adapter' -import type { ListOptions, ListResult } from '../core/types' -import { DBALError } from '../core/errors' - -export class PrismaAdapter implements DBALAdapter { - private prisma: PrismaClient - private queryTimeout: number - - constructor(databaseUrl?: string, options?: { queryTimeout?: number }) { - this.prisma = new PrismaClient({ - datasources: databaseUrl ? { - db: { url: databaseUrl } - } : undefined, - }) - this.queryTimeout = options?.queryTimeout || 30000 - } - - async create(entity: string, data: Record): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.create({ data: data as never }) - ) - return result - } catch (error) { - throw this.handleError(error, 'create', entity) - } - } - - async read(entity: string, id: string): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.findUnique({ where: { id } as never }) - ) - return result - } catch (error) { - throw this.handleError(error, 'read', entity) - } - } - - async update(entity: string, id: string, data: Record): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.update({ - where: { id } as never, - data: data as never - }) - ) - return result - } catch (error) { - throw this.handleError(error, 'update', entity) - } - } - - async delete(entity: string, id: string): Promise { - try { - const model = this.getModel(entity) - await this.withTimeout( - model.delete({ where: { id } as never }) - ) - return true - } catch (error) { - if (this.isNotFoundError(error)) { - return false - } - throw this.handleError(error, 'delete', entity) - } - } - - async list(entity: string, options?: ListOptions): Promise> { - try { - const model = this.getModel(entity) - const page = options?.page || 1 - const limit = options?.limit || 50 - const skip = (page - 1) * limit - - const where = options?.filter ? this.buildWhereClause(options.filter) : undefined - const orderBy = options?.sort ? this.buildOrderBy(options.sort) : undefined - - const [data, total] = await Promise.all([ - this.withTimeout( - model.findMany({ - where: where as never, - orderBy: orderBy as never, - skip, - take: limit, - }) - ), - this.withTimeout( - model.count({ where: where as never }) - ) - ]) as [unknown[], number] - - return { - data: data as unknown[], - total, - page, - limit, - hasMore: skip + limit < total, - } - } catch (error) { - throw this.handleError(error, 'list', entity) - } - } - - async findFirst(entity: string, filter?: Record): Promise { - try { - const model = this.getModel(entity) - const where = filter ? this.buildWhereClause(filter) : undefined - const result = await this.withTimeout( - model.findFirst({ where: where as never }) - ) - return result - } catch (error) { - throw this.handleError(error, 'findFirst', entity) - } - } - - async findByField(entity: string, field: string, value: unknown): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.findUnique({ where: { [field]: value } as never }) - ) - return result - } catch (error) { - throw this.handleError(error, 'findByField', entity) - } - } - - async upsert( - entity: string, - uniqueField: string, - uniqueValue: unknown, - createData: Record, - updateData: Record - ): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.upsert({ - where: { [uniqueField]: uniqueValue } as never, - create: createData as never, - update: updateData as never, - }) - ) - return result - } catch (error) { - throw this.handleError(error, 'upsert', entity) - } - } - - async updateByField(entity: string, field: string, value: unknown, data: Record): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.update({ - where: { [field]: value } as never, - data: data as never, - }) - ) - return result - } catch (error) { - throw this.handleError(error, 'updateByField', entity) - } - } - - async deleteByField(entity: string, field: string, value: unknown): Promise { - try { - const model = this.getModel(entity) - await this.withTimeout( - model.delete({ where: { [field]: value } as never }) - ) - return true - } catch (error) { - if (this.isNotFoundError(error)) { - return false - } - throw this.handleError(error, 'deleteByField', entity) - } - } - - async deleteMany(entity: string, filter?: Record): Promise { - try { - const model = this.getModel(entity) - const where = filter ? this.buildWhereClause(filter) : undefined - const result = await this.withTimeout( - model.deleteMany({ where: where as never }) - ) - return result.count - } catch (error) { - throw this.handleError(error, 'deleteMany', entity) - } - } - - async updateMany(entity: string, filter: Record, data: Record): Promise { - try { - const model = this.getModel(entity) - const where = this.buildWhereClause(filter) - const result = await this.withTimeout( - model.updateMany({ where: where as never, data: data as never }) - ) - return result.count - } catch (error) { - throw this.handleError(error, 'updateMany', entity) - } - } - - async createMany(entity: string, data: Record[]): Promise { - try { - const model = this.getModel(entity) - const result = await this.withTimeout( - model.createMany({ data: data as never }) - ) - return result.count - } catch (error) { - throw this.handleError(error, 'createMany', entity) - } - } - - async getCapabilities(): Promise { - return { - transactions: true, - joins: true, - fullTextSearch: false, - ttl: false, - jsonQueries: true, - aggregations: true, - relations: true, - } - } - - async close(): Promise { - await this.prisma.$disconnect() - } - - private getModel(entity: string): any { - const modelName = entity.charAt(0).toLowerCase() + entity.slice(1) - const model = (this.prisma as any)[modelName] - - if (!model) { - throw DBALError.notFound(`Entity ${entity} not found`) - } - - return model - } - - private buildWhereClause(filter: Record): Record { - const where: Record = {} - - for (const [key, value] of Object.entries(filter)) { - if (value === null || value === undefined) { - where[key] = null - } else if (typeof value === 'object' && !Array.isArray(value)) { - where[key] = value - } else { - where[key] = value - } - } - - return where - } - - private buildOrderBy(sort: Record): Record { - return sort - } - - private async withTimeout(promise: Promise): Promise { - return Promise.race([ - promise, - new Promise((_, reject) => - setTimeout(() => reject(DBALError.timeout()), this.queryTimeout) - ) - ]) - } - - private isNotFoundError(error: unknown): boolean { - return error instanceof Error && error.message.includes('not found') - } - - private handleError(error: unknown, operation: string, entity: string): DBALError { - if (error instanceof DBALError) { - return error - } - - if (error instanceof Error) { - if (error.message.includes('Unique constraint')) { - return DBALError.conflict(`${entity} already exists`) - } - if (error.message.includes('Foreign key constraint')) { - return DBALError.validationError('Related resource not found') - } - if (error.message.includes('not found')) { - return DBALError.notFound(`${entity} not found`) - } - return DBALError.internal(`Database error during ${operation}: ${error.message}`) - } - - return DBALError.internal(`Unknown error during ${operation}`) - } -} diff --git a/frontends/nextjs/src/lib/db/sessions/delete-session-by-token.ts b/frontends/nextjs/src/lib/db/sessions/delete-session-by-token.ts new file mode 100644 index 000000000..80c3b2737 --- /dev/null +++ b/frontends/nextjs/src/lib/db/sessions/delete-session-by-token.ts @@ -0,0 +1 @@ +export { deleteSessionByToken } from './crud/delete/delete-session-by-token' diff --git a/frontends/nextjs/src/lib/db/sessions/delete-session.ts b/frontends/nextjs/src/lib/db/sessions/delete-session.ts new file mode 100644 index 000000000..a7f329e18 --- /dev/null +++ b/frontends/nextjs/src/lib/db/sessions/delete-session.ts @@ -0,0 +1 @@ +export { deleteSession } from './crud/delete/delete-session' diff --git a/frontends/nextjs/src/lib/db/sessions/get-session-by-token.ts b/frontends/nextjs/src/lib/db/sessions/get-session-by-token.ts new file mode 100644 index 000000000..ccd088372 --- /dev/null +++ b/frontends/nextjs/src/lib/db/sessions/get-session-by-token.ts @@ -0,0 +1 @@ +export { getSessionByToken } from './getters/get-session-by-token'