@gobing-ai/ts-db 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/base-dao.d.ts.map +1 -1
- package/dist/base-dao.js +4 -1
- package/dist/entity-dao.d.ts.map +1 -1
- package/dist/entity-dao.js +11 -9
- package/dist/queue-job-dao.d.ts.map +1 -1
- 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/package.json +2 -2
- package/src/base-dao.ts +18 -10
- package/src/entity-dao.ts +51 -40
- package/src/queue-job-dao.ts +59 -51
- package/src/schema/index.ts +1 -0
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.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());
|
|
@@ -181,9 +182,7 @@ export class EntityDao extends BaseDao {
|
|
|
181
182
|
async count(where, includeDeleted = false) {
|
|
182
183
|
const condition = this.withActive(where, includeDeleted);
|
|
183
184
|
const compiled = condition ? compilePredicate(condition) : undefined;
|
|
184
|
-
const base = this.db
|
|
185
|
-
.select({ value: countFn() })
|
|
186
|
-
.from(this.table);
|
|
185
|
+
const base = this.db.select({ value: countFn() }).from(this.table);
|
|
187
186
|
const result = (await (compiled ? base.where(compiled) : base));
|
|
188
187
|
return result[0]?.value ?? 0;
|
|
189
188
|
}
|
|
@@ -191,7 +190,10 @@ export class EntityDao extends BaseDao {
|
|
|
191
190
|
withActive(where, includeDeleted) {
|
|
192
191
|
if (includeDeleted || !this.hasSoftDelete)
|
|
193
192
|
return where;
|
|
194
|
-
const
|
|
193
|
+
const table = this.table;
|
|
194
|
+
if (!('inUsed' in table))
|
|
195
|
+
return where;
|
|
196
|
+
const active = { col: table.inUsed, op: 'eq', value: 1 };
|
|
195
197
|
if (!where)
|
|
196
198
|
return active;
|
|
197
199
|
return { and: [where, active] };
|
|
@@ -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"}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/schema/index.ts"],"names":[],"mappings":"AAAA,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"}
|
|
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
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.5",
|
|
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",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
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"
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
|
-
"@gobing-ai/ts-runtime": "^0.2.
|
|
65
|
+
"@gobing-ai/ts-runtime": "^0.2.5"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
68
|
"drizzle-orm": ">=0.38.0",
|
package/src/base-dao.ts
CHANGED
|
@@ -2,6 +2,21 @@ import type { SQLiteTable } from 'drizzle-orm/sqlite-core';
|
|
|
2
2
|
import type { DbAdapter, InternalDb } from './adapter';
|
|
3
3
|
import { compileOrderBy, compilePredicate, type ListSpec, type Predicate } from './query-spec';
|
|
4
4
|
|
|
5
|
+
type TransactionalDb = {
|
|
6
|
+
transaction: <T>(cb: (tx: TxHandle) => Promise<T>) => Promise<T>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type SelectQuery<T> = Promise<T[]> & {
|
|
10
|
+
where: (condition: unknown) => SelectQuery<T>;
|
|
11
|
+
orderBy: (...order: unknown[]) => SelectQuery<T>;
|
|
12
|
+
limit: (limit: number) => SelectQuery<T>;
|
|
13
|
+
offset: (offset: number) => SelectQuery<T>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function asSelectQuery<T>(query: object): SelectQuery<T> {
|
|
17
|
+
return query as SelectQuery<T>;
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
/**
|
|
6
21
|
* A transaction-scoped handle passed to {@link BaseDao.tx} callbacks.
|
|
7
22
|
*
|
|
@@ -42,9 +57,7 @@ export abstract class BaseDao {
|
|
|
42
57
|
* The callback receives a transaction-scoped db handle.
|
|
43
58
|
*/
|
|
44
59
|
protected async tx<T>(fn: (tx: TxHandle) => Promise<T>): Promise<T> {
|
|
45
|
-
return (this.db as
|
|
46
|
-
fn(tx),
|
|
47
|
-
);
|
|
60
|
+
return (this.db as TransactionalDb).transaction((tx) => fn(tx));
|
|
48
61
|
}
|
|
49
62
|
|
|
50
63
|
/**
|
|
@@ -58,17 +71,12 @@ export abstract class BaseDao {
|
|
|
58
71
|
const order = spec.orderBy ? compileOrderBy(spec.orderBy) : [];
|
|
59
72
|
|
|
60
73
|
// drizzle's fluent builder is internal here; the public input is the spec.
|
|
61
|
-
let q = (this.db
|
|
62
|
-
where: (c: unknown) => typeof q;
|
|
63
|
-
orderBy: (...o: unknown[]) => typeof q;
|
|
64
|
-
limit: (n: number) => typeof q;
|
|
65
|
-
offset: (n: number) => typeof q;
|
|
66
|
-
};
|
|
74
|
+
let q = asSelectQuery<T>(this.db.select().from(table));
|
|
67
75
|
if (condition) q = q.where(condition);
|
|
68
76
|
if (order.length > 0) q = q.orderBy(...order);
|
|
69
77
|
if (spec.limit !== undefined) q = q.limit(spec.limit);
|
|
70
78
|
if (spec.offset !== undefined) q = q.offset(spec.offset);
|
|
71
|
-
return (await
|
|
79
|
+
return (await q) ?? [];
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
/** Run a SELECT and return the first matching row, or undefined. */
|
package/src/entity-dao.ts
CHANGED
|
@@ -4,6 +4,36 @@ import type { DbAdapter } from './adapter';
|
|
|
4
4
|
import { BaseDao } from './base-dao';
|
|
5
5
|
import { compilePredicate, type OrderTerm, type Predicate } from './query-spec';
|
|
6
6
|
|
|
7
|
+
type ReturningRows = {
|
|
8
|
+
returning: () => Promise<unknown[]>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type InsertBuilder = {
|
|
12
|
+
values: (record: unknown) => ReturningRows & {
|
|
13
|
+
onConflictDoUpdate: (cfg: { target: SQLiteColumn[]; set: unknown }) => ReturningRows;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type UpdateBuilder = {
|
|
18
|
+
set: (data: unknown) => {
|
|
19
|
+
where: (condition: SQL) => ReturningRows;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type DeleteBuilder = {
|
|
24
|
+
where: (condition: SQL) => Promise<unknown>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type CountQuery = Promise<unknown[]> & {
|
|
28
|
+
where: (condition: SQL) => Promise<unknown[]>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type CountDb = {
|
|
32
|
+
select: (projection: unknown) => {
|
|
33
|
+
from: (table: unknown) => CountQuery;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
7
37
|
/**
|
|
8
38
|
* Type for tables compatible with EntityDao.
|
|
9
39
|
* Must have standard columns: createdAt, updatedAt.
|
|
@@ -127,8 +157,9 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
127
157
|
|
|
128
158
|
/** Condition filtering out soft-deleted rows, or undefined when unsupported. */
|
|
129
159
|
protected get activeCondition(): SQL | undefined {
|
|
130
|
-
|
|
131
|
-
|
|
160
|
+
const table = this.table;
|
|
161
|
+
if ('inUsed' in table) {
|
|
162
|
+
return eq(table.inUsed as SQLiteColumn, 1);
|
|
132
163
|
}
|
|
133
164
|
return undefined;
|
|
134
165
|
}
|
|
@@ -146,7 +177,7 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
146
177
|
}
|
|
147
178
|
|
|
148
179
|
private get insertBuilder() {
|
|
149
|
-
return this.db.insert(this.table as
|
|
180
|
+
return this.db.insert(this.table as Parameters<typeof this.db.insert>[0]) as InsertBuilder;
|
|
150
181
|
}
|
|
151
182
|
|
|
152
183
|
/**
|
|
@@ -159,9 +190,7 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
159
190
|
const now = this.now();
|
|
160
191
|
const record = { createdAt: now, updatedAt: now, ...data };
|
|
161
192
|
this.validate('create', record);
|
|
162
|
-
const rows = (await (
|
|
163
|
-
this.insertBuilder.values(record) as unknown as { returning: () => Promise<unknown[]> }
|
|
164
|
-
).returning()) as TTable['$inferSelect'][];
|
|
193
|
+
const rows = (await this.insertBuilder.values(record).returning()) as TTable['$inferSelect'][];
|
|
165
194
|
return rows[0] as TTable['$inferSelect'];
|
|
166
195
|
}
|
|
167
196
|
|
|
@@ -179,9 +208,7 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
179
208
|
const now = this.now();
|
|
180
209
|
const records = data.map((d) => ({ createdAt: now, updatedAt: now, ...d }));
|
|
181
210
|
for (const record of records) this.validate('createMany', record);
|
|
182
|
-
return (await (
|
|
183
|
-
this.insertBuilder.values(records) as unknown as { returning: () => Promise<unknown[]> }
|
|
184
|
-
).returning()) as TTable['$inferSelect'][];
|
|
211
|
+
return (await this.insertBuilder.values(records).returning()) as TTable['$inferSelect'][];
|
|
185
212
|
}
|
|
186
213
|
|
|
187
214
|
/**
|
|
@@ -202,21 +229,16 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
202
229
|
// their table property key (not DB column name) to handle snake_case columns.
|
|
203
230
|
const identityCols = new Set<SQLiteColumn>([...conflictColumns, ...this.primaryKey]);
|
|
204
231
|
const identityProps = new Set(
|
|
205
|
-
Object.entries(this.table
|
|
206
|
-
.filter(([, col]) => identityCols.has(col))
|
|
232
|
+
Object.entries(this.table)
|
|
233
|
+
.filter(([, col]) => identityCols.has(col as SQLiteColumn))
|
|
207
234
|
.map(([key]) => key),
|
|
208
235
|
);
|
|
209
236
|
const defaultSet = Object.fromEntries(
|
|
210
237
|
Object.entries(data as Record<string, unknown>).filter(([key]) => !identityProps.has(key)),
|
|
211
238
|
);
|
|
212
239
|
const setOnConflict = { ...(updateColumns ?? defaultSet), updatedAt: now };
|
|
213
|
-
const rows = (await
|
|
214
|
-
|
|
215
|
-
onConflictDoUpdate: (cfg: { target: SQLiteColumn[]; set: unknown }) => {
|
|
216
|
-
returning: () => Promise<unknown[]>;
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
)
|
|
240
|
+
const rows = (await this.insertBuilder
|
|
241
|
+
.values(record)
|
|
220
242
|
.onConflictDoUpdate({ target: conflictColumns, set: setOnConflict })
|
|
221
243
|
.returning()) as TTable['$inferSelect'][];
|
|
222
244
|
return rows[0] as TTable['$inferSelect'];
|
|
@@ -261,13 +283,8 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
261
283
|
async update(id: PKValue, data: Partial<TTable['$inferInsert']>): Promise<TTable['$inferSelect'] | undefined> {
|
|
262
284
|
const updateData = { ...data, updatedAt: this.now() };
|
|
263
285
|
this.validate('update', updateData);
|
|
264
|
-
const rows = (await (
|
|
265
|
-
|
|
266
|
-
.update(this.table as unknown as Parameters<typeof this.db.update>[0])
|
|
267
|
-
.set(updateData) as unknown as {
|
|
268
|
-
where: (c: SQL) => { returning: () => Promise<unknown[]> };
|
|
269
|
-
}
|
|
270
|
-
)
|
|
286
|
+
const rows = (await (this.db.update(this.table as Parameters<typeof this.db.update>[0]) as UpdateBuilder)
|
|
287
|
+
.set(updateData)
|
|
271
288
|
.where(this.pkCondition(id))
|
|
272
289
|
.returning()) as TTable['$inferSelect'][];
|
|
273
290
|
return rows[0];
|
|
@@ -279,11 +296,9 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
279
296
|
if (useSoftDelete && this.hasSoftDelete) {
|
|
280
297
|
return this.update(id, { inUsed: 0 } as Partial<TTable['$inferInsert']>);
|
|
281
298
|
}
|
|
282
|
-
await (
|
|
283
|
-
this.
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
).where(this.pkCondition(id));
|
|
299
|
+
await (this.db.delete(this.table as Parameters<typeof this.db.delete>[0]) as DeleteBuilder).where(
|
|
300
|
+
this.pkCondition(id),
|
|
301
|
+
);
|
|
287
302
|
return undefined;
|
|
288
303
|
}
|
|
289
304
|
|
|
@@ -325,21 +340,15 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
325
340
|
for (const [key, value] of Object.entries(this.table)) {
|
|
326
341
|
if (value === column) return key;
|
|
327
342
|
}
|
|
328
|
-
return (column as
|
|
343
|
+
return (column as { name: string }).name;
|
|
329
344
|
}
|
|
330
345
|
|
|
331
346
|
/** Count records matching an optional predicate. */
|
|
332
347
|
async count(where?: Predicate, includeDeleted = false): Promise<number> {
|
|
333
348
|
const condition = this.withActive(where, includeDeleted);
|
|
334
349
|
const compiled = condition ? compilePredicate(condition) : undefined;
|
|
335
|
-
const base = (
|
|
336
|
-
|
|
337
|
-
select: (p: unknown) => { from: (t: unknown) => { where: (c: SQL) => Promise<unknown[]> } };
|
|
338
|
-
}
|
|
339
|
-
)
|
|
340
|
-
.select({ value: countFn() })
|
|
341
|
-
.from(this.table);
|
|
342
|
-
const result = (await (compiled ? base.where(compiled) : (base as unknown as Promise<unknown[]>))) as {
|
|
350
|
+
const base = (this.db as CountDb).select({ value: countFn() }).from(this.table);
|
|
351
|
+
const result = (await (compiled ? base.where(compiled) : base)) as {
|
|
343
352
|
value: number;
|
|
344
353
|
}[];
|
|
345
354
|
return result[0]?.value ?? 0;
|
|
@@ -348,7 +357,9 @@ export class EntityDao<TTable extends EntityTable, TPK extends SQLiteColumn> ext
|
|
|
348
357
|
/** Combine a caller predicate with the soft-delete active filter. */
|
|
349
358
|
private withActive(where: Predicate | undefined, includeDeleted?: boolean): Predicate | undefined {
|
|
350
359
|
if (includeDeleted || !this.hasSoftDelete) return where;
|
|
351
|
-
const
|
|
360
|
+
const table = this.table;
|
|
361
|
+
if (!('inUsed' in table)) return where;
|
|
362
|
+
const active: Predicate = { col: table.inUsed as SQLiteColumn, op: 'eq', value: 1 };
|
|
352
363
|
if (!where) return active;
|
|
353
364
|
return { and: [where, active] };
|
|
354
365
|
}
|
package/src/queue-job-dao.ts
CHANGED
|
@@ -3,6 +3,58 @@ import type { DbAdapter } from './adapter';
|
|
|
3
3
|
import { EntityDao } from './entity-dao';
|
|
4
4
|
import { queueJobs } from './schema/queue-jobs';
|
|
5
5
|
|
|
6
|
+
type SelectGroupByQuery = {
|
|
7
|
+
groupBy: (group: unknown) => Promise<unknown[]>;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type SelectWhereQuery = {
|
|
11
|
+
where: (where: unknown) => Promise<unknown[]>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type SelectReadyQuery = {
|
|
15
|
+
where: (where: unknown) => {
|
|
16
|
+
orderBy: (order: unknown) => { limit: (limit: number) => Promise<unknown[]> };
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type QueueSelectDb = {
|
|
21
|
+
select: (projection: unknown) => {
|
|
22
|
+
from: (table: unknown) => SelectGroupByQuery & SelectWhereQuery;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type QueueReadyDb = {
|
|
27
|
+
select: () => {
|
|
28
|
+
from: (table: unknown) => SelectReadyQuery;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type QueueUpdateReturningDb = {
|
|
33
|
+
update: (table: unknown) => {
|
|
34
|
+
set: (value: unknown) => {
|
|
35
|
+
where: (where: unknown) => {
|
|
36
|
+
returning: () => Promise<unknown[]>;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type QueueUpdateVoidDb = {
|
|
43
|
+
update: (table: unknown) => {
|
|
44
|
+
set: (value: unknown) => {
|
|
45
|
+
where: (where: unknown) => Promise<unknown>;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type QueueUpdateChangesDb = {
|
|
51
|
+
update: (table: unknown) => {
|
|
52
|
+
set: (value: unknown) => {
|
|
53
|
+
where: (where: unknown) => Promise<{ changes: number }>;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
|
|
6
58
|
/**
|
|
7
59
|
* Aggregate queue statistics by job status.
|
|
8
60
|
*/
|
|
@@ -101,11 +153,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
101
153
|
* Get aggregate job counts by status.
|
|
102
154
|
*/
|
|
103
155
|
async getStats(): Promise<QueueStats> {
|
|
104
|
-
const result = await (
|
|
105
|
-
this.db as unknown as {
|
|
106
|
-
select: (fn: unknown) => { from: (t: unknown) => { groupBy: (g: unknown) => Promise<unknown[]> } };
|
|
107
|
-
}
|
|
108
|
-
)
|
|
156
|
+
const result = await (this.db as QueueSelectDb)
|
|
109
157
|
.select({
|
|
110
158
|
status: queueJobs.status,
|
|
111
159
|
count: sql`count(*)`,
|
|
@@ -128,11 +176,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
128
176
|
* Count jobs by status.
|
|
129
177
|
*/
|
|
130
178
|
async countByStatus(status: string): Promise<number> {
|
|
131
|
-
const result = await (
|
|
132
|
-
this.db as unknown as {
|
|
133
|
-
select: (fn: unknown) => { from: (t: unknown) => { where: (w: unknown) => Promise<unknown[]> } };
|
|
134
|
-
}
|
|
135
|
-
)
|
|
179
|
+
const result = await (this.db as QueueSelectDb)
|
|
136
180
|
.select({ value: sql`count(*)` })
|
|
137
181
|
.from(queueJobs)
|
|
138
182
|
.where(sql`${queueJobs.status} = ${status}`);
|
|
@@ -146,17 +190,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
146
190
|
async findPending(batchSize: number): Promise<QueueJobRecord[]> {
|
|
147
191
|
const now = this.now();
|
|
148
192
|
|
|
149
|
-
const result = await (
|
|
150
|
-
this.db as unknown as {
|
|
151
|
-
select: () => {
|
|
152
|
-
from: (t: unknown) => {
|
|
153
|
-
where: (w: unknown) => {
|
|
154
|
-
orderBy: (o: unknown) => { limit: (l: number) => Promise<unknown[]> };
|
|
155
|
-
};
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
)
|
|
193
|
+
const result = await (this.db as QueueReadyDb)
|
|
160
194
|
.select()
|
|
161
195
|
.from(queueJobs)
|
|
162
196
|
.where(
|
|
@@ -180,17 +214,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
180
214
|
|
|
181
215
|
const now = this.now();
|
|
182
216
|
|
|
183
|
-
const result = await (
|
|
184
|
-
this.db as unknown as {
|
|
185
|
-
update: (t: unknown) => {
|
|
186
|
-
set: (v: unknown) => {
|
|
187
|
-
where: (w: unknown) => {
|
|
188
|
-
returning: () => Promise<unknown[]>;
|
|
189
|
-
};
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
)
|
|
217
|
+
const result = await (this.db as QueueUpdateReturningDb)
|
|
194
218
|
.update(queueJobs)
|
|
195
219
|
.set({ status: 'processing', processingAt: now, updatedAt: now })
|
|
196
220
|
.where(
|
|
@@ -217,11 +241,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
217
241
|
|
|
218
242
|
const now = this.now();
|
|
219
243
|
|
|
220
|
-
await (
|
|
221
|
-
this.db as unknown as {
|
|
222
|
-
update: (t: unknown) => { set: (v: unknown) => { where: (w: unknown) => Promise<unknown> } };
|
|
223
|
-
}
|
|
224
|
-
)
|
|
244
|
+
await (this.db as QueueUpdateVoidDb)
|
|
225
245
|
.update(queueJobs)
|
|
226
246
|
.set({ status: 'processing', processingAt: now, updatedAt: now })
|
|
227
247
|
.where(and(inArray(queueJobs.id, ids), eq(queueJobs.status, 'pending')));
|
|
@@ -268,13 +288,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
268
288
|
async resetStuckJobs(visibilityTimeout: number): Promise<number> {
|
|
269
289
|
const cutoff = this.now() - visibilityTimeout;
|
|
270
290
|
|
|
271
|
-
const result = await (
|
|
272
|
-
this.db as unknown as {
|
|
273
|
-
update: (t: unknown) => {
|
|
274
|
-
set: (v: unknown) => { where: (w: unknown) => Promise<{ changes: number }> };
|
|
275
|
-
};
|
|
276
|
-
}
|
|
277
|
-
)
|
|
291
|
+
const result = await (this.db as QueueUpdateChangesDb)
|
|
278
292
|
.update(queueJobs)
|
|
279
293
|
.set({ status: 'pending', processingAt: null, updatedAt: this.now() })
|
|
280
294
|
.where(
|
|
@@ -293,13 +307,7 @@ export class QueueJobDao extends EntityDao<typeof queueJobs, typeof queueJobs.id
|
|
|
293
307
|
async failExpiredJobs(): Promise<number> {
|
|
294
308
|
const now = this.now();
|
|
295
309
|
|
|
296
|
-
const result = await (
|
|
297
|
-
this.db as unknown as {
|
|
298
|
-
update: (t: unknown) => {
|
|
299
|
-
set: (v: unknown) => { where: (w: unknown) => Promise<{ changes: number }> };
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
)
|
|
310
|
+
const result = await (this.db as QueueUpdateChangesDb)
|
|
303
311
|
.update(queueJobs)
|
|
304
312
|
.set({
|
|
305
313
|
status: 'failed',
|
package/src/schema/index.ts
CHANGED