@murumets-ee/db 0.2.0 → 0.4.0
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/dist/index.d.mts +356 -126
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
|
-
import
|
|
2
|
+
import * as _$drizzle_orm0 from "drizzle-orm";
|
|
3
|
+
import { InferInsertModel, SQL } from "drizzle-orm";
|
|
4
|
+
import * as _$drizzle_orm_pg_core0 from "drizzle-orm/pg-core";
|
|
5
|
+
import { AnyPgColumn, PgColumnBuilderBase, PgTable, PgTableWithColumns, TableConfig } from "drizzle-orm/pg-core";
|
|
3
6
|
|
|
4
7
|
//#region src/client.d.ts
|
|
5
8
|
interface DbConfig {
|
|
@@ -159,6 +162,14 @@ interface ColumnFactory<TType = unknown, TKind extends ColumnKind = ColumnKind,
|
|
|
159
162
|
readonly __kind: TKind;
|
|
160
163
|
readonly __notNull: TNotNull;
|
|
161
164
|
readonly __hasDefault: THasDefault;
|
|
165
|
+
/**
|
|
166
|
+
* Optional explicit Postgres column name. When set, the column uses this
|
|
167
|
+
* name in the database instead of the JS property name. Needed when porting
|
|
168
|
+
* existing tables that use snake_case column names to `defineTable`.
|
|
169
|
+
*/
|
|
170
|
+
readonly __pgName?: string;
|
|
171
|
+
/** True when the column is declared as a primary key at the column level. */
|
|
172
|
+
readonly __primaryKey?: boolean;
|
|
162
173
|
}
|
|
163
174
|
/**
|
|
164
175
|
* Convenience helper: extract the JS value type for a single column.
|
|
@@ -325,124 +336,110 @@ interface TableDefinition<TCols extends Record<string, ColumnFactory>> {
|
|
|
325
336
|
//#endregion
|
|
326
337
|
//#region src/table/columns.d.ts
|
|
327
338
|
/**
|
|
328
|
-
*
|
|
339
|
+
* Type interface for the `column` builder namespace.
|
|
329
340
|
*
|
|
330
|
-
*
|
|
331
|
-
* `
|
|
332
|
-
* resulting `Row` and `InsertRow` types track each column's value type
|
|
333
|
-
* and nullability.
|
|
341
|
+
* Overloads discriminate on whether `default` is present, so
|
|
342
|
+
* `THasDefault` is inferred correctly:
|
|
334
343
|
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
* import { column, defineTable } from '@murumets-ee/db'
|
|
344
|
+
* - `column.varchar({ length: 20, default: 'x' })` → `hasDefault = true`
|
|
345
|
+
* - `column.varchar({ length: 20 })` → `hasDefault = false`
|
|
338
346
|
*
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
*
|
|
342
|
-
* id: column.uuid({ primaryKey: true, defaultRandom: true }),
|
|
343
|
-
* type: column.varchar({ length: 100, notNull: true }),
|
|
344
|
-
* payload: column.jsonb<{ subject: string; body: string }>({ notNull: true }),
|
|
345
|
-
* status: column.varchar({ length: 20, notNull: true, default: 'pending' }),
|
|
346
|
-
* priority: column.integer({ notNull: true, default: 0 }),
|
|
347
|
-
* runAt: column.timestamp({ notNull: true, defaultNow: true, withTimezone: true }),
|
|
348
|
-
* },
|
|
349
|
-
* })
|
|
350
|
-
* ```
|
|
347
|
+
* Object-literal methods don't support overloads in TypeScript, so we
|
|
348
|
+
* declare the overloaded signatures on an interface and cast the
|
|
349
|
+
* implementation object.
|
|
351
350
|
*/
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
* For primary keys, use `{ primaryKey: true, defaultRandom: true }` to
|
|
357
|
-
* get a server-generated UUIDv4.
|
|
358
|
-
*/
|
|
359
|
-
uuid<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
360
|
-
primaryKey?: boolean;
|
|
361
|
-
notNull?: TNotNull; /** Server-side `gen_random_uuid()` default. Counts as a default for type inference. */
|
|
351
|
+
interface ColumnBuilders {
|
|
352
|
+
uuid<TPrimaryKey extends boolean = false, TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
353
|
+
primaryKey?: TPrimaryKey;
|
|
354
|
+
notNull?: TNotNull;
|
|
362
355
|
defaultRandom?: THasDefault;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
* positive integer up to Postgres' actual `varchar` ceiling
|
|
367
|
-
* (1073741823 — i.e. ~1GB / 4 bytes per char). For unbounded text use
|
|
368
|
-
* `column.text()` instead — it stores the same way and skips the
|
|
369
|
-
* length check at write time.
|
|
370
|
-
*
|
|
371
|
-
* Conventional sizes for reference:
|
|
372
|
-
* - 50–100: short identifiers, slugs, status codes
|
|
373
|
-
* - 255: legacy "common max length" — fits a tweet, an email, etc.
|
|
374
|
-
* - 1024: file paths, URLs
|
|
375
|
-
* - 10000+: prefer `text` instead, varchar with very large lengths
|
|
376
|
-
* buys you nothing
|
|
377
|
-
*/
|
|
378
|
-
varchar<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts: {
|
|
356
|
+
pgName?: string;
|
|
357
|
+
}): ColumnFactory<string, 'uuid', TPrimaryKey extends true ? true : TNotNull extends true ? true : false, TPrimaryKey extends true ? true : THasDefault extends true ? true : false>;
|
|
358
|
+
varchar<TNotNull extends boolean = false>(opts: {
|
|
379
359
|
length: number;
|
|
380
360
|
notNull?: TNotNull;
|
|
381
|
-
default
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
text<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
361
|
+
default: string;
|
|
362
|
+
pgName?: string;
|
|
363
|
+
}): ColumnFactory<string, 'varchar', TNotNull extends true ? true : false, true>;
|
|
364
|
+
varchar<TNotNull extends boolean = false>(opts: {
|
|
365
|
+
length: number;
|
|
387
366
|
notNull?: TNotNull;
|
|
388
|
-
|
|
389
|
-
}): ColumnFactory<string,
|
|
390
|
-
|
|
391
|
-
* 32-bit integer column.
|
|
392
|
-
*/
|
|
393
|
-
integer<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
367
|
+
pgName?: string;
|
|
368
|
+
}): ColumnFactory<string, 'varchar', TNotNull extends true ? true : false, false>;
|
|
369
|
+
text<TNotNull extends boolean = false>(opts: {
|
|
394
370
|
notNull?: TNotNull;
|
|
395
|
-
default
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
371
|
+
default: string;
|
|
372
|
+
pgName?: string;
|
|
373
|
+
}): ColumnFactory<string, 'text', TNotNull extends true ? true : false, true>;
|
|
374
|
+
text<TNotNull extends boolean = false>(opts?: {
|
|
375
|
+
notNull?: TNotNull;
|
|
376
|
+
pgName?: string;
|
|
377
|
+
}): ColumnFactory<string, 'text', TNotNull extends true ? true : false, false>;
|
|
378
|
+
integer<TNotNull extends boolean = false>(opts: {
|
|
379
|
+
notNull?: TNotNull;
|
|
380
|
+
default: number;
|
|
381
|
+
pgName?: string;
|
|
382
|
+
}): ColumnFactory<number, 'integer', TNotNull extends true ? true : false, true>;
|
|
383
|
+
integer<TNotNull extends boolean = false>(opts?: {
|
|
384
|
+
notNull?: TNotNull;
|
|
385
|
+
pgName?: string;
|
|
386
|
+
}): ColumnFactory<number, 'integer', TNotNull extends true ? true : false, false>;
|
|
387
|
+
bigint<TMode extends 'number' | 'bigint' = 'number', TNotNull extends boolean = false>(opts: {
|
|
402
388
|
mode?: TMode;
|
|
403
389
|
notNull?: TNotNull;
|
|
404
|
-
default
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
double<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
390
|
+
default: TMode extends 'bigint' ? bigint : number;
|
|
391
|
+
pgName?: string;
|
|
392
|
+
}): ColumnFactory<TMode extends 'bigint' ? bigint : number, 'bigint', TNotNull extends true ? true : false, true>;
|
|
393
|
+
bigint<TMode extends 'number' | 'bigint' = 'number', TNotNull extends boolean = false>(opts?: {
|
|
394
|
+
mode?: TMode;
|
|
410
395
|
notNull?: TNotNull;
|
|
411
|
-
|
|
412
|
-
}): ColumnFactory<
|
|
413
|
-
|
|
414
|
-
* Boolean column. Defaults to `false` if no explicit default is supplied
|
|
415
|
-
* AND `notNull` is true — matches the entity package convention.
|
|
416
|
-
*/
|
|
417
|
-
boolean<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
396
|
+
pgName?: string;
|
|
397
|
+
}): ColumnFactory<TMode extends 'bigint' ? bigint : number, 'bigint', TNotNull extends true ? true : false, false>;
|
|
398
|
+
double<TNotNull extends boolean = false>(opts: {
|
|
418
399
|
notNull?: TNotNull;
|
|
419
|
-
default
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
400
|
+
default: number;
|
|
401
|
+
pgName?: string;
|
|
402
|
+
}): ColumnFactory<number, 'double', TNotNull extends true ? true : false, true>;
|
|
403
|
+
double<TNotNull extends boolean = false>(opts?: {
|
|
404
|
+
notNull?: TNotNull;
|
|
405
|
+
pgName?: string;
|
|
406
|
+
}): ColumnFactory<number, 'double', TNotNull extends true ? true : false, false>;
|
|
407
|
+
boolean<TNotNull extends boolean = false>(opts: {
|
|
408
|
+
notNull?: TNotNull;
|
|
409
|
+
default: boolean;
|
|
410
|
+
pgName?: string;
|
|
411
|
+
}): ColumnFactory<boolean, 'boolean', TNotNull extends true ? true : false, true>;
|
|
412
|
+
boolean<TNotNull extends boolean = false>(opts?: {
|
|
413
|
+
notNull?: TNotNull;
|
|
414
|
+
pgName?: string;
|
|
415
|
+
}): ColumnFactory<boolean, 'boolean', TNotNull extends true ? true : false, false>;
|
|
425
416
|
timestamp<TNotNull extends boolean = false, THasDefault extends boolean = false>(opts?: {
|
|
426
|
-
notNull?: TNotNull;
|
|
417
|
+
notNull?: TNotNull;
|
|
427
418
|
defaultNow?: THasDefault;
|
|
428
419
|
withTimezone?: boolean;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
420
|
+
pgName?: string;
|
|
421
|
+
}): ColumnFactory<Date, 'timestamp', TNotNull extends true ? true : false, THasDefault extends true ? true : false>;
|
|
422
|
+
jsonb<T = unknown, TNotNull extends boolean = false>(opts: {
|
|
423
|
+
notNull?: TNotNull;
|
|
424
|
+
default: T;
|
|
425
|
+
pgName?: string;
|
|
426
|
+
}): ColumnFactory<T, 'jsonb', TNotNull extends true ? true : false, true>;
|
|
436
427
|
jsonb<T = unknown, TNotNull extends boolean = false>(opts?: {
|
|
437
428
|
notNull?: TNotNull;
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
* UUID array column (`uuid[]`).
|
|
441
|
-
*/
|
|
429
|
+
pgName?: string;
|
|
430
|
+
}): ColumnFactory<T, 'jsonb', TNotNull extends true ? true : false, false>;
|
|
442
431
|
uuidArray<TNotNull extends boolean = false>(opts?: {
|
|
443
432
|
notNull?: TNotNull;
|
|
444
|
-
|
|
445
|
-
}
|
|
433
|
+
pgName?: string;
|
|
434
|
+
}): ColumnFactory<string[], 'uuidArray', TNotNull extends true ? true : false, false>;
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Column builder namespace — overloaded interface applied via single
|
|
438
|
+
* assertion. Each builder's implementation returns `makeFactory(...)` with
|
|
439
|
+
* widened boolean params; the `ColumnBuilders` overloads narrow them for
|
|
440
|
+
* callers based on whether `default`/`primaryKey` etc. are present.
|
|
441
|
+
*/
|
|
442
|
+
declare const column: ColumnBuilders;
|
|
446
443
|
//#endregion
|
|
447
444
|
//#region src/table/client.d.ts
|
|
448
445
|
/**
|
|
@@ -487,6 +484,50 @@ interface FindManyOptions<TCols extends Record<string, ColumnFactory>> {
|
|
|
487
484
|
limit?: number;
|
|
488
485
|
offset?: number;
|
|
489
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* Options for the `claim()` atomic locking operation.
|
|
489
|
+
*
|
|
490
|
+
* @see {@link TableClient.claim}
|
|
491
|
+
*/
|
|
492
|
+
interface ClaimOptions<TCols extends Record<string, ColumnFactory>, TTable extends PgTable = PgTable> {
|
|
493
|
+
/** Filter for rows eligible to be claimed. Must be non-empty. */
|
|
494
|
+
where: WhereClause<TCols>;
|
|
495
|
+
/** Literal values to SET on claimed rows. */
|
|
496
|
+
set?: Partial<InferInsertModel<TTable>>;
|
|
497
|
+
/** Raw SQL expressions to SET (e.g. `{ attempts: sql\`attempts + 1\` }`). */
|
|
498
|
+
setSql?: Record<string, SQL>;
|
|
499
|
+
/** ORDER BY for the subselect — controls claim priority. */
|
|
500
|
+
orderBy?: OrderBySpec<TCols>[];
|
|
501
|
+
/** Maximum number of rows to claim. Must be 1..MAX_LIMIT. */
|
|
502
|
+
limit: number;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Specification for a single aggregate function.
|
|
506
|
+
*/
|
|
507
|
+
type AggregateSpec<TCols extends Record<string, ColumnFactory>> = {
|
|
508
|
+
fn: 'count';
|
|
509
|
+
} | {
|
|
510
|
+
fn: 'count';
|
|
511
|
+
column: keyof TCols & string;
|
|
512
|
+
} | {
|
|
513
|
+
fn: 'sum' | 'avg' | 'min' | 'max';
|
|
514
|
+
column: keyof TCols & string;
|
|
515
|
+
};
|
|
516
|
+
/**
|
|
517
|
+
* Options for the `aggregate()` method.
|
|
518
|
+
*/
|
|
519
|
+
interface AggregateOptions<TCols extends Record<string, ColumnFactory>> {
|
|
520
|
+
/** Named aggregate expressions. Each key becomes an output column. */
|
|
521
|
+
select: Record<string, AggregateSpec<TCols>>;
|
|
522
|
+
/** Columns to GROUP BY. Included automatically in the result. */
|
|
523
|
+
groupBy?: (keyof TCols & string)[];
|
|
524
|
+
/** Filter rows before aggregation (WHERE). */
|
|
525
|
+
where?: WhereClause<TCols>;
|
|
526
|
+
/** Order results. Can reference both grouped columns and aliases. */
|
|
527
|
+
orderBy?: OrderBySpec<TCols>[];
|
|
528
|
+
/** Limit the number of groups returned. */
|
|
529
|
+
limit?: number;
|
|
530
|
+
}
|
|
490
531
|
/**
|
|
491
532
|
* Generic CRUD client. Constructed by `defineTable` — never instantiated
|
|
492
533
|
* directly by callers.
|
|
@@ -496,11 +537,17 @@ interface FindManyOptions<TCols extends Record<string, ColumnFactory>> {
|
|
|
496
537
|
* (using the transactional `tx` handle), so user code is identical
|
|
497
538
|
* regardless of transactional context.
|
|
498
539
|
*
|
|
499
|
-
* @template TCols The columns record passed to `defineTable`.
|
|
540
|
+
* @template TCols The columns record passed to `defineTable`. Drives the
|
|
541
|
+
* where-builder DSL and the `Row<TCols>` / `InsertRow<TCols>` shapes.
|
|
542
|
+
* @template TTable The underlying Drizzle pgTable type, inferred from the
|
|
543
|
+
* table value passed to `new TableClient(...)`. Carrying this through
|
|
544
|
+
* lets `.insert().values(...)`, `.update().set(...)`, and `.returning()`
|
|
545
|
+
* use Drizzle's own `InferInsertModel` / `InferSelectModel` instead of
|
|
546
|
+
* falling back to `as never` casts.
|
|
500
547
|
*/
|
|
501
|
-
declare class TableClient<TCols extends Record<string, ColumnFactory
|
|
548
|
+
declare class TableClient<TCols extends Record<string, ColumnFactory>, TTable extends PgTable = PgTable> {
|
|
502
549
|
/** The Drizzle table object. Exposed via `defineTable().table` for typed JOINs. */
|
|
503
|
-
readonly table:
|
|
550
|
+
readonly table: TTable;
|
|
504
551
|
/** Per-column kind metadata. Used by the where-builder for jsonb path validation. */
|
|
505
552
|
private readonly columnKinds;
|
|
506
553
|
/**
|
|
@@ -509,12 +556,14 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
509
556
|
* distinguish.
|
|
510
557
|
*/
|
|
511
558
|
private readonly db;
|
|
559
|
+
/** Primary key column names. Required by `claim()`. Empty for tables without a declared PK. */
|
|
560
|
+
private readonly primaryKeyColumns;
|
|
512
561
|
/**
|
|
513
562
|
* @internal — instances are created by `defineTable()`.
|
|
514
563
|
*/
|
|
515
564
|
constructor(/** The Drizzle table object. Exposed via `defineTable().table` for typed JOINs. */
|
|
516
565
|
|
|
517
|
-
table:
|
|
566
|
+
table: TTable, /** Per-column kind metadata. Used by the where-builder for jsonb path validation. */
|
|
518
567
|
|
|
519
568
|
columnKinds: Readonly<Record<string, ColumnKind>>,
|
|
520
569
|
/**
|
|
@@ -523,7 +572,23 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
523
572
|
* distinguish.
|
|
524
573
|
*/
|
|
525
574
|
|
|
526
|
-
db: PostgresJsDatabase)
|
|
575
|
+
db: PostgresJsDatabase, /** Primary key column names. Required by `claim()`. Empty for tables without a declared PK. */
|
|
576
|
+
|
|
577
|
+
primaryKeyColumns?: readonly string[]);
|
|
578
|
+
/**
|
|
579
|
+
* The table typed as the non-generic `PgTable` base.
|
|
580
|
+
*
|
|
581
|
+
* Drizzle's `.from()` (select) uses a conditional type
|
|
582
|
+
* `TableLikeHasEmptySelection<TTable>` that TypeScript cannot evaluate
|
|
583
|
+
* against a bounded generic `TTable extends PgTable` — it can only
|
|
584
|
+
* resolve when the argument is the concrete base `PgTable`. `.insert()`,
|
|
585
|
+
* `.update()`, and `.delete()` have simpler signatures (`<T extends
|
|
586
|
+
* PgTable>(t: T)`) that DO accept the generic directly, so those call
|
|
587
|
+
* sites keep `this.table` and still get `InferInsertModel<TTable>` /
|
|
588
|
+
* `InferSelectModel<TTable>` inference for `.values()`, `.set()`, and
|
|
589
|
+
* `.returning()`.
|
|
590
|
+
*/
|
|
591
|
+
private get _selectTable();
|
|
527
592
|
/**
|
|
528
593
|
* Find a single row matching the given where clause, or `null` if no row
|
|
529
594
|
* matches. Throws if the where is empty.
|
|
@@ -565,11 +630,36 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
565
630
|
* large tables.
|
|
566
631
|
*/
|
|
567
632
|
exists(where: WhereClause<TCols>): Promise<boolean>;
|
|
633
|
+
/**
|
|
634
|
+
* Return unique non-null values for a single column.
|
|
635
|
+
*
|
|
636
|
+
* Null values are excluded by default — pass `includeNull: true` to
|
|
637
|
+
* include them. Results can be filtered with `where` and ordered with
|
|
638
|
+
* `orderBy` (ascending or descending on the distinct column).
|
|
639
|
+
*
|
|
640
|
+
* @example Get distinct entity types from the audit log
|
|
641
|
+
* ```ts
|
|
642
|
+
* const types = await audit.client.distinct('entityType', { orderBy: 'asc' })
|
|
643
|
+
* ```
|
|
644
|
+
*
|
|
645
|
+
* @example Distinct with a filter
|
|
646
|
+
* ```ts
|
|
647
|
+
* const actions = await audit.client.distinct('action', {
|
|
648
|
+
* where: { userId: 'u_1' },
|
|
649
|
+
* orderBy: 'asc',
|
|
650
|
+
* })
|
|
651
|
+
* ```
|
|
652
|
+
*/
|
|
653
|
+
distinct<K extends keyof TCols & string>(column: K, options?: {
|
|
654
|
+
where?: WhereClause<TCols>;
|
|
655
|
+
orderBy?: 'asc' | 'desc'; /** Include null values in the result. Defaults to `false`. */
|
|
656
|
+
includeNull?: boolean;
|
|
657
|
+
}): Promise<ColumnValue<TCols[K]>[]>;
|
|
568
658
|
/**
|
|
569
659
|
* Insert a single row. Returns the inserted row (server-generated
|
|
570
660
|
* defaults populated).
|
|
571
661
|
*/
|
|
572
|
-
insert(values:
|
|
662
|
+
insert(values: InferInsertModel<TTable>): Promise<Row<TCols>>;
|
|
573
663
|
/**
|
|
574
664
|
* Upsert: insert a row, or update an existing row if a unique constraint
|
|
575
665
|
* conflict occurs.
|
|
@@ -577,9 +667,13 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
577
667
|
* `target` names the column(s) whose unique constraint should trigger
|
|
578
668
|
* the conflict path. `set` is the patch applied on conflict — when
|
|
579
669
|
* omitted, the conflict path applies the same `values` (i.e. "last
|
|
580
|
-
* write wins").
|
|
581
|
-
*
|
|
582
|
-
*
|
|
670
|
+
* write wins").
|
|
671
|
+
*
|
|
672
|
+
* `setWhere` adds a conditional WHERE to the conflict update path. If
|
|
673
|
+
* the condition does not match, the update is skipped and the existing
|
|
674
|
+
* row is returned unchanged (via a fallback SELECT). This enables
|
|
675
|
+
* patterns like "only update if the new version is higher than the
|
|
676
|
+
* existing one".
|
|
583
677
|
*
|
|
584
678
|
* @example Idempotent "mark as read" tracking
|
|
585
679
|
* ```ts
|
|
@@ -589,23 +683,24 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
589
683
|
* )
|
|
590
684
|
* ```
|
|
591
685
|
*
|
|
592
|
-
* @example
|
|
686
|
+
* @example Conditional update — only bump if newer
|
|
593
687
|
* ```ts
|
|
594
|
-
* await
|
|
595
|
-
* { key: '
|
|
596
|
-
* { target: 'key',
|
|
688
|
+
* await state.client.upsert(
|
|
689
|
+
* { key: 'sync', version: 5, data: '...' },
|
|
690
|
+
* { target: 'key', setWhere: { version: { lt: 5 } } },
|
|
597
691
|
* )
|
|
598
692
|
* ```
|
|
599
693
|
*/
|
|
600
|
-
upsert(values:
|
|
694
|
+
upsert(values: InferInsertModel<TTable>, opts: {
|
|
601
695
|
target: (keyof TCols & string) | (keyof TCols & string)[];
|
|
602
|
-
set?: Partial<
|
|
696
|
+
set?: Partial<InferInsertModel<TTable>>; /** Conditional WHERE on the conflict update path. Empty objects are ignored. */
|
|
697
|
+
setWhere?: WhereClause<TCols>;
|
|
603
698
|
}): Promise<Row<TCols>>;
|
|
604
699
|
/**
|
|
605
700
|
* Insert many rows in a single statement. Capped at {@link MAX_BATCH}.
|
|
606
701
|
* Returns all inserted rows in input order.
|
|
607
702
|
*/
|
|
608
|
-
insertMany(values:
|
|
703
|
+
insertMany(values: InferInsertModel<TTable>[]): Promise<Row<TCols>[]>;
|
|
609
704
|
/**
|
|
610
705
|
* Update **at most one** row matching the where clause. Returns the
|
|
611
706
|
* updated row, or `null` if no row matched.
|
|
@@ -627,12 +722,12 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
627
722
|
* the throw is to surface the bug, not to prevent it. Wrap in a
|
|
628
723
|
* transaction if you need atomic rollback.
|
|
629
724
|
*/
|
|
630
|
-
update(where: WhereClause<TCols>, patch: Partial<
|
|
725
|
+
update(where: WhereClause<TCols>, patch: Partial<InferInsertModel<TTable>>): Promise<Row<TCols> | null>;
|
|
631
726
|
/**
|
|
632
727
|
* Update all rows matching the where clause. Returns every updated row.
|
|
633
728
|
* Throws if the where is empty — there is no "update everything" path.
|
|
634
729
|
*/
|
|
635
|
-
updateMany(where: WhereClause<TCols>, patch: Partial<
|
|
730
|
+
updateMany(where: WhereClause<TCols>, patch: Partial<InferInsertModel<TTable>>): Promise<Row<TCols>[]>;
|
|
636
731
|
/**
|
|
637
732
|
* Delete **at most one** row matching the where clause. Returns the
|
|
638
733
|
* deleted row, or `null` if no row matched.
|
|
@@ -670,7 +765,79 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
670
765
|
* })
|
|
671
766
|
* ```
|
|
672
767
|
*/
|
|
673
|
-
transaction<T>(fn: (tx: TableClient<TCols>) => Promise<T>): Promise<T>;
|
|
768
|
+
transaction<T>(fn: (tx: TableClient<TCols, TTable>) => Promise<T>): Promise<T>;
|
|
769
|
+
/**
|
|
770
|
+
* Atomically claim rows using `FOR UPDATE SKIP LOCKED`.
|
|
771
|
+
*
|
|
772
|
+
* Selects rows matching `where`, locks them (skipping any already locked
|
|
773
|
+
* by another worker), updates them with `set`/`setSql`, and returns the
|
|
774
|
+
* claimed rows in a single atomic operation. This is the standard pattern
|
|
775
|
+
* for job queues, task distribution, and any producer-consumer table.
|
|
776
|
+
*
|
|
777
|
+
* Requires the table to have a declared primary key (either via
|
|
778
|
+
* `column.uuid({ primaryKey: true })` or `defineTable({ primaryKey })`.
|
|
779
|
+
*
|
|
780
|
+
* @example Job queue claim
|
|
781
|
+
* ```ts
|
|
782
|
+
* const jobs = await client.claim({
|
|
783
|
+
* where: { status: 'pending', runAt: { lte: new Date() } },
|
|
784
|
+
* set: { status: 'processing', lockedBy: workerId, lockedAt: new Date() },
|
|
785
|
+
* setSql: { attempts: sql`${jobsTable.table.attempts} + 1` },
|
|
786
|
+
* orderBy: [{ column: 'priority', dir: 'desc' }, { column: 'createdAt', dir: 'asc' }],
|
|
787
|
+
* limit: 5,
|
|
788
|
+
* })
|
|
789
|
+
* ```
|
|
790
|
+
*/
|
|
791
|
+
claim(options: ClaimOptions<TCols, TTable>): Promise<Row<TCols>[]>;
|
|
792
|
+
/**
|
|
793
|
+
* Run an aggregate query with GROUP BY.
|
|
794
|
+
*
|
|
795
|
+
* Each key in `select` is an output alias mapped to an aggregate
|
|
796
|
+
* specification. The `groupBy` columns are included automatically in
|
|
797
|
+
* the result. Returns typed rows with grouped column values plus the
|
|
798
|
+
* computed aggregates.
|
|
799
|
+
*
|
|
800
|
+
* @example Count jobs by status
|
|
801
|
+
* ```ts
|
|
802
|
+
* const rows = await client.aggregate({
|
|
803
|
+
* select: { count: { fn: 'count' } },
|
|
804
|
+
* groupBy: ['status'],
|
|
805
|
+
* })
|
|
806
|
+
* // → [{ status: 'pending', count: 12 }, { status: 'completed', count: 45 }]
|
|
807
|
+
* ```
|
|
808
|
+
*
|
|
809
|
+
* @example Average priority of open jobs
|
|
810
|
+
* ```ts
|
|
811
|
+
* const [row] = await client.aggregate({
|
|
812
|
+
* select: { avgPriority: { fn: 'avg', column: 'priority' } },
|
|
813
|
+
* where: { status: 'open' },
|
|
814
|
+
* })
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
817
|
+
aggregate<TResult extends Record<string, unknown> = Record<string, unknown>>(options: AggregateOptions<TCols>): Promise<TResult[]>;
|
|
818
|
+
/**
|
|
819
|
+
* Fast approximate row count using Postgres `reltuples` statistics.
|
|
820
|
+
*
|
|
821
|
+
* Returns the estimated row count from `pg_class` — updated by
|
|
822
|
+
* `ANALYZE` and autovacuum. Much faster than `COUNT(*)` on large
|
|
823
|
+
* tables (no sequential scan), but may be stale by up to a few
|
|
824
|
+
* percent. Returns 0 for tables that have never been analyzed.
|
|
825
|
+
*
|
|
826
|
+
* Use `count()` when you need an exact number. Use `countEstimate()`
|
|
827
|
+
* for UI display, pagination hints, or "is this table large?" checks
|
|
828
|
+
* where ±5% accuracy is fine.
|
|
829
|
+
*
|
|
830
|
+
* @example
|
|
831
|
+
* ```ts
|
|
832
|
+
* const approx = await client.countEstimate()
|
|
833
|
+
* if (approx > 100_000) {
|
|
834
|
+
* // Switch to keyset pagination instead of offset
|
|
835
|
+
* }
|
|
836
|
+
* ```
|
|
837
|
+
*/
|
|
838
|
+
countEstimate(): Promise<number>;
|
|
839
|
+
/** Build a single aggregate SQL expression from a spec. */
|
|
840
|
+
private buildAggregateExpr;
|
|
674
841
|
private buildWhereOrThrow;
|
|
675
842
|
private validateLimit;
|
|
676
843
|
}
|
|
@@ -680,14 +847,19 @@ declare class TableClient<TCols extends Record<string, ColumnFactory>> {
|
|
|
680
847
|
* The result of `defineTable()`.
|
|
681
848
|
*
|
|
682
849
|
* @template TCols The columns record passed to `defineTable`.
|
|
850
|
+
* @template TTable The concrete Drizzle `pgTable` type produced by the
|
|
851
|
+
* definition. Defaulted to the non-generic `PgTable` for callers that
|
|
852
|
+
* pass `DefinedTable` around without propagating inference — inside
|
|
853
|
+
* `defineTable` itself, the actual `typeof table` is captured so
|
|
854
|
+
* `makeClient` returns a fully-typed `TableClient<TCols, typeof table>`.
|
|
683
855
|
*/
|
|
684
|
-
interface DefinedTable<TCols extends Record<string, ColumnFactory>> {
|
|
856
|
+
interface DefinedTable<TCols extends Record<string, ColumnFactory>, TTable extends PgTable = PgTableWithColumns<TableConfig>> {
|
|
685
857
|
/**
|
|
686
858
|
* The underlying Drizzle `pgTable`. Exposed so callers can use it in
|
|
687
859
|
* typed JOINs (the one sanctioned escape valve), and so it can be
|
|
688
|
-
*
|
|
860
|
+
* included in `Plugin.tables` for migration discovery by `lumi migrate`.
|
|
689
861
|
*/
|
|
690
|
-
table:
|
|
862
|
+
table: TTable;
|
|
691
863
|
/**
|
|
692
864
|
* The original schema metadata. Useful for introspection / tooling
|
|
693
865
|
* that needs to know about indexes, unique constraints, etc.
|
|
@@ -698,6 +870,12 @@ interface DefinedTable<TCols extends Record<string, ColumnFactory>> {
|
|
|
698
870
|
* by the where-builder for jsonb path validation.
|
|
699
871
|
*/
|
|
700
872
|
columnKinds: Readonly<Record<string, ColumnKind>>;
|
|
873
|
+
/**
|
|
874
|
+
* Primary key column names (JS property names). Detected from either
|
|
875
|
+
* `schema.primaryKey` or column-level `{ primaryKey: true }`. Empty
|
|
876
|
+
* array if no PK is declared. Required by `claim()`.
|
|
877
|
+
*/
|
|
878
|
+
primaryKeyColumns: readonly string[];
|
|
701
879
|
/**
|
|
702
880
|
* Build a typed CRUD client wired to the given database handle.
|
|
703
881
|
*
|
|
@@ -705,7 +883,7 @@ interface DefinedTable<TCols extends Record<string, ColumnFactory>> {
|
|
|
705
883
|
* cache it. The client is stateless aside from the db handle, so it
|
|
706
884
|
* is safe to share.
|
|
707
885
|
*/
|
|
708
|
-
makeClient(db: PostgresJsDatabase): TableClient<TCols>;
|
|
886
|
+
makeClient(db: PostgresJsDatabase): TableClient<TCols, TTable>;
|
|
709
887
|
}
|
|
710
888
|
/**
|
|
711
889
|
* Define a typed table.
|
|
@@ -718,7 +896,59 @@ interface DefinedTable<TCols extends Record<string, ColumnFactory>> {
|
|
|
718
896
|
* @throws if the table name doesn't match the snake_case regex, or if
|
|
719
897
|
* the same name is registered twice with different table objects.
|
|
720
898
|
*/
|
|
721
|
-
declare function defineTable<const TCols extends Record<string, ColumnFactory>>(def: TableDefinition<TCols>):
|
|
899
|
+
declare function defineTable<const TCols extends Record<string, ColumnFactory>>(def: TableDefinition<TCols>): {
|
|
900
|
+
table: PgTableWithColumns<{
|
|
901
|
+
name: string;
|
|
902
|
+
schema: undefined;
|
|
903
|
+
columns: {
|
|
904
|
+
[x: string]: _$drizzle_orm_pg_core0.PgColumn<{
|
|
905
|
+
name: string;
|
|
906
|
+
tableName: string;
|
|
907
|
+
dataType: _$drizzle_orm0.ColumnDataType;
|
|
908
|
+
columnType: string;
|
|
909
|
+
data: unknown;
|
|
910
|
+
driverParam: unknown;
|
|
911
|
+
notNull: false;
|
|
912
|
+
hasDefault: false;
|
|
913
|
+
isPrimaryKey: false;
|
|
914
|
+
isAutoincrement: false;
|
|
915
|
+
hasRuntimeDefault: false;
|
|
916
|
+
enumValues: string[] | undefined;
|
|
917
|
+
baseColumn: never;
|
|
918
|
+
identity: undefined;
|
|
919
|
+
generated: undefined;
|
|
920
|
+
}, {}, {}>;
|
|
921
|
+
};
|
|
922
|
+
dialect: "pg";
|
|
923
|
+
}>;
|
|
924
|
+
schema: TableDefinition<TCols>;
|
|
925
|
+
columnKinds: Readonly<Record<string, ColumnKind>>;
|
|
926
|
+
primaryKeyColumns: readonly string[];
|
|
927
|
+
makeClient: (db: PostgresJsDatabase) => TableClient<TCols, PgTableWithColumns<{
|
|
928
|
+
name: string;
|
|
929
|
+
schema: undefined;
|
|
930
|
+
columns: {
|
|
931
|
+
[x: string]: _$drizzle_orm_pg_core0.PgColumn<{
|
|
932
|
+
name: string;
|
|
933
|
+
tableName: string;
|
|
934
|
+
dataType: _$drizzle_orm0.ColumnDataType;
|
|
935
|
+
columnType: string;
|
|
936
|
+
data: unknown;
|
|
937
|
+
driverParam: unknown;
|
|
938
|
+
notNull: false;
|
|
939
|
+
hasDefault: false;
|
|
940
|
+
isPrimaryKey: false;
|
|
941
|
+
isAutoincrement: false;
|
|
942
|
+
hasRuntimeDefault: false;
|
|
943
|
+
enumValues: string[] | undefined;
|
|
944
|
+
baseColumn: never;
|
|
945
|
+
identity: undefined;
|
|
946
|
+
generated: undefined;
|
|
947
|
+
}, {}, {}>;
|
|
948
|
+
};
|
|
949
|
+
dialect: "pg";
|
|
950
|
+
}>>;
|
|
951
|
+
};
|
|
722
952
|
//#endregion
|
|
723
953
|
//#region src/table/registry.d.ts
|
|
724
954
|
declare class TableRegistryImpl {
|
|
@@ -740,8 +970,8 @@ declare class TableRegistryImpl {
|
|
|
740
970
|
/**
|
|
741
971
|
* Return every registered table as a `{ [name]: PgTable }` map.
|
|
742
972
|
*
|
|
743
|
-
* Useful for `createTestDb().push(tableRegistry.allTables())` and
|
|
744
|
-
*
|
|
973
|
+
* Useful for `createTestDb().push(tableRegistry.allTables())` and
|
|
974
|
+
* runtime introspection.
|
|
745
975
|
*/
|
|
746
976
|
allTables(): Record<string, PgTable>;
|
|
747
977
|
/**
|
|
@@ -792,5 +1022,5 @@ declare class WhereBuilderError extends Error {
|
|
|
792
1022
|
*/
|
|
793
1023
|
declare function isNonEmptyWhere(clause: unknown): boolean;
|
|
794
1024
|
//#endregion
|
|
795
|
-
export { type AnyPgColumn, type ColumnFactory, type ColumnKind, type ColumnOperators, type ColumnValue, DEFAULT_LIMIT, type DbConfig, type DefinedTable, type FindManyOptions, type IndexDefinition, type InsertRow, MAX_BATCH, MAX_LIMIT, type MigrateArgs, type MigrationLoader, type MigrationModule, type MigrationSource, type MigrationStatus, type OrderBySpec, type Row, type SchemaRegistry, TableClient, TableClientError, type TableDefinition, type UniqueDefinition, WhereBuilderError, type WhereClause, column, createDbClient, createReadOnlyClient, createSchemaRegistry, createTableRegistry, defineTable, discoverMigrations, getMigrationStatus, isNonEmptyWhere, rollbackMigrations, runMigrations, schemaRegistry, tableRegistry };
|
|
1025
|
+
export { type AnyPgColumn, type ClaimOptions, type ColumnFactory, type ColumnKind, type ColumnOperators, type ColumnValue, DEFAULT_LIMIT, type DbConfig, type DefinedTable, type FindManyOptions, type IndexDefinition, type InsertRow, MAX_BATCH, MAX_LIMIT, type MigrateArgs, type MigrationLoader, type MigrationModule, type MigrationSource, type MigrationStatus, type OrderBySpec, type Row, type SchemaRegistry, TableClient, TableClientError, type TableDefinition, type UniqueDefinition, WhereBuilderError, type WhereClause, column, createDbClient, createReadOnlyClient, createSchemaRegistry, createTableRegistry, defineTable, discoverMigrations, getMigrationStatus, isNonEmptyWhere, rollbackMigrations, runMigrations, schemaRegistry, tableRegistry };
|
|
796
1026
|
//# sourceMappingURL=index.d.mts.map
|