@ddd-ts-kit/drizzle 0.0.0-stage → 0.1.1

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.
Files changed (98) hide show
  1. package/README.md +476 -2
  2. package/dist/postgres/columns/audit-columns.d.ts +13 -0
  3. package/dist/postgres/columns/audit-columns.d.ts.map +1 -0
  4. package/dist/postgres/columns/audit-columns.js +17 -0
  5. package/dist/postgres/columns/audit-columns.js.map +1 -0
  6. package/dist/postgres/columns/instant.d.ts +3 -0
  7. package/dist/postgres/columns/instant.d.ts.map +1 -0
  8. package/dist/postgres/columns/instant.js +6 -0
  9. package/dist/postgres/columns/instant.js.map +1 -0
  10. package/dist/postgres/columns/tenant-column.d.ts +5 -0
  11. package/dist/postgres/columns/tenant-column.d.ts.map +1 -0
  12. package/dist/postgres/columns/tenant-column.js +6 -0
  13. package/dist/postgres/columns/tenant-column.js.map +1 -0
  14. package/dist/postgres/outbox/drizzle-outbox-store.d.ts +39 -0
  15. package/dist/postgres/outbox/drizzle-outbox-store.d.ts.map +1 -0
  16. package/dist/postgres/outbox/drizzle-outbox-store.js +139 -0
  17. package/dist/postgres/outbox/drizzle-outbox-store.js.map +1 -0
  18. package/dist/postgres/outbox/drizzle-processed-event-store.d.ts +21 -0
  19. package/dist/postgres/outbox/drizzle-processed-event-store.d.ts.map +1 -0
  20. package/dist/postgres/outbox/drizzle-processed-event-store.js +24 -0
  21. package/dist/postgres/outbox/drizzle-processed-event-store.js.map +1 -0
  22. package/dist/postgres/outbox/outbox-table.d.ts +254 -0
  23. package/dist/postgres/outbox/outbox-table.d.ts.map +1 -0
  24. package/dist/postgres/outbox/outbox-table.js +33 -0
  25. package/dist/postgres/outbox/outbox-table.js.map +1 -0
  26. package/dist/postgres/outbox/processed-events-table.d.ts +61 -0
  27. package/dist/postgres/outbox/processed-events-table.d.ts.map +1 -0
  28. package/dist/postgres/outbox/processed-events-table.js +14 -0
  29. package/dist/postgres/outbox/processed-events-table.js.map +1 -0
  30. package/dist/postgres/read-model/column-of.d.ts +4 -0
  31. package/dist/postgres/read-model/column-of.d.ts.map +1 -0
  32. package/dist/postgres/read-model/column-of.js +9 -0
  33. package/dist/postgres/read-model/column-of.js.map +1 -0
  34. package/dist/postgres/read-model/criteria-to-drizzle.d.ts +21 -0
  35. package/dist/postgres/read-model/criteria-to-drizzle.d.ts.map +1 -0
  36. package/dist/postgres/read-model/criteria-to-drizzle.js +26 -0
  37. package/dist/postgres/read-model/criteria-to-drizzle.js.map +1 -0
  38. package/dist/postgres/read-model/drizzle-read-model-options.d.ts +10 -0
  39. package/dist/postgres/read-model/drizzle-read-model-options.d.ts.map +1 -0
  40. package/dist/postgres/read-model/drizzle-read-model-options.js +2 -0
  41. package/dist/postgres/read-model/drizzle-read-model-options.js.map +1 -0
  42. package/dist/postgres/read-model/drizzle-read-model-store.d.ts +18 -0
  43. package/dist/postgres/read-model/drizzle-read-model-store.d.ts.map +1 -0
  44. package/dist/postgres/read-model/drizzle-read-model-store.js +13 -0
  45. package/dist/postgres/read-model/drizzle-read-model-store.js.map +1 -0
  46. package/dist/postgres/read-model/drizzle-read-model-table.d.ts +35 -0
  47. package/dist/postgres/read-model/drizzle-read-model-table.d.ts.map +1 -0
  48. package/dist/postgres/read-model/drizzle-read-model-table.js +92 -0
  49. package/dist/postgres/read-model/drizzle-read-model-table.js.map +1 -0
  50. package/dist/postgres/read-model/drizzle-stamped-rows.d.ts +29 -0
  51. package/dist/postgres/read-model/drizzle-stamped-rows.d.ts.map +1 -0
  52. package/dist/postgres/read-model/drizzle-stamped-rows.js +79 -0
  53. package/dist/postgres/read-model/drizzle-stamped-rows.js.map +1 -0
  54. package/dist/postgres/read-model/like-pattern.d.ts +4 -0
  55. package/dist/postgres/read-model/like-pattern.d.ts.map +1 -0
  56. package/dist/postgres/read-model/like-pattern.js +6 -0
  57. package/dist/postgres/read-model/like-pattern.js.map +1 -0
  58. package/dist/postgres/read-model/predicate-to-drizzle.d.ts +12 -0
  59. package/dist/postgres/read-model/predicate-to-drizzle.d.ts.map +1 -0
  60. package/dist/postgres/read-model/predicate-to-drizzle.js +43 -0
  61. package/dist/postgres/read-model/predicate-to-drizzle.js.map +1 -0
  62. package/dist/postgres/read-model/read-model-columns.d.ts +13 -0
  63. package/dist/postgres/read-model/read-model-columns.d.ts.map +1 -0
  64. package/dist/postgres/read-model/read-model-columns.js +17 -0
  65. package/dist/postgres/read-model/read-model-columns.js.map +1 -0
  66. package/dist/postgres/read-model/row.mapper.d.ts +15 -0
  67. package/dist/postgres/read-model/row.mapper.d.ts.map +1 -0
  68. package/dist/postgres/read-model/row.mapper.js +26 -0
  69. package/dist/postgres/read-model/row.mapper.js.map +1 -0
  70. package/dist/postgres/read-model/rows-of.d.ts +3 -0
  71. package/dist/postgres/read-model/rows-of.d.ts.map +1 -0
  72. package/dist/postgres/read-model/rows-of.js +10 -0
  73. package/dist/postgres/read-model/rows-of.js.map +1 -0
  74. package/dist/postgres/read-model/stamp-columns.d.ts +10 -0
  75. package/dist/postgres/read-model/stamp-columns.d.ts.map +1 -0
  76. package/dist/postgres/read-model/stamp-columns.js +14 -0
  77. package/dist/postgres/read-model/stamp-columns.js.map +1 -0
  78. package/dist/postgres/schema/context-schema.d.ts +4 -0
  79. package/dist/postgres/schema/context-schema.d.ts.map +1 -0
  80. package/dist/postgres/schema/context-schema.js +7 -0
  81. package/dist/postgres/schema/context-schema.js.map +1 -0
  82. package/dist/postgres/schema/table-in.d.ts +3 -0
  83. package/dist/postgres/schema/table-in.d.ts.map +1 -0
  84. package/dist/postgres/schema/table-in.js +5 -0
  85. package/dist/postgres/schema/table-in.js.map +1 -0
  86. package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.d.ts +16 -0
  87. package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.d.ts.map +1 -0
  88. package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.js +25 -0
  89. package/dist/postgres/unit-of-work/create-drizzle-unit-of-work.js.map +1 -0
  90. package/dist/postgres/unit-of-work/drizzle-context.d.ts +19 -0
  91. package/dist/postgres/unit-of-work/drizzle-context.d.ts.map +1 -0
  92. package/dist/postgres/unit-of-work/drizzle-context.js +15 -0
  93. package/dist/postgres/unit-of-work/drizzle-context.js.map +1 -0
  94. package/dist/postgres.d.ts +17 -0
  95. package/dist/postgres.d.ts.map +1 -0
  96. package/dist/postgres.js +17 -0
  97. package/dist/postgres.js.map +1 -0
  98. package/package.json +40 -4
