@ddd-ts-kit/drizzle 0.0.0-stage → 0.1.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/README.md +476 -2
- package/dist/postgres/columns/audit-columns.d.ts +13 -0
- package/dist/postgres/columns/audit-columns.d.ts.map +1 -0
- package/dist/postgres/columns/audit-columns.js +17 -0
- package/dist/postgres/columns/audit-columns.js.map +1 -0
- package/dist/postgres/columns/instant.d.ts +3 -0
- package/dist/postgres/columns/instant.d.ts.map +1 -0
- package/dist/postgres/columns/instant.js +6 -0
- package/dist/postgres/columns/instant.js.map +1 -0
- package/dist/postgres/columns/tenant-column.d.ts +5 -0
- package/dist/postgres/columns/tenant-column.d.ts.map +1 -0
- package/dist/postgres/columns/tenant-column.js +6 -0
- package/dist/postgres/columns/tenant-column.js.map +1 -0
- package/dist/postgres/outbox/drizzle-outbox-store.d.ts +39 -0
- package/dist/postgres/outbox/drizzle-outbox-store.d.ts.map +1 -0
- package/dist/postgres/outbox/drizzle-outbox-store.js +139 -0
- package/dist/postgres/outbox/drizzle-outbox-store.js.map +1 -0
- package/dist/postgres/outbox/drizzle-processed-event-store.d.ts +21 -0
- package/dist/postgres/outbox/drizzle-processed-event-store.d.ts.map +1 -0
- package/dist/postgres/outbox/drizzle-processed-event-store.js +24 -0
- package/dist/postgres/outbox/drizzle-processed-event-store.js.map +1 -0
- package/dist/postgres/outbox/outbox-table.d.ts +254 -0
- package/dist/postgres/outbox/outbox-table.d.ts.map +1 -0
- package/dist/postgres/outbox/outbox-table.js +33 -0
- package/dist/postgres/outbox/outbox-table.js.map +1 -0
- package/dist/postgres/outbox/processed-events-table.d.ts +61 -0
- package/dist/postgres/outbox/processed-events-table.d.ts.map +1 -0
- package/dist/postgres/outbox/processed-events-table.js +14 -0
- package/dist/postgres/outbox/processed-events-table.js.map +1 -0
- package/dist/postgres/read-model/column-of.d.ts +4 -0
- package/dist/postgres/read-model/column-of.d.ts.map +1 -0
- package/dist/postgres/read-model/column-of.js +9 -0
- package/dist/postgres/read-model/column-of.js.map +1 -0
- package/dist/postgres/read-model/criteria-to-drizzle.d.ts +21 -0
- package/dist/postgres/read-model/criteria-to-drizzle.d.ts.map +1 -0
- package/dist/postgres/read-model/criteria-to-drizzle.js +26 -0
- package/dist/postgres/read-model/criteria-to-drizzle.js.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-options.d.ts +10 -0
- package/dist/postgres/read-model/drizzle-read-model-options.d.ts.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-options.js +2 -0
- package/dist/postgres/read-model/drizzle-read-model-options.js.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-store.d.ts +18 -0
- package/dist/postgres/read-model/drizzle-read-model-store.d.ts.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-store.js +13 -0
- package/dist/postgres/read-model/drizzle-read-model-store.js.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-table.d.ts +35 -0
- package/dist/postgres/read-model/drizzle-read-model-table.d.ts.map +1 -0
- package/dist/postgres/read-model/drizzle-read-model-table.js +92 -0
- package/dist/postgres/read-model/drizzle-read-model-table.js.map +1 -0
- package/dist/postgres/read-model/drizzle-stamped-rows.d.ts +29 -0
- package/dist/postgres/read-model/drizzle-stamped-rows.d.ts.map +1 -0
- package/dist/postgres/read-model/drizzle-stamped-rows.js +79 -0
- package/dist/postgres/read-model/drizzle-stamped-rows.js.map +1 -0
- package/dist/postgres/read-model/like-pattern.d.ts +4 -0
- package/dist/postgres/read-model/like-pattern.d.ts.map +1 -0
- package/dist/postgres/read-model/like-pattern.js +6 -0
- package/dist/postgres/read-model/like-pattern.js.map +1 -0
- package/dist/postgres/read-model/predicate-to-drizzle.d.ts +12 -0
- package/dist/postgres/read-model/predicate-to-drizzle.d.ts.map +1 -0
- package/dist/postgres/read-model/predicate-to-drizzle.js +43 -0
- package/dist/postgres/read-model/predicate-to-drizzle.js.map +1 -0
- package/dist/postgres/read-model/read-model-columns.d.ts +13 -0
- package/dist/postgres/read-model/read-model-columns.d.ts.map +1 -0
- package/dist/postgres/read-model/read-model-columns.js +17 -0
- package/dist/postgres/read-model/read-model-columns.js.map +1 -0
- package/dist/postgres/read-model/row.mapper.d.ts +15 -0
- package/dist/postgres/read-model/row.mapper.d.ts.map +1 -0
- package/dist/postgres/read-model/row.mapper.js +26 -0
- package/dist/postgres/read-model/row.mapper.js.map +1 -0
- package/dist/postgres/read-model/rows-of.d.ts +3 -0
- package/dist/postgres/read-model/rows-of.d.ts.map +1 -0
- package/dist/postgres/read-model/rows-of.js +10 -0
- package/dist/postgres/read-model/rows-of.js.map +1 -0
- package/dist/postgres/read-model/stamp-columns.d.ts +10 -0
- package/dist/postgres/read-model/stamp-columns.d.ts.map +1 -0
- package/dist/postgres/read-model/stamp-columns.js +14 -0
- package/dist/postgres/read-model/stamp-columns.js.map +1 -0
- package/dist/postgres/schema/context-schema.d.ts +4 -0
- package/dist/postgres/schema/context-schema.d.ts.map +1 -0
- package/dist/postgres/schema/context-schema.js +7 -0
- package/dist/postgres/schema/context-schema.js.map +1 -0
- package/dist/postgres/schema/table-in.d.ts +3 -0
- package/dist/postgres/schema/table-in.d.ts.map +1 -0
- package/dist/postgres/schema/table-in.js +5 -0
- package/dist/postgres/schema/table-in.js.map +1 -0
- package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.d.ts +16 -0
- package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.d.ts.map +1 -0
- package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.js +25 -0
- package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.js.map +1 -0
- package/dist/postgres/unit-of-work/drizzle-context.d.ts +19 -0
- package/dist/postgres/unit-of-work/drizzle-context.d.ts.map +1 -0
- package/dist/postgres/unit-of-work/drizzle-context.js +15 -0
- package/dist/postgres/unit-of-work/drizzle-context.js.map +1 -0
- package/dist/postgres.d.ts +17 -0
- package/dist/postgres.d.ts.map +1 -0
- package/dist/postgres.js +17 -0
- package/dist/postgres.js.map +1 -0
- package/package.json +40 -4
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { and, asc, desc, sql } from 'drizzle-orm';
|
|
2
|
+
import { columnOf } from './column-of.js';
|
|
3
|
+
import { predicateToDrizzle } from './predicate-to-drizzle.js';
|
|
4
|
+
/**
|
|
5
|
+
* Turns a criteria plan into the parts of a query on the table of a read model:
|
|
6
|
+
* `db.select().from(appointments).where(where).orderBy(...orderBy).limit(limit).offset(offset)`,
|
|
7
|
+
* then `pageOfPlan(plan, rows)`. A field that may be null is ordered as the plan means it:
|
|
8
|
+
* nulls last ascending, first descending.
|
|
9
|
+
*/
|
|
10
|
+
export function criteriaToDrizzle(plan, columns) {
|
|
11
|
+
const counted = predicateToDrizzle(plan.filter, columns);
|
|
12
|
+
return {
|
|
13
|
+
where: and(counted, predicateToDrizzle(plan.seek, columns)),
|
|
14
|
+
counted,
|
|
15
|
+
orderBy: plan.sort.map(({ field, direction }) => {
|
|
16
|
+
const column = columnOf(columns, field);
|
|
17
|
+
if (plan.fields[field]?.nullable !== true) {
|
|
18
|
+
return direction === 'asc' ? asc(column) : desc(column);
|
|
19
|
+
}
|
|
20
|
+
return direction === 'asc' ? sql `${column} asc nulls last` : sql `${column} desc nulls first`;
|
|
21
|
+
}),
|
|
22
|
+
limit: plan.fetch,
|
|
23
|
+
offset: plan.offset,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=criteria-to-drizzle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"criteria-to-drizzle.js","sourceRoot":"","sources":["../../../src/postgres/read-model/criteria-to-drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAY,MAAM,aAAa,CAAC;AAG5D,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAa/D;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAkB,EAAE,OAA2C;IAC/F,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEzD,OAAO;QACL,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3D,OAAO;QACP,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE;YAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAExC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,KAAK,IAAI,EAAE,CAAC;gBAC1C,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1D,CAAC;YAED,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAA,GAAG,MAAM,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAA,GAAG,MAAM,mBAAmB,CAAC;QAC/F,CAAC,CAAC;QACF,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PgColumn, PgTable } from 'drizzle-orm/pg-core';
|
|
2
|
+
export interface DrizzleReadModelOptions<Row> {
|
|
3
|
+
/** The table of the read model, declared with `...readModelColumns()`. */
|
|
4
|
+
readonly table: PgTable;
|
|
5
|
+
/** The column of the key, which is the primary key of the table. */
|
|
6
|
+
readonly key: PgColumn;
|
|
7
|
+
/** The column of every field of the row: `{ startsAt: appointments.startsAt }`. */
|
|
8
|
+
readonly columns: Readonly<Record<keyof Row & string, PgColumn>>;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=drizzle-read-model-options.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-options.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,uBAAuB,CAAC,GAAG;IAC1C,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;CAClE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-options.js","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-options.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ExtractTablesWithRelations, TablesRelationalConfig } from 'drizzle-orm';
|
|
2
|
+
import type { PgQueryResultHKT } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { TableReadModelStore, type CriteriaDefinition } from '@ddd-ts-kit/kernel';
|
|
4
|
+
import type { DrizzleContext } from '../unit-of-work/drizzle-context.js';
|
|
5
|
+
import type { DrizzleReadModelOptions } from './drizzle-read-model-options.js';
|
|
6
|
+
export interface DrizzleReadModel<Row> extends DrizzleReadModelOptions<Row> {
|
|
7
|
+
/** What a read of the read model may filter and sort by. */
|
|
8
|
+
readonly definition: CriteriaDefinition<Row>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The read model of a projection in a drizzle table. The adapter of a read model port extends
|
|
12
|
+
* it and adds nothing: `class DrizzleAppointmentList extends DrizzleReadModelStore<AppointmentRow, NodePgQueryResultHKT>
|
|
13
|
+
* implements AppointmentList`. Its `table` is what a `ProjectionRebuild` takes.
|
|
14
|
+
*/
|
|
15
|
+
export declare class DrizzleReadModelStore<Row extends object, Q extends PgQueryResultHKT, F extends Record<string, unknown> = Record<string, never>, S extends TablesRelationalConfig = ExtractTablesWithRelations<F>> extends TableReadModelStore<Row> {
|
|
16
|
+
constructor(context: DrizzleContext<Q, F, S>, { definition, ...options }: DrizzleReadModel<Row>);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=drizzle-read-model-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-store.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG/E,MAAM,WAAW,gBAAgB,CAAC,GAAG,CAAE,SAAQ,uBAAuB,CAAC,GAAG,CAAC;IACzE,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;CAC9C;AAED;;;;GAIG;AACH,qBAAa,qBAAqB,CAChC,GAAG,SAAS,MAAM,EAClB,CAAC,SAAS,gBAAgB,EAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACzD,CAAC,SAAS,sBAAsB,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAChE,SAAQ,mBAAmB,CAAC,GAAG,CAAC;IAChC,YAAY,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,EAAE,EAAE,gBAAgB,CAAC,GAAG,CAAC,EAE9F;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { TableReadModelStore } from '@ddd-ts-kit/kernel';
|
|
2
|
+
import { DrizzleReadModelTable } from './drizzle-read-model-table.js';
|
|
3
|
+
/**
|
|
4
|
+
* The read model of a projection in a drizzle table. The adapter of a read model port extends
|
|
5
|
+
* it and adds nothing: `class DrizzleAppointmentList extends DrizzleReadModelStore<AppointmentRow, NodePgQueryResultHKT>
|
|
6
|
+
* implements AppointmentList`. Its `table` is what a `ProjectionRebuild` takes.
|
|
7
|
+
*/
|
|
8
|
+
export class DrizzleReadModelStore extends TableReadModelStore {
|
|
9
|
+
constructor(context, { definition, ...options }) {
|
|
10
|
+
super(new DrizzleReadModelTable(context, options), definition);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=drizzle-read-model-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-store.js","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAA2B,MAAM,oBAAoB,CAAC;AAGlF,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAOtE;;;;GAIG;AACH,MAAM,OAAO,qBAKX,SAAQ,mBAAwB;IAChC,YAAY,OAAgC,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,EAAyB;QAC7F,KAAK,CAAC,IAAI,qBAAqB,CAAe,OAAO,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/E,CAAC;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ExtractTablesWithRelations, type TablesRelationalConfig } from 'drizzle-orm';
|
|
2
|
+
import { type PgQueryResultHKT } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { type CriteriaPlan, type EventStamp, type SearchedRows, type ReadModelRows, type ReadModelTable, type StampedRow, type TouchedKey } from '@ddd-ts-kit/kernel';
|
|
4
|
+
import type { DrizzleContext } from '../unit-of-work/drizzle-context.js';
|
|
5
|
+
import type { DrizzleReadModelOptions } from './drizzle-read-model-options.js';
|
|
6
|
+
/**
|
|
7
|
+
* The table of one read model on drizzle: what `TableReadModelStore` and `ProjectionRebuild`
|
|
8
|
+
* are given. Every statement runs on the executor of the context, so a write made by a
|
|
9
|
+
* projection commits with the processed mark of its event.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DrizzleReadModelTable<Row extends object, Q extends PgQueryResultHKT, F extends Record<string, unknown> = Record<string, never>, S extends TablesRelationalConfig = ExtractTablesWithRelations<F>> implements ReadModelTable<Row> {
|
|
12
|
+
private readonly context;
|
|
13
|
+
private readonly options;
|
|
14
|
+
private readonly target;
|
|
15
|
+
private readonly rows;
|
|
16
|
+
private readonly copy;
|
|
17
|
+
private readonly rebuild;
|
|
18
|
+
constructor(context: DrizzleContext<Q, F, S>, options: DrizzleReadModelOptions<Row>);
|
|
19
|
+
find(key: string): Promise<StampedRow<Row> | undefined>;
|
|
20
|
+
insert(entry: StampedRow<Row>): Promise<boolean>;
|
|
21
|
+
replace(entry: StampedRow<Row>, held: EventStamp): Promise<boolean>;
|
|
22
|
+
search(plan: CriteriaPlan): Promise<SearchedRows<Row>>;
|
|
23
|
+
rebuilding(): Promise<boolean>;
|
|
24
|
+
touch(key: string): Promise<void>;
|
|
25
|
+
beginRebuild(): Promise<void>;
|
|
26
|
+
shadow(): ReadModelRows<Row>;
|
|
27
|
+
touched(limit: number): Promise<readonly TouchedKey[]>;
|
|
28
|
+
settle(keys: readonly TouchedKey[]): Promise<void>;
|
|
29
|
+
holdWriters(): Promise<void>;
|
|
30
|
+
promote(): Promise<void>;
|
|
31
|
+
abandonRebuild(): Promise<void>;
|
|
32
|
+
/** The text between the `$n` of a statement is raw SQL written by the kernel; each `$n` becomes a parameter. */
|
|
33
|
+
private run;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=drizzle-read-model-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-table.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,0BAA0B,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAM/E;;;;GAIG;AACH,qBAAa,qBAAqB,CAChC,GAAG,SAAS,MAAM,EAClB,CAAC,SAAS,gBAAgB,EAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EACzD,CAAC,SAAS,sBAAsB,GAAG,0BAA0B,CAAC,CAAC,CAAC,CAChE,YAAW,cAAc,CAAC,GAAG,CAAC;IAW5B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAV1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IAEtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IAExD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IAExD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2B;IAEnD,YACmB,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAChC,OAAO,EAAE,uBAAuB,CAAC,GAAG,CAAC,EAYvD;IAED,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAEtD;IAED,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/C;IAED,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAElE;IAEK,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAkB3D;IAED,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAE7B;IAED,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEhC;IAED,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5B;IAED,MAAM,IAAI,aAAa,CAAC,GAAG,CAAC,CAE3B;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAErD;IAED,MAAM,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjD;IAED,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;IAED,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvB;IAED,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAE9B;IAED,gHAAgH;YAClG,GAAG;CAelB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { and, eq, sql } from 'drizzle-orm';
|
|
2
|
+
import { getTableConfig } from 'drizzle-orm/pg-core';
|
|
3
|
+
import { PostgresReadModelRebuild, } from '@ddd-ts-kit/kernel';
|
|
4
|
+
import { criteriaToDrizzle } from './criteria-to-drizzle.js';
|
|
5
|
+
import { DrizzleStampedRows } from './drizzle-stamped-rows.js';
|
|
6
|
+
import { RowMapper } from './row.mapper.js';
|
|
7
|
+
import { rowsOf } from './rows-of.js';
|
|
8
|
+
import { stampColumns } from './stamp-columns.js';
|
|
9
|
+
/**
|
|
10
|
+
* The table of one read model on drizzle: what `TableReadModelStore` and `ProjectionRebuild`
|
|
11
|
+
* are given. Every statement runs on the executor of the context, so a write made by a
|
|
12
|
+
* projection commits with the processed mark of its event.
|
|
13
|
+
*/
|
|
14
|
+
export class DrizzleReadModelTable {
|
|
15
|
+
context;
|
|
16
|
+
options;
|
|
17
|
+
target;
|
|
18
|
+
rows;
|
|
19
|
+
copy;
|
|
20
|
+
rebuild;
|
|
21
|
+
constructor(context, options) {
|
|
22
|
+
this.context = context;
|
|
23
|
+
this.options = options;
|
|
24
|
+
const { name, schema } = getTableConfig(options.table);
|
|
25
|
+
this.target = { schema, name, key: options.key, columns: options.columns, stamps: stampColumns(options.table) };
|
|
26
|
+
this.rows = new DrizzleStampedRows(context, this.target);
|
|
27
|
+
this.copy = new DrizzleStampedRows(context, { ...this.target, name: PostgresReadModelRebuild.shadowOf(name) });
|
|
28
|
+
this.rebuild = new PostgresReadModelRebuild((statement, parameters) => this.run(statement, parameters), {
|
|
29
|
+
table: name,
|
|
30
|
+
...(schema === undefined ? {} : { schema }),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
find(key) {
|
|
34
|
+
return this.rows.find(key);
|
|
35
|
+
}
|
|
36
|
+
insert(entry) {
|
|
37
|
+
return this.rows.insert(entry);
|
|
38
|
+
}
|
|
39
|
+
replace(entry, held) {
|
|
40
|
+
return this.rows.replace(entry, held);
|
|
41
|
+
}
|
|
42
|
+
async search(plan) {
|
|
43
|
+
const { table, columns } = this.options;
|
|
44
|
+
const { where, counted, orderBy, limit, offset } = criteriaToDrizzle(plan, columns);
|
|
45
|
+
const kept = eq(this.target.stamps.deleted, false);
|
|
46
|
+
const db = this.context.executor();
|
|
47
|
+
const mapper = new RowMapper(columns);
|
|
48
|
+
const records = await db
|
|
49
|
+
.select(columns)
|
|
50
|
+
.from(table)
|
|
51
|
+
.where(and(kept, where))
|
|
52
|
+
.orderBy(...orderBy)
|
|
53
|
+
.limit(limit)
|
|
54
|
+
.offset(offset);
|
|
55
|
+
const rows = records.map((record) => mapper.fromSelected(record));
|
|
56
|
+
return plan.kind === 'cursor' ? { rows } : { rows, total: await db.$count(table, and(kept, counted)) };
|
|
57
|
+
}
|
|
58
|
+
rebuilding() {
|
|
59
|
+
return this.rebuild.rebuilding();
|
|
60
|
+
}
|
|
61
|
+
touch(key) {
|
|
62
|
+
return this.rebuild.touch(key);
|
|
63
|
+
}
|
|
64
|
+
beginRebuild() {
|
|
65
|
+
return this.rebuild.begin();
|
|
66
|
+
}
|
|
67
|
+
shadow() {
|
|
68
|
+
return this.copy;
|
|
69
|
+
}
|
|
70
|
+
touched(limit) {
|
|
71
|
+
return this.rebuild.touched(limit);
|
|
72
|
+
}
|
|
73
|
+
settle(keys) {
|
|
74
|
+
return this.rebuild.settle(keys);
|
|
75
|
+
}
|
|
76
|
+
holdWriters() {
|
|
77
|
+
return this.rebuild.holdWriters();
|
|
78
|
+
}
|
|
79
|
+
promote() {
|
|
80
|
+
return this.rebuild.promote();
|
|
81
|
+
}
|
|
82
|
+
abandonRebuild() {
|
|
83
|
+
return this.rebuild.abandon();
|
|
84
|
+
}
|
|
85
|
+
/** The text between the `$n` of a statement is raw SQL written by the kernel; each `$n` becomes a parameter. */
|
|
86
|
+
async run(statement, parameters) {
|
|
87
|
+
const pieces = statement.split(/\$\d+/);
|
|
88
|
+
const query = sql.join(pieces.flatMap((piece, index) => index < parameters.length ? [sql.raw(piece), sql `${parameters[index]}`] : [sql.raw(piece)]), sql.raw(''));
|
|
89
|
+
return rowsOf(await this.context.executor().execute(query));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=drizzle-read-model-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-read-model-table.js","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-read-model-table.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type TablesRelationalConfig } from 'drizzle-orm';
|
|
2
|
+
import type { PgColumn, PgQueryResultHKT } from 'drizzle-orm/pg-core';
|
|
3
|
+
import type { EventStamp, ReadModelRows, StampedRow } from '@ddd-ts-kit/kernel';
|
|
4
|
+
import type { DrizzleContext } from '../unit-of-work/drizzle-context.js';
|
|
5
|
+
import type { StampColumns } from './stamp-columns.js';
|
|
6
|
+
export interface StampedTable {
|
|
7
|
+
readonly schema: string | undefined;
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly key: PgColumn;
|
|
10
|
+
readonly columns: Readonly<Record<string, PgColumn>>;
|
|
11
|
+
readonly stamps: StampColumns;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The stamped rows of one table, the copy of a rebuild as well as the table itself: the
|
|
15
|
+
* table is named, since the copy has no drizzle definition of its own. Identifiers are quoted
|
|
16
|
+
* by drizzle and every value is a parameter.
|
|
17
|
+
*/
|
|
18
|
+
export declare class DrizzleStampedRows<Row extends object, Q extends PgQueryResultHKT, F extends Record<string, unknown>, S extends TablesRelationalConfig> implements ReadModelRows<Row> {
|
|
19
|
+
private readonly context;
|
|
20
|
+
private readonly target;
|
|
21
|
+
private readonly mapper;
|
|
22
|
+
constructor(context: DrizzleContext<Q, F, S>, target: StampedTable);
|
|
23
|
+
find(key: string): Promise<StampedRow<Row> | undefined>;
|
|
24
|
+
insert(entry: StampedRow<Row>): Promise<boolean>;
|
|
25
|
+
replace(entry: StampedRow<Row>, held: EventStamp): Promise<boolean>;
|
|
26
|
+
private valuesOf;
|
|
27
|
+
private table;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=drizzle-stamped-rows.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-stamped-rows.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-stamped-rows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;CAC/B;AAED;;;;GAIG;AACH,qBAAa,kBAAkB,CAC7B,GAAG,SAAS,MAAM,EAClB,CAAC,SAAS,gBAAgB,EAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,sBAAsB,CAChC,YAAW,aAAa,CAAC,GAAG,CAAC;IAK3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IAExC,YACmB,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAChC,MAAM,EAAE,YAAY,EAGtC;IAEK,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,CAwB5D;IAEK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CA0BrD;IAEK,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAiBxE;IAED,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,KAAK;CAKd"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { RowMapper } from './row.mapper.js';
|
|
3
|
+
import { rowsOf } from './rows-of.js';
|
|
4
|
+
/**
|
|
5
|
+
* The stamped rows of one table, the copy of a rebuild as well as the table itself: the
|
|
6
|
+
* table is named, since the copy has no drizzle definition of its own. Identifiers are quoted
|
|
7
|
+
* by drizzle and every value is a parameter.
|
|
8
|
+
*/
|
|
9
|
+
export class DrizzleStampedRows {
|
|
10
|
+
context;
|
|
11
|
+
target;
|
|
12
|
+
mapper;
|
|
13
|
+
constructor(context, target) {
|
|
14
|
+
this.context = context;
|
|
15
|
+
this.target = target;
|
|
16
|
+
this.mapper = new RowMapper(target.columns);
|
|
17
|
+
}
|
|
18
|
+
async find(key) {
|
|
19
|
+
const { stamps } = this.target;
|
|
20
|
+
const [record] = rowsOf(await this.context
|
|
21
|
+
.executor()
|
|
22
|
+
.execute(sql `select * from ${this.table()} where ${named(this.target.key)} = ${key} limit 1`));
|
|
23
|
+
if (record === undefined) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const version = record[stamps.lastEventVersion.name];
|
|
27
|
+
return {
|
|
28
|
+
key,
|
|
29
|
+
row: record[stamps.deleted.name] === true ? undefined : this.mapper.toRow(record),
|
|
30
|
+
stamp: {
|
|
31
|
+
eventId: String(record[stamps.lastEventId.name]),
|
|
32
|
+
occurredAt: new Date(String(record[stamps.lastEventAt.name])),
|
|
33
|
+
...(version === null || version === undefined ? {} : { version: Number(version) }),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async insert(entry) {
|
|
38
|
+
if (entry.row === undefined) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
const values = this.valuesOf(entry);
|
|
42
|
+
const columns = sql.join(values.map(([column]) => named(column)), sql `, `);
|
|
43
|
+
const written = sql.join(values.map(([, value]) => sql `${value}`), sql `, `);
|
|
44
|
+
const key = named(this.target.key);
|
|
45
|
+
const inserted = await this.context
|
|
46
|
+
.executor()
|
|
47
|
+
.execute(sql `insert into ${this.table()} (${columns}) values (${written}) on conflict (${key}) do nothing returning ${key}`);
|
|
48
|
+
return rowsOf(inserted).length === 1;
|
|
49
|
+
}
|
|
50
|
+
async replace(entry, held) {
|
|
51
|
+
const { stamps } = this.target;
|
|
52
|
+
const changes = sql.join(this.valuesOf(entry).map(([column, value]) => sql `${named(column)} = ${value}`), sql `, `);
|
|
53
|
+
const key = named(this.target.key);
|
|
54
|
+
const replaced = await this.context
|
|
55
|
+
.executor()
|
|
56
|
+
.execute(sql `update ${this.table()} set ${changes} where ${key} = ${entry.key} and ${named(stamps.lastEventId)} = ${held.eventId} and ${named(stamps.lastEventAt)} = ${held.occurredAt.toISOString()} returning ${key}`);
|
|
57
|
+
return rowsOf(replaced).length === 1;
|
|
58
|
+
}
|
|
59
|
+
valuesOf({ key, row, stamp }) {
|
|
60
|
+
const { stamps } = this.target;
|
|
61
|
+
const written = row === undefined ? [] : this.mapper.toValues(row).filter(([column]) => column !== this.target.key);
|
|
62
|
+
return [
|
|
63
|
+
...written,
|
|
64
|
+
[this.target.key, key],
|
|
65
|
+
[stamps.lastEventId, stamp.eventId],
|
|
66
|
+
[stamps.lastEventAt, stamp.occurredAt.toISOString()],
|
|
67
|
+
[stamps.lastEventVersion, stamp.version ?? null],
|
|
68
|
+
[stamps.deleted, row === undefined],
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
table() {
|
|
72
|
+
const { schema, name } = this.target;
|
|
73
|
+
return schema === undefined ? sql `${sql.identifier(name)}` : sql `${sql.identifier(schema)}.${sql.identifier(name)}`;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function named(column) {
|
|
77
|
+
return sql `${sql.identifier(column.name)}`;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=drizzle-stamped-rows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-stamped-rows.js","sourceRoot":"","sources":["../../../src/postgres/read-model/drizzle-stamped-rows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FilterOperator } from '@ddd-ts-kit/kernel';
|
|
2
|
+
/** The `LIKE` pattern of a text search, the text itself taken literally: `%`, `_` and `\` are escaped by `\`. */
|
|
3
|
+
export declare function likePattern(operator: FilterOperator, text: string): string;
|
|
4
|
+
//# sourceMappingURL=like-pattern.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"like-pattern.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/like-pattern.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,iHAAiH;AACjH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAI1E"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The `LIKE` pattern of a text search, the text itself taken literally: `%`, `_` and `\` are escaped by `\`. */
|
|
2
|
+
export function likePattern(operator, text) {
|
|
3
|
+
const literal = text.replace(/[\\%_]/g, (special) => `\\${special}`);
|
|
4
|
+
return operator === 'startsWith' ? `${literal}%` : `%${literal}%`;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=like-pattern.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"like-pattern.js","sourceRoot":"","sources":["../../../src/postgres/read-model/like-pattern.ts"],"names":[],"mappings":"AAEA,iHAAiH;AACjH,MAAM,UAAU,WAAW,CAAC,QAAwB,EAAE,IAAY;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC;IAErE,OAAO,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type SQL } from 'drizzle-orm';
|
|
2
|
+
import type { PgColumn } from 'drizzle-orm/pg-core';
|
|
3
|
+
import type { Predicate } from '@ddd-ts-kit/kernel';
|
|
4
|
+
type Columns = Readonly<Record<string, PgColumn>>;
|
|
5
|
+
/**
|
|
6
|
+
* A predicate of a criteria plan as a drizzle condition. Every value is a parameter, encoded
|
|
7
|
+
* by its column, and every column comes from the mapping of the adapter: nothing a caller
|
|
8
|
+
* wrote is ever part of the statement.
|
|
9
|
+
*/
|
|
10
|
+
export declare function predicateToDrizzle(predicate: Predicate | undefined, columns: Columns): SQL | undefined;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=predicate-to-drizzle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicate-to-drizzle.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/predicate-to-drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAeL,KAAK,GAAG,EACT,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAc,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAI/E,KAAK,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAIlD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,GAAG,SAAS,CAYtG"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { and, between, eq, gt, gte, inArray, isNotNull, isNull, lt, lte, ne, not, or, sql, } from 'drizzle-orm';
|
|
2
|
+
import { columnOf } from './column-of.js';
|
|
3
|
+
import { likePattern } from './like-pattern.js';
|
|
4
|
+
const COMPARISONS = { eq, ne, gt, gte, lt, lte };
|
|
5
|
+
/**
|
|
6
|
+
* A predicate of a criteria plan as a drizzle condition. Every value is a parameter, encoded
|
|
7
|
+
* by its column, and every column comes from the mapping of the adapter: nothing a caller
|
|
8
|
+
* wrote is ever part of the statement.
|
|
9
|
+
*/
|
|
10
|
+
export function predicateToDrizzle(predicate, columns) {
|
|
11
|
+
if (predicate === undefined) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
if (predicate.kind === 'test') {
|
|
15
|
+
return tested(predicate, columnOf(columns, predicate.field));
|
|
16
|
+
}
|
|
17
|
+
const parts = predicate.parts.map((part) => predicateToDrizzle(part, columns));
|
|
18
|
+
return predicate.kind === 'and' ? and(...parts) : or(...parts);
|
|
19
|
+
}
|
|
20
|
+
function tested(test, column) {
|
|
21
|
+
if (test.operator === 'isNull') {
|
|
22
|
+
return test.value === true ? isNull(column) : isNotNull(column);
|
|
23
|
+
}
|
|
24
|
+
return test.negated ? not(compared(test, column)) : compared(test, column);
|
|
25
|
+
}
|
|
26
|
+
function compared({ operator, value }, column) {
|
|
27
|
+
const values = typeof value === 'object' && !(value instanceof Date) ? [...value] : [value];
|
|
28
|
+
const [first = null, second = null] = values;
|
|
29
|
+
switch (operator) {
|
|
30
|
+
case 'in':
|
|
31
|
+
return inArray(column, values);
|
|
32
|
+
case 'between':
|
|
33
|
+
return between(column, first, second);
|
|
34
|
+
case 'contains':
|
|
35
|
+
case 'startsWith':
|
|
36
|
+
return sql `${column} like ${likePattern(operator, String(first))} escape ${'\\'}`;
|
|
37
|
+
case 'isNull':
|
|
38
|
+
return isNull(column);
|
|
39
|
+
default:
|
|
40
|
+
return COMPARISONS[operator](column, first);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=predicate-to-drizzle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicate-to-drizzle.js","sourceRoot":"","sources":["../../../src/postgres/read-model/predicate-to-drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,GAAG,EACH,OAAO,EACP,EAAE,EACF,EAAE,EACF,GAAG,EACH,OAAO,EACP,SAAS,EACT,MAAM,EACN,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,EACH,EAAE,EACF,GAAG,GAEJ,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,MAAM,WAAW,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAW,CAAC;AAE1D;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAgC,EAAE,OAAgB;IACnF,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,kBAAkB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAE/E,OAAO,SAAS,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,MAAM,CAAC,IAAmB,EAAE,MAAgB;IACnD,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,QAAQ,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAiB,EAAE,MAAgB;IACpE,MAAM,MAAM,GAAiB,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1G,MAAM,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC;IAE7C,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,IAAI;YACP,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,KAAK,SAAS;YACZ,OAAO,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACxC,KAAK,UAAU,CAAC;QAChB,KAAK,YAAY;YACf,OAAO,GAAG,CAAA,GAAG,MAAM,SAAS,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC;QACpF,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;QACxB;YACE,OAAO,WAAW,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The columns a projection orders its events by, to spread into the table of a read model,
|
|
3
|
+
* under the same names in every project: `last_event_id`, `last_event_at`,
|
|
4
|
+
* `last_event_version` and `deleted`, the trace a removed row leaves so that a late event does
|
|
5
|
+
* not bring it back.
|
|
6
|
+
*/
|
|
7
|
+
export declare function readModelColumns(): {
|
|
8
|
+
lastEventId: import("drizzle-orm").NotNull<import("drizzle-orm/pg-core").PgTextBuilderInitial<"last_event_id", [string, ...string[]]>>;
|
|
9
|
+
lastEventAt: import("drizzle-orm").NotNull<import("drizzle-orm/pg-core").PgTimestampBuilderInitial<string>>;
|
|
10
|
+
lastEventVersion: import("drizzle-orm/pg-core").PgBigInt53BuilderInitial<"last_event_version">;
|
|
11
|
+
deleted: import("drizzle-orm").HasDefault<import("drizzle-orm").NotNull<import("drizzle-orm/pg-core").PgBooleanBuilderInitial<"deleted">>>;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=read-model-columns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-model-columns.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/read-model-columns.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,gBAAgB;IAE5B,WAAW;IACX,WAAW;IACX,gBAAgB;IAChB,OAAO;EAEV"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { bigint, boolean, text } from 'drizzle-orm/pg-core';
|
|
2
|
+
import { instant } from '../columns/instant.js';
|
|
3
|
+
/**
|
|
4
|
+
* The columns a projection orders its events by, to spread into the table of a read model,
|
|
5
|
+
* under the same names in every project: `last_event_id`, `last_event_at`,
|
|
6
|
+
* `last_event_version` and `deleted`, the trace a removed row leaves so that a late event does
|
|
7
|
+
* not bring it back.
|
|
8
|
+
*/
|
|
9
|
+
export function readModelColumns() {
|
|
10
|
+
return {
|
|
11
|
+
lastEventId: text('last_event_id').notNull(),
|
|
12
|
+
lastEventAt: instant('last_event_at').notNull(),
|
|
13
|
+
lastEventVersion: bigint('last_event_version', { mode: 'number' }),
|
|
14
|
+
deleted: boolean('deleted').notNull().default(false),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=read-model-columns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-model-columns.js","sourceRoot":"","sources":["../../../src/postgres/read-model/read-model-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO;QACL,WAAW,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;QAC5C,WAAW,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC,OAAO,EAAE;QAC/C,gBAAgB,EAAE,MAAM,CAAC,oBAAoB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAClE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;KACrD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PgColumn } from 'drizzle-orm/pg-core';
|
|
2
|
+
type Columns = Readonly<Record<string, PgColumn>>;
|
|
3
|
+
/** Translates between the row of a read model, keyed by field, and what its columns hold. */
|
|
4
|
+
export declare class RowMapper<Row extends object> {
|
|
5
|
+
private readonly columns;
|
|
6
|
+
constructor(columns: Columns);
|
|
7
|
+
/** From a record keyed by column name, as a statement written in SQL answers it. */
|
|
8
|
+
toRow(record: Readonly<Record<string, unknown>>): Row;
|
|
9
|
+
/** From a record keyed by field, already decoded: what `select(columns)` of the query builder answers. */
|
|
10
|
+
fromSelected(selected: Readonly<Record<string, unknown>>): Row;
|
|
11
|
+
/** The values of the row by column, encoded as the driver expects them. */
|
|
12
|
+
toValues(row: Row): [PgColumn, unknown][];
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=row.mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row.mapper.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/row.mapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,KAAK,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;AAElD,6FAA6F;AAC7F,qBAAa,SAAS,CAAC,GAAG,SAAS,MAAM;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAApC,YAA6B,OAAO,EAAE,OAAO,EAAI;IAEjD,oFAAoF;IACpF,KAAK,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,GAAG,CAIpD;IAED,0GAA0G;IAC1G,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,GAAG,CAE7D;IAED,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAExC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Translates between the row of a read model, keyed by field, and what its columns hold. */
|
|
2
|
+
export class RowMapper {
|
|
3
|
+
columns;
|
|
4
|
+
constructor(columns) {
|
|
5
|
+
this.columns = columns;
|
|
6
|
+
}
|
|
7
|
+
/** From a record keyed by column name, as a statement written in SQL answers it. */
|
|
8
|
+
toRow(record) {
|
|
9
|
+
return Object.fromEntries(Object.entries(this.columns).map(([field, column]) => [field, decoded(column, record[column.name])]));
|
|
10
|
+
}
|
|
11
|
+
/** From a record keyed by field, already decoded: what `select(columns)` of the query builder answers. */
|
|
12
|
+
fromSelected(selected) {
|
|
13
|
+
return Object.fromEntries(Object.keys(this.columns).map((field) => [field, selected[field] ?? null]));
|
|
14
|
+
}
|
|
15
|
+
/** The values of the row by column, encoded as the driver expects them. */
|
|
16
|
+
toValues(row) {
|
|
17
|
+
return Object.entries(this.columns).map(([field, column]) => [column, encoded(column, Reflect.get(row, field))]);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function decoded(column, value) {
|
|
21
|
+
return value === null || value === undefined ? null : column.mapFromDriverValue(value);
|
|
22
|
+
}
|
|
23
|
+
function encoded(column, value) {
|
|
24
|
+
return value === null || value === undefined ? null : column.mapToDriverValue(value);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=row.mapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row.mapper.js","sourceRoot":"","sources":["../../../src/postgres/read-model/row.mapper.ts"],"names":[],"mappings":"AAIA,6FAA6F;AAC7F,MAAM,OAAO,SAAS;IACS,OAAO;IAApC,YAA6B,OAAgB;uBAAhB,OAAO;IAAY,CAAC;IAEjD,oFAAoF;IACpF,KAAK,CAAC,MAAyC;QAC7C,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAC9F,CAAC;IACX,CAAC;IAED,0GAA0G;IAC1G,YAAY,CAAC,QAA2C;QACtD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAQ,CAAC;IAC/G,CAAC;IAED,2EAA2E;IAC3E,QAAQ,CAAC,GAAQ;QACf,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnH,CAAC;CACF;AAED,SAAS,OAAO,CAAC,MAAgB,EAAE,KAAc;IAC/C,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC;AAED,SAAS,OAAO,CAAC,MAAgB,EAAE,KAAc;IAC/C,OAAO,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACvF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rows-of.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/rows-of.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,wBAAgB,MAAM,CAAC,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,CAO7E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** The rows a driver answered a statement with: node-postgres and PGlite wrap them, postgres-js does not. */
|
|
2
|
+
export function rowsOf(answered) {
|
|
3
|
+
const wrapped = typeof answered === 'object' && answered !== null && 'rows' in answered ? answered.rows : answered;
|
|
4
|
+
const rows = Array.isArray(wrapped) ? wrapped : [];
|
|
5
|
+
return rows.filter(isRecord);
|
|
6
|
+
}
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === 'object' && value !== null;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=rows-of.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rows-of.js","sourceRoot":"","sources":["../../../src/postgres/read-model/rows-of.ts"],"names":[],"mappings":"AAAA,6GAA6G;AAC7G,MAAM,UAAU,MAAM,CAAC,QAAiB;IACtC,MAAM,OAAO,GACX,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,MAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;IAErG,MAAM,IAAI,GAAuB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAEvE,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { PgColumn, PgTable } from 'drizzle-orm/pg-core';
|
|
2
|
+
export interface StampColumns {
|
|
3
|
+
readonly lastEventId: PgColumn;
|
|
4
|
+
readonly lastEventAt: PgColumn;
|
|
5
|
+
readonly lastEventVersion: PgColumn;
|
|
6
|
+
readonly deleted: PgColumn;
|
|
7
|
+
}
|
|
8
|
+
/** The columns `readModelColumns()` gave a table. A table declared without them is refused. */
|
|
9
|
+
export declare function stampColumns(table: PgTable): StampColumns;
|
|
10
|
+
//# sourceMappingURL=stamp-columns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stamp-columns.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/stamp-columns.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,QAAQ,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;CAC5B;AAED,+FAA+F;AAC/F,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAczD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getTableColumns } from 'drizzle-orm';
|
|
2
|
+
/** The columns `readModelColumns()` gave a table. A table declared without them is refused. */
|
|
3
|
+
export function stampColumns(table) {
|
|
4
|
+
const columns = getTableColumns(table);
|
|
5
|
+
const { lastEventId, lastEventAt, lastEventVersion, deleted } = columns;
|
|
6
|
+
if (lastEventId === undefined ||
|
|
7
|
+
lastEventAt === undefined ||
|
|
8
|
+
lastEventVersion === undefined ||
|
|
9
|
+
deleted === undefined) {
|
|
10
|
+
throw new Error('The table of a read model is declared with ...readModelColumns()');
|
|
11
|
+
}
|
|
12
|
+
return { lastEventId, lastEventAt, lastEventVersion, deleted };
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=stamp-columns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stamp-columns.js","sourceRoot":"","sources":["../../../src/postgres/read-model/stamp-columns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAU9C,+FAA+F;AAC/F,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,MAAM,OAAO,GAAuC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC3E,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;IAExE,IACE,WAAW,KAAK,SAAS;QACzB,WAAW,KAAK,SAAS;QACzB,gBAAgB,KAAK,SAAS;QAC9B,OAAO,KAAK,SAAS,EACrB,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
|