Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
56
src/lib/db/utils.ts
Normal file
56
src/lib/db/utils.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { eq, sql } from 'drizzle-orm';
|
||||
import type { PgTable, PgColumn } from 'drizzle-orm/pg-core';
|
||||
import { db } from './index';
|
||||
|
||||
/**
|
||||
* Wraps a database operation in a transaction.
|
||||
* Rolls back automatically on error.
|
||||
*
|
||||
* @example
|
||||
* const result = await withTransaction(async (tx) => {
|
||||
* await tx.insert(clients).values({ ... });
|
||||
* await tx.insert(interests).values({ ... });
|
||||
* return result;
|
||||
* });
|
||||
*/
|
||||
export async function withTransaction<T>(
|
||||
callback: (tx: typeof db) => Promise<T>,
|
||||
): Promise<T> {
|
||||
return db.transaction(callback as any) as Promise<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-deletes a record by setting `archived_at` to now.
|
||||
* The table must have an `archived_at` column.
|
||||
*
|
||||
* @example
|
||||
* await softDelete(clients, clients.id, clientId);
|
||||
*/
|
||||
export async function softDelete<TTable extends PgTable>(
|
||||
table: TTable,
|
||||
idColumn: PgColumn,
|
||||
id: string,
|
||||
): Promise<void> {
|
||||
await db
|
||||
.update(table)
|
||||
.set({ archived_at: sql`now()` } as any)
|
||||
.where(eq(idColumn, id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores a soft-deleted record by clearing `archived_at`.
|
||||
* The table must have an `archived_at` column.
|
||||
*
|
||||
* @example
|
||||
* await restore(clients, clients.id, clientId);
|
||||
*/
|
||||
export async function restore<TTable extends PgTable>(
|
||||
table: TTable,
|
||||
idColumn: PgColumn,
|
||||
id: string,
|
||||
): Promise<void> {
|
||||
await db
|
||||
.update(table)
|
||||
.set({ archived_at: null } as any)
|
||||
.where(eq(idColumn, id));
|
||||
}
|
||||
Reference in New Issue
Block a user