@primate/sqlite 0.8.0 → 0.10.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.
@@ -1,16 +1,19 @@
1
- import type { As, DataDict, DB, Schema, Sort, With } from "@primate/core/db";
1
+ import type { As, CheckPlaceholders, DataDict, ExtractPlaceholders, Schema, Sort, SQLDB, With } from "@primate/core/db";
2
+ import Client from "@rcompat/sqlite";
2
3
  import type { Dict } from "@rcompat/type";
3
- declare const schema: import("pema").ObjectType<import("pema").NormalizeSchemaObject<{
4
+ import type { ObjectType, Parsed } from "pema";
5
+ declare const schema: ObjectType<import("pema").NormalizeSchemaObject<{
4
6
  readonly database: import("pema").DefaultType<import("pema").StringType, ":memory:">;
5
- }>, {
7
+ }>, undefined, {
6
8
  database: string;
7
9
  }>;
8
- export default class SQLite implements DB {
10
+ export default class SQLite implements SQLDB<Client> {
9
11
  #private;
10
12
  static config: typeof schema.input;
11
13
  constructor(config?: typeof schema.input, options?: {
12
14
  debug?: boolean;
13
15
  });
16
+ get client(): Client;
14
17
  get explain(): Dict<{
15
18
  query: string;
16
19
  plans: string[];
@@ -37,6 +40,13 @@ export default class SQLite implements DB {
37
40
  where: DataDict;
38
41
  }): Promise<number>;
39
42
  close(): void;
43
+ sql<Q extends string, I extends ObjectType<{
44
+ [K in ExtractPlaceholders<Q>]: Parsed<unknown>;
45
+ }> | undefined, O extends Parsed<unknown> | undefined>(options: {
46
+ input?: I extends ObjectType<any> ? CheckPlaceholders<I, Q> : I;
47
+ query: Q;
48
+ output?: O;
49
+ }): (args: I extends ObjectType<any> ? I["infer"] : void) => Promise<O extends Parsed<unknown> ? O["infer"] : void>;
40
50
  }
41
51
  export {};
42
52
  //# sourceMappingURL=SQLite.d.ts.map
@@ -134,6 +134,9 @@ export default class SQLite {
134
134
  get #db() {
135
135
  return this.#client ??= this.#factory();
136
136
  }
137
+ get client() {
138
+ return this.#db;
139
+ }
137
140
  #sql(query) {
138
141
  return this.#db.prepare(query);
139
142
  }
@@ -216,7 +219,7 @@ export default class SQLite {
216
219
  const value = where[field];
217
220
  const datatype = types[field];
218
221
  const q = sql.quote(field);
219
- const quoted = alias ? `${alias}.${q}` : q;
222
+ const quoted = is.defined(alias) ? `${alias}.${q}` : q;
220
223
  if (value === null) {
221
224
  parts.push(`${quoted} IS NULL`);
222
225
  continue;
@@ -245,6 +248,12 @@ export default class SQLite {
245
248
  case "$before":
246
249
  parts.push(cmp_expr(quoted, bound_key, op, datatype));
247
250
  break;
251
+ case "$in": {
252
+ const arr = value.$in;
253
+ const placeholders = arr.map((_, i) => `${BIND_BY}${sql.bindKey(field, `in${i}`)}`);
254
+ parts.push(`${quoted} IN (${placeholders.join(", ")})`);
255
+ break;
256
+ }
248
257
  default:
249
258
  throw E.operator_unknown(field, op);
250
259
  }
@@ -278,6 +287,14 @@ export default class SQLite {
278
287
  case "$ne":
279
288
  filtered[bound_key] = op_value;
280
289
  break;
290
+ case "$in": {
291
+ const arr = op_value;
292
+ for (let i = 0; i < arr.length; i++) {
293
+ const bound_key = sql.bindKey(field, `in${i}`);
294
+ filtered[bound_key] = arr[i];
295
+ }
296
+ break;
297
+ }
281
298
  default:
282
299
  throw E.operator_unknown(field, op);
283
300
  }
@@ -512,8 +529,9 @@ export default class SQLite {
512
529
  const WHERE = this.#where(as.types, args.where);
513
530
  const ORDER_BY = sql.orderBy(as.types, args.sort);
514
531
  const LIMIT = sql.limit(args.limit);
532
+ const OFFSET = args.offset !== undefined ? ` OFFSET ${args.offset}` : "";
515
533
  const table = sql.quote(as.table);
516
- return `SELECT ${SELECT} FROM ${table} ${WHERE}${ORDER_BY}${LIMIT}`;
534
+ return `SELECT ${SELECT} FROM ${table} ${WHERE}${ORDER_BY}${LIMIT}${OFFSET}`;
517
535
  }
518
536
  async #read_joined(as, args) {
519
537
  if (as.pk === null)
@@ -563,5 +581,33 @@ export default class SQLite {
563
581
  close() {
564
582
  this.#db.close();
565
583
  }
584
+ sql(options) {
585
+ if (is.defined(options.input)) {
586
+ const placeholders = new Set([...options.query.matchAll(/:(\w+)/g)].map(m => m[1]));
587
+ const input_keys = new Set(Object.keys(options.input.properties));
588
+ for (const key of input_keys) {
589
+ if (!placeholders.has(key))
590
+ throw E.sql_placeholder_missing(key);
591
+ }
592
+ for (const key of placeholders) {
593
+ if (!input_keys.has(key))
594
+ throw E.sql_input_missing(key);
595
+ }
596
+ }
597
+ return async (args) => {
598
+ const input = is.defined(options.input)
599
+ ? options.input.parse(args)
600
+ : undefined;
601
+ const query = options.query.replace(/:(\w+)/g, (_, name) => `$${name}`);
602
+ const binds = is.defined(input)
603
+ ? await bind(Object.fromEntries(Object.entries(options.input.properties)
604
+ .map(([k, v]) => [k, v.datatype])), input)
605
+ : {};
606
+ const rows = this.#sql(query).all(binds);
607
+ return (is.defined(options.output)
608
+ ? options.output.parse(rows)
609
+ : undefined);
610
+ };
611
+ }
566
612
  }
567
613
  //# sourceMappingURL=SQLite.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@primate/sqlite",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "SQLite databases for Primate",
5
5
  "homepage": "https://primate.run/docs/database/sqlite",
6
6
  "bugs": "https://github.com/primate-run/primate/issues",
@@ -17,17 +17,17 @@
17
17
  "!/**/*.spec.*"
18
18
  ],
19
19
  "dependencies": {
20
- "@rcompat/assert": "^0.8.1",
21
- "@rcompat/is": "^0.6.1",
22
- "@rcompat/sqlite": "^0.11.1",
23
- "@primate/core": "^0.6.0"
20
+ "@rcompat/assert": "^0.13.0",
21
+ "@rcompat/is": "^0.11.0",
22
+ "@rcompat/sqlite": "^0.16.0",
23
+ "@primate/core": "^0.8.0"
24
24
  },
25
25
  "devDependencies": {
26
- "@rcompat/type": "^0.11.1",
27
- "pema": "^0.6.0"
26
+ "@rcompat/type": "^0.17.0",
27
+ "pema": "^0.8.0"
28
28
  },
29
29
  "peerDependencies": {
30
- "primate": "^0.37.0"
30
+ "primate": "^0.39.0"
31
31
  },
32
32
  "imports": {
33
33
  "#*": {
@@ -42,7 +42,7 @@
42
42
  }
43
43
  },
44
44
  "scripts": {
45
- "build": "npm run clean && tsc",
45
+ "build": "npm run clean && tsgo",
46
46
  "clean": "rm -rf ./lib",
47
47
  "lint": "eslint .",
48
48
  "test": "npx proby",