@gobing-ai/ts-db 0.2.8 → 0.3.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 +52 -1
- package/dist/drizzle-builders.d.ts +96 -0
- package/dist/drizzle-builders.d.ts.map +1 -0
- package/dist/drizzle-builders.js +17 -0
- package/dist/embedded-migrations.d.ts.map +1 -1
- package/dist/embedded-migrations.js +10 -0
- package/dist/entity-dao.d.ts.map +1 -1
- package/dist/inbox-message-dao.d.ts +19 -0
- package/dist/inbox-message-dao.d.ts.map +1 -0
- package/dist/inbox-message-dao.js +75 -0
- package/dist/inbox.d.ts +3 -0
- package/dist/inbox.d.ts.map +1 -0
- package/dist/inbox.js +2 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/migrate.d.ts +12 -5
- package/dist/migrate.d.ts.map +1 -1
- package/dist/migrate.js +19 -25
- package/dist/queue-job-dao.d.ts.map +1 -1
- package/dist/schema/ddl.d.ts.map +1 -1
- package/dist/schema/ddl.js +4 -36
- package/dist/schema/drizzle-internals.d.ts +25 -0
- package/dist/schema/drizzle-internals.d.ts.map +1 -0
- package/dist/schema/drizzle-internals.js +47 -0
- package/dist/schema/inbox-messages.d.ts +212 -0
- package/dist/schema/inbox-messages.d.ts.map +1 -0
- package/dist/schema/inbox-messages.js +17 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +1 -0
- package/dist/schema/runtime.d.ts +1 -0
- package/dist/schema/runtime.d.ts.map +1 -1
- package/dist/schema/runtime.js +1 -0
- package/package.json +7 -2
- package/src/drizzle-builders.ts +98 -0
- package/src/embedded-migrations.ts +10 -0
- package/src/entity-dao.ts +2 -21
- package/src/inbox-message-dao.ts +91 -0
- package/src/inbox.ts +2 -0
- package/src/index.ts +3 -1
- package/src/migrate.ts +34 -22
- package/src/queue-job-dao.ts +14 -59
- package/src/schema/ddl.ts +4 -40
- package/src/schema/drizzle-internals.ts +55 -0
- package/src/schema/inbox-messages.ts +22 -0
- package/src/schema/index.ts +1 -0
- package/src/schema/runtime.ts +1 -0
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ Application code imports only `@gobing-ai/ts-db` — never `drizzle-orm`. drizzl
|
|
|
22
22
|
| `defineTable` | Single source of truth — one table → drizzle table + derived zod insert/select schemas (optional peers) |
|
|
23
23
|
| `Predicate` / `ListSpec` / `OrderTerm` | The drizzle-free query vocabulary |
|
|
24
24
|
| `QueueJobDao` | Job queue persistence — `enqueue`, `claimReady`, `markCompleted`, `failExpiredJobs` |
|
|
25
|
+
| `InboxMessageDao` | Durable inter-agent message persistence (`@gobing-ai/ts-db/inbox`) |
|
|
25
26
|
| `applyMigrations` | Drizzle migration runner (file-based + embedded fallback) |
|
|
26
27
|
| `schema` helpers | `standardColumns`, `appendOnlyColumns`, soft-delete columns |
|
|
27
28
|
| `SpanContext` | Re-exported from `@gobing-ai/ts-runtime` for telemetry |
|
|
@@ -102,6 +103,15 @@ classDiagram
|
|
|
102
103
|
+getStats() QueueStats
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
class InboxMessageDao {
|
|
107
|
+
+enqueue(fromId, toId, body, inReplyTo?) string
|
|
108
|
+
+drainPending(toId) InboxMessage[]
|
|
109
|
+
+markDelivered(msgId) void
|
|
110
|
+
+markFailed(msgId, error) void
|
|
111
|
+
+inbox(toId, limit?, offset?) InboxMessage[]
|
|
112
|
+
+countPending(toId) number
|
|
113
|
+
}
|
|
114
|
+
|
|
105
115
|
class ColumnHelpers {
|
|
106
116
|
+standardColumns
|
|
107
117
|
+standardColumnsWithSoftDelete
|
|
@@ -112,6 +122,10 @@ classDiagram
|
|
|
112
122
|
+queueJobs
|
|
113
123
|
}
|
|
114
124
|
|
|
125
|
+
class InboxMessagesTable {
|
|
126
|
+
+inboxMessages
|
|
127
|
+
}
|
|
128
|
+
|
|
115
129
|
class MigrationRunner {
|
|
116
130
|
+applyMigrations(adapter, opts?) void
|
|
117
131
|
}
|
|
@@ -124,7 +138,9 @@ classDiagram
|
|
|
124
138
|
DbAdapter <|.. D1Adapter : implements
|
|
125
139
|
BaseDao <|-- EntityDao : extends
|
|
126
140
|
EntityDao <|-- QueueJobDao : extends
|
|
141
|
+
EntityDao <|-- InboxMessageDao : extends
|
|
127
142
|
QueueJobDao --> QueueJobsTable : "uses"
|
|
143
|
+
InboxMessageDao --> InboxMessagesTable : "uses"
|
|
128
144
|
MigrationRunner --> EmbeddedMigrations : "uses"
|
|
129
145
|
MigrationRunner --> BunSqliteAdapter : "requires"
|
|
130
146
|
```
|
|
@@ -233,6 +249,39 @@ const stats = await queue.getStats();
|
|
|
233
249
|
// → { pending: 5, processing: 2, completed: 100, failed: 3 }
|
|
234
250
|
```
|
|
235
251
|
|
|
252
|
+
### InboxMessageDao — durable inter-agent messages
|
|
253
|
+
|
|
254
|
+
`InboxMessageDao` persists directed messages for team-mode or multi-agent workflows. It lives on the
|
|
255
|
+
`@gobing-ai/ts-db/inbox` subpath so consumers can depend on the inbox surface without pulling schema
|
|
256
|
+
helpers.
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
import { InboxMessageDao } from '@gobing-ai/ts-db/inbox';
|
|
260
|
+
|
|
261
|
+
const inbox = new InboxMessageDao(adapter);
|
|
262
|
+
|
|
263
|
+
// Operator sends a task to an agent.
|
|
264
|
+
const msgId = await inbox.enqueue(null, 'coder', 'Please inspect packages/db');
|
|
265
|
+
|
|
266
|
+
// Agent process startup/live-injection path atomically drains queued work.
|
|
267
|
+
const pending = await inbox.drainPending('coder');
|
|
268
|
+
for (const msg of pending) {
|
|
269
|
+
try {
|
|
270
|
+
await injectIntoAgentStdin(`[task from=${msg.fromId ?? 'operator'} id=${msg.id}] ${msg.body}`);
|
|
271
|
+
await inbox.markDelivered(msg.id);
|
|
272
|
+
} catch (error) {
|
|
273
|
+
await inbox.markFailed(msg.id, String(error));
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const history = await inbox.inbox('coder', 20);
|
|
278
|
+
const queued = await inbox.countPending('coder');
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
The `inbox_messages` table is additive and included in embedded migrations. It stores `from_id`,
|
|
282
|
+
`to_id`, `body`, `status`, optional reply linkage, delivery timestamp, injection attempts, and the
|
|
283
|
+
last injection error. The indexed access path is `(to_id, status)` for efficient pending drains.
|
|
284
|
+
|
|
236
285
|
### Migrations
|
|
237
286
|
|
|
238
287
|
```ts
|
|
@@ -252,7 +301,7 @@ await applyMigrations(adapter);
|
|
|
252
301
|
|
|
253
302
|
```ts
|
|
254
303
|
import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
255
|
-
import { standardColumns, standardColumnsWithSoftDelete, queueJobs } from '@gobing-ai/ts-db';
|
|
304
|
+
import { standardColumns, standardColumnsWithSoftDelete, queueJobs, inboxMessages } from '@gobing-ai/ts-db';
|
|
256
305
|
|
|
257
306
|
// Standard columns (createdAt, updatedAt)
|
|
258
307
|
const docs = sqliteTable('docs', {
|
|
@@ -269,6 +318,8 @@ const projects = sqliteTable('projects', {
|
|
|
269
318
|
});
|
|
270
319
|
|
|
271
320
|
// queue_jobs table is pre-built for use with QueueJobDao
|
|
321
|
+
|
|
322
|
+
// inbox_messages table is pre-built for use with InboxMessageDao
|
|
272
323
|
```
|
|
273
324
|
|
|
274
325
|
## Usage
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared structural types for drizzle's fluent query builders.
|
|
3
|
+
*
|
|
4
|
+
* `InternalDb` is typed as the bare drizzle union (ADR-005 keeps drizzle internal),
|
|
5
|
+
* so its fluent builders (`insert().values().returning()`, `update().set().where()`,
|
|
6
|
+
* `select(proj).from()...`) are not surfaced as call-shapes. Each DAO previously
|
|
7
|
+
* re-declared these narrowings inline — three files independently describing the
|
|
8
|
+
* same `update → set → where → returning` chain. Centralising them here means the
|
|
9
|
+
* cast shape lives in one place: when drizzle's builder surface shifts, this file
|
|
10
|
+
* changes, not every DAO.
|
|
11
|
+
*
|
|
12
|
+
* These are deliberately minimal — each type narrows only the chain a DAO actually
|
|
13
|
+
* invokes. Table-specific projections (`select({ status, count })`) stay local to
|
|
14
|
+
* their DAO; only the recurring chain skeletons live here.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
18
|
+
/** Terminal `.returning()` returning the written rows. */
|
|
19
|
+
export interface ReturningRows {
|
|
20
|
+
returning: () => Promise<unknown[]>;
|
|
21
|
+
}
|
|
22
|
+
/** `insert(table).values(record)` → returning, with optional upsert. */
|
|
23
|
+
export interface InsertBuilder {
|
|
24
|
+
values: (record: unknown) => ReturningRows & {
|
|
25
|
+
onConflictDoUpdate: (cfg: {
|
|
26
|
+
target: unknown;
|
|
27
|
+
set: unknown;
|
|
28
|
+
}) => ReturningRows;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/** `update(table).set(data).where(cond)` → `.returning()` rows. */
|
|
32
|
+
export interface UpdateReturningDb {
|
|
33
|
+
update: (table: unknown) => {
|
|
34
|
+
set: (data: unknown) => {
|
|
35
|
+
where: (cond: unknown) => ReturningRows;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/** `update(table).set(data).where(cond)` → void (no rows). */
|
|
40
|
+
export interface UpdateVoidDb {
|
|
41
|
+
update: (table: unknown) => {
|
|
42
|
+
set: (data: unknown) => {
|
|
43
|
+
where: (cond: unknown) => Promise<unknown>;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** `update(table).set(data).where(cond)` → `{ changes }` (affected-row count). */
|
|
48
|
+
export interface UpdateChangesDb {
|
|
49
|
+
update: (table: unknown) => {
|
|
50
|
+
set: (data: unknown) => {
|
|
51
|
+
where: (cond: unknown) => Promise<{
|
|
52
|
+
changes: number;
|
|
53
|
+
}>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** `update(table).set(data).where(cond)` → arbitrary single condition (no projection). */
|
|
58
|
+
export interface SimpleUpdateDb {
|
|
59
|
+
update: (table: unknown) => {
|
|
60
|
+
set: (data: unknown) => {
|
|
61
|
+
where: (cond: unknown) => ReturningRows;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** `select(projection).from(table)` exposing `.where(...)` and `.groupBy(...)` terminals. */
|
|
66
|
+
export interface SelectProjectionDb {
|
|
67
|
+
select: (projection: unknown) => {
|
|
68
|
+
from: (table: unknown) => {
|
|
69
|
+
where: (cond: unknown) => Promise<unknown[]>;
|
|
70
|
+
groupBy: (group: unknown) => Promise<unknown[]>;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/** `select().from(table).where(cond).orderBy(o).limit(n)` — the ready-rows read chain. */
|
|
75
|
+
export interface SelectOrderedLimitDb {
|
|
76
|
+
select: () => {
|
|
77
|
+
from: (table: unknown) => {
|
|
78
|
+
where: (cond: unknown) => {
|
|
79
|
+
orderBy: (order: unknown) => {
|
|
80
|
+
limit: (limit: number) => Promise<unknown[]>;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** `select(count).from(table)` that is awaitable and chainable with `.where(...)`. */
|
|
87
|
+
export type CountQuery = Promise<unknown[]> & {
|
|
88
|
+
where: (condition: unknown) => Promise<unknown[]>;
|
|
89
|
+
};
|
|
90
|
+
/** `select({ value: count() }).from(table)` → awaitable count, optionally filtered. */
|
|
91
|
+
export interface CountSelectDb {
|
|
92
|
+
select: (projection: unknown) => {
|
|
93
|
+
from: (table: unknown) => CountQuery;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=drizzle-builders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle-builders.d.ts","sourceRoot":"","sources":["../src/drizzle-builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared structural types for drizzle's fluent query builders.
|
|
3
|
+
*
|
|
4
|
+
* `InternalDb` is typed as the bare drizzle union (ADR-005 keeps drizzle internal),
|
|
5
|
+
* so its fluent builders (`insert().values().returning()`, `update().set().where()`,
|
|
6
|
+
* `select(proj).from()...`) are not surfaced as call-shapes. Each DAO previously
|
|
7
|
+
* re-declared these narrowings inline — three files independently describing the
|
|
8
|
+
* same `update → set → where → returning` chain. Centralising them here means the
|
|
9
|
+
* cast shape lives in one place: when drizzle's builder surface shifts, this file
|
|
10
|
+
* changes, not every DAO.
|
|
11
|
+
*
|
|
12
|
+
* These are deliberately minimal — each type narrows only the chain a DAO actually
|
|
13
|
+
* invokes. Table-specific projections (`select({ status, count })`) stay local to
|
|
14
|
+
* their DAO; only the recurring chain skeletons live here.
|
|
15
|
+
*
|
|
16
|
+
* @internal
|
|
17
|
+
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedded-migrations.d.ts","sourceRoot":"","sources":["../src/embedded-migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"embedded-migrations.d.ts","sourceRoot":"","sources":["../src/embedded-migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,iBAAiB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,kBAAkB,EAAE,iBAAiB,EA0BjD,CAAC"}
|
|
@@ -22,4 +22,14 @@ export const embeddedMigrations = [
|
|
|
22
22
|
sql: 'ALTER TABLE `queue_jobs` ADD `expires_at` integer;',
|
|
23
23
|
hash: '7380f8c162352a61b15205af5a87e0e7313a499203dae98fe62151a1dc7fec0e',
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
tag: '0003_inbox_messages',
|
|
27
|
+
sql: "CREATE TABLE `inbox_messages` (\n\t`id` text PRIMARY KEY NOT NULL,\n\t`from_id` text,\n\t`to_id` text NOT NULL,\n\t`body` text NOT NULL,\n\t`status` text DEFAULT 'queued' NOT NULL,\n\t`in_reply_to` text,\n\t`created_at` integer NOT NULL,\n\t`updated_at` integer NOT NULL,\n\t`delivered_at` integer,\n\t`inject_attempts` integer DEFAULT 0 NOT NULL,\n\t`inject_error` text\n);",
|
|
28
|
+
hash: 'c4ba569172d1be276c42b5c164c668404e6229dcf48b41d7fb2bc93e8d29d11b',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
tag: '0004_inbox_messages_to_status_idx',
|
|
32
|
+
sql: 'CREATE INDEX `idx_inbox_messages_to_status` ON `inbox_messages` (`to_id`,`status`);',
|
|
33
|
+
hash: '3c00f1bce4f569e442f3142df31ff478d6c9b3d460824d46575f50a324bfae61',
|
|
34
|
+
},
|
|
25
35
|
];
|
package/dist/entity-dao.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-dao.d.ts","sourceRoot":"","sources":["../src/entity-dao.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"entity-dao.d.ts","sourceRoot":"","sources":["../src/entity-dao.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { DbAdapter } from './adapter';
|
|
2
|
+
import { EntityDao } from './entity-dao';
|
|
3
|
+
import { inboxMessages } from './schema/inbox-messages';
|
|
4
|
+
/** Row type inferred from the inbox_messages Drizzle schema. */
|
|
5
|
+
export type InboxMessage = typeof inboxMessages.$inferSelect;
|
|
6
|
+
/**
|
|
7
|
+
* DAO for durable inter-agent inbox messages.
|
|
8
|
+
*/
|
|
9
|
+
export declare class InboxMessageDao extends EntityDao<typeof inboxMessages, typeof inboxMessages.id> {
|
|
10
|
+
constructor(adapter: DbAdapter);
|
|
11
|
+
enqueue(fromId: string | null, toId: string, body: string, inReplyTo?: string): Promise<string>;
|
|
12
|
+
drainPending(toId: string): Promise<InboxMessage[]>;
|
|
13
|
+
markDelivered(msgId: string): Promise<void>;
|
|
14
|
+
markFailed(msgId: string, error: string): Promise<void>;
|
|
15
|
+
inbox(toId: string, limit?: number, offset?: number): Promise<InboxMessage[]>;
|
|
16
|
+
countPending(toId: string): Promise<number>;
|
|
17
|
+
getById(id: string): Promise<InboxMessage | undefined>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=inbox-message-dao.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox-message-dao.d.ts","sourceRoot":"","sources":["../src/inbox-message-dao.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,gEAAgE;AAChE,MAAM,MAAM,YAAY,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAE7D;;GAEG;AACH,qBAAa,eAAgB,SAAQ,SAAS,CAAC,OAAO,aAAa,EAAE,OAAO,aAAa,CAAC,EAAE,CAAC;gBAC7E,OAAO,EAAE,SAAS;IAIxB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAc/F,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAwBnD,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAS7E,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAS3C,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC;CAG/D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { EntityDao } from './entity-dao.js';
|
|
3
|
+
import { inboxMessages } from './schema/inbox-messages.js';
|
|
4
|
+
/**
|
|
5
|
+
* DAO for durable inter-agent inbox messages.
|
|
6
|
+
*/
|
|
7
|
+
export class InboxMessageDao extends EntityDao {
|
|
8
|
+
constructor(adapter) {
|
|
9
|
+
super(adapter, inboxMessages, [inboxMessages.id], 'inbox_messages');
|
|
10
|
+
}
|
|
11
|
+
async enqueue(fromId, toId, body, inReplyTo) {
|
|
12
|
+
const id = crypto.randomUUID();
|
|
13
|
+
await this.create({
|
|
14
|
+
id,
|
|
15
|
+
fromId,
|
|
16
|
+
toId,
|
|
17
|
+
body,
|
|
18
|
+
status: 'queued',
|
|
19
|
+
injectAttempts: 0,
|
|
20
|
+
...(inReplyTo !== undefined ? { inReplyTo } : {}),
|
|
21
|
+
});
|
|
22
|
+
return id;
|
|
23
|
+
}
|
|
24
|
+
async drainPending(toId) {
|
|
25
|
+
const now = this.now();
|
|
26
|
+
const rows = await this.db
|
|
27
|
+
.update(inboxMessages)
|
|
28
|
+
.set({
|
|
29
|
+
status: 'injected',
|
|
30
|
+
injectAttempts: sql `${inboxMessages.injectAttempts} + 1`,
|
|
31
|
+
updatedAt: now,
|
|
32
|
+
})
|
|
33
|
+
.where(sql `${inboxMessages.id} IN (
|
|
34
|
+
SELECT id
|
|
35
|
+
FROM ${inboxMessages}
|
|
36
|
+
WHERE to_id = ${toId}
|
|
37
|
+
AND status = 'queued'
|
|
38
|
+
ORDER BY created_at
|
|
39
|
+
)
|
|
40
|
+
AND ${inboxMessages.status} = 'queued'`)
|
|
41
|
+
.returning();
|
|
42
|
+
return rows;
|
|
43
|
+
}
|
|
44
|
+
async markDelivered(msgId) {
|
|
45
|
+
await this.update(msgId, {
|
|
46
|
+
status: 'delivered',
|
|
47
|
+
deliveredAt: this.now(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async markFailed(msgId, error) {
|
|
51
|
+
await this.update(msgId, {
|
|
52
|
+
status: 'failed',
|
|
53
|
+
injectError: error,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async inbox(toId, limit, offset) {
|
|
57
|
+
return this.list({
|
|
58
|
+
where: { col: inboxMessages.toId, op: 'eq', value: toId },
|
|
59
|
+
orderBy: [{ col: inboxMessages.createdAt, dir: 'desc' }],
|
|
60
|
+
...(limit !== undefined ? { limit } : {}),
|
|
61
|
+
...(offset !== undefined ? { offset } : {}),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async countPending(toId) {
|
|
65
|
+
return this.count({
|
|
66
|
+
and: [
|
|
67
|
+
{ col: inboxMessages.toId, op: 'eq', value: toId },
|
|
68
|
+
{ col: inboxMessages.status, op: 'eq', value: 'queued' },
|
|
69
|
+
],
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async getById(id) {
|
|
73
|
+
return this.findBy(inboxMessages.id, id);
|
|
74
|
+
}
|
|
75
|
+
}
|
package/dist/inbox.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/inbox.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -3,10 +3,12 @@ export { D1Adapter } from './adapters/d1';
|
|
|
3
3
|
export { BaseDao, type TxHandle } from './base-dao';
|
|
4
4
|
export { type EmbeddedMigration, embeddedMigrations } from './embedded-migrations';
|
|
5
5
|
export { type CursorListSpec, type DaoValidator, EntityDao, type EntityDaoOptions, type EntityListSpec, type EntityTable, type PKColumn, type PKValue, type SoftDeletableTable, } from './entity-dao';
|
|
6
|
-
export {
|
|
6
|
+
export { type InboxMessage, InboxMessageDao } from './inbox-message-dao';
|
|
7
|
+
export { applyMigrations, type MigrationLogger, type MigrationOptions } from './migrate';
|
|
7
8
|
export { type ColRef, type ComparisonOp, compileOrderBy, compilePredicate, type ListSpec, type OrderTerm, type Predicate, } from './query-spec';
|
|
8
9
|
export { QueueJobDao, type QueueJobRecord, type QueueStats } from './queue-job-dao';
|
|
9
10
|
export { appendOnlyColumns, buildAppendOnlyColumns, buildStandardColumns, buildStandardColumnsWithSoftDelete, nowTimestamp, standardColumns, standardColumnsWithSoftDelete, } from './schema/common';
|
|
11
|
+
export { inboxMessages } from './schema/inbox-messages';
|
|
10
12
|
export { queueJobs } from './schema/queue-jobs';
|
|
11
13
|
export type { SpanContext } from './span-context';
|
|
12
14
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,kBAAkB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AACnG,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,KAAK,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACH,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,SAAS,EACT,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,kBAAkB,GAC1B,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,WAAW,CAAC;AACzF,OAAO,EACH,KAAK,MAAM,EACX,KAAK,YAAY,EACjB,cAAc,EACd,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,SAAS,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACpF,OAAO,EACH,iBAAiB,EACjB,sBAAsB,EACtB,oBAAoB,EACpB,kCAAkC,EAClC,YAAY,EACZ,eAAe,EACf,6BAA6B,GAChC,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,8 +3,10 @@ export { D1Adapter } from './adapters/d1.js';
|
|
|
3
3
|
export { BaseDao } from './base-dao.js';
|
|
4
4
|
export { embeddedMigrations } from './embedded-migrations.js';
|
|
5
5
|
export { EntityDao, } from './entity-dao.js';
|
|
6
|
+
export { InboxMessageDao } from './inbox-message-dao.js';
|
|
6
7
|
export { applyMigrations } from './migrate.js';
|
|
7
8
|
export { compileOrderBy, compilePredicate, } from './query-spec.js';
|
|
8
9
|
export { QueueJobDao } from './queue-job-dao.js';
|
|
9
10
|
export { appendOnlyColumns, buildAppendOnlyColumns, buildStandardColumns, buildStandardColumnsWithSoftDelete, nowTimestamp, standardColumns, standardColumnsWithSoftDelete, } from './schema/common.js';
|
|
11
|
+
export { inboxMessages } from './schema/inbox-messages.js';
|
|
10
12
|
export { queueJobs } from './schema/queue-jobs.js';
|
package/dist/migrate.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import type { FileSystem } from '@gobing-ai/ts-runtime';
|
|
2
2
|
import type { DbAdapter } from './adapter';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Minimal structural logger for migration progress.
|
|
5
|
+
*
|
|
6
|
+
* Structurally compatible with `@gobing-ai/ts-infra`'s `Logger` so consumers can
|
|
7
|
+
* pass theirs directly — ts-db never imports ts-infra (keeps the package
|
|
8
|
+
* boundary). Defaults to `console` when absent.
|
|
7
9
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
export interface MigrationLogger {
|
|
11
|
+
info(msg: string): void;
|
|
12
|
+
warn(msg: string): void;
|
|
13
|
+
error(msg: string): void;
|
|
14
|
+
}
|
|
10
15
|
/**
|
|
11
16
|
* Options for configuring migration behaviour (folder path, table name).
|
|
12
17
|
*/
|
|
@@ -17,6 +22,8 @@ export interface MigrationOptions {
|
|
|
17
22
|
migrationsTable?: string;
|
|
18
23
|
/** File system abstraction for path resolution. */
|
|
19
24
|
fs?: FileSystem;
|
|
25
|
+
/** Logger for migration progress. Default: `console`. */
|
|
26
|
+
logger?: MigrationLogger;
|
|
20
27
|
}
|
|
21
28
|
/**
|
|
22
29
|
* Apply pending migrations using drizzle-orm's built-in migrator.
|
package/dist/migrate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mDAAmD;IACnD,EAAE,CAAC,EAAE,UAAU,CAAC;IAChB,yDAAyD;IACzD,MAAM,CAAC,EAAE,eAAe,CAAC;CAC5B;AA8ED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDnG"}
|
package/dist/migrate.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { embeddedMigrations } from './embedded-migrations.js';
|
|
3
|
-
/**
|
|
4
|
-
* Find project root by walking up looking for bun.lock.
|
|
5
|
-
* @deprecated Use `FileSystem.getProjectRoot()` instead.
|
|
6
|
-
* @internal — only used for backward compatibility.
|
|
7
|
-
*/
|
|
8
|
-
/** @internal */
|
|
9
|
-
export function findProjectRoot(_startDir) {
|
|
10
|
-
return process.cwd();
|
|
11
|
-
}
|
|
12
3
|
/**
|
|
13
4
|
* Ensure the migration tracking table exists with proper SQLite types.
|
|
14
5
|
*
|
|
@@ -35,7 +26,7 @@ function validateMigrationTableName(table) {
|
|
|
35
26
|
* Checks the journal table and applies only migrations that haven't run yet.
|
|
36
27
|
* Each migration is executed with adapter.exec() for file-based or adapter.run() for journal tracking.
|
|
37
28
|
*/
|
|
38
|
-
async function applyEmbeddedMigrations(adapter, journalTable) {
|
|
29
|
+
async function applyEmbeddedMigrations(adapter, journalTable, logger) {
|
|
39
30
|
// Validate journal table name — this is an internal constant, never user input.
|
|
40
31
|
if (!/^__[a-z_]+$/.test(journalTable)) {
|
|
41
32
|
throw new Error(`Invalid migration journal table name: ${journalTable}`);
|
|
@@ -55,7 +46,7 @@ async function applyEmbeddedMigrations(adapter, journalTable) {
|
|
|
55
46
|
for (const migration of embeddedMigrations) {
|
|
56
47
|
if (appliedHashes.has(migration.hash))
|
|
57
48
|
continue;
|
|
58
|
-
|
|
49
|
+
logger.info(`Applying embedded migration: ${migration.tag}`);
|
|
59
50
|
// Split on semicolons and execute each non-empty statement
|
|
60
51
|
const statements = migration.sql
|
|
61
52
|
.split(';')
|
|
@@ -69,7 +60,7 @@ async function applyEmbeddedMigrations(adapter, journalTable) {
|
|
|
69
60
|
applied++;
|
|
70
61
|
}
|
|
71
62
|
if (applied > 0) {
|
|
72
|
-
|
|
63
|
+
logger.info(`Applied ${applied} embedded migration(s)`);
|
|
73
64
|
}
|
|
74
65
|
}
|
|
75
66
|
/**
|
|
@@ -89,43 +80,46 @@ async function applyEmbeddedMigrations(adapter, journalTable) {
|
|
|
89
80
|
* @param options - Optional migration folder and table name overrides.
|
|
90
81
|
*/
|
|
91
82
|
export async function applyMigrations(adapter, options) {
|
|
83
|
+
const logger = options?.logger ?? console;
|
|
92
84
|
const { BunSqliteAdapter } = await import('./adapters/bun-sqlite.js');
|
|
93
85
|
if (!(adapter instanceof BunSqliteAdapter)) {
|
|
94
|
-
|
|
86
|
+
logger.warn('Skipping in-app migrations: only supported for bun-sqlite adapter');
|
|
95
87
|
return;
|
|
96
88
|
}
|
|
97
89
|
const table = validateMigrationTableName(options?.migrationsTable ?? '__drizzle_migrations');
|
|
98
90
|
await ensureJournalTable(adapter, table);
|
|
99
|
-
const folder = options?.migrationsFolder ?? resolve(
|
|
100
|
-
// File-based migrations: attempt if drizzle/ folder is
|
|
101
|
-
//
|
|
91
|
+
const folder = options?.migrationsFolder ?? resolve(process.cwd(), 'drizzle');
|
|
92
|
+
// File-based migrations: attempt only if the drizzle/ folder is present.
|
|
93
|
+
// With an injected fs we get a definitive answer (await the Promise — a bare
|
|
94
|
+
// `fs.exists(...)` is always truthy and silently disables the check); without
|
|
95
|
+
// one we attempt optimistically and fall back on the migrator's own error.
|
|
102
96
|
const fs = options?.fs;
|
|
103
|
-
const tryFileBased = fs
|
|
97
|
+
const tryFileBased = fs ? await fs.exists(folder) : true;
|
|
104
98
|
if (tryFileBased) {
|
|
105
99
|
try {
|
|
106
100
|
const { migrate: drizzleMigrate } = await import('drizzle-orm/bun-sqlite/migrator');
|
|
107
|
-
|
|
101
|
+
logger.info(`Applying database migrations from ${folder}`);
|
|
108
102
|
await drizzleMigrate(adapter.getDrizzleDb(), {
|
|
109
103
|
migrationsFolder: folder,
|
|
110
104
|
...(options?.migrationsTable !== undefined ? { migrationsTable: options.migrationsTable } : {}),
|
|
111
105
|
});
|
|
112
|
-
|
|
106
|
+
logger.info('Database migrations complete');
|
|
113
107
|
return;
|
|
114
108
|
}
|
|
115
109
|
catch (error) {
|
|
116
|
-
//
|
|
117
|
-
// Any other
|
|
110
|
+
// A missing/empty migrations folder is expected in compiled binaries —
|
|
111
|
+
// fall through to embedded. Any other failure is real; rethrow it.
|
|
118
112
|
const message = error instanceof Error ? error.message : String(error);
|
|
119
113
|
if (message.includes('journal') || message.includes('ENOENT') || message.includes('meta')) {
|
|
120
|
-
|
|
114
|
+
logger.info(`File-based migrations unavailable, using embedded: ${message}`);
|
|
121
115
|
}
|
|
122
116
|
else {
|
|
123
|
-
|
|
117
|
+
logger.error(`[MIGRATE] drizzleMigrate failed: ${message}`);
|
|
124
118
|
throw error;
|
|
125
119
|
}
|
|
126
120
|
}
|
|
127
121
|
}
|
|
128
122
|
// Fallback: embedded migrations (for compiled binaries)
|
|
129
|
-
|
|
130
|
-
await applyEmbeddedMigrations(adapter, table);
|
|
123
|
+
logger.info('No drizzle/ folder found — applying embedded migrations');
|
|
124
|
+
await applyEmbeddedMigrations(adapter, table, logger);
|
|
131
125
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue-job-dao.d.ts","sourceRoot":"","sources":["../src/queue-job-dao.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"queue-job-dao.d.ts","sourceRoot":"","sources":["../src/queue-job-dao.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAQ3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AAE3D;;;;;GAKG;AACH,qBAAa,WAAY,SAAQ,SAAS,CAAC,OAAO,SAAS,EAAE,OAAO,SAAS,CAAC,EAAE,CAAC;gBACjE,OAAO,EAAE,SAAS;IAI9B;;OAEG;IACG,OAAO,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,EAChB,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAClE,OAAO,CAAC,MAAM,CAAC;IAkBlB;;OAEG;IACG,YAAY,CACd,IAAI,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAC1G,OAAO,CAAC,MAAM,EAAE,CAAC;IA+BpB;;OAEG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAI9D;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC;IAoBrC;;OAEG;IACG,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASpD;;OAEG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAe/D;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAyB9D;;OAEG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlD;;OAEG;IACG,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9C;;OAEG;IACG,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5E;;OAEG;IACG,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU1G;;OAEG;IACG,cAAc,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAahE;;;;;OAKG;IACG,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC;CAkB3C"}
|
package/dist/schema/ddl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../src/schema/ddl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"ddl.d.ts","sourceRoot":"","sources":["../../src/schema/ddl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAmC3E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAsFjE"}
|
package/dist/schema/ddl.js
CHANGED
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
import { getTableConfig } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
import { getDrizzleTableName, sqlExpressionToText } from './drizzle-internals.js';
|
|
2
3
|
/**
|
|
3
4
|
* Quote an identifier for use in SQL (double-quoted for SQLite compatibility).
|
|
4
5
|
*/
|
|
5
6
|
function quoteIdent(name) {
|
|
6
7
|
return `"${name.replace(/"/g, '""')}"`;
|
|
7
8
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Extract the SQL string from a drizzle-orm SQL expression by walking its
|
|
10
|
-
* internal `queryChunks` — StringChunk values plus Param placeholders.
|
|
11
|
-
*/
|
|
12
|
-
function sqlToString(chunks) {
|
|
13
|
-
return chunks
|
|
14
|
-
.map((chunk) => {
|
|
15
|
-
// StringChunk — the literal SQL fragment
|
|
16
|
-
if ('value' in chunk && typeof chunk.value === 'string') {
|
|
17
|
-
return chunk.value;
|
|
18
|
-
}
|
|
19
|
-
// Param — use the input value if available
|
|
20
|
-
if ('input' in chunk && chunk.input !== undefined) {
|
|
21
|
-
return String(chunk.input);
|
|
22
|
-
}
|
|
23
|
-
return String(chunk.value ?? '?');
|
|
24
|
-
})
|
|
25
|
-
.join('');
|
|
26
|
-
}
|
|
27
9
|
/**
|
|
28
10
|
* Map a column default value to its SQL literal representation.
|
|
29
11
|
*
|
|
@@ -45,22 +27,8 @@ function defaultToSql(value) {
|
|
|
45
27
|
if (typeof value === 'boolean') {
|
|
46
28
|
return value ? '1' : '0';
|
|
47
29
|
}
|
|
48
|
-
// drizzle-orm SQL expression (
|
|
49
|
-
|
|
50
|
-
const chunks = value.queryChunks;
|
|
51
|
-
if (chunks) {
|
|
52
|
-
return sqlToString(chunks);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return String(value);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Resolve a drizzle table object to its string name.
|
|
59
|
-
*/
|
|
60
|
-
function getTableName(table) {
|
|
61
|
-
// Drizzle tables store name at Symbol.for('drizzle:Name')
|
|
62
|
-
const nameSym = Symbol.for('drizzle:Name');
|
|
63
|
-
return String(table[nameSym]);
|
|
30
|
+
// drizzle-orm SQL expression (sql`...`) — rendered via the internals quarantine.
|
|
31
|
+
return sqlExpressionToText(value) ?? String(value);
|
|
64
32
|
}
|
|
65
33
|
/**
|
|
66
34
|
* Generate a `CREATE TABLE IF NOT EXISTS` DDL statement from a Drizzle SQLite table.
|
|
@@ -141,7 +109,7 @@ export function generateCreateTableSql(table) {
|
|
|
141
109
|
const ref = fk.reference();
|
|
142
110
|
const localCols = ref.columns.map((c) => quoteIdent(c.name)).join(', ');
|
|
143
111
|
const foreignCols = ref.foreignColumns.map((c) => quoteIdent(c.name)).join(', ');
|
|
144
|
-
const foreignTableName =
|
|
112
|
+
const foreignTableName = getDrizzleTableName(ref.foreignTable);
|
|
145
113
|
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${quoteIdent(foreignTableName)} (${foreignCols})`;
|
|
146
114
|
if (fk.onDelete) {
|
|
147
115
|
constraint += ` ON DELETE ${fk.onDelete}`;
|