@spfn/core 0.2.0-beta.9 → 0.3.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +693 -279
- package/dist/app-config/index.d.ts +96 -0
- package/dist/app-config/index.js +58 -0
- package/dist/app-config/index.js.map +1 -0
- package/dist/authz/index.d.ts +34 -0
- package/dist/authz/index.js +430 -0
- package/dist/authz/index.js.map +1 -0
- package/dist/boss-BiDCbbAQ.d.ts +337 -0
- package/dist/cache/index.js +42 -30
- package/dist/cache/index.js.map +1 -1
- package/dist/codegen/index.d.ts +121 -13
- package/dist/codegen/index.js +212 -15
- package/dist/codegen/index.js.map +1 -1
- package/dist/config/index.d.ts +576 -30
- package/dist/config/index.js +136 -17
- package/dist/config/index.js.map +1 -1
- package/dist/contract/index.d.ts +221 -0
- package/dist/contract/index.js +558 -0
- package/dist/contract/index.js.map +1 -0
- package/dist/db/index.d.ts +704 -94
- package/dist/db/index.js +1105 -260
- package/dist/db/index.js.map +1 -1
- package/dist/define-middleware-CVKgqo8S.d.ts +167 -0
- package/dist/env/index.d.ts +26 -2
- package/dist/env/index.js +15 -5
- package/dist/env/index.js.map +1 -1
- package/dist/env/loader.d.ts +26 -19
- package/dist/env/loader.js +55 -25
- package/dist/env/loader.js.map +1 -1
- package/dist/errors/index.d.ts +10 -0
- package/dist/errors/index.js +40 -7
- package/dist/errors/index.js.map +1 -1
- package/dist/event/index.d.ts +33 -3
- package/dist/event/index.js +24 -3
- package/dist/event/index.js.map +1 -1
- package/dist/event/sse/client.d.ts +55 -3
- package/dist/event/sse/client.js +164 -45
- package/dist/event/sse/client.js.map +1 -1
- package/dist/event/sse/index.d.ts +12 -5
- package/dist/event/sse/index.js +280 -32
- package/dist/event/sse/index.js.map +1 -1
- package/dist/event/ws/client.d.ts +59 -0
- package/dist/event/ws/client.js +273 -0
- package/dist/event/ws/client.js.map +1 -0
- package/dist/event/ws/index.d.ts +94 -0
- package/dist/event/ws/index.js +272 -0
- package/dist/event/ws/index.js.map +1 -0
- package/dist/job/index.d.ts +48 -3
- package/dist/job/index.js +265 -74
- package/dist/job/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -0
- package/dist/logger/index.js +14 -12
- package/dist/logger/index.js.map +1 -1
- package/dist/middleware/index.d.ts +352 -10
- package/dist/middleware/index.js +1079 -13
- package/dist/middleware/index.js.map +1 -1
- package/dist/nextjs/index.d.ts +39 -3
- package/dist/nextjs/index.js +82 -29
- package/dist/nextjs/index.js.map +1 -1
- package/dist/nextjs/server.d.ts +69 -52
- package/dist/nextjs/server.js +140 -60
- package/dist/nextjs/server.js.map +1 -1
- package/dist/ops/index.d.ts +208 -0
- package/dist/ops/index.js +800 -0
- package/dist/ops/index.js.map +1 -0
- package/dist/route/index.d.ts +10 -694
- package/dist/route/index.js +112 -23
- package/dist/route/index.js.map +1 -1
- package/dist/route-builder-2ani2jEI.d.ts +553 -0
- package/dist/router-DJdpwuB6.d.ts +127 -0
- package/dist/security/index.d.ts +83 -0
- package/dist/security/index.js +173 -0
- package/dist/security/index.js.map +1 -0
- package/dist/server/index.d.ts +619 -31
- package/dist/server/index.js +2583 -360
- package/dist/server/index.js.map +1 -1
- package/dist/token-manager-BT5EnUAR.d.ts +278 -0
- package/dist/types-2AbaW4Ie.d.ts +205 -0
- package/dist/{types-BOPTApC2.d.ts → types-9oszaJqp.d.ts} +7 -2
- package/dist/types-ClQVomgV.d.ts +115 -0
- package/dist/types-ZQODsBft.d.ts +282 -0
- package/docs/file-upload.md +195 -333
- package/package.json +250 -208
- package/src/cache/README.md +330 -0
- package/src/codegen/README.md +516 -0
- package/src/config/README.md +326 -0
- package/src/contract/README.md +326 -0
- package/src/db/README.md +589 -0
- package/src/db/manager/README.md +500 -0
- package/src/db/schema/README.md +354 -0
- package/src/db/transaction/README.md +822 -0
- package/src/env/README.md +651 -0
- package/src/errors/README.md +429 -0
- package/src/event/README.md +741 -0
- package/src/job/README.md +613 -0
- package/src/logger/README.md +321 -0
- package/src/middleware/README.md +634 -0
- package/src/nextjs/README.md +608 -0
- package/src/route/README.md +738 -0
- package/src/security/README.md +100 -0
- package/src/server/README.md +704 -0
- package/dist/boss-DI1r4kTS.d.ts +0 -244
- package/dist/router-Di7ENoah.d.ts +0 -151
- package/dist/types-B-e_f2dQ.d.ts +0 -121
- package/docs/cache.md +0 -133
- package/docs/codegen.md +0 -74
- package/docs/database.md +0 -346
- package/docs/entity.md +0 -539
- package/docs/env.md +0 -477
- package/docs/errors.md +0 -319
- package/docs/event.md +0 -116
- package/docs/job.md +0 -131
- package/docs/logger.md +0 -108
- package/docs/middleware.md +0 -337
- package/docs/nextjs.md +0 -241
- package/docs/repository.md +0 -496
- package/docs/route.md +0 -497
- package/docs/server.md +0 -307
package/dist/db/index.d.ts
CHANGED
|
@@ -1,12 +1,48 @@
|
|
|
1
1
|
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
2
2
|
import postgres, { Sql } from 'postgres';
|
|
3
|
-
import * as drizzle_orm from 'drizzle-orm';
|
|
4
|
-
import { SQL } from 'drizzle-orm';
|
|
5
3
|
import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
|
|
6
|
-
import { PgColumn, PgTable } from 'drizzle-orm/pg-core';
|
|
4
|
+
import { PgAsyncDatabase, PgAsyncTransaction, PgColumn, PgTable } from 'drizzle-orm/pg-core';
|
|
5
|
+
import * as drizzle_orm from 'drizzle-orm';
|
|
6
|
+
import { SQL, InferSelectModel, InferInsertModel, AnyRelations, EmptyRelations } from 'drizzle-orm';
|
|
7
7
|
import * as hono_types from 'hono/types';
|
|
8
8
|
import { DatabaseError } from '@spfn/core/errors';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Database Manager Types
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* DB connection type
|
|
16
|
+
*/
|
|
17
|
+
type DbConnectionType = 'read' | 'write';
|
|
18
|
+
/**
|
|
19
|
+
* Common base for PostgreSQL Drizzle drivers.
|
|
20
|
+
*
|
|
21
|
+
* Both the built-in postgres.js database and externally supplied drivers such
|
|
22
|
+
* as PGlite extend this class.
|
|
23
|
+
*/
|
|
24
|
+
type DrizzleDatabase = PgAsyncDatabase<any, any>;
|
|
25
|
+
/** Default database type used by the environment-backed postgres.js path. */
|
|
26
|
+
type DefaultDatabase = PostgresJsDatabase;
|
|
27
|
+
/** Resolve the transaction type belonging to a PostgreSQL Drizzle database. */
|
|
28
|
+
type DatabaseTransaction<TDatabase extends DrizzleDatabase> = TDatabase extends PgAsyncDatabase<infer TQueryResult, infer TRelations> ? PgAsyncTransaction<TQueryResult, TRelations> : never;
|
|
29
|
+
/**
|
|
30
|
+
* An externally owned PostgreSQL Drizzle database.
|
|
31
|
+
*
|
|
32
|
+
* The provider owns connection creation. SPFN calls `close` at most once when
|
|
33
|
+
* `closeDatabase()` or server shutdown releases the registered provider.
|
|
34
|
+
*/
|
|
35
|
+
interface DatabaseProvider<TDatabase extends DrizzleDatabase = DrizzleDatabase> {
|
|
36
|
+
/** Primary database for writes (and reads when no replica is supplied). */
|
|
37
|
+
write: TDatabase;
|
|
38
|
+
/** Optional read replica. Falls back to `write`. */
|
|
39
|
+
read?: TDatabase;
|
|
40
|
+
/** Driver identifier used for diagnostics, for example `pglite`. */
|
|
41
|
+
kind: string;
|
|
42
|
+
/** Release provider-owned resources. */
|
|
43
|
+
close?: () => void | Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
10
46
|
/**
|
|
11
47
|
* Database Configuration
|
|
12
48
|
*
|
|
@@ -23,11 +59,11 @@ import { DatabaseError } from '@spfn/core/errors';
|
|
|
23
59
|
* - src/server/core/db/index.ts (main exports)
|
|
24
60
|
*/
|
|
25
61
|
|
|
26
|
-
interface DatabaseClients {
|
|
62
|
+
interface DatabaseClients<TDatabase extends DrizzleDatabase = PostgresJsDatabase> {
|
|
27
63
|
/** Primary database for writes (or both read/write if no replica) */
|
|
28
|
-
write?:
|
|
64
|
+
write?: TDatabase;
|
|
29
65
|
/** Replica database for reads (optional, falls back to write) */
|
|
30
|
-
read?:
|
|
66
|
+
read?: TDatabase;
|
|
31
67
|
/** Raw postgres client for write operations (for cleanup) */
|
|
32
68
|
writeClient?: Sql;
|
|
33
69
|
/** Raw postgres client for read operations (for cleanup) */
|
|
@@ -71,6 +107,17 @@ interface DatabaseOptions {
|
|
|
71
107
|
*/
|
|
72
108
|
monitoring?: Partial<MonitoringConfig>;
|
|
73
109
|
}
|
|
110
|
+
/** Database initialization options, including an optional external provider. */
|
|
111
|
+
interface DatabaseInitOptions<TDatabase extends DrizzleDatabase = PostgresJsDatabase> extends DatabaseOptions {
|
|
112
|
+
/**
|
|
113
|
+
* Externally owned PostgreSQL Drizzle provider.
|
|
114
|
+
*
|
|
115
|
+
* When set, environment-based postgres.js initialization, health checks,
|
|
116
|
+
* and automatic reconnect are skipped. The provider's `close` callback is
|
|
117
|
+
* used during shutdown.
|
|
118
|
+
*/
|
|
119
|
+
provider?: DatabaseProvider<TDatabase>;
|
|
120
|
+
}
|
|
74
121
|
/**
|
|
75
122
|
* Connection pool configuration
|
|
76
123
|
*
|
|
@@ -81,6 +128,21 @@ interface PoolConfig {
|
|
|
81
128
|
max: number;
|
|
82
129
|
/** Idle connection timeout in seconds */
|
|
83
130
|
idleTimeout: number;
|
|
131
|
+
/**
|
|
132
|
+
* Maximum connections for the read-replica pool. Defaults to `max`. Set
|
|
133
|
+
* separately (DB_POOL_READ_MAX) so a master-replica app can size the two
|
|
134
|
+
* pools independently and keep `write.max + read.max` under the server's
|
|
135
|
+
* `max_connections` (otherwise each process opens up to 2 × max).
|
|
136
|
+
*/
|
|
137
|
+
readMax?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Use server-side prepared statements (postgres-js `prepare`). When
|
|
140
|
+
* `undefined`, the connection layer auto-detects: it is disabled for
|
|
141
|
+
* transaction-mode poolers (PgBouncer/Supavisor, e.g. Supabase :6543),
|
|
142
|
+
* where cached statements break as the pooler rotates backends, and
|
|
143
|
+
* enabled otherwise. Set explicitly (or via `SPFN_DB_PREPARE`) to override.
|
|
144
|
+
*/
|
|
145
|
+
prepare?: boolean;
|
|
84
146
|
}
|
|
85
147
|
/**
|
|
86
148
|
* Retry configuration for exponential backoff algorithm
|
|
@@ -134,15 +196,6 @@ interface RetryConfig {
|
|
|
134
196
|
*/
|
|
135
197
|
declare function createDatabaseFromEnv(options?: DatabaseOptions): Promise<DatabaseClients>;
|
|
136
198
|
|
|
137
|
-
/**
|
|
138
|
-
* Database Manager Types
|
|
139
|
-
*/
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* DB connection type
|
|
143
|
-
*/
|
|
144
|
-
type DbConnectionType = 'read' | 'write';
|
|
145
|
-
|
|
146
199
|
/**
|
|
147
200
|
* Global Database instance manager
|
|
148
201
|
* Provides singleton access to database across all modules
|
|
@@ -169,7 +222,7 @@ type DbConnectionType = 'read' | 'write';
|
|
|
169
222
|
* const posts = await dbRead.select().from(postsTable);
|
|
170
223
|
* ```
|
|
171
224
|
*/
|
|
172
|
-
declare function getDatabase(type?: DbConnectionType):
|
|
225
|
+
declare function getDatabase<TDatabase extends DrizzleDatabase = DefaultDatabase>(type?: DbConnectionType): TDatabase;
|
|
173
226
|
/**
|
|
174
227
|
* Set global database instances (for testing or manual configuration)
|
|
175
228
|
*
|
|
@@ -193,15 +246,23 @@ declare function getDatabase(type?: DbConnectionType): PostgresJsDatabase<Record
|
|
|
193
246
|
* // Set custom database instances (testing)
|
|
194
247
|
* const writeClient = postgres('postgresql://primary:5432/mydb');
|
|
195
248
|
* const readClient = postgres('postgresql://replica:5432/mydb');
|
|
196
|
-
* setDatabase(drizzle(writeClient), drizzle(readClient));
|
|
249
|
+
* setDatabase(drizzle({ client: writeClient }), drizzle({ client: readClient }));
|
|
197
250
|
*
|
|
198
251
|
* // Clear instances (not recommended - use closeDatabase() instead)
|
|
199
252
|
* setDatabase(undefined, undefined);
|
|
200
253
|
* ```
|
|
201
254
|
*/
|
|
202
|
-
declare function setDatabase(write:
|
|
255
|
+
declare function setDatabase<TDatabase extends DrizzleDatabase = DefaultDatabase>(write: TDatabase | undefined, read?: TDatabase | undefined): void;
|
|
203
256
|
/**
|
|
204
|
-
*
|
|
257
|
+
* Register an externally owned PostgreSQL Drizzle provider.
|
|
258
|
+
*
|
|
259
|
+
* This is the synchronous/manual counterpart to `initDatabase({ provider })`.
|
|
260
|
+
* It performs no connection test. Use `closeDatabase()` to invoke the
|
|
261
|
+
* provider's close callback and clear the global instances.
|
|
262
|
+
*/
|
|
263
|
+
declare function setDatabaseProvider<TDatabase extends DrizzleDatabase>(provider: DatabaseProvider<TDatabase>): DatabaseClients<TDatabase>;
|
|
264
|
+
/**
|
|
265
|
+
* Initialize a database provider or create postgres.js clients from environment variables
|
|
205
266
|
* Automatically called by server startup
|
|
206
267
|
*
|
|
207
268
|
* Supported environment variables:
|
|
@@ -246,14 +307,11 @@ declare function setDatabase(write: PostgresJsDatabase<Record<string, unknown>>
|
|
|
246
307
|
* });
|
|
247
308
|
* ```
|
|
248
309
|
*/
|
|
249
|
-
declare function initDatabase(options?:
|
|
250
|
-
write?: PostgresJsDatabase<Record<string, unknown>>;
|
|
251
|
-
read?: PostgresJsDatabase<Record<string, unknown>>;
|
|
252
|
-
}>;
|
|
310
|
+
declare function initDatabase<TDatabase extends DrizzleDatabase = DefaultDatabase>(options?: DatabaseInitOptions<TDatabase>): Promise<DatabaseClients<TDatabase>>;
|
|
253
311
|
/**
|
|
254
|
-
* Close
|
|
312
|
+
* Close the active database provider or postgres.js connections and clean up
|
|
255
313
|
*
|
|
256
|
-
*
|
|
314
|
+
* Invokes an external provider's close callback, or closes postgres.js pools with timeout.
|
|
257
315
|
* Should be called during graceful shutdown or after tests.
|
|
258
316
|
*
|
|
259
317
|
* @example
|
|
@@ -273,6 +331,36 @@ declare function initDatabase(options?: DatabaseOptions): Promise<{
|
|
|
273
331
|
* ```
|
|
274
332
|
*/
|
|
275
333
|
declare function closeDatabase(): Promise<void>;
|
|
334
|
+
/**
|
|
335
|
+
* Force an immediate database pool rebuild
|
|
336
|
+
*
|
|
337
|
+
* Destroys the current postgres.js pool(s) and rebuilds them with the same
|
|
338
|
+
* configuration passed to the original `initDatabase()` call (or whatever
|
|
339
|
+
* was detected from environment variables). Uses the same atomic-swap
|
|
340
|
+
* strategy as the periodic health check: new connections are created and
|
|
341
|
+
* tested BEFORE the old ones are torn down, so `getDatabase()` callers never
|
|
342
|
+
* observe a missing instance.
|
|
343
|
+
*
|
|
344
|
+
* Use this when application code detects that the pool is stuck and does not
|
|
345
|
+
* want to wait for the next periodic health check tick. Concurrent calls are
|
|
346
|
+
* coalesced — if a reconnect is already in progress, this resolves to `false`
|
|
347
|
+
* without starting a second one.
|
|
348
|
+
*
|
|
349
|
+
* @param reason - Short label describing why the rebuild was requested (for logs)
|
|
350
|
+
* @returns `true` if a reconnection ran, `false` if one was already in-flight.
|
|
351
|
+
* Resolves after the rebuild completes (success or max retries exhausted).
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* import { forceReconnectDatabase } from '@spfn/core/db';
|
|
356
|
+
*
|
|
357
|
+
* app.post('/admin/db/reconnect', async (c) => {
|
|
358
|
+
* const ran = await forceReconnectDatabase('admin_request');
|
|
359
|
+
* return c.json({ reconnected: ran });
|
|
360
|
+
* });
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
declare function forceReconnectDatabase(reason?: string): Promise<boolean>;
|
|
276
364
|
/**
|
|
277
365
|
* Get database connection info (for debugging)
|
|
278
366
|
*
|
|
@@ -306,8 +394,42 @@ declare function getDatabaseInfo(): {
|
|
|
306
394
|
hasWrite: boolean;
|
|
307
395
|
hasRead: boolean;
|
|
308
396
|
isReplica: boolean;
|
|
397
|
+
providerKind?: string;
|
|
309
398
|
};
|
|
310
399
|
|
|
400
|
+
/**
|
|
401
|
+
* Determine whether an error looks like a pool/connection failure
|
|
402
|
+
*
|
|
403
|
+
* Returns true when any layer in the error chain exposes a connection-level
|
|
404
|
+
* code (postgres.js driver code, Node network errno, PG SQLSTATE class 08 etc.)
|
|
405
|
+
* or is an instance of our own ConnectionError wrapper.
|
|
406
|
+
*
|
|
407
|
+
* Returns false for query errors (syntax, constraint violations, etc.) — those
|
|
408
|
+
* should NOT trigger a pool rebuild.
|
|
409
|
+
*/
|
|
410
|
+
declare function isConnectionLevelError(error: unknown): boolean;
|
|
411
|
+
/**
|
|
412
|
+
* Reset the internal error counter
|
|
413
|
+
*
|
|
414
|
+
* Exposed for tests that need a clean slate between cases. Does not clear
|
|
415
|
+
* the WeakSet (which is GC-backed and self-cleans with error lifetimes).
|
|
416
|
+
*/
|
|
417
|
+
declare function resetConnectionErrorCounter(): void;
|
|
418
|
+
/**
|
|
419
|
+
* Report a database error to the reconnect trigger
|
|
420
|
+
*
|
|
421
|
+
* Call this from any site that catches a query error before rethrowing.
|
|
422
|
+
* It is a no-op for non-connection-level errors. When the threshold is
|
|
423
|
+
* crossed it calls triggerForceReconnect() in the background — callers
|
|
424
|
+
* should NOT await it.
|
|
425
|
+
*
|
|
426
|
+
* Safe to call from any context: catches its own errors so it cannot
|
|
427
|
+
* disrupt the calling catch block. Deduplicates across error-chain
|
|
428
|
+
* re-wrapping so one failure counts exactly once regardless of how many
|
|
429
|
+
* catch layers it passes through.
|
|
430
|
+
*/
|
|
431
|
+
declare function reportDatabaseError(error: unknown): void;
|
|
432
|
+
|
|
311
433
|
/**
|
|
312
434
|
* Create database connection with exponential backoff retry strategy
|
|
313
435
|
*
|
|
@@ -362,7 +484,7 @@ declare function checkConnection(client: Sql): Promise<boolean>;
|
|
|
362
484
|
interface DrizzleConfigOptions {
|
|
363
485
|
/** Database connection URL (defaults to process.env.DATABASE_URL) */
|
|
364
486
|
databaseUrl?: string;
|
|
365
|
-
/** Schema
|
|
487
|
+
/** Schema entry file(s), directories or glob pattern(s). Default: './src/server/entities/\*\*\/*.ts', or the registry `DRIZZLE_SCHEMA_PATH` (./src/server/entities/config.ts) when that scan finds no entity file; `schemaRegistry` reports the registry when both exist */
|
|
366
488
|
schema?: string | string[];
|
|
367
489
|
/** Migration output directory (defaults to './src/server/drizzle') */
|
|
368
490
|
out?: string;
|
|
@@ -378,8 +500,8 @@ interface DrizzleConfigOptions {
|
|
|
378
500
|
expandGlobs?: boolean;
|
|
379
501
|
/** PostgreSQL schema filter for push/introspect commands */
|
|
380
502
|
schemaFilter?: string[];
|
|
381
|
-
/**
|
|
382
|
-
|
|
503
|
+
/** Migration prefix strategy (default: 'timestamp') */
|
|
504
|
+
migrationPrefix?: 'index' | 'timestamp' | 'unix' | 'none';
|
|
383
505
|
}
|
|
384
506
|
/**
|
|
385
507
|
* Detect database dialect from connection URL
|
|
@@ -406,26 +528,55 @@ declare function detectDialect(url: string): 'postgresql' | 'mysql' | 'sqlite';
|
|
|
406
528
|
*/
|
|
407
529
|
declare function getDrizzleConfig(options?: DrizzleConfigOptions): {
|
|
408
530
|
schema: string | string[];
|
|
531
|
+
schemaSource: string;
|
|
532
|
+
schemaRegistry: string | undefined;
|
|
409
533
|
out: string;
|
|
410
534
|
dialect: "postgresql" | "mysql" | "sqlite";
|
|
411
535
|
dbCredentials: {
|
|
412
536
|
url: string;
|
|
413
537
|
};
|
|
538
|
+
migrations: {
|
|
539
|
+
prefix: "timestamp" | "none" | "index" | "unix";
|
|
540
|
+
};
|
|
414
541
|
schemaFilter?: undefined;
|
|
415
542
|
} | {
|
|
416
543
|
schema: string | string[];
|
|
544
|
+
schemaSource: string;
|
|
545
|
+
schemaRegistry: string | undefined;
|
|
417
546
|
out: string;
|
|
418
547
|
dialect: "postgresql" | "mysql" | "sqlite";
|
|
419
548
|
dbCredentials: {
|
|
420
549
|
url: string;
|
|
421
550
|
};
|
|
422
551
|
schemaFilter: string[] | undefined;
|
|
552
|
+
migrations: {
|
|
553
|
+
prefix: "timestamp" | "none" | "index" | "unix";
|
|
554
|
+
};
|
|
423
555
|
};
|
|
424
556
|
/**
|
|
425
|
-
*
|
|
557
|
+
* The schema fields a rendered drizzle.config.ts needs
|
|
558
|
+
*/
|
|
559
|
+
interface RenderableDrizzleConfig {
|
|
560
|
+
schema: string | string[];
|
|
561
|
+
out: string;
|
|
562
|
+
dialect: string;
|
|
563
|
+
dbCredentials: Record<string, unknown>;
|
|
564
|
+
schemaFilter?: string[];
|
|
565
|
+
migrations?: Record<string, unknown>;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Render an already-resolved config as drizzle.config.ts source, schema
|
|
569
|
+
* paths made absolute for Drizzle Studio
|
|
426
570
|
*
|
|
427
|
-
* @param
|
|
428
|
-
* @
|
|
571
|
+
* @param config - Result of getDrizzleConfig, possibly with the schema replaced
|
|
572
|
+
* @param cwd - Base for relative schema paths (default: process.cwd())
|
|
573
|
+
*/
|
|
574
|
+
declare function renderDrizzleConfig(config: RenderableDrizzleConfig, cwd?: string): string;
|
|
575
|
+
/**
|
|
576
|
+
* Generate drizzle.config.ts source from options: resolve the config, then render it
|
|
577
|
+
*
|
|
578
|
+
* @param options - Configuration options (see getDrizzleConfig)
|
|
579
|
+
* @returns drizzle.config.ts source
|
|
429
580
|
*/
|
|
430
581
|
declare function generateDrizzleConfigFile(options?: DrizzleConfigOptions): string;
|
|
431
582
|
|
|
@@ -442,12 +593,23 @@ declare function generateDrizzleConfigFile(options?: DrizzleConfigOptions): stri
|
|
|
442
593
|
* });
|
|
443
594
|
* ```
|
|
444
595
|
*/
|
|
445
|
-
declare function id():
|
|
596
|
+
declare function id(): drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.PgBigSerial53Builder>;
|
|
446
597
|
/**
|
|
447
598
|
* Standard timestamp fields (createdAt, updatedAt)
|
|
448
599
|
*
|
|
449
|
-
* Both fields are timezone-aware
|
|
450
|
-
*
|
|
600
|
+
* Both fields are timezone-aware and come from the database clock, never from the
|
|
601
|
+
* application process. On insert both take `now()` through their column default, so a
|
|
602
|
+
* new row's two timestamps are equal. On update Drizzle sets `updated_at = now()` for
|
|
603
|
+
* you — do not pass `new Date()` yourself.
|
|
604
|
+
*
|
|
605
|
+
* Stamping `updated_at` from the application would read a second clock: the app host
|
|
606
|
+
* and the database host are the same machine in development and different machines in
|
|
607
|
+
* production, so a row could record an update earlier than its own creation, and
|
|
608
|
+
* ordering rows by `updated_at` would order by whichever host's clock ran ahead.
|
|
609
|
+
*
|
|
610
|
+
* `now()` is the transaction's start time, matching what `.defaultNow()` writes. It is
|
|
611
|
+
* not a commit-order sequence — anything that needs a true sequence needs a sequence
|
|
612
|
+
* column, not a timestamp.
|
|
451
613
|
*
|
|
452
614
|
* @returns Object with createdAt and updatedAt columns
|
|
453
615
|
*
|
|
@@ -459,23 +621,20 @@ declare function id(): drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_orm_
|
|
|
459
621
|
* ...timestamps(),
|
|
460
622
|
* });
|
|
461
623
|
*
|
|
462
|
-
* //
|
|
624
|
+
* // updated_at is stamped by the database — it is not named here
|
|
463
625
|
* await db.update(users)
|
|
464
|
-
* .set({
|
|
465
|
-
* email: 'new@example.com',
|
|
466
|
-
* updatedAt: new Date()
|
|
467
|
-
* })
|
|
626
|
+
* .set({ email: 'new@example.com' })
|
|
468
627
|
* .where(eq(users.id, userId));
|
|
469
628
|
* ```
|
|
470
629
|
*/
|
|
471
630
|
declare function timestamps(): {
|
|
472
|
-
createdAt:
|
|
473
|
-
updatedAt:
|
|
631
|
+
createdAt: drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>;
|
|
632
|
+
updatedAt: drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgTimestampBuilder>>>;
|
|
474
633
|
};
|
|
475
634
|
/**
|
|
476
635
|
* Foreign key reference to another table
|
|
477
636
|
*
|
|
478
|
-
* Creates a
|
|
637
|
+
* Creates a bigint column with cascade delete.
|
|
479
638
|
* Type-safe: ensures the reference points to a valid PostgreSQL column.
|
|
480
639
|
*
|
|
481
640
|
* @param name - Column name (e.g., 'author' creates 'author_id')
|
|
@@ -495,7 +654,7 @@ declare function timestamps(): {
|
|
|
495
654
|
*/
|
|
496
655
|
declare function foreignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
|
|
497
656
|
onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
|
|
498
|
-
}):
|
|
657
|
+
}): drizzle_orm_pg_core.SetNotNull<drizzle_orm_pg_core.PgBigInt53Builder>;
|
|
499
658
|
/**
|
|
500
659
|
* Optional foreign key reference (nullable)
|
|
501
660
|
*
|
|
@@ -515,7 +674,7 @@ declare function foreignKey<T extends PgColumn>(name: string, reference: () => T
|
|
|
515
674
|
*/
|
|
516
675
|
declare function optionalForeignKey<T extends PgColumn>(name: string, reference: () => T, options?: {
|
|
517
676
|
onDelete?: 'cascade' | 'set null' | 'restrict' | 'no action';
|
|
518
|
-
}): drizzle_orm_pg_core.
|
|
677
|
+
}): drizzle_orm_pg_core.PgBigInt53Builder;
|
|
519
678
|
/**
|
|
520
679
|
* UUID primary key
|
|
521
680
|
*
|
|
@@ -533,7 +692,7 @@ declare function optionalForeignKey<T extends PgColumn>(name: string, reference:
|
|
|
533
692
|
* });
|
|
534
693
|
* ```
|
|
535
694
|
*/
|
|
536
|
-
declare function uuid():
|
|
695
|
+
declare function uuid(): drizzle_orm_pg_core.SetIsPrimaryKey<drizzle_orm_pg_core.SetHasDefault<drizzle_orm_pg_core.PgUUIDBuilder>>;
|
|
537
696
|
/**
|
|
538
697
|
* Audit fields for tracking record creators and updaters
|
|
539
698
|
*
|
|
@@ -559,8 +718,8 @@ declare function uuid(): drizzle_orm.IsPrimaryKey<drizzle_orm.NotNull<drizzle_or
|
|
|
559
718
|
* ```
|
|
560
719
|
*/
|
|
561
720
|
declare function auditFields(): {
|
|
562
|
-
createdBy: drizzle_orm_pg_core.
|
|
563
|
-
updatedBy: drizzle_orm_pg_core.
|
|
721
|
+
createdBy: drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>;
|
|
722
|
+
updatedBy: drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>;
|
|
564
723
|
};
|
|
565
724
|
/**
|
|
566
725
|
* Publishing fields for content management
|
|
@@ -591,8 +750,8 @@ declare function auditFields(): {
|
|
|
591
750
|
* ```
|
|
592
751
|
*/
|
|
593
752
|
declare function publishingFields(): {
|
|
594
|
-
publishedAt: drizzle_orm_pg_core.
|
|
595
|
-
publishedBy: drizzle_orm_pg_core.
|
|
753
|
+
publishedAt: drizzle_orm_pg_core.PgTimestampBuilder;
|
|
754
|
+
publishedBy: drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>;
|
|
596
755
|
};
|
|
597
756
|
/**
|
|
598
757
|
* Custom verification timestamp field
|
|
@@ -621,7 +780,7 @@ declare function publishingFields(): {
|
|
|
621
780
|
* ```
|
|
622
781
|
*/
|
|
623
782
|
declare function verificationTimestamp(fieldName: string): {
|
|
624
|
-
[x: string]: drizzle_orm_pg_core.
|
|
783
|
+
[x: string]: drizzle_orm_pg_core.PgTimestampBuilder;
|
|
625
784
|
};
|
|
626
785
|
/**
|
|
627
786
|
* Soft delete fields
|
|
@@ -655,8 +814,8 @@ declare function verificationTimestamp(fieldName: string): {
|
|
|
655
814
|
* ```
|
|
656
815
|
*/
|
|
657
816
|
declare function softDelete(): {
|
|
658
|
-
deletedAt: drizzle_orm_pg_core.
|
|
659
|
-
deletedBy: drizzle_orm_pg_core.
|
|
817
|
+
deletedAt: drizzle_orm_pg_core.PgTimestampBuilder;
|
|
818
|
+
deletedBy: drizzle_orm_pg_core.PgTextBuilder<[string, ...string[]]>;
|
|
660
819
|
};
|
|
661
820
|
/**
|
|
662
821
|
* UTC timestamp field
|
|
@@ -688,7 +847,7 @@ declare function softDelete(): {
|
|
|
688
847
|
* });
|
|
689
848
|
* ```
|
|
690
849
|
*/
|
|
691
|
-
declare function utcTimestamp(fieldName: string, mode?: 'date' | 'string'): drizzle_orm_pg_core.
|
|
850
|
+
declare function utcTimestamp(fieldName: string, mode?: 'date' | 'string'): drizzle_orm_pg_core.PgTimestampBuilder;
|
|
692
851
|
/**
|
|
693
852
|
* Type-safe enum text field
|
|
694
853
|
*
|
|
@@ -722,7 +881,7 @@ declare function utcTimestamp(fieldName: string, mode?: 'date' | 'string'): driz
|
|
|
722
881
|
* });
|
|
723
882
|
* ```
|
|
724
883
|
*/
|
|
725
|
-
declare function enumText<T extends readonly [string, ...string[]]>(fieldName: string, values: T): drizzle_orm_pg_core.
|
|
884
|
+
declare function enumText<T extends readonly [string, ...string[]]>(fieldName: string, values: T): drizzle_orm_pg_core.PgTextBuilder<drizzle_orm.Writable<T & [string, ...string[]]>>;
|
|
726
885
|
/**
|
|
727
886
|
* Type-safe JSONB field
|
|
728
887
|
*
|
|
@@ -765,7 +924,7 @@ declare function enumText<T extends readonly [string, ...string[]]>(fieldName: s
|
|
|
765
924
|
* tags: typedJsonb<string[]>('tags').notNull(),
|
|
766
925
|
* ```
|
|
767
926
|
*/
|
|
768
|
-
declare function typedJsonb<T>(fieldName: string):
|
|
927
|
+
declare function typedJsonb<T>(fieldName: string): drizzle_orm_pg_core.Set$Type<drizzle_orm_pg_core.PgJsonbBuilder, T>;
|
|
769
928
|
|
|
770
929
|
/**
|
|
771
930
|
* Database Schema Helper
|
|
@@ -828,6 +987,137 @@ declare function getSchemaInfo(packageName: string): {
|
|
|
828
987
|
scope: string | null;
|
|
829
988
|
};
|
|
830
989
|
|
|
990
|
+
/**
|
|
991
|
+
* Function Package Migration Discovery
|
|
992
|
+
*
|
|
993
|
+
* Finds the migrations shipped by installed SPFN function packages (e.g.
|
|
994
|
+
* `@spfn/auth`) and reads their entries. Both drizzle-kit layouts are
|
|
995
|
+
* supported — `NNNN_name.sql` + `meta/_journal.json` (≤0.31) and
|
|
996
|
+
* `<YYYYMMDDHHMMSS>_name/migration.sql` (1.0) — so an installed package keeps
|
|
997
|
+
* working regardless of which drizzle-kit generated it.
|
|
998
|
+
*
|
|
999
|
+
* This module only reads the filesystem. Applying migrations is the CLI's job
|
|
1000
|
+
* (`spfn db migrate`); the server and `spfn db status` share the reading half.
|
|
1001
|
+
*/
|
|
1002
|
+
type FunctionMigrationInfo = {
|
|
1003
|
+
packageName: string;
|
|
1004
|
+
migrationsDir: string;
|
|
1005
|
+
packagePath: string;
|
|
1006
|
+
};
|
|
1007
|
+
type FunctionMigrationEntry = {
|
|
1008
|
+
name: string;
|
|
1009
|
+
statements: string[];
|
|
1010
|
+
hash: string;
|
|
1011
|
+
millis: number;
|
|
1012
|
+
};
|
|
1013
|
+
/**
|
|
1014
|
+
* Per-package migrations table name — must match the CLI's migration runner.
|
|
1015
|
+
*/
|
|
1016
|
+
declare function functionMigrationsTable(packageName: string): string;
|
|
1017
|
+
/**
|
|
1018
|
+
* Discover all installed SPFN function packages that ship migrations.
|
|
1019
|
+
*
|
|
1020
|
+
* A package opts in with a `spfn.migrations.dir` field in its package.json.
|
|
1021
|
+
* Returns an empty list when the project has no `node_modules/@spfn` at all,
|
|
1022
|
+
* which is also the "nothing to check" answer for apps without function packages.
|
|
1023
|
+
*/
|
|
1024
|
+
declare function discoverFunctionMigrations(cwd?: string): FunctionMigrationInfo[];
|
|
1025
|
+
/**
|
|
1026
|
+
* Read a package's migration entries, auto-detecting the folder layout.
|
|
1027
|
+
*
|
|
1028
|
+
* A `meta/_journal.json` marks the drizzle-kit ≤0.31 layout; without it the
|
|
1029
|
+
* directory is read as the drizzle-kit 1.0 layout.
|
|
1030
|
+
*/
|
|
1031
|
+
declare function readMigrationEntries(migrationsDir: string, packageName: string): FunctionMigrationEntry[];
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* Migration Status Inspection
|
|
1035
|
+
*
|
|
1036
|
+
* Compares what each migration folder ships (function packages, plus the
|
|
1037
|
+
* project's own `src/server/drizzle`) against what the database records as
|
|
1038
|
+
* applied. `spfn db status`, the server's boot gate and the detailed health
|
|
1039
|
+
* endpoint all read this one implementation.
|
|
1040
|
+
*/
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Project migrations use drizzle's default table, in the `drizzle` schema.
|
|
1044
|
+
*/
|
|
1045
|
+
declare const PROJECT_MIGRATIONS_TABLE = "__drizzle_migrations";
|
|
1046
|
+
/**
|
|
1047
|
+
* The name `spfn db status` and health use for the project's own migrations.
|
|
1048
|
+
*/
|
|
1049
|
+
declare const PROJECT_TARGET_NAME = "project (src/server/drizzle)";
|
|
1050
|
+
type MigrationTargetStatus = {
|
|
1051
|
+
name: string;
|
|
1052
|
+
total: number;
|
|
1053
|
+
applied: number;
|
|
1054
|
+
pending: number;
|
|
1055
|
+
pendingTags: string[];
|
|
1056
|
+
};
|
|
1057
|
+
type MigrationStatus = {
|
|
1058
|
+
packages: MigrationTargetStatus[];
|
|
1059
|
+
project: MigrationTargetStatus | null;
|
|
1060
|
+
};
|
|
1061
|
+
/**
|
|
1062
|
+
* The minimum surface needed to read migration bookkeeping: anything that can
|
|
1063
|
+
* run a drizzle `sql` fragment. The server passes its own pool, the CLI passes
|
|
1064
|
+
* a short-lived connection.
|
|
1065
|
+
*/
|
|
1066
|
+
interface MigrationStatusDb {
|
|
1067
|
+
execute(query: SQL): Promise<unknown>;
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* An entry counts as applied when its name is recorded (drizzle-orm 1.0
|
|
1071
|
+
* projects) or its timestamp is not newer than the last applied record —
|
|
1072
|
+
* the rule the CLI's function-migration runner and drizzle-orm ≤0.45 share.
|
|
1073
|
+
*/
|
|
1074
|
+
declare function filterPendingEntries(entries: FunctionMigrationEntry[], lastAppliedMillis: number, appliedNames: Set<string>): FunctionMigrationEntry[];
|
|
1075
|
+
/**
|
|
1076
|
+
* Every target the status covers, packages first, in the order `spfn db status`
|
|
1077
|
+
* prints them.
|
|
1078
|
+
*/
|
|
1079
|
+
declare function migrationTargets(status: MigrationStatus): MigrationTargetStatus[];
|
|
1080
|
+
/**
|
|
1081
|
+
* The targets that still have migrations waiting.
|
|
1082
|
+
*/
|
|
1083
|
+
declare function pendingMigrationTargets(status: MigrationStatus): MigrationTargetStatus[];
|
|
1084
|
+
/**
|
|
1085
|
+
* Total number of migrations waiting across every target.
|
|
1086
|
+
*/
|
|
1087
|
+
declare function countPendingMigrations(status: MigrationStatus): number;
|
|
1088
|
+
/**
|
|
1089
|
+
* True when the project has nothing whose migration state could be inspected —
|
|
1090
|
+
* no function package ships migrations and there is no project migrations
|
|
1091
|
+
* folder. Callers use this to skip the database round-trip entirely.
|
|
1092
|
+
*/
|
|
1093
|
+
declare function hasMigrationTargets(cwd?: string): boolean;
|
|
1094
|
+
declare function projectMigrationsDir(cwd?: string): string;
|
|
1095
|
+
/**
|
|
1096
|
+
* Read applied/pending counts for every function package and for the project.
|
|
1097
|
+
*
|
|
1098
|
+
* The project's own migrations are included when `src/server/drizzle` exists.
|
|
1099
|
+
* A built server image usually does not ship that folder, so the project target
|
|
1100
|
+
* is simply absent there — never reported as drift.
|
|
1101
|
+
*/
|
|
1102
|
+
declare function collectMigrationStatus(db: MigrationStatusDb, cwd?: string): Promise<MigrationStatus>;
|
|
1103
|
+
|
|
1104
|
+
/**
|
|
1105
|
+
* One wording for pending migrations, shared by the server's boot gate and the
|
|
1106
|
+
* CLI's pre-flight check — an operator should read the same lines wherever the
|
|
1107
|
+
* refusal comes from.
|
|
1108
|
+
*/
|
|
1109
|
+
|
|
1110
|
+
declare const RUN_MIGRATIONS_HINT = "Run: pnpm spfn db migrate";
|
|
1111
|
+
/**
|
|
1112
|
+
* Plain (uncoloured) lines listing every target with pending migrations and the
|
|
1113
|
+
* name of each migration still waiting.
|
|
1114
|
+
*/
|
|
1115
|
+
declare function formatPendingMigrations(targets: MigrationTargetStatus[]): string[];
|
|
1116
|
+
/**
|
|
1117
|
+
* The single-sentence reason a boot was refused.
|
|
1118
|
+
*/
|
|
1119
|
+
declare function pendingMigrationsSummary(targets: MigrationTargetStatus[]): string;
|
|
1120
|
+
|
|
831
1121
|
/**
|
|
832
1122
|
* AsyncLocalStorage-based Transaction Context
|
|
833
1123
|
*
|
|
@@ -842,26 +1132,60 @@ declare function getSchemaInfo(packageName: string): {
|
|
|
842
1132
|
*/
|
|
843
1133
|
|
|
844
1134
|
/**
|
|
845
|
-
* Transaction database
|
|
846
|
-
|
|
1135
|
+
* Transaction type belonging to a PostgreSQL Drizzle database.
|
|
1136
|
+
*/
|
|
1137
|
+
type TransactionDB<TDatabase extends DrizzleDatabase = DefaultDatabase> = DatabaseTransaction<TDatabase>;
|
|
1138
|
+
/**
|
|
1139
|
+
* afterCommit callback type
|
|
1140
|
+
*/
|
|
1141
|
+
type AfterCommitCallback = () => void | Promise<void>;
|
|
1142
|
+
/**
|
|
1143
|
+
* beforeCommit callback type
|
|
1144
|
+
*/
|
|
1145
|
+
type BeforeCommitCallback = () => void | Promise<void>;
|
|
1146
|
+
/**
|
|
1147
|
+
* afterRollback callback type
|
|
1148
|
+
*/
|
|
1149
|
+
type AfterRollbackCallback = () => void | Promise<void>;
|
|
1150
|
+
/**
|
|
1151
|
+
* Serializes the savepoint frames opened directly off one transaction context
|
|
1152
|
+
*
|
|
1153
|
+
* @see createNestedFrameGate
|
|
847
1154
|
*/
|
|
848
|
-
type
|
|
1155
|
+
type NestedFrameGate = {
|
|
1156
|
+
/** Run `frame` once every frame queued before it on this context has finished */
|
|
1157
|
+
run<T>(frame: () => Promise<T>): Promise<T>;
|
|
1158
|
+
};
|
|
849
1159
|
/**
|
|
850
1160
|
* Transaction context stored in AsyncLocalStorage
|
|
851
1161
|
*/
|
|
852
|
-
type TransactionContext = {
|
|
1162
|
+
type TransactionContext<TDatabase extends DrizzleDatabase = DrizzleDatabase> = {
|
|
853
1163
|
/** The actual Drizzle transaction object */
|
|
854
|
-
tx: TransactionDB
|
|
1164
|
+
tx: TransactionDB<TDatabase>;
|
|
855
1165
|
/** Unique transaction ID for logging and tracing */
|
|
856
1166
|
txId: string;
|
|
857
1167
|
level: number;
|
|
1168
|
+
/** Callbacks to execute before the root transaction commits (still inside it) */
|
|
1169
|
+
beforeCommitCallbacks: BeforeCommitCallback[];
|
|
1170
|
+
/** Callbacks to execute after root transaction commits */
|
|
1171
|
+
afterCommitCallbacks: AfterCommitCallback[];
|
|
1172
|
+
/** Callbacks to execute after the root transaction rolled back */
|
|
1173
|
+
afterRollbackCallbacks: AfterRollbackCallback[];
|
|
1174
|
+
/** Serializes the savepoint frames opened directly off THIS context */
|
|
1175
|
+
nestedFrames: NestedFrameGate;
|
|
858
1176
|
};
|
|
1177
|
+
/**
|
|
1178
|
+
* Get current transaction object and metadata from AsyncLocalStorage
|
|
1179
|
+
*
|
|
1180
|
+
* @returns TransactionContext if available, null otherwise
|
|
1181
|
+
*/
|
|
1182
|
+
declare function getTransactionContext<TDatabase extends DrizzleDatabase = DefaultDatabase>(): TransactionContext<TDatabase> | null;
|
|
859
1183
|
/**
|
|
860
1184
|
* Get current transaction from AsyncLocalStorage
|
|
861
1185
|
*
|
|
862
1186
|
* @returns Transaction if available, null otherwise
|
|
863
1187
|
*/
|
|
864
|
-
declare function getTransaction(): TransactionDB | null;
|
|
1188
|
+
declare function getTransaction<TDatabase extends DrizzleDatabase = DefaultDatabase>(): TransactionDB<TDatabase> | null;
|
|
865
1189
|
/**
|
|
866
1190
|
* Run a function within a transaction context
|
|
867
1191
|
*
|
|
@@ -873,8 +1197,104 @@ declare function getTransaction(): TransactionDB | null;
|
|
|
873
1197
|
* @param callback - Function to run within transaction context
|
|
874
1198
|
* @returns Result of the callback
|
|
875
1199
|
*/
|
|
876
|
-
declare function runWithTransaction<T>(tx: TransactionDB
|
|
1200
|
+
declare function runWithTransaction<T, TDatabase extends DrizzleDatabase = DefaultDatabase>(tx: TransactionDB<TDatabase>, txId: string, // Add txId parameter
|
|
877
1201
|
callback: () => Promise<T>): Promise<T>;
|
|
1202
|
+
/**
|
|
1203
|
+
* Register a callback to run after the current transaction commits
|
|
1204
|
+
*
|
|
1205
|
+
* - Inside a transaction: queued and executed after root transaction commits
|
|
1206
|
+
* - Outside a transaction: executed immediately (already "committed")
|
|
1207
|
+
* - Nested transactions: callbacks bubble up to root transaction
|
|
1208
|
+
* - Callbacks run outside transaction context (new connection for DB access)
|
|
1209
|
+
* - Errors are logged but never thrown (commit already succeeded)
|
|
1210
|
+
*
|
|
1211
|
+
* @example
|
|
1212
|
+
* ```typescript
|
|
1213
|
+
* import { onAfterCommit } from '@spfn/core/db';
|
|
1214
|
+
*
|
|
1215
|
+
* async function submit(spaceId: string, chatId: string)
|
|
1216
|
+
* {
|
|
1217
|
+
* const publication = await publicationRepo.create({...});
|
|
1218
|
+
* await requestRepo.updateStatusAtomically(...);
|
|
1219
|
+
*
|
|
1220
|
+
* onAfterCommit(() => generateArticle(spaceId, chatId, publication.id));
|
|
1221
|
+
*
|
|
1222
|
+
* return publication;
|
|
1223
|
+
* }
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
declare function onAfterCommit(callback: AfterCommitCallback): void;
|
|
1227
|
+
/**
|
|
1228
|
+
* Register a callback to run just before the current transaction commits
|
|
1229
|
+
*
|
|
1230
|
+
* - Inside a transaction: queued and executed after the root callback resolves,
|
|
1231
|
+
* while the transaction is still open — the callback MAY run statements and
|
|
1232
|
+
* they are part of the same commit
|
|
1233
|
+
* - Outside a transaction: executed immediately with a WARNING (same rationale as
|
|
1234
|
+
* onAfterCommit — there is nothing left to commit), and the abort semantics
|
|
1235
|
+
* below do not apply: there is no transaction for a throw to roll back
|
|
1236
|
+
* - Nested transactions: callbacks bubble up to root transaction
|
|
1237
|
+
* - Callbacks run in registration order, inside the transaction context
|
|
1238
|
+
* (getTransaction() returns the live tx)
|
|
1239
|
+
* - The queue is snapshot before the pass, so a callback registered BY a
|
|
1240
|
+
* beforeCommit callback does not run for this commit — it would otherwise
|
|
1241
|
+
* grow the queue mid-iteration and loop forever inside the open transaction
|
|
1242
|
+
* - A throw ABORTS: later callbacks are skipped, the transaction rolls back,
|
|
1243
|
+
* the error propagates to the caller, and afterRollback callbacks fire
|
|
1244
|
+
*
|
|
1245
|
+
* @example
|
|
1246
|
+
* ```typescript
|
|
1247
|
+
* import { runInTransaction, onBeforeCommit } from '@spfn/core/db';
|
|
1248
|
+
*
|
|
1249
|
+
* async function transfer(fromId: string, toId: string, amount: number)
|
|
1250
|
+
* {
|
|
1251
|
+
* // The transaction is what gives the check teeth — registered outside one,
|
|
1252
|
+
* // the callback runs immediately and its throw aborts nothing.
|
|
1253
|
+
* await runInTransaction(async () =>
|
|
1254
|
+
* {
|
|
1255
|
+
* await accountRepo.debit(fromId, amount);
|
|
1256
|
+
* await accountRepo.credit(toId, amount);
|
|
1257
|
+
*
|
|
1258
|
+
* // Last-moment invariant check: a throw here rolls the whole transfer back.
|
|
1259
|
+
* onBeforeCommit(() => assertNoNegativeBalance(fromId));
|
|
1260
|
+
* });
|
|
1261
|
+
* }
|
|
1262
|
+
* ```
|
|
1263
|
+
*/
|
|
1264
|
+
declare function onBeforeCommit(callback: BeforeCommitCallback): void;
|
|
1265
|
+
/**
|
|
1266
|
+
* Register a callback to run after the current transaction rolled back
|
|
1267
|
+
*
|
|
1268
|
+
* - Inside a transaction: queued and executed after the ROOT transaction rolled
|
|
1269
|
+
* back, before the causing error leaves runInTransaction / the middleware
|
|
1270
|
+
* - Outside a transaction: no-op with a warning — there is no rollback to wait for
|
|
1271
|
+
* - Nested transactions: callbacks bubble up to root transaction. A nested
|
|
1272
|
+
* rollback that the root survives does NOT fire them; these hooks are about
|
|
1273
|
+
* the root transaction's fate, not a savepoint's
|
|
1274
|
+
* - Callbacks run outside the transaction context (new connection for DB access)
|
|
1275
|
+
* - Errors are logged but never thrown: the original error keeps propagating
|
|
1276
|
+
* unchanged, never replaced by a callback failure
|
|
1277
|
+
*
|
|
1278
|
+
* @example
|
|
1279
|
+
* ```typescript
|
|
1280
|
+
* import { runInTransaction, onAfterRollback } from '@spfn/core/db';
|
|
1281
|
+
*
|
|
1282
|
+
* async function importAvatar(userId: string, file: Blob)
|
|
1283
|
+
* {
|
|
1284
|
+
* // Upload first: external I/O never belongs inside the transaction.
|
|
1285
|
+
* const key = await objectStore.put(file);
|
|
1286
|
+
*
|
|
1287
|
+
* await runInTransaction(async () =>
|
|
1288
|
+
* {
|
|
1289
|
+
* await userRepo.updateAvatar(userId, key);
|
|
1290
|
+
*
|
|
1291
|
+
* // The upload cannot roll back on its own — undo it if the write never lands.
|
|
1292
|
+
* onAfterRollback(() => objectStore.delete(key));
|
|
1293
|
+
* });
|
|
1294
|
+
* }
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
declare function onAfterRollback(callback: AfterRollbackCallback): void;
|
|
878
1298
|
|
|
879
1299
|
/**
|
|
880
1300
|
* Transaction middleware options
|
|
@@ -910,6 +1330,30 @@ interface TransactionalOptions {
|
|
|
910
1330
|
* ```
|
|
911
1331
|
*/
|
|
912
1332
|
timeout?: number;
|
|
1333
|
+
/**
|
|
1334
|
+
* Idle-in-transaction timeout in milliseconds — Postgres reclaims the pooled
|
|
1335
|
+
* connection if the transaction sits idle (e.g. the handler awaits external
|
|
1336
|
+
* I/O) longer than this. A backstop against pool starvation, not a license
|
|
1337
|
+
* to do non-DB work inside a transaction. `0` disables it.
|
|
1338
|
+
*
|
|
1339
|
+
* @default 30000 (30s) or TRANSACTION_IDLE_TIMEOUT environment variable
|
|
1340
|
+
*/
|
|
1341
|
+
idleTimeout?: number;
|
|
1342
|
+
/**
|
|
1343
|
+
* Run in an independent transaction instead of joining an ambient one.
|
|
1344
|
+
*
|
|
1345
|
+
* Only bites when the middleware itself runs nested — a sub-app mounted
|
|
1346
|
+
* under a route that already applied `Transactional()`, or a handler invoked
|
|
1347
|
+
* from inside `runInTransaction`. By default that inner run takes a SAVEPOINT
|
|
1348
|
+
* on the outer transaction; `requiresNew: true` gives it a real `BEGIN` on a
|
|
1349
|
+
* second pooled connection, with its own timeouts and its own hook queues.
|
|
1350
|
+
*
|
|
1351
|
+
* See `RunInTransactionOptions.requiresNew` for the pool and self-deadlock
|
|
1352
|
+
* costs — they apply here unchanged.
|
|
1353
|
+
*
|
|
1354
|
+
* @default false
|
|
1355
|
+
*/
|
|
1356
|
+
requiresNew?: boolean;
|
|
913
1357
|
}
|
|
914
1358
|
/**
|
|
915
1359
|
* Transaction middleware for Hono routes
|
|
@@ -947,6 +1391,9 @@ interface TransactionalOptions {
|
|
|
947
1391
|
* - Success: Auto-commit
|
|
948
1392
|
* - Error: Auto-rollback
|
|
949
1393
|
* - Detects context.error to trigger rollback
|
|
1394
|
+
* - Hooks: this delegates to runInTransaction, so onBeforeCommit, onAfterCommit
|
|
1395
|
+
* and onAfterRollback behave exactly as they do there. afterRollback callbacks
|
|
1396
|
+
* have already run by the time the error reaches the conversion below.
|
|
950
1397
|
*
|
|
951
1398
|
* 📊 Transaction logging:
|
|
952
1399
|
* - Auto-logs transaction start/commit/rollback
|
|
@@ -955,6 +1402,148 @@ interface TransactionalOptions {
|
|
|
955
1402
|
*/
|
|
956
1403
|
declare function Transactional(options?: TransactionalOptions): hono_types.MiddlewareHandler<any, string, {}, Response>;
|
|
957
1404
|
|
|
1405
|
+
/**
|
|
1406
|
+
* Transaction runner options
|
|
1407
|
+
*/
|
|
1408
|
+
interface RunInTransactionOptions {
|
|
1409
|
+
/**
|
|
1410
|
+
* Slow transaction warning threshold in milliseconds
|
|
1411
|
+
* @default 1000 (1 second)
|
|
1412
|
+
*/
|
|
1413
|
+
slowThreshold?: number;
|
|
1414
|
+
/**
|
|
1415
|
+
* Enable transaction logging
|
|
1416
|
+
* @default true
|
|
1417
|
+
*/
|
|
1418
|
+
enableLogging?: boolean;
|
|
1419
|
+
/**
|
|
1420
|
+
* Transaction timeout in milliseconds
|
|
1421
|
+
*
|
|
1422
|
+
* Sets PostgreSQL `statement_timeout` to enforce database-level timeout.
|
|
1423
|
+
* If transaction exceeds this duration, PostgreSQL will automatically cancel
|
|
1424
|
+
* the query and rollback the transaction, ensuring data consistency.
|
|
1425
|
+
*
|
|
1426
|
+
* Behavior:
|
|
1427
|
+
* - `timeout: 0` - Disables timeout (unlimited execution time)
|
|
1428
|
+
* - `timeout: null` - Uses default (30s or TRANSACTION_TIMEOUT env var)
|
|
1429
|
+
* - `timeout: undefined` - Uses default (30s or TRANSACTION_TIMEOUT env var)
|
|
1430
|
+
* - `timeout: N` - Sets timeout to N milliseconds (1 to 2147483647)
|
|
1431
|
+
*
|
|
1432
|
+
* Note: Timeout is only applied to root transactions. A nested call takes a
|
|
1433
|
+
* SAVEPOINT on the outer transaction's connection, where the outer
|
|
1434
|
+
* transaction's `SET LOCAL statement_timeout` is already in force — so the
|
|
1435
|
+
* nested call genuinely inherits it, and its own `timeout` is ignored (a
|
|
1436
|
+
* warning is logged when the caller passed one explicitly). A
|
|
1437
|
+
* `requiresNew: true` call is a root and gets its own.
|
|
1438
|
+
*
|
|
1439
|
+
* @default 30000 (30 seconds) or TRANSACTION_TIMEOUT environment variable
|
|
1440
|
+
*
|
|
1441
|
+
* @example
|
|
1442
|
+
* ```typescript
|
|
1443
|
+
* // Use default timeout (30s)
|
|
1444
|
+
* await runInTransaction(callback);
|
|
1445
|
+
*
|
|
1446
|
+
* // Disable timeout for long-running operations
|
|
1447
|
+
* await runInTransaction(callback, { timeout: 0 });
|
|
1448
|
+
*
|
|
1449
|
+
* // Set custom timeout (60s)
|
|
1450
|
+
* await runInTransaction(callback, { timeout: 60000 });
|
|
1451
|
+
* ```
|
|
1452
|
+
*/
|
|
1453
|
+
timeout?: number;
|
|
1454
|
+
/**
|
|
1455
|
+
* Idle-in-transaction timeout in milliseconds (root transactions only).
|
|
1456
|
+
*
|
|
1457
|
+
* Sets PostgreSQL `idle_in_transaction_session_timeout`: if the transaction
|
|
1458
|
+
* sits open without running a query for longer than this — e.g. while the
|
|
1459
|
+
* handler awaits external I/O inside the transaction — Postgres terminates
|
|
1460
|
+
* the session and rolls back, reclaiming the pooled connection instead of
|
|
1461
|
+
* letting one stuck request hold it (and its row locks) indefinitely.
|
|
1462
|
+
*
|
|
1463
|
+
* Do not put external I/O inside a transaction; this is a backstop, not a
|
|
1464
|
+
* license. `0` disables it.
|
|
1465
|
+
*
|
|
1466
|
+
* @default 30000 (30s) or TRANSACTION_IDLE_TIMEOUT environment variable
|
|
1467
|
+
*/
|
|
1468
|
+
idleTimeout?: number;
|
|
1469
|
+
/**
|
|
1470
|
+
* Context string for logging (e.g., 'migration:add-user', 'script:cleanup')
|
|
1471
|
+
* @default 'transaction'
|
|
1472
|
+
*/
|
|
1473
|
+
context?: string;
|
|
1474
|
+
/**
|
|
1475
|
+
* Run in an independent transaction instead of joining an ambient one.
|
|
1476
|
+
*
|
|
1477
|
+
* By default a call made while another transaction is open takes a SAVEPOINT
|
|
1478
|
+
* on that transaction's connection: its writes commit or roll back with the
|
|
1479
|
+
* outer transaction. `requiresNew: true` opens a real `BEGIN` on a SECOND
|
|
1480
|
+
* pooled connection instead, so the work commits on its own and survives an
|
|
1481
|
+
* outer rollback — an audit trail or a failed-attempt record, for example.
|
|
1482
|
+
*
|
|
1483
|
+
* Being a root transaction, it gets its own `statement_timeout`,
|
|
1484
|
+
* `idle_in_transaction_session_timeout`, and its OWN hook queues:
|
|
1485
|
+
* `onBeforeCommit` / `onAfterCommit` / `onAfterRollback` registered inside it
|
|
1486
|
+
* fire on ITS outcome, not the outer transaction's.
|
|
1487
|
+
*
|
|
1488
|
+
* Two costs, both consequences of the second connection:
|
|
1489
|
+
* - It holds a second connection for its whole duration, so it counts twice
|
|
1490
|
+
* against the pool. Keep it short and don't fan it out.
|
|
1491
|
+
* - It cannot see the outer transaction's uncommitted writes, and it BLOCKS
|
|
1492
|
+
* on any row the outer transaction has locked. Since the outer transaction
|
|
1493
|
+
* is waiting for this call to return, that block is a self-deadlock that
|
|
1494
|
+
* only `statement_timeout` breaks. Never touch rows the outer transaction
|
|
1495
|
+
* wrote.
|
|
1496
|
+
*
|
|
1497
|
+
* @default false
|
|
1498
|
+
*
|
|
1499
|
+
* @example
|
|
1500
|
+
* ```typescript
|
|
1501
|
+
* await runInTransaction(async () =>
|
|
1502
|
+
* {
|
|
1503
|
+
* await orderRepo.create(order);
|
|
1504
|
+
*
|
|
1505
|
+
* // Lands even if the order below rolls the outer transaction back.
|
|
1506
|
+
* await runInTransaction(
|
|
1507
|
+
* () => auditRepo.record('order.attempted', order.id),
|
|
1508
|
+
* { requiresNew: true },
|
|
1509
|
+
* );
|
|
1510
|
+
*
|
|
1511
|
+
* await inventoryRepo.reserve(order.items); // may throw
|
|
1512
|
+
* });
|
|
1513
|
+
* ```
|
|
1514
|
+
*/
|
|
1515
|
+
requiresNew?: boolean;
|
|
1516
|
+
}
|
|
1517
|
+
/**
|
|
1518
|
+
* Run a callback function within a database transaction
|
|
1519
|
+
*
|
|
1520
|
+
* Automatically manages transaction lifecycle:
|
|
1521
|
+
* - Commits on success
|
|
1522
|
+
* - Rolls back on error
|
|
1523
|
+
* - Tracks execution time
|
|
1524
|
+
* - Warns about slow transactions
|
|
1525
|
+
* - Enforces timeout if configured
|
|
1526
|
+
*
|
|
1527
|
+
* Called with a transaction already open on the async call chain, it takes a
|
|
1528
|
+
* SAVEPOINT on that transaction rather than opening an independent one: the work
|
|
1529
|
+
* runs on the same connection, sees the outer transaction's uncommitted writes,
|
|
1530
|
+
* and commits with it. A throw that the caller catches unwinds to the SAVEPOINT
|
|
1531
|
+
* and leaves the outer transaction healthy; a throw that propagates rolls the
|
|
1532
|
+
* whole thing back. Nested calls off one transaction are serialized — see
|
|
1533
|
+
* `openTransaction` — so `Promise.all` over them runs them one at a time. Pass
|
|
1534
|
+
* `requiresNew: true` for an independent transaction on its own connection.
|
|
1535
|
+
*
|
|
1536
|
+
* Errors are propagated to the caller without modification.
|
|
1537
|
+
* Caller is responsible for error handling and conversion.
|
|
1538
|
+
*
|
|
1539
|
+
* @param callback - Function to execute within transaction
|
|
1540
|
+
* @param options - Transaction options
|
|
1541
|
+
* @returns Result of callback function
|
|
1542
|
+
* @throws TransactionError if database not initialized or timeout exceeded
|
|
1543
|
+
* @throws Any error thrown by callback function
|
|
1544
|
+
*/
|
|
1545
|
+
declare function runInTransaction<T, TDatabase extends DrizzleDatabase = DefaultDatabase>(callback: (tx: TransactionDB<TDatabase>) => Promise<T>, options?: RunInTransactionOptions): Promise<T>;
|
|
1546
|
+
|
|
958
1547
|
/**
|
|
959
1548
|
* PostgreSQL Error Conversion Utilities
|
|
960
1549
|
*
|
|
@@ -1007,14 +1596,6 @@ declare function fromPostgresError(error: any): DatabaseError;
|
|
|
1007
1596
|
* ```
|
|
1008
1597
|
*/
|
|
1009
1598
|
|
|
1010
|
-
/**
|
|
1011
|
-
* Infer SELECT model from PgTable
|
|
1012
|
-
*/
|
|
1013
|
-
type InferSelectModel<T extends PgTable> = T['$inferSelect'];
|
|
1014
|
-
/**
|
|
1015
|
-
* Infer INSERT model from PgTable
|
|
1016
|
-
*/
|
|
1017
|
-
type InferInsertModel<T extends PgTable> = T['$inferInsert'];
|
|
1018
1599
|
/**
|
|
1019
1600
|
* Object-based where condition (AND only, equality only)
|
|
1020
1601
|
*/
|
|
@@ -1126,8 +1707,8 @@ declare function createMany<T extends PgTable>(table: T, data: InferInsertModel<
|
|
|
1126
1707
|
* }, {
|
|
1127
1708
|
* target: [cmsPublishedCache.section, cmsPublishedCache.locale],
|
|
1128
1709
|
* set: {
|
|
1129
|
-
* content: data.content
|
|
1130
|
-
* updatedAt
|
|
1710
|
+
* content: data.content
|
|
1711
|
+
* // updatedAt is stamped by the database — do not name it here
|
|
1131
1712
|
* }
|
|
1132
1713
|
* });
|
|
1133
1714
|
*
|
|
@@ -1266,11 +1847,11 @@ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSel
|
|
|
1266
1847
|
*
|
|
1267
1848
|
* @example With Transactions
|
|
1268
1849
|
* ```typescript
|
|
1269
|
-
* import {
|
|
1850
|
+
* import { runInTransaction } from '@spfn/core/db';
|
|
1270
1851
|
*
|
|
1271
1852
|
* const userRepo = new UserRepository();
|
|
1272
1853
|
*
|
|
1273
|
-
* await
|
|
1854
|
+
* await runInTransaction(async () => {
|
|
1274
1855
|
* // Both db and readDb automatically use the transaction context
|
|
1275
1856
|
* const user = await userRepo.create({ name: 'John' });
|
|
1276
1857
|
* await userRepo.findById(user.id); // Uses same transaction
|
|
@@ -1279,10 +1860,10 @@ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSel
|
|
|
1279
1860
|
*
|
|
1280
1861
|
* @example With Custom Schema Type
|
|
1281
1862
|
* ```typescript
|
|
1282
|
-
* import type {
|
|
1863
|
+
* import type { AppRelations } from './relations';
|
|
1283
1864
|
*
|
|
1284
|
-
* export class UserRepository extends BaseRepository<
|
|
1285
|
-
* // Now this.db and this.readDb
|
|
1865
|
+
* export class UserRepository extends BaseRepository<AppRelations> {
|
|
1866
|
+
* // Now this.db and this.readDb preserve the app's Drizzle relations
|
|
1286
1867
|
* }
|
|
1287
1868
|
* ```
|
|
1288
1869
|
*
|
|
@@ -1302,6 +1883,8 @@ declare function count<T extends PgTable>(table: T, where?: WhereObject<InferSel
|
|
|
1302
1883
|
* ```
|
|
1303
1884
|
*/
|
|
1304
1885
|
|
|
1886
|
+
/** Database surface available to repositories inside and outside transactions. */
|
|
1887
|
+
type RepositoryDatabase<TDatabase extends DrizzleDatabase> = TDatabase extends PgAsyncDatabase<infer TQueryResult, infer TRelations> ? PgAsyncDatabase<TQueryResult, TRelations> : never;
|
|
1305
1888
|
/**
|
|
1306
1889
|
* Enhanced error class that includes repository context
|
|
1307
1890
|
*/
|
|
@@ -1323,9 +1906,10 @@ declare class RepositoryError extends Error {
|
|
|
1323
1906
|
* - Inside transaction: Uses transaction DB
|
|
1324
1907
|
* - Outside transaction: Uses global DB instance (with read/write separation)
|
|
1325
1908
|
*
|
|
1326
|
-
* @template
|
|
1909
|
+
* @template TRelations - Drizzle relations type (defaults to no relations)
|
|
1910
|
+
* @template TDatabase - PostgreSQL Drizzle driver type (defaults to postgres.js)
|
|
1327
1911
|
*/
|
|
1328
|
-
declare abstract class BaseRepository<
|
|
1912
|
+
declare abstract class BaseRepository<TRelations extends AnyRelations = EmptyRelations, TDatabase extends DrizzleDatabase = PostgresJsDatabase<TRelations>> {
|
|
1329
1913
|
/**
|
|
1330
1914
|
* Write database instance
|
|
1331
1915
|
*
|
|
@@ -1342,7 +1926,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1342
1926
|
* }
|
|
1343
1927
|
* ```
|
|
1344
1928
|
*/
|
|
1345
|
-
protected get db():
|
|
1929
|
+
protected get db(): RepositoryDatabase<TDatabase>;
|
|
1346
1930
|
/**
|
|
1347
1931
|
* Read database instance
|
|
1348
1932
|
*
|
|
@@ -1363,7 +1947,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1363
1947
|
* }
|
|
1364
1948
|
* ```
|
|
1365
1949
|
*/
|
|
1366
|
-
protected get readDb():
|
|
1950
|
+
protected get readDb(): RepositoryDatabase<TDatabase>;
|
|
1367
1951
|
/**
|
|
1368
1952
|
* Wrap query execution with repository context
|
|
1369
1953
|
*
|
|
@@ -1409,7 +1993,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1409
1993
|
* const user = await this._findOne(users, eq(users.id, 1));
|
|
1410
1994
|
* ```
|
|
1411
1995
|
*/
|
|
1412
|
-
protected _findOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<T
|
|
1996
|
+
protected _findOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<InferSelectModel<T> | null>;
|
|
1413
1997
|
/**
|
|
1414
1998
|
* Find multiple records
|
|
1415
1999
|
*
|
|
@@ -1431,7 +2015,33 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1431
2015
|
orderBy?: SQL | SQL[];
|
|
1432
2016
|
limit?: number;
|
|
1433
2017
|
offset?: number;
|
|
1434
|
-
}): Promise<T[
|
|
2018
|
+
}): Promise<InferSelectModel<T>[]>;
|
|
2019
|
+
/**
|
|
2020
|
+
* Keyset (cursor) pagination — O(limit) instead of OFFSET's O(offset).
|
|
2021
|
+
*
|
|
2022
|
+
* Pages by a strictly-ordered, unique column instead of a numeric offset, so a
|
|
2023
|
+
* deep page doesn't scan and discard everything before it. Pass the cursor
|
|
2024
|
+
* column's value from the last row of the previous page as `after`; omit it for
|
|
2025
|
+
* the first page. The column must be unique and the sole sort key (e.g. an
|
|
2026
|
+
* auto-increment id or a ULID).
|
|
2027
|
+
*
|
|
2028
|
+
* @example
|
|
2029
|
+
* ```typescript
|
|
2030
|
+
* const page1 = await this._findManyKeyset(users, { cursorColumn: users.id, limit: 20 });
|
|
2031
|
+
* const page2 = await this._findManyKeyset(users, {
|
|
2032
|
+
* cursorColumn: users.id,
|
|
2033
|
+
* after: page1.at(-1)?.id,
|
|
2034
|
+
* limit: 20,
|
|
2035
|
+
* });
|
|
2036
|
+
* ```
|
|
2037
|
+
*/
|
|
2038
|
+
protected _findManyKeyset<T extends PgTable>(table: T, options: {
|
|
2039
|
+
cursorColumn: PgColumn;
|
|
2040
|
+
limit: number;
|
|
2041
|
+
after?: string | number | bigint | Date;
|
|
2042
|
+
order?: 'asc' | 'desc';
|
|
2043
|
+
where?: Record<string, any> | SQL | undefined;
|
|
2044
|
+
}): Promise<InferSelectModel<T>[]>;
|
|
1435
2045
|
/**
|
|
1436
2046
|
* Create a new record
|
|
1437
2047
|
*
|
|
@@ -1447,7 +2057,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1447
2057
|
* });
|
|
1448
2058
|
* ```
|
|
1449
2059
|
*/
|
|
1450
|
-
protected _create<T extends PgTable>(table: T, data: T
|
|
2060
|
+
protected _create<T extends PgTable>(table: T, data: InferInsertModel<T>): Promise<InferSelectModel<T>>;
|
|
1451
2061
|
/**
|
|
1452
2062
|
* Create multiple records
|
|
1453
2063
|
*
|
|
@@ -1463,7 +2073,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1463
2073
|
* ]);
|
|
1464
2074
|
* ```
|
|
1465
2075
|
*/
|
|
1466
|
-
protected _createMany<T extends PgTable>(table: T, data: T[
|
|
2076
|
+
protected _createMany<T extends PgTable>(table: T, data: InferInsertModel<T>[]): Promise<InferSelectModel<T>[]>;
|
|
1467
2077
|
/**
|
|
1468
2078
|
* Upsert a record (INSERT or UPDATE on conflict)
|
|
1469
2079
|
*
|
|
@@ -1479,14 +2089,14 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1479
2089
|
* value: {...}
|
|
1480
2090
|
* }, {
|
|
1481
2091
|
* target: [cache.key],
|
|
1482
|
-
* set: { value: data.value
|
|
2092
|
+
* set: { value: data.value } // updatedAt is stamped by the database
|
|
1483
2093
|
* });
|
|
1484
2094
|
* ```
|
|
1485
2095
|
*/
|
|
1486
|
-
protected _upsert<T extends PgTable>(table: T, data: T
|
|
2096
|
+
protected _upsert<T extends PgTable>(table: T, data: InferInsertModel<T>, options: {
|
|
1487
2097
|
target: PgColumn[];
|
|
1488
|
-
set?: Partial<T
|
|
1489
|
-
}): Promise<T
|
|
2098
|
+
set?: Partial<InferInsertModel<T>> | Record<string, SQL | any>;
|
|
2099
|
+
}): Promise<InferSelectModel<T>>;
|
|
1490
2100
|
/**
|
|
1491
2101
|
* Update a single record
|
|
1492
2102
|
*
|
|
@@ -1503,7 +2113,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1503
2113
|
* );
|
|
1504
2114
|
* ```
|
|
1505
2115
|
*/
|
|
1506
|
-
protected _updateOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined, data: Partial<T
|
|
2116
|
+
protected _updateOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined, data: Partial<InferInsertModel<T>>): Promise<InferSelectModel<T> | null>;
|
|
1507
2117
|
/**
|
|
1508
2118
|
* Update multiple records
|
|
1509
2119
|
*
|
|
@@ -1520,7 +2130,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1520
2130
|
* );
|
|
1521
2131
|
* ```
|
|
1522
2132
|
*/
|
|
1523
|
-
protected _updateMany<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined, data: Partial<T
|
|
2133
|
+
protected _updateMany<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined, data: Partial<InferInsertModel<T>>): Promise<InferSelectModel<T>[]>;
|
|
1524
2134
|
/**
|
|
1525
2135
|
* Delete a single record
|
|
1526
2136
|
*
|
|
@@ -1533,7 +2143,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1533
2143
|
* const user = await this._deleteOne(users, { id: 1 });
|
|
1534
2144
|
* ```
|
|
1535
2145
|
*/
|
|
1536
|
-
protected _deleteOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<T
|
|
2146
|
+
protected _deleteOne<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<InferSelectModel<T> | null>;
|
|
1537
2147
|
/**
|
|
1538
2148
|
* Delete multiple records
|
|
1539
2149
|
*
|
|
@@ -1546,7 +2156,7 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1546
2156
|
* const users = await this._deleteMany(users, { verified: false });
|
|
1547
2157
|
* ```
|
|
1548
2158
|
*/
|
|
1549
|
-
protected _deleteMany<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<T[
|
|
2159
|
+
protected _deleteMany<T extends PgTable>(table: T, where: Record<string, any> | SQL | undefined): Promise<InferSelectModel<T>[]>;
|
|
1550
2160
|
/**
|
|
1551
2161
|
* Count records
|
|
1552
2162
|
*
|
|
@@ -1563,4 +2173,4 @@ declare abstract class BaseRepository<TSchema extends Record<string, unknown> =
|
|
|
1563
2173
|
protected _count<T extends PgTable>(table: T, where?: Record<string, any> | SQL | undefined): Promise<number>;
|
|
1564
2174
|
}
|
|
1565
2175
|
|
|
1566
|
-
export { BaseRepository, type DatabaseClients, type DrizzleConfigOptions, type PoolConfig, RepositoryError, type RetryConfig, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, count, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, enumText, findMany, findOne, foreignKey, fromPostgresError, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, id, initDatabase, optionalForeignKey, packageNameToSchema, publishingFields, runWithTransaction, setDatabase, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };
|
|
2176
|
+
export { type AfterCommitCallback, type AfterRollbackCallback, BaseRepository, type BeforeCommitCallback, type DatabaseClients, type DatabaseInitOptions, type DatabaseOptions, type DatabaseProvider, type DatabaseTransaction, type DefaultDatabase, type DrizzleConfigOptions, type DrizzleDatabase, type FunctionMigrationEntry, type FunctionMigrationInfo, type MigrationStatus, type MigrationStatusDb, type MigrationTargetStatus, type NestedFrameGate, PROJECT_MIGRATIONS_TABLE, PROJECT_TARGET_NAME, type PoolConfig, RUN_MIGRATIONS_HINT, type RenderableDrizzleConfig, type RepositoryDatabase, RepositoryError, type RetryConfig, type RunInTransactionOptions, type TransactionContext, type TransactionDB, Transactional, type TransactionalOptions, auditFields, checkConnection, closeDatabase, collectMigrationStatus, count, countPendingMigrations, create, createDatabaseConnection, createDatabaseFromEnv, createMany, createSchema, deleteMany, deleteOne, detectDialect, discoverFunctionMigrations, enumText, filterPendingEntries, findMany, findOne, forceReconnectDatabase, foreignKey, formatPendingMigrations, fromPostgresError, functionMigrationsTable, generateDrizzleConfigFile, getDatabase, getDatabaseInfo, getDrizzleConfig, getSchemaInfo, getTransaction, getTransactionContext, hasMigrationTargets, id, initDatabase, isConnectionLevelError, migrationTargets, onAfterCommit, onAfterRollback, onBeforeCommit, optionalForeignKey, packageNameToSchema, pendingMigrationTargets, pendingMigrationsSummary, projectMigrationsDir, publishingFields, readMigrationEntries, renderDrizzleConfig, reportDatabaseError, resetConnectionErrorCounter, runInTransaction, runWithTransaction, setDatabase, setDatabaseProvider, softDelete, timestamps, typedJsonb, updateMany, updateOne, upsert, utcTimestamp, uuid, verificationTimestamp };
|