@@ -0,0 +1,139 @@
1
+ import { and, eq, inArray, lt, lte, ne, sql } from 'drizzle-orm';
2
+ import { outboxTable } from './outbox-table.js';
3
+ // A fresh record is due at once, whatever clock the relay runs on.
4
+ const DUE_IMMEDIATELY = new Date(0);
5
+ /**
6
+ * The outbox in PostgreSQL. `append` runs on the executor of the context: called inside a
7
+ * unit of work, the events are written by the transaction of the command and share its fate,
8
+ * which is the whole point of an outbox.
9
+ */
10
+ export class DrizzleOutboxStore {
11
+ context;
12
+ outbox;
13
+ leaseDurationMs;
14
+ constructor(context, options = {}) {
15
+ this.context = context;
16
+ this.outbox = options.table ?? outboxTable();
17
+ this.leaseDurationMs = options.leaseMs ?? 30_000;
18
+ }
19
+ async append(events) {
20
+ if (events.length === 0) {
21
+ return;
22
+ }
23
+ await this.context
24
+ .executor()
25
+ .insert(this.outbox)
26
+ .values(events.map((event) => ({
27
+ id: event.id,
28
+ type: event.type,
29
+ version: event.version,
30
+ occurredAt: event.occurredAt,
31
+ payload: event.payload,
32
+ traceparent: event.traceparent ?? null,
33
+ correlationId: event.correlationId ?? null,
34
+ nextAttemptAt: DUE_IMMEDIATELY,
35
+ })));
36
+ }
37
+ /**
38
+ * Selects the due rows `FOR UPDATE SKIP LOCKED`, so concurrent relays pass over each other's
39
+ * rows instead of waiting, then leases them in the same transaction by pushing
40
+ * `next_attempt_at` forward. The row locks last a few milliseconds; the lease is what covers
41
+ * the publication.
42
+ */
43
+ async claimBatch(limit, now) {
44
+ const outbox = this.outbox;
45
+ const leasedUntil = new Date(now.getTime() + this.leaseDurationMs);
46
+ return this.context.executor().transaction(async (transaction) => {
47
+ const due = await transaction
48
+ .select({ id: outbox.id })
49
+ .from(outbox)
50
+ .where(and(eq(outbox.status, 'pending'), lte(outbox.nextAttemptAt, now)))
51
+ .orderBy(outbox.nextAttemptAt, outbox.sequence)
52
+ .limit(Math.max(0, limit))
53
+ .for('update', { skipLocked: true });
54
+ if (due.length === 0) {
55
+ return [];
56
+ }
57
+ const order = new Map(due.map(({ id }, index) => [id, index]));
58
+ const claimed = await transaction
59
+ .update(outbox)
60
+ .set({ attempts: sql `${outbox.attempts} + 1`, nextAttemptAt: leasedUntil })
61
+ .where(inArray(outbox.id, [...order.keys()]))
62
+ .returning();
63
+ // RETURNING gives no order guarantee: restore the one of the claim.
64
+ return claimed.sort((a, b) => (order.get(a.id) ?? 0) - (order.get(b.id) ?? 0)).map(toRecord);
65
+ });
66
+ }
67
+ async markPublished(ids, at) {
68
+ if (ids.length === 0) {
69
+ return;
70
+ }
71
+ await this.context
72
+ .executor()
73
+ .update(this.outbox)
74
+ .set({ status: 'published', publishedAt: at })
75
+ .where(inArray(this.outbox.id, [...ids]));
76
+ }
77
+ async markFailed(id, error, nextAttemptAt) {
78
+ await this.context
79
+ .executor()
80
+ .update(this.outbox)
81
+ .set(nextAttemptAt === null
82
+ ? { status: 'dead', lastErrorCode: error.code }
83
+ : { nextAttemptAt, lastErrorCode: error.code })
84
+ .where(and(eq(this.outbox.id, id), ne(this.outbox.status, 'published')));
85
+ }
86
+ async retryDead(ids, now) {
87
+ if (ids.length === 0) {
88
+ return 0;
89
+ }
90
+ const revived = await this.context
91
+ .executor()
92
+ .update(this.outbox)
93
+ .set({ status: 'pending', attempts: 0, nextAttemptAt: now })
94
+ .where(and(inArray(this.outbox.id, [...ids]), eq(this.outbox.status, 'dead')))
95
+ .returning({ id: this.outbox.id });
96
+ return revived.length;
97
+ }
98
+ async purgePublished(before) {
99
+ const purged = await this.context
100
+ .executor()
101
+ .delete(this.outbox)
102
+ .where(and(eq(this.outbox.status, 'published'), lt(this.outbox.publishedAt, before)))
103
+ .returning({ id: this.outbox.id });
104
+ return purged.length;
105
+ }
106
+ async stats() {
107
+ const { status, lastErrorCode } = this.outbox;
108
+ // count() is a bigint, which some drivers return as a string.
109
+ const count = (condition) => sql `count(*) filter (where ${condition})`.mapWith(Number);
110
+ const [row] = await this.context
111
+ .executor()
112
+ .select({
113
+ pending: count(sql `${status} = 'pending'`),
114
+ failed: count(sql `${status} = 'pending' and ${lastErrorCode} is not null`),
115
+ dead: count(sql `${status} = 'dead'`),
116
+ })
117
+ .from(this.outbox);
118
+ return row ?? { pending: 0, failed: 0, dead: 0 };
119
+ }
120
+ }
121
+ function toRecord(row) {
122
+ return {
123
+ event: {
124
+ id: row.id,
125
+ type: row.type,
126
+ version: row.version,
127
+ occurredAt: row.occurredAt,
128
+ payload: row.payload,
129
+ ...(row.traceparent === null ? {} : { traceparent: row.traceparent }),
130
+ ...(row.correlationId === null ? {} : { correlationId: row.correlationId }),
131
+ },
132
+ status: row.status,
133
+ attempts: row.attempts,
134
+ nextAttemptAt: row.nextAttemptAt,
135
+ ...(row.lastErrorCode === null ? {} : { lastErrorCode: row.lastErrorCode }),
136
+ ...(row.publishedAt === null ? {} : { publishedAt: row.publishedAt }),
137
+ };
138
+ }
139
+ //# sourceMappingURL=drizzle-outbox-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle-outbox-store.js","sourceRoot":"","sources":["../../../src/postgres/outbox/drizzle-outbox-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { TablesRelationalConfig } from 'drizzle-orm';
2
+ import type { PgQueryResultHKT } from 'drizzle-orm/pg-core';
3
+ import type { ProcessedEventStore } from '@ddd-ts-kit/kernel';
4
+ import type { DrizzleContext } from '../unit-of-work/drizzle-context.js';
5
+ import { type ProcessedEventsTable } from './processed-events-table.js';
6
+ export interface DrizzleProcessedEventStoreOptions {
7
+ /** Default `processedEventsTable()`, in the `public` schema. */
8
+ readonly table?: ProcessedEventsTable;
9
+ }
10
+ /**
11
+ * Idempotency of consumers in PostgreSQL. It writes on the executor of the context: when the
12
+ * consumer runs inside a unit of work, the mark commits with the effects of the handler and
13
+ * disappears with them if the handler fails, so the redelivery is processed.
14
+ */
15
+ export declare class DrizzleProcessedEventStore<Q extends PgQueryResultHKT, F extends Record<string, unknown>, S extends TablesRelationalConfig> implements ProcessedEventStore {
16
+ private readonly context;
17
+ private readonly processedEvents;
18
+ constructor(context: DrizzleContext<Q, F, S>, options?: DrizzleProcessedEventStoreOptions);
19
+ markProcessed(consumer: string, eventId: string): Promise<boolean>;
20
+ }
21
+ //# sourceMappingURL=drizzle-processed-event-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle-processed-event-store.d.ts","sourceRoot":"","sources":["../../../src/postgres/outbox/drizzle-processed-event-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAwB,KAAK,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAE9F,MAAM,WAAW,iCAAiC;IAChD,gEAAgE;IAChE,QAAQ,CAAC,KAAK,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED;;;;GAIG;AACH,qBAAa,0BAA0B,CACrC,CAAC,SAAS,gBAAgB,EAC1B,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,sBAAsB,CAChC,YAAW,mBAAmB;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAElD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAuB;IAEvD,YAAY,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,GAAE,iCAAsC,EAG5F;IAEK,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CASvE;CACF"}
@@ -0,0 +1,24 @@
1
+ import { processedEventsTable } from './processed-events-table.js';
2
+ /**
3
+ * Idempotency of consumers in PostgreSQL. It writes on the executor of the context: when the
4
+ * consumer runs inside a unit of work, the mark commits with the effects of the handler and
5
+ * disappears with them if the handler fails, so the redelivery is processed.
6
+ */
7
+ export class DrizzleProcessedEventStore {
8
+ context;
9
+ processedEvents;
10
+ constructor(context, options = {}) {
11
+ this.context = context;
12
+ this.processedEvents = options.table ?? processedEventsTable();
13
+ }
14
+ async markProcessed(consumer, eventId) {
15
+ const inserted = await this.context
16
+ .executor()
17
+ .insert(this.processedEvents)
18
+ .values({ consumer, eventId })
19
+ .onConflictDoNothing()
20
+ .returning({ eventId: this.processedEvents.eventId });
21
+ return inserted.length === 1;
22
+ }
23
+ }
24
+ //# sourceMappingURL=drizzle-processed-event-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drizzle-processed-event-store.js","sourceRoot":"","sources":["../../../src/postgres/outbox/drizzle-processed-event-store.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAA6B,MAAM,6BAA6B,CAAC;AAO9F;;;;GAIG;AACH,MAAM,OAAO,0BAA0B;IAMpB,OAAO,CAA0B;IAEjC,eAAe,CAAuB;IAEvD,YAAY,OAAgC,EAAE,OAAO,GAAsC,EAAE;QAC3F,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,KAAK,IAAI,oBAAoB,EAAE,CAAC;IACjE,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,OAAe;QACnD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO;aAChC,QAAQ,EAAE;aACV,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;aAC5B,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;aAC7B,mBAAmB,EAAE;aACrB,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAExD,OAAO,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,254 @@
1
+ import type { OutboxStatus } from '@ddd-ts-kit/events';
2
+ export type OutboxTable = ReturnType<typeof outboxTable>;
3
+ /**
4
+ * The outbox table, to include in the schema files drizzle-kit reads so that it is created by
5
+ * the migrations of the consuming project. Without a schema name it lives in `public`.
6
+ */
7
+ export declare function outboxTable(schemaName?: string): import("drizzle-orm/pg-core").PgTableWithColumns<{
8
+ name: "outbox";
9
+ schema: string | undefined;
10
+ columns: {
11
+ id: import("drizzle-orm/pg-core").PgColumn<{
12
+ name: "id";
13
+ tableName: "outbox";
14
+ dataType: "string";
15
+ columnType: "PgText";
16
+ data: string;
17
+ driverParam: string;
18
+ notNull: true;
19
+ hasDefault: false;
20
+ isPrimaryKey: true;
21
+ isAutoincrement: false;
22
+ hasRuntimeDefault: false;
23
+ enumValues: [string, ...string[]];
24
+ baseColumn: never;
25
+ identity: undefined;
26
+ generated: undefined;
27
+ }, {}, {}>;
28
+ sequence: import("drizzle-orm/pg-core").PgColumn<{
29
+ name: "sequence";
30
+ tableName: "outbox";
31
+ dataType: "number";
32
+ columnType: "PgBigInt53";
33
+ data: number;
34
+ driverParam: string | number;
35
+ notNull: true;
36
+ hasDefault: true;
37
+ isPrimaryKey: false;
38
+ isAutoincrement: false;
39
+ hasRuntimeDefault: false;
40
+ enumValues: undefined;
41
+ baseColumn: never;
42
+ identity: "always";
43
+ generated: undefined;
44
+ }, {}, {}>;
45
+ type: import("drizzle-orm/pg-core").PgColumn<{
46
+ name: "type";
47
+ tableName: "outbox";
48
+ dataType: "string";
49
+ columnType: "PgText";
50
+ data: string;
51
+ driverParam: string;
52
+ notNull: true;
53
+ hasDefault: false;
54
+ isPrimaryKey: false;
55
+ isAutoincrement: false;
56
+ hasRuntimeDefault: false;
57
+ enumValues: [string, ...string[]];
58
+ baseColumn: never;
59
+ identity: undefined;
60
+ generated: undefined;
61
+ }, {}, {}>;
62
+ version: import("drizzle-orm/pg-core").PgColumn<{
63
+ name: "version";
64
+ tableName: "outbox";
65
+ dataType: "number";
66
+ columnType: "PgInteger";
67
+ data: number;
68
+ driverParam: string | number;
69
+ notNull: true;
70
+ hasDefault: false;
71
+ isPrimaryKey: false;
72
+ isAutoincrement: false;
73
+ hasRuntimeDefault: false;
74
+ enumValues: undefined;
75
+ baseColumn: never;
76
+ identity: undefined;
77
+ generated: undefined;
78
+ }, {}, {}>;
79
+ occurredAt: import("drizzle-orm/pg-core").PgColumn<{
80
+ name: "occurred_at";
81
+ tableName: "outbox";
82
+ dataType: "string";
83
+ columnType: "PgText";
84
+ data: string;
85
+ driverParam: string;
86
+ notNull: true;
87
+ hasDefault: false;
88
+ isPrimaryKey: false;
89
+ isAutoincrement: false;
90
+ hasRuntimeDefault: false;
91
+ enumValues: [string, ...string[]];
92
+ baseColumn: never;
93
+ identity: undefined;
94
+ generated: undefined;
95
+ }, {}, {}>;
96
+ payload: import("drizzle-orm/pg-core").PgColumn<{
97
+ name: "payload";
98
+ tableName: "outbox";
99
+ dataType: "json";
100
+ columnType: "PgJsonb";
101
+ data: unknown;
102
+ driverParam: unknown;
103
+ notNull: false;
104
+ hasDefault: false;
105
+ isPrimaryKey: false;
106
+ isAutoincrement: false;
107
+ hasRuntimeDefault: false;
108
+ enumValues: undefined;
109
+ baseColumn: never;
110
+ identity: undefined;
111
+ generated: undefined;
112
+ }, {}, {}>;
113
+ traceparent: import("drizzle-orm/pg-core").PgColumn<{
114
+ name: "traceparent";
115
+ tableName: "outbox";
116
+ dataType: "string";
117
+ columnType: "PgText";
118
+ data: string;
119
+ driverParam: string;
120
+ notNull: false;
121
+ hasDefault: false;
122
+ isPrimaryKey: false;
123
+ isAutoincrement: false;
124
+ hasRuntimeDefault: false;
125
+ enumValues: [string, ...string[]];
126
+ baseColumn: never;
127
+ identity: undefined;
128
+ generated: undefined;
129
+ }, {}, {}>;
130
+ correlationId: import("drizzle-orm/pg-core").PgColumn<{
131
+ name: "correlation_id";
132
+ tableName: "outbox";
133
+ dataType: "string";
134
+ columnType: "PgText";
135
+ data: string;
136
+ driverParam: string;
137
+ notNull: false;
138
+ hasDefault: false;
139
+ isPrimaryKey: false;
140
+ isAutoincrement: false;
141
+ hasRuntimeDefault: false;
142
+ enumValues: [string, ...string[]];
143
+ baseColumn: never;
144
+ identity: undefined;
145
+ generated: undefined;
146
+ }, {}, {}>;
147
+ status: import("drizzle-orm/pg-core").PgColumn<{
148
+ name: "status";
149
+ tableName: "outbox";
150
+ dataType: "string";
151
+ columnType: "PgText";
152
+ data: OutboxStatus;
153
+ driverParam: string;
154
+ notNull: true;
155
+ hasDefault: true;
156
+ isPrimaryKey: false;
157
+ isAutoincrement: false;
158
+ hasRuntimeDefault: false;
159
+ enumValues: [string, ...string[]];
160
+ baseColumn: never;
161
+ identity: undefined;
162
+ generated: undefined;
163
+ }, {}, {
164
+ $type: OutboxStatus;
165
+ }>;
166
+ attempts: import("drizzle-orm/pg-core").PgColumn<{
167
+ name: "attempts";
168
+ tableName: "outbox";
169
+ dataType: "number";
170
+ columnType: "PgInteger";
171
+ data: number;
172
+ driverParam: string | number;
173
+ notNull: true;
174
+ hasDefault: true;
175
+ isPrimaryKey: false;
176
+ isAutoincrement: false;
177
+ hasRuntimeDefault: false;
178
+ enumValues: undefined;
179
+ baseColumn: never;
180
+ identity: undefined;
181
+ generated: undefined;
182
+ }, {}, {}>;
183
+ nextAttemptAt: import("drizzle-orm/pg-core").PgColumn<{
184
+ name: string;
185
+ tableName: "outbox";
186
+ dataType: "date";
187
+ columnType: "PgTimestamp";
188
+ data: Date;
189
+ driverParam: string;
190
+ notNull: true;
191
+ hasDefault: false;
192
+ isPrimaryKey: false;
193
+ isAutoincrement: false;
194
+ hasRuntimeDefault: false;
195
+ enumValues: undefined;
196
+ baseColumn: never;
197
+ identity: undefined;
198
+ generated: undefined;
199
+ }, {}, {}>;
200
+ lastErrorCode: import("drizzle-orm/pg-core").PgColumn<{
201
+ name: "last_error_code";
202
+ tableName: "outbox";
203
+ dataType: "string";
204
+ columnType: "PgText";
205
+ data: string;
206
+ driverParam: string;
207
+ notNull: false;
208
+ hasDefault: false;
209
+ isPrimaryKey: false;
210
+ isAutoincrement: false;
211
+ hasRuntimeDefault: false;
212
+ enumValues: [string, ...string[]];
213
+ baseColumn: never;
214
+ identity: undefined;
215
+ generated: undefined;
216
+ }, {}, {}>;
217
+ publishedAt: import("drizzle-orm/pg-core").PgColumn<{
218
+ name: string;
219
+ tableName: "outbox";
220
+ dataType: "date";
221
+ columnType: "PgTimestamp";
222
+ data: Date;
223
+ driverParam: string;
224
+ notNull: false;
225
+ hasDefault: false;
226
+ isPrimaryKey: false;
227
+ isAutoincrement: false;
228
+ hasRuntimeDefault: false;
229
+ enumValues: undefined;
230
+ baseColumn: never;
231
+ identity: undefined;
232
+ generated: undefined;
233
+ }, {}, {}>;
234
+ createdAt: import("drizzle-orm/pg-core").PgColumn<{
235
+ name: string;
236
+ tableName: "outbox";
237
+ dataType: "date";
238
+ columnType: "PgTimestamp";
239
+ data: Date;
240
+ driverParam: string;
241
+ notNull: true;
242
+ hasDefault: true;
243
+ isPrimaryKey: false;
244
+ isAutoincrement: false;
245
+ hasRuntimeDefault: false;
246
+ enumValues: undefined;
247
+ baseColumn: never;
248
+ identity: undefined;
249
+ generated: undefined;
250
+ }, {}, {}>;
251
+ };
252
+ dialect: 'pg';
253
+ }>;
254
+ //# sourceMappingURL=outbox-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-table.d.ts","sourceRoot":"","sources":["../../../src/postgres/outbox/outbox-table.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2B9C"}
@@ -0,0 +1,33 @@
1
+ import { sql } from 'drizzle-orm';
2
+ import { bigint, index, integer, jsonb, text } from 'drizzle-orm/pg-core';
3
+ import { instant } from '../columns/instant.js';
4
+ import { tableIn } from '../schema/table-in.js';
5
+ /**
6
+ * The outbox table, to include in the schema files drizzle-kit reads so that it is created by
7
+ * the migrations of the consuming project. Without a schema name it lives in `public`.
8
+ */
9
+ export function outboxTable(schemaName) {
10
+ return tableIn(schemaName)('outbox', {
11
+ id: text('id').primaryKey(),
12
+ /** Insertion order, the tie-breaker of the claim. */
13
+ sequence: bigint('sequence', { mode: 'number' }).generatedAlwaysAsIdentity(),
14
+ type: text('type').notNull(),
15
+ version: integer('version').notNull(),
16
+ // Text, not timestamptz: the envelope must come back exactly as published, offset included.
17
+ occurredAt: text('occurred_at').notNull(),
18
+ // Nullable because JSON `null` is a legal payload and is stored as SQL NULL.
19
+ payload: jsonb('payload'),
20
+ traceparent: text('traceparent'),
21
+ correlationId: text('correlation_id'),
22
+ status: text('status').$type().notNull().default('pending'),
23
+ attempts: integer('attempts').notNull().default(0),
24
+ nextAttemptAt: instant('next_attempt_at').notNull(),
25
+ lastErrorCode: text('last_error_code'),
26
+ publishedAt: instant('published_at'),
27
+ createdAt: instant('created_at').notNull().defaultNow(),
28
+ }, (table) => [
29
+ // Partial: the relay only ever scans what is pending, and published rows dominate.
30
+ index('outbox_pending_idx').on(table.nextAttemptAt, table.sequence).where(sql `${table.status} = 'pending'`),
31
+ ]);
32
+ }
33
+ //# sourceMappingURL=outbox-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outbox-table.js","sourceRoot":"","sources":["../../../src/postgres/outbox/outbox-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE1E,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIhD;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,UAAmB;IAC7C,OAAO,OAAO,CAAC,UAAU,CAAC,CACxB,QAAQ,EACR;QACE,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE;QAC3B,qDAAqD;QACrD,QAAQ,EAAE,MAAM,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,yBAAyB,EAAE;QAC5E,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;QAC5B,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;QACrC,4FAA4F;QAC5F,UAAU,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,OAAO,EAAE;QACzC,6EAA6E;QAC7E,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC;QACzB,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC;QAChC,aAAa,EAAE,IAAI,CAAC,gBAAgB,CAAC;QACrC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAgB,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC;QACzE,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAClD,aAAa,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAO,EAAE;QACnD,aAAa,EAAE,IAAI,CAAC,iBAAiB,CAAC;QACtC,WAAW,EAAE,OAAO,CAAC,cAAc,CAAC;QACpC,SAAS,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;KACxD,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;QACT,mFAAmF;QACnF,KAAK,CAAC,oBAAoB,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,CAAA,GAAG,KAAK,CAAC,MAAM,cAAc,CAAC;KAC5G,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,61 @@
1
+ export type ProcessedEventsTable = ReturnType<typeof processedEventsTable>;
2
+ /** The idempotency table of the consumers, to include in the migrations like the outbox. */
3
+ export declare function processedEventsTable(schemaName?: string): import("drizzle-orm/pg-core").PgTableWithColumns<{
4
+ name: "processed_events";
5
+ schema: string | undefined;
6
+ columns: {
7
+ consumer: import("drizzle-orm/pg-core").PgColumn<{
8
+ name: "consumer";
9
+ tableName: "processed_events";
10
+ dataType: "string";
11
+ columnType: "PgText";
12
+ data: string;
13
+ driverParam: string;
14
+ notNull: true;
15
+ hasDefault: false;
16
+ isPrimaryKey: false;
17
+ isAutoincrement: false;
18
+ hasRuntimeDefault: false;
19
+ enumValues: [string, ...string[]];
20
+ baseColumn: never;
21
+ identity: undefined;
22
+ generated: undefined;
23
+ }, {}, {}>;
24
+ eventId: import("drizzle-orm/pg-core").PgColumn<{
25
+ name: "event_id";
26
+ tableName: "processed_events";
27
+ dataType: "string";
28
+ columnType: "PgText";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: false;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {}>;
41
+ processedAt: import("drizzle-orm/pg-core").PgColumn<{
42
+ name: string;
43
+ tableName: "processed_events";
44
+ dataType: "date";
45
+ columnType: "PgTimestamp";
46
+ data: Date;
47
+ driverParam: string;
48
+ notNull: true;
49
+ hasDefault: true;
50
+ isPrimaryKey: false;
51
+ isAutoincrement: false;
52
+ hasRuntimeDefault: false;
53
+ enumValues: undefined;
54
+ baseColumn: never;
55
+ identity: undefined;
56
+ generated: undefined;
57
+ }, {}, {}>;
58
+ };
59
+ dialect: 'pg';
60
+ }>;
61
+ //# sourceMappingURL=processed-events-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processed-events-table.d.ts","sourceRoot":"","sources":["../../../src/postgres/outbox/processed-events-table.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAE3E,4FAA4F;AAC5F,wBAAgB,oBAAoB,CAAC,UAAU,CAAC,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAWvD"}
@@ -0,0 +1,14 @@
1
+ import { primaryKey, text } from 'drizzle-orm/pg-core';
2
+ import { instant } from '../columns/instant.js';
3
+ import { tableIn } from '../schema/table-in.js';
4
+ /** The idempotency table of the consumers, to include in the migrations like the outbox. */
5
+ export function processedEventsTable(schemaName) {
6
+ return tableIn(schemaName)('processed_events', {
7
+ consumer: text('consumer').notNull(),
8
+ eventId: text('event_id').notNull(),
9
+ processedAt: instant('processed_at').notNull().defaultNow(),
10
+ },
11
+ // The primary key is the unique (consumer, event_id) the store relies on.
12
+ (table) => [primaryKey({ columns: [table.consumer, table.eventId] })]);
13
+ }
14
+ //# sourceMappingURL=processed-events-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"processed-events-table.js","sourceRoot":"","sources":["../../../src/postgres/outbox/processed-events-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIhD,4FAA4F;AAC5F,MAAM,UAAU,oBAAoB,CAAC,UAAmB;IACtD,OAAO,OAAO,CAAC,UAAU,CAAC,CACxB,kBAAkB,EAClB;QACE,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;QACpC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE;QACnC,WAAW,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE;KAC5D;IACD,0EAA0E;IAC1E,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CACtE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PgColumn } from 'drizzle-orm/pg-core';
2
+ /** The column a field is mapped to. A field without a column is a mistake of the adapter, never of a caller. */
3
+ export declare function columnOf(columns: Readonly<Record<string, PgColumn>>, field: string): PgColumn;
4
+ //# sourceMappingURL=column-of.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-of.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/column-of.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,gHAAgH;AAChH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAQ7F"}
@@ -0,0 +1,9 @@
1
+ /** The column a field is mapped to. A field without a column is a mistake of the adapter, never of a caller. */
2
+ export function columnOf(columns, field) {
3
+ const column = Object.hasOwn(columns, field) ? columns[field] : undefined;
4
+ if (column === undefined) {
5
+ throw new Error(`The field "${field}" is mapped to no column`);
6
+ }
7
+ return column;
8
+ }
9
+ //# sourceMappingURL=column-of.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-of.js","sourceRoot":"","sources":["../../../src/postgres/read-model/column-of.ts"],"names":[],"mappings":"AAEA,gHAAgH;AAChH,MAAM,UAAU,QAAQ,CAAC,OAA2C,EAAE,KAAa;IACjF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1E,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,cAAc,KAAK,0BAA0B,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import { type SQL } from 'drizzle-orm';
2
+ import type { PgColumn } from 'drizzle-orm/pg-core';
3
+ import type { CriteriaPlan } from '@ddd-ts-kit/kernel';
4
+ /** A criteria plan as the parts of a drizzle query. */
5
+ export interface DrizzleCriteria {
6
+ /** The filters, the scope of the actor and the keyset of a cursor page. */
7
+ readonly where: SQL | undefined;
8
+ /** The filters and the scope alone: what the total of an offset page counts. */
9
+ readonly counted: SQL | undefined;
10
+ readonly orderBy: SQL[];
11
+ readonly limit: number;
12
+ readonly offset: number;
13
+ }
14
+ /**
15
+ * Turns a criteria plan into the parts of a query on the table of a read model:
16
+ * `db.select().from(appointments).where(where).orderBy(...orderBy).limit(limit).offset(offset)`,
17
+ * then `pageOfPlan(plan, rows)`. A field that may be null is ordered as the plan means it:
18
+ * nulls last ascending, first descending.
19
+ */
20
+ export declare function criteriaToDrizzle(plan: CriteriaPlan, columns: Readonly<Record<string, PgColumn>>): DrizzleCriteria;
21
+ //# sourceMappingURL=criteria-to-drizzle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"criteria-to-drizzle.d.ts","sourceRoot":"","sources":["../../../src/postgres/read-model/criteria-to-drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAC5D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD,uDAAuD;AACvD,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAAC;IAChC,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,GAAG,eAAe,CAkBlH"}