@gobing-ai/ts-db 0.2.2 → 0.2.4
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 +4 -3
- package/dist/adapters/bun-sqlite.d.ts +1 -1
- package/dist/adapters/bun-sqlite.d.ts.map +1 -1
- package/dist/adapters/bun-sqlite.js +2 -2
- package/dist/adapters/d1.d.ts +1 -1
- package/dist/adapters/d1.d.ts.map +1 -1
- package/dist/adapters/d1.js +1 -1
- package/dist/base-dao.d.ts.map +1 -1
- package/dist/base-dao.js +4 -1
- package/dist/entity-dao.d.ts +1 -0
- package/dist/entity-dao.d.ts.map +1 -1
- package/dist/entity-dao.js +20 -12
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/queue-job-dao.d.ts.map +1 -1
- package/dist/schema/ddl.d.ts +19 -0
- package/dist/schema/ddl.d.ts.map +1 -0
- package/dist/schema/ddl.js +156 -0
- package/dist/{define-table.d.ts → schema/define-table.d.ts} +18 -9
- package/dist/schema/define-table.d.ts.map +1 -0
- package/dist/{define-table.js → schema/define-table.js} +12 -1
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -0
- package/dist/schema/runtime.d.ts +2 -0
- package/dist/schema/runtime.d.ts.map +1 -0
- package/dist/schema/runtime.js +1 -0
- package/package.json +14 -2
- package/src/adapters/bun-sqlite.ts +2 -2
- package/src/adapters/d1.ts +1 -1
- package/src/base-dao.ts +18 -10
- package/src/entity-dao.ts +59 -42
- package/src/index.ts +1 -2
- package/src/queue-job-dao.ts +59 -51
- package/src/schema/ddl.ts +174 -0
- package/src/{define-table.ts → schema/define-table.ts} +26 -9
- package/src/schema/index.ts +3 -0
- package/src/schema/runtime.ts +1 -0
- package/dist/define-table.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A **drizzle-free database facade**: typed DAOs over Bun SQLite / Cloudflare D1, a small predicate query spec, single-source-of-truth tables, and migration tooling. Drizzle ORM powers it internally but never appears in your application code — so the storage layer is swappable without touching call sites.
|
|
4
4
|
|
|
5
|
-
> **v0.2.
|
|
5
|
+
> **v0.2.3 is a breaking redesign.** The public `DbClient` interface and `adapter.getDb()` are removed; DAOs now take a `DbAdapter`; `where`/`orderBy` use a ts-db predicate spec instead of drizzle expressions. See [Migrating from 0.1.x](#migrating-from-01x).
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ Application code imports only `@gobing-ai/ts-db` — never `drizzle-orm`. drizzl
|
|
|
15
15
|
| Component | Purpose |
|
|
16
16
|
|-----------|---------|
|
|
17
17
|
| `createDbAdapter` / `DbAdapter` | Construction + lifecycle + string-SQL escape; exposes an internal typed db to the DAO layer only |
|
|
18
|
-
| `BunSqliteAdapter` | Bun SQLite implementation with statement caching and WAL pragmas |
|
|
18
|
+
| `BunSqliteAdapter` | Bun SQLite implementation with statement caching and WAL pragmas (`@gobing-ai/ts-db/bun-sqlite`) |
|
|
19
19
|
| `D1Adapter` | Cloudflare D1 implementation (no `@cloudflare/workers-types` dependency) |
|
|
20
20
|
| `BaseDao` | Raw tier — `query`/`one`/`tx`, drizzle-free signatures |
|
|
21
21
|
| `EntityDao` | Structured CRUD — predicate filters, soft delete, RETURNING, batch, upsert, cursor pagination, composite PK |
|
|
@@ -236,7 +236,8 @@ const stats = await queue.getStats();
|
|
|
236
236
|
### Migrations
|
|
237
237
|
|
|
238
238
|
```ts
|
|
239
|
-
import {
|
|
239
|
+
import { applyMigrations } from '@gobing-ai/ts-db';
|
|
240
|
+
import { BunSqliteAdapter } from '@gobing-ai/ts-db/bun-sqlite';
|
|
240
241
|
|
|
241
242
|
const adapter = new BunSqliteAdapter({ databaseUrl: './data/app.db' });
|
|
242
243
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite';
|
|
2
2
|
import type { DbAdapter, InternalDb } from '../adapter';
|
|
3
|
-
import * as schema from '../schema/
|
|
3
|
+
import * as schema from '../schema/runtime';
|
|
4
4
|
/**
|
|
5
5
|
* Configuration options for the bun:sqlite adapter (path, pragmas).
|
|
6
6
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bun-sqlite.d.ts","sourceRoot":"","sources":["../../src/adapters/bun-sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"bun-sqlite.d.ts","sourceRoot":"","sources":["../../src/adapters/bun-sqlite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAS5C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,OAAO,CAAC,EAAE;QACN,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACL;AAUD;;GAEG;AACH,qBAAa,gBAAiB,YAAW,SAAS;IAC9C,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,SAAS,CAAmC;IACpD;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IAEpE,OAAO,CAAC,YAAY;gBAUR,OAAO,CAAC,EAAE,gBAAgB;IAkBtC,+EAA+E;IAC/E,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED,wEAAwE;IACxE,YAAY,IAAI,iBAAiB,CAAC,OAAO,MAAM,CAAC;IAI1C,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrD,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAKxE,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAKlE,KAAK,IAAI,IAAI;CAGhB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Database } from 'bun:sqlite';
|
|
2
1
|
import { isAbsolute, resolve } from 'node:path';
|
|
2
|
+
import { Database } from '@gobing-ai/ts-runtime/bun-sqlite';
|
|
3
3
|
import { drizzle } from 'drizzle-orm/bun-sqlite';
|
|
4
|
-
import * as schema from '../schema/
|
|
4
|
+
import * as schema from '../schema/runtime.js';
|
|
5
5
|
const DEFAULT_PRAGMAS = {
|
|
6
6
|
journalMode: 'PRAGMA journal_mode = WAL',
|
|
7
7
|
synchronous: 'PRAGMA synchronous = NORMAL',
|
package/dist/adapters/d1.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DrizzleD1Database } from 'drizzle-orm/d1';
|
|
2
2
|
import type { DbAdapter, InternalDb } from '../adapter';
|
|
3
|
-
import * as schema from '../schema/
|
|
3
|
+
import * as schema from '../schema/runtime';
|
|
4
4
|
/**
|
|
5
5
|
* Minimal D1 binding interface — avoids depending on @cloudflare/workers-types.
|
|
6
6
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/adapters/d1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"d1.d.ts","sourceRoot":"","sources":["../../src/adapters/d1.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,gBAAgB,CAAC;AACjE,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,SAAS;IACtB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG;QAClB,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC;QAC7C,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/B,GAAG,CAAC,IAAI,OAAO,CAAC;YAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YAAC,OAAO,EAAE,OAAO,CAAA;SAAE,CAAC,CAAC;KAC7D,CAAC;IACF,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,UAAU,gBAAgB;IACtB,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtD,GAAG,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACzD,GAAG,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACvB,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,qBAAa,SAAU,YAAW,SAAS;IACvC,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,SAAS,CAAmC;gBAExC,OAAO,EAAE,SAAS;IAK9B,kEAAkE;IAClE,IAAI,EAAE,IAAI,UAAU,CAEnB;IAED,wEAAwE;IACxE,YAAY,IAAI,iBAAiB,CAAC,OAAO,MAAM,CAAC;IAIhD,qEAAqE;IACrE,UAAU,IAAI,SAAS;IAIjB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMrD,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAQxE,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAOlE,KAAK,IAAI,IAAI;CAGhB"}
|
package/dist/adapters/d1.js
CHANGED
package/dist/base-dao.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-dao.d.ts","sourceRoot":"","sources":["../src/base-dao.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAoC,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"base-dao.d.ts","sourceRoot":"","sources":["../src/base-dao.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvD,OAAO,EAAoC,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAiB/F;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC;AAElC;;;;;;;;;GASG;AACH,8BAAsB,OAAO;IACH,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS;IAA3D,SAAS,aAAgC,OAAO,EAAE,SAAS;IAE3D,mFAAmF;IACnF,SAAS,KAAK,EAAE,IAAI,UAAU,CAE7B;IAED,+DAA+D;IAC/D,SAAS,CAAC,GAAG,IAAI,MAAM;IAIvB;;;;;OAKG;cACa,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAInE;;;;;OAKG;cACa,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAa/E,oEAAoE;cACpD,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CAIvF"}
|
package/dist/base-dao.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { compileOrderBy, compilePredicate } from './query-spec.js';
|
|
2
|
+
function asSelectQuery(query) {
|
|
3
|
+
return query;
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* Abstract base DAO — the RAW tier of the ts-db facade.
|
|
4
7
|
*
|
|
@@ -41,7 +44,7 @@ export class BaseDao {
|
|
|
41
44
|
const condition = spec.where ? compilePredicate(spec.where) : undefined;
|
|
42
45
|
const order = spec.orderBy ? compileOrderBy(spec.orderBy) : [];
|
|
43
46
|
// drizzle's fluent builder is internal here; the public input is the spec.
|
|
44
|
-
let q = this.db.select().from(table);
|
|
47
|
+
let q = asSelectQuery(this.db.select().from(table));
|
|
45
48
|
if (condition)
|
|
46
49
|
q = q.where(condition);
|
|
47
50
|
if (order.length > 0)
|
package/dist/entity-dao.d.ts
CHANGED
|
@@ -138,6 +138,7 @@ export declare class EntityDao<TTable extends EntityTable, TPK extends SQLiteCol
|
|
|
138
138
|
rows: TTable['$inferSelect'][];
|
|
139
139
|
nextCursor?: string | number;
|
|
140
140
|
}>;
|
|
141
|
+
private resultKeyForColumn;
|
|
141
142
|
/** Count records matching an optional predicate. */
|
|
142
143
|
count(where?: Predicate, includeDeleted?: boolean): Promise<number>;
|
|
143
144
|
/** Combine a caller predicate with the soft-delete active filter. */
|
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;AACrC,OAAO,EAAoB,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"entity-dao.d.ts","sourceRoot":"","sources":["../src/entity-dao.ts"],"names":[],"mappings":"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"}
|
package/dist/entity-dao.js
CHANGED
|
@@ -32,8 +32,9 @@ export class EntityDao extends BaseDao {
|
|
|
32
32
|
}
|
|
33
33
|
/** Condition filtering out soft-deleted rows, or undefined when unsupported. */
|
|
34
34
|
get activeCondition() {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
const table = this.table;
|
|
36
|
+
if ('inUsed' in table) {
|
|
37
|
+
return eq(table.inUsed, 1);
|
|
37
38
|
}
|
|
38
39
|
return undefined;
|
|
39
40
|
}
|
|
@@ -91,7 +92,8 @@ export class EntityDao extends BaseDao {
|
|
|
91
92
|
.map(([key]) => key));
|
|
92
93
|
const defaultSet = Object.fromEntries(Object.entries(data).filter(([key]) => !identityProps.has(key)));
|
|
93
94
|
const setOnConflict = { ...(updateColumns ?? defaultSet), updatedAt: now };
|
|
94
|
-
const rows = (await this.insertBuilder
|
|
95
|
+
const rows = (await this.insertBuilder
|
|
96
|
+
.values(record)
|
|
95
97
|
.onConflictDoUpdate({ target: conflictColumns, set: setOnConflict })
|
|
96
98
|
.returning());
|
|
97
99
|
return rows[0];
|
|
@@ -124,8 +126,7 @@ export class EntityDao extends BaseDao {
|
|
|
124
126
|
async update(id, data) {
|
|
125
127
|
const updateData = { ...data, updatedAt: this.now() };
|
|
126
128
|
this.validate('update', updateData);
|
|
127
|
-
const rows = (await this.db
|
|
128
|
-
.update(this.table)
|
|
129
|
+
const rows = (await this.db.update(this.table)
|
|
129
130
|
.set(updateData)
|
|
130
131
|
.where(this.pkCondition(id))
|
|
131
132
|
.returning());
|
|
@@ -166,18 +167,22 @@ export class EntityDao extends BaseDao {
|
|
|
166
167
|
limit: spec.limit,
|
|
167
168
|
});
|
|
168
169
|
const last = rows[rows.length - 1];
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
: undefined;
|
|
170
|
+
const cursorResultKey = this.resultKeyForColumn(spec.cursorColumn);
|
|
171
|
+
const nextCursor = rows.length === spec.limit && last ? last[cursorResultKey] : undefined;
|
|
172
172
|
return nextCursor !== undefined ? { rows, nextCursor } : { rows };
|
|
173
173
|
}
|
|
174
|
+
resultKeyForColumn(column) {
|
|
175
|
+
for (const [key, value] of Object.entries(this.table)) {
|
|
176
|
+
if (value === column)
|
|
177
|
+
return key;
|
|
178
|
+
}
|
|
179
|
+
return column.name;
|
|
180
|
+
}
|
|
174
181
|
/** Count records matching an optional predicate. */
|
|
175
182
|
async count(where, includeDeleted = false) {
|
|
176
183
|
const condition = this.withActive(where, includeDeleted);
|
|
177
184
|
const compiled = condition ? compilePredicate(condition) : undefined;
|
|
178
|
-
const base = this.db
|
|
179
|
-
.select({ value: countFn() })
|
|
180
|
-
.from(this.table);
|
|
185
|
+
const base = this.db.select({ value: countFn() }).from(this.table);
|
|
181
186
|
const result = (await (compiled ? base.where(compiled) : base));
|
|
182
187
|
return result[0]?.value ?? 0;
|
|
183
188
|
}
|
|
@@ -185,7 +190,10 @@ export class EntityDao extends BaseDao {
|
|
|
185
190
|
withActive(where, includeDeleted) {
|
|
186
191
|
if (includeDeleted || !this.hasSoftDelete)
|
|
187
192
|
return where;
|
|
188
|
-
const
|
|
193
|
+
const table = this.table;
|
|
194
|
+
if (!('inUsed' in table))
|
|
195
|
+
return where;
|
|
196
|
+
const active = { col: table.inUsed, op: 'eq', value: 1 };
|
|
189
197
|
if (!where)
|
|
190
198
|
return active;
|
|
191
199
|
return { and: [where, active] };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export { createDbAdapter, type DbAdapter, type DbAdapterConfig, type InternalDb } from './adapter';
|
|
2
|
-
export { BunSqliteAdapter, type BunSqliteOptions } from './adapters/bun-sqlite';
|
|
3
2
|
export { D1Adapter } from './adapters/d1';
|
|
4
3
|
export { BaseDao, type TxHandle } from './base-dao';
|
|
5
|
-
export { type DefinedTable, defineTable } from './define-table';
|
|
6
4
|
export { type EmbeddedMigration, embeddedMigrations } from './embedded-migrations';
|
|
7
5
|
export { type CursorListSpec, type DaoValidator, EntityDao, type EntityDaoOptions, type EntityListSpec, type EntityTable, type PKColumn, type PKValue, type SoftDeletableTable, } from './entity-dao';
|
|
8
6
|
export { applyMigrations, type MigrationOptions } from './migrate';
|
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,
|
|
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;AACnE,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,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export { createDbAdapter } from './adapter.js';
|
|
2
|
-
export { BunSqliteAdapter } from './adapters/bun-sqlite.js';
|
|
3
2
|
export { D1Adapter } from './adapters/d1.js';
|
|
4
3
|
export { BaseDao } from './base-dao.js';
|
|
5
|
-
export { defineTable } from './define-table.js';
|
|
6
4
|
export { embeddedMigrations } from './embedded-migrations.js';
|
|
7
5
|
export { EntityDao, } from './entity-dao.js';
|
|
8
6
|
export { applyMigrations } from './migrate.js';
|
|
@@ -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;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,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;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAsDhD;;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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a `CREATE TABLE IF NOT EXISTS` DDL statement from a Drizzle SQLite table.
|
|
4
|
+
*
|
|
5
|
+
* Uses `getTableConfig` (drizzle-orm runtime introspection) to extract columns,
|
|
6
|
+
* types, constraints, and foreign keys — no drizzle-kit CLI required.
|
|
7
|
+
*
|
|
8
|
+
* The output is deterministic: columns are emitted in definition order, identifiers
|
|
9
|
+
* are double-quoted, and table constraints follow column definitions.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const users = sqliteTable('users', { id: text('id').primaryKey() });
|
|
14
|
+
* const ddl = generateCreateTableSql(users);
|
|
15
|
+
* // CREATE TABLE IF NOT EXISTS "users" ("id" text PRIMARY KEY NOT NULL)
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateCreateTableSql(table: SQLiteTable): string;
|
|
19
|
+
//# sourceMappingURL=ddl.d.ts.map
|
|
@@ -0,0 +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;AAuE3E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAsFjE"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { getTableConfig } from 'drizzle-orm/sqlite-core';
|
|
2
|
+
/**
|
|
3
|
+
* Quote an identifier for use in SQL (double-quoted for SQLite compatibility).
|
|
4
|
+
*/
|
|
5
|
+
function quoteIdent(name) {
|
|
6
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
7
|
+
}
|
|
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
|
+
/**
|
|
28
|
+
* Map a column default value to its SQL literal representation.
|
|
29
|
+
*
|
|
30
|
+
* drizzle-orm defaults can be:
|
|
31
|
+
* - primitives: number, string, boolean, null
|
|
32
|
+
* - SQL expressions (sql\`...\` template results)
|
|
33
|
+
* - undefined (no default, or runtime-only $defaultFn)
|
|
34
|
+
*/
|
|
35
|
+
function defaultToSql(value) {
|
|
36
|
+
if (value == null) {
|
|
37
|
+
return value === null ? 'NULL' : undefined;
|
|
38
|
+
}
|
|
39
|
+
if (typeof value === 'number') {
|
|
40
|
+
return String(value);
|
|
41
|
+
}
|
|
42
|
+
if (typeof value === 'string') {
|
|
43
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === 'boolean') {
|
|
46
|
+
return value ? '1' : '0';
|
|
47
|
+
}
|
|
48
|
+
// drizzle-orm SQL expression (has queryChunks)
|
|
49
|
+
if (typeof value === 'object' && value !== null && 'queryChunks' in value) {
|
|
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]);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Generate a `CREATE TABLE IF NOT EXISTS` DDL statement from a Drizzle SQLite table.
|
|
67
|
+
*
|
|
68
|
+
* Uses `getTableConfig` (drizzle-orm runtime introspection) to extract columns,
|
|
69
|
+
* types, constraints, and foreign keys — no drizzle-kit CLI required.
|
|
70
|
+
*
|
|
71
|
+
* The output is deterministic: columns are emitted in definition order, identifiers
|
|
72
|
+
* are double-quoted, and table constraints follow column definitions.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const users = sqliteTable('users', { id: text('id').primaryKey() });
|
|
77
|
+
* const ddl = generateCreateTableSql(users);
|
|
78
|
+
* // CREATE TABLE IF NOT EXISTS "users" ("id" text PRIMARY KEY NOT NULL)
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function generateCreateTableSql(table) {
|
|
82
|
+
const config = getTableConfig(table);
|
|
83
|
+
const columnDefs = [];
|
|
84
|
+
const tableConstraints = [];
|
|
85
|
+
// Track which columns participate in composite unique constraints
|
|
86
|
+
const compositeUniqueCols = new Set();
|
|
87
|
+
for (const uc of config.uniqueConstraints) {
|
|
88
|
+
if (uc.columns.length > 1) {
|
|
89
|
+
for (const col of uc.columns) {
|
|
90
|
+
compositeUniqueCols.add(col.name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Track which columns participate in composite primary keys
|
|
95
|
+
const compositePkCols = new Set();
|
|
96
|
+
for (const pk of config.primaryKeys) {
|
|
97
|
+
if (pk.columns.length > 1) {
|
|
98
|
+
for (const col of pk.columns) {
|
|
99
|
+
compositePkCols.add(col.name);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const col of config.columns) {
|
|
104
|
+
const parts = [quoteIdent(col.name), col.getSQLType()];
|
|
105
|
+
// Column-level PRIMARY KEY only for single-column PKs
|
|
106
|
+
if (col.primary && !compositePkCols.has(col.name)) {
|
|
107
|
+
parts.push('PRIMARY KEY');
|
|
108
|
+
}
|
|
109
|
+
if (col.notNull) {
|
|
110
|
+
parts.push('NOT NULL');
|
|
111
|
+
}
|
|
112
|
+
// DEFAULT — only for SQL-level defaults (not runtime $defaultFn)
|
|
113
|
+
if (col.hasDefault && col.default !== undefined) {
|
|
114
|
+
const sqlDefault = defaultToSql(col.default);
|
|
115
|
+
if (sqlDefault !== undefined) {
|
|
116
|
+
parts.push(`DEFAULT ${sqlDefault}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// UNIQUE at column level only when it's a single-column unique constraint
|
|
120
|
+
if (col.isUnique && !compositeUniqueCols.has(col.name)) {
|
|
121
|
+
parts.push('UNIQUE');
|
|
122
|
+
}
|
|
123
|
+
columnDefs.push(parts.join(' '));
|
|
124
|
+
}
|
|
125
|
+
// Composite PRIMARY KEY
|
|
126
|
+
for (const pk of config.primaryKeys) {
|
|
127
|
+
if (pk.columns.length > 1) {
|
|
128
|
+
const pkCols = pk.columns.map((c) => quoteIdent(c.name)).join(', ');
|
|
129
|
+
tableConstraints.push(`PRIMARY KEY (${pkCols})`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Composite UNIQUE constraints
|
|
133
|
+
for (const uc of config.uniqueConstraints) {
|
|
134
|
+
if (uc.columns.length > 1) {
|
|
135
|
+
const cols = uc.columns.map((c) => quoteIdent(c.name)).join(', ');
|
|
136
|
+
tableConstraints.push(`UNIQUE (${cols})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Foreign keys
|
|
140
|
+
for (const fk of config.foreignKeys) {
|
|
141
|
+
const ref = fk.reference();
|
|
142
|
+
const localCols = ref.columns.map((c) => quoteIdent(c.name)).join(', ');
|
|
143
|
+
const foreignCols = ref.foreignColumns.map((c) => quoteIdent(c.name)).join(', ');
|
|
144
|
+
const foreignTableName = getTableName(ref.foreignTable);
|
|
145
|
+
let constraint = `FOREIGN KEY (${localCols}) REFERENCES ${quoteIdent(foreignTableName)} (${foreignCols})`;
|
|
146
|
+
if (fk.onDelete) {
|
|
147
|
+
constraint += ` ON DELETE ${fk.onDelete}`;
|
|
148
|
+
}
|
|
149
|
+
if (fk.onUpdate) {
|
|
150
|
+
constraint += ` ON UPDATE ${fk.onUpdate}`;
|
|
151
|
+
}
|
|
152
|
+
tableConstraints.push(constraint);
|
|
153
|
+
}
|
|
154
|
+
const allDefs = [...columnDefs, ...tableConstraints];
|
|
155
|
+
return `CREATE TABLE IF NOT EXISTS ${quoteIdent(config.name)} (\n ${allDefs.join(',\n ')}\n)`;
|
|
156
|
+
}
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { type SQLiteColumnBuilderBase, sqliteTable } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import type { ZodType } from 'zod';
|
|
3
3
|
/**
|
|
4
|
-
* A table definition bundled with its drizzle-zod validation schemas.
|
|
4
|
+
* A table definition bundled with its drizzle-zod validation schemas and DDL.
|
|
5
5
|
*
|
|
6
6
|
* The single source of truth (G2): one table authored once yields the drizzle
|
|
7
|
-
* table (for queries/migrations)
|
|
8
|
-
* validation), with no parallel
|
|
7
|
+
* table (for queries/migrations), insert/select zod schemas (for boundary
|
|
8
|
+
* validation), and CREATE TABLE DDL (for migrations) — with no parallel
|
|
9
|
+
* re-authoring.
|
|
9
10
|
*
|
|
10
|
-
* The zod schemas are derived lazily — only materialised the first
|
|
11
|
-
* read — so a consumer that only needs the table pays nothing
|
|
11
|
+
* The zod schemas and DDL are derived lazily — only materialised the first
|
|
12
|
+
* time they are read — so a consumer that only needs the table pays nothing
|
|
13
|
+
* extra.
|
|
12
14
|
*
|
|
13
|
-
* `defineTable`, `insertSchema`, and `
|
|
14
|
-
* `zod` and `drizzle-zod`. Consumers that never validate
|
|
15
|
-
*
|
|
15
|
+
* `defineTable`, `insertSchema`, `selectSchema`, and `createTableSql` require
|
|
16
|
+
* the optional peers `zod` and `drizzle-zod`. Consumers that never validate and
|
|
17
|
+
* don't need generated DDL can use `createDbAdapter` + raw `sqliteTable` +
|
|
18
|
+
* column helpers without installing those peers. Import from
|
|
19
|
+
* `@gobing-ai/ts-db/schema` to opt in.
|
|
16
20
|
*/
|
|
17
21
|
export interface DefinedTable<TTable> {
|
|
18
22
|
/** The underlying drizzle table — pass to DAOs, migrations, queries. */
|
|
@@ -21,12 +25,16 @@ export interface DefinedTable<TTable> {
|
|
|
21
25
|
readonly insertSchema: ZodType;
|
|
22
26
|
/** Zod schema validating a selected row. */
|
|
23
27
|
readonly selectSchema: ZodType;
|
|
28
|
+
/** `CREATE TABLE IF NOT EXISTS` DDL generated from the table definition (lazy). */
|
|
29
|
+
readonly createTableSql: string;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
26
|
-
* Define a SQLite table and derive its validation schemas in one place (G2).
|
|
32
|
+
* Define a SQLite table and derive its validation schemas and DDL in one place (G2).
|
|
27
33
|
*
|
|
28
34
|
* @example
|
|
29
35
|
* ```ts
|
|
36
|
+
* import { defineTable } from '@gobing-ai/ts-db/schema';
|
|
37
|
+
*
|
|
30
38
|
* export const users = defineTable('users', {
|
|
31
39
|
* id: text('id').primaryKey(),
|
|
32
40
|
* email: text('email').notNull().unique(),
|
|
@@ -34,6 +42,7 @@ export interface DefinedTable<TTable> {
|
|
|
34
42
|
* });
|
|
35
43
|
* users.table // drizzle table for DAOs/migrations
|
|
36
44
|
* users.insertSchema // zod schema derived from the table
|
|
45
|
+
* users.createTableSql // CREATE TABLE IF NOT EXISTS "users" (...)
|
|
37
46
|
* ```
|
|
38
47
|
*/
|
|
39
48
|
export declare function defineTable<TName extends string, TColumns extends Record<string, SQLiteColumnBuilderBase>>(name: TName, columns: TColumns): DefinedTable<ReturnType<typeof sqliteTable<TName, TColumns>>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"define-table.d.ts","sourceRoot":"","sources":["../../src/schema/define-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,uBAAuB,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEpF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,CAAC;AAGnC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY,CAAC,MAAM;IAChC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,4CAA4C;IAC5C,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,uBAAuB,CAAC,EACtG,IAAI,EAAE,KAAK,EACX,OAAO,EAAE,QAAQ,GAClB,YAAY,CAAC,UAAU,CAAC,OAAO,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CA4B/D"}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { sqliteTable } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
|
|
3
|
+
import { generateCreateTableSql } from './ddl.js';
|
|
3
4
|
/**
|
|
4
|
-
* Define a SQLite table and derive its validation schemas in one place (G2).
|
|
5
|
+
* Define a SQLite table and derive its validation schemas and DDL in one place (G2).
|
|
5
6
|
*
|
|
6
7
|
* @example
|
|
7
8
|
* ```ts
|
|
9
|
+
* import { defineTable } from '@gobing-ai/ts-db/schema';
|
|
10
|
+
*
|
|
8
11
|
* export const users = defineTable('users', {
|
|
9
12
|
* id: text('id').primaryKey(),
|
|
10
13
|
* email: text('email').notNull().unique(),
|
|
@@ -12,12 +15,14 @@ import { createInsertSchema, createSelectSchema } from 'drizzle-zod';
|
|
|
12
15
|
* });
|
|
13
16
|
* users.table // drizzle table for DAOs/migrations
|
|
14
17
|
* users.insertSchema // zod schema derived from the table
|
|
18
|
+
* users.createTableSql // CREATE TABLE IF NOT EXISTS "users" (...)
|
|
15
19
|
* ```
|
|
16
20
|
*/
|
|
17
21
|
export function defineTable(name, columns) {
|
|
18
22
|
const table = sqliteTable(name, columns);
|
|
19
23
|
let insert;
|
|
20
24
|
let select;
|
|
25
|
+
let ddl;
|
|
21
26
|
return {
|
|
22
27
|
table,
|
|
23
28
|
get insertSchema() {
|
|
@@ -32,5 +37,11 @@ export function defineTable(name, columns) {
|
|
|
32
37
|
}
|
|
33
38
|
return select;
|
|
34
39
|
},
|
|
40
|
+
get createTableSql() {
|
|
41
|
+
if (ddl === undefined) {
|
|
42
|
+
ddl = generateCreateTableSql(table);
|
|
43
|
+
}
|
|
44
|
+
return ddl;
|
|
45
|
+
},
|
|
35
46
|
};
|
|
36
47
|
}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export { index, integer, text } from 'drizzle-orm/sqlite-core';
|
|
1
2
|
export * from './common';
|
|
3
|
+
export { generateCreateTableSql } from './ddl';
|
|
4
|
+
export { type DefinedTable, defineTable } from './define-table';
|
|
2
5
|
export { queueJobs } from './queue-jobs';
|
|
3
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/D,cAAc,UAAU,CAAC;AACzB,OAAO,EAAE,sBAAsB,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,KAAK,YAAY,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/schema/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/schema/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { queueJobs } from './queue-jobs.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-db",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "@gobing-ai/ts-db — a drizzle-free database facade: typed DAOs over Bun SQLite / Cloudflare D1, a small predicate query spec, single-source-of-truth tables, and migrations. Drizzle stays an internal detail.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -31,6 +31,18 @@
|
|
|
31
31
|
".": {
|
|
32
32
|
"types": "./dist/index.d.ts",
|
|
33
33
|
"import": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"./bun-sqlite": {
|
|
36
|
+
"types": "./dist/adapters/bun-sqlite.d.ts",
|
|
37
|
+
"import": "./dist/adapters/bun-sqlite.js"
|
|
38
|
+
},
|
|
39
|
+
"./d1": {
|
|
40
|
+
"types": "./dist/adapters/d1.d.ts",
|
|
41
|
+
"import": "./dist/adapters/d1.js"
|
|
42
|
+
},
|
|
43
|
+
"./schema": {
|
|
44
|
+
"types": "./dist/schema/index.d.ts",
|
|
45
|
+
"import": "./dist/schema/index.js"
|
|
34
46
|
}
|
|
35
47
|
},
|
|
36
48
|
"files": [
|
|
@@ -50,7 +62,7 @@
|
|
|
50
62
|
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-db-v<version> && git push --tags' && exit 1"
|
|
51
63
|
},
|
|
52
64
|
"dependencies": {
|
|
53
|
-
"@gobing-ai/ts-runtime": "^0.2.
|
|
65
|
+
"@gobing-ai/ts-runtime": "^0.2.4"
|
|
54
66
|
},
|
|
55
67
|
"peerDependencies": {
|
|
56
68
|
"drizzle-orm": ">=0.38.0",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Database } from 'bun:sqlite';
|
|
2
1
|
import { isAbsolute, resolve } from 'node:path';
|
|
2
|
+
import { Database } from '@gobing-ai/ts-runtime/bun-sqlite';
|
|
3
3
|
import { type BunSQLiteDatabase, drizzle } from 'drizzle-orm/bun-sqlite';
|
|
4
4
|
import type { DbAdapter, InternalDb } from '../adapter';
|
|
5
|
-
import * as schema from '../schema/
|
|
5
|
+
import * as schema from '../schema/runtime';
|
|
6
6
|
|
|
7
7
|
type SqliteStatementLike = {
|
|
8
8
|
all: (...params: unknown[]) => unknown;
|
package/src/adapters/d1.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type DrizzleD1Database, drizzle } from 'drizzle-orm/d1';
|
|
2
2
|
import type { DbAdapter, InternalDb } from '../adapter';
|
|
3
|
-
import * as schema from '../schema/
|
|
3
|
+
import * as schema from '../schema/runtime';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Minimal D1 binding interface — avoids depending on @cloudflare/workers-types.
|