rado 0.1.40 → 0.1.42

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,14 +1,14 @@
1
1
  import type { Database } from 'better-sqlite3';
2
2
  import { Driver } from '../lib/Driver';
3
3
  import { SchemaInstructions } from '../lib/Schema';
4
- import { CompiledStatement } from '../lib/Statement';
4
+ import { Statement } from '../lib/Statement';
5
5
  import { SqliteSchema } from '../sqlite/SqliteSchema';
6
6
  export declare class BetterSqlite3Driver extends Driver.Sync {
7
7
  db: Database;
8
8
  tableData: (tableName: string) => Array<SqliteSchema.Column>;
9
9
  indexData: (tableName: string) => Array<SqliteSchema.Index>;
10
10
  constructor(db: Database);
11
- prepareStatement(stmt: CompiledStatement): Driver.Sync.PreparedStatement;
11
+ prepareStatement(stmt: Statement): Driver.Sync.PreparedStatement;
12
12
  schemaInstructions(tableName: string): SchemaInstructions | undefined;
13
13
  export(): Uint8Array;
14
14
  }
@@ -0,0 +1,18 @@
1
+ /// <reference types="bun-types" />
2
+ import type { Database } from 'bun:sqlite';
3
+ import { Driver } from '../lib/Driver';
4
+ import { SchemaInstructions } from '../lib/Schema';
5
+ import { Statement } from '../lib/Statement';
6
+ import { SqliteSchema } from '../sqlite/SqliteSchema';
7
+ export declare class BunSqliteDriver extends Driver.Sync {
8
+ db: Database;
9
+ tableData: (tableName: string) => Array<SqliteSchema.Column>;
10
+ indexData: (tableName: string) => Array<SqliteSchema.Index>;
11
+ lastChanges: () => {
12
+ rowsAffected: number;
13
+ };
14
+ constructor(db: Database);
15
+ prepareStatement(stmt: Statement): Driver.Sync.PreparedStatement;
16
+ schemaInstructions(tableName: string): SchemaInstructions | undefined;
17
+ }
18
+ export declare function connect(db: Database): BunSqliteDriver;
@@ -0,0 +1,64 @@
1
+ // src/driver/bun-sqlite.ts
2
+ import { Cursor } from "../lib/Cursor.js";
3
+ import { Driver } from "../lib/Driver.js";
4
+ import { Query } from "../lib/Query.js";
5
+ import { SqliteFormatter } from "../sqlite/SqliteFormatter.js";
6
+ import { SqliteSchema } from "../sqlite/SqliteSchema.js";
7
+ var PreparedStatement = class {
8
+ constructor(lastChanges, stmt) {
9
+ this.lastChanges = lastChanges;
10
+ this.stmt = stmt;
11
+ }
12
+ *iterate(params = []) {
13
+ for (const row of this.stmt.all(...params))
14
+ yield row;
15
+ }
16
+ all(params = []) {
17
+ return this.stmt.all(...params);
18
+ }
19
+ run(params = []) {
20
+ this.stmt.run(...params);
21
+ return this.lastChanges();
22
+ }
23
+ get(params = []) {
24
+ return this.stmt.get(...params);
25
+ }
26
+ execute(params = []) {
27
+ this.stmt.run(...params);
28
+ }
29
+ };
30
+ var BunSqliteDriver = class extends Driver.Sync {
31
+ constructor(db) {
32
+ super(new SqliteFormatter());
33
+ this.db = db;
34
+ this.tableData = this.prepare(SqliteSchema.tableData);
35
+ this.indexData = this.prepare(SqliteSchema.indexData);
36
+ this.lastChanges = this.prepare(() => {
37
+ return new Cursor.SelectSingle(
38
+ Query.Raw({
39
+ expectedReturn: "row",
40
+ strings: ["SELECT changes() as rowsAffected"],
41
+ params: []
42
+ })
43
+ );
44
+ });
45
+ }
46
+ tableData;
47
+ indexData;
48
+ lastChanges;
49
+ prepareStatement(stmt) {
50
+ return new PreparedStatement(this.lastChanges, this.db.prepare(stmt.sql));
51
+ }
52
+ schemaInstructions(tableName) {
53
+ const columnData = this.tableData(tableName);
54
+ const indexData = this.indexData(tableName);
55
+ return SqliteSchema.createInstructions(columnData, indexData);
56
+ }
57
+ };
58
+ function connect(db) {
59
+ return new BunSqliteDriver(db);
60
+ }
61
+ export {
62
+ BunSqliteDriver,
63
+ connect
64
+ };
@@ -1,14 +1,14 @@
1
1
  import type { Database } from 'sql.js';
2
2
  import { Driver } from '../lib/Driver';
3
3
  import { SchemaInstructions } from '../lib/Schema';
4
- import { CompiledStatement } from '../lib/Statement';
4
+ import { Statement } from '../lib/Statement';
5
5
  import { SqliteSchema } from '../sqlite/SqliteSchema';
6
6
  export declare class SqlJsDriver extends Driver.Sync {
7
7
  db: Database;
8
8
  tableData: (tableName: string) => Array<SqliteSchema.Column>;
9
9
  indexData: (tableName: string) => Array<SqliteSchema.Index>;
10
10
  constructor(db: Database);
11
- prepareStatement(stmt: CompiledStatement): Driver.Sync.PreparedStatement;
11
+ prepareStatement(stmt: Statement, discardAfter: boolean): Driver.Sync.PreparedStatement;
12
12
  schemaInstructions(tableName: string): SchemaInstructions | undefined;
13
13
  export(): Uint8Array;
14
14
  }
@@ -3,20 +3,25 @@ import { Driver } from "../lib/Driver.js";
3
3
  import { SqliteFormatter } from "../sqlite/SqliteFormatter.js";
4
4
  import { SqliteSchema } from "../sqlite/SqliteSchema.js";
5
5
  var PreparedStatement = class {
6
- constructor(db, stmt) {
6
+ constructor(db, stmt, discardAfter) {
7
7
  this.db = db;
8
8
  this.stmt = stmt;
9
+ this.discardAfter = discardAfter;
9
10
  }
10
11
  *iterate(params) {
11
12
  this.stmt.bind(params);
12
13
  while (this.stmt.step())
13
14
  yield this.stmt.getAsObject();
15
+ if (this.discardAfter)
16
+ this.stmt.free();
14
17
  }
15
18
  all(params) {
16
19
  return Array.from(this.iterate(params));
17
20
  }
18
21
  run(params) {
19
22
  this.stmt.run(params);
23
+ if (this.discardAfter)
24
+ this.stmt.free();
20
25
  return { rowsAffected: this.db.getRowsModified() };
21
26
  }
22
27
  get(params) {
@@ -24,6 +29,8 @@ var PreparedStatement = class {
24
29
  }
25
30
  execute(params) {
26
31
  this.stmt.run(params);
32
+ if (this.discardAfter)
33
+ this.stmt.free();
27
34
  }
28
35
  };
29
36
  var SqlJsDriver = class extends Driver.Sync {
@@ -35,8 +42,12 @@ var SqlJsDriver = class extends Driver.Sync {
35
42
  }
36
43
  tableData;
37
44
  indexData;
38
- prepareStatement(stmt) {
39
- return new PreparedStatement(this.db, this.db.prepare(stmt.sql));
45
+ prepareStatement(stmt, discardAfter) {
46
+ return new PreparedStatement(
47
+ this.db,
48
+ this.db.prepare(stmt.sql),
49
+ discardAfter
50
+ );
40
51
  }
41
52
  schemaInstructions(tableName) {
42
53
  const columnData = this.tableData(tableName);
@@ -2,7 +2,7 @@ import type { Database } from 'sqlite3';
2
2
  import { Driver } from '../lib/Driver';
3
3
  import { Query } from '../lib/Query';
4
4
  import { SchemaInstructions } from '../lib/Schema';
5
- import { CompiledStatement } from '../lib/Statement';
5
+ import { Statement } from '../lib/Statement';
6
6
  import { SqliteSchema } from '../sqlite/SqliteSchema';
7
7
  export declare class Sqlite3Driver extends Driver.Async {
8
8
  private db;
@@ -11,7 +11,7 @@ export declare class Sqlite3Driver extends Driver.Async {
11
11
  indexData: (tableName: string) => Promise<Array<SqliteSchema.Index>>;
12
12
  constructor(db: Database);
13
13
  executeQuery<T>(query: Query<T>, stmt?: Driver.Async.PreparedStatement, params?: any[] | undefined): Promise<T>;
14
- prepareStatement(stmt: CompiledStatement): Driver.Async.PreparedStatement;
14
+ prepareStatement(stmt: Statement): Driver.Async.PreparedStatement;
15
15
  schemaInstructions(tableName: string): Promise<SchemaInstructions | undefined>;
16
16
  isolate(): [connection: Driver.Async, release: () => Promise<void>];
17
17
  }
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export * from './lib/Driver';
4
4
  export * from './lib/Expr';
5
5
  export * from './lib/Fields';
6
6
  export * from './lib/Formatter';
7
- export { Functions } from './lib/Functions';
7
+ export * from './lib/Functions';
8
8
  export * from './lib/Id';
9
9
  export * from './lib/Index';
10
10
  export * from './lib/Ops';
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ export * from "./lib/Driver.js";
5
5
  export * from "./lib/Expr.js";
6
6
  export * from "./lib/Fields.js";
7
7
  export * from "./lib/Formatter.js";
8
- import { Functions } from "./lib/Functions.js";
8
+ export * from "./lib/Functions.js";
9
9
  export * from "./lib/Id.js";
10
10
  export * from "./lib/Index.js";
11
11
  export * from "./lib/Ops.js";
@@ -19,6 +19,3 @@ export * from "./lib/Statement.js";
19
19
  export * from "./lib/Table.js";
20
20
  export * from "./lib/Target.js";
21
21
  export * from "./lib/Update.js";
22
- export {
23
- Functions
24
- };
@@ -27,7 +27,7 @@ export declare class Column<T> {
27
27
  nullable(): Column<T | null>;
28
28
  autoIncrement(): Column<Column.IsOptional<T>>;
29
29
  primaryKey<K extends string>(): Column<Column.IsPrimary<T, K>>;
30
- references<X extends T>(column: Expr<X>): Column<X>;
30
+ references<X extends T>(column: Expr<X> | (() => Expr<X>)): Column<X>;
31
31
  unique(): Column<T>;
32
32
  defaultValue(value: EV<T>): Column<Column.IsOptional<T>>;
33
33
  }
@@ -25,7 +25,12 @@ var Column = class {
25
25
  return new Column({ ...this.data, primaryKey: true });
26
26
  }
27
27
  references(column2) {
28
- return new Column({ ...this.data, references: ExprData.create(column2) });
28
+ return new Column({
29
+ ...this.data,
30
+ get references() {
31
+ return ExprData.create(typeof column2 === "function" ? column2() : column2);
32
+ }
33
+ });
29
34
  }
30
35
  unique() {
31
36
  return new Column({ ...this.data, unique: true });
@@ -11,8 +11,8 @@ export declare class Cursor<T> {
11
11
  constructor(query: Query<T>);
12
12
  static all(strings: TemplateStringsArray, ...params: Array<any>): Cursor<any>;
13
13
  query(): Query<T>;
14
- run(driver: Driver.Sync): T;
15
- run(driver: Driver.Async): Promise<T>;
14
+ on(driver: Driver.Sync): T;
15
+ on(driver: Driver.Async): Promise<T>;
16
16
  toJSON(): Query<T>;
17
17
  }
18
18
  export declare namespace Cursor {
@@ -27,7 +27,7 @@ export declare namespace Cursor {
27
27
  class Update<T> extends Cursor<{
28
28
  rowsAffected: number;
29
29
  }> {
30
- query: () => Query.Update;
30
+ query(): Query.Update;
31
31
  set(set: UpdateSet<T>): Update<T>;
32
32
  where(...where: Array<EV<boolean>>): Update<T>;
33
33
  take(limit: number | undefined): Update<T>;
@@ -21,7 +21,7 @@ var Cursor = class {
21
21
  query() {
22
22
  throw new Error("Not implemented");
23
23
  }
24
- run(driver) {
24
+ on(driver) {
25
25
  return driver.executeQuery(this.query());
26
26
  }
27
27
  toJSON() {
@@ -54,6 +54,9 @@ function addWhere(query, where) {
54
54
  }
55
55
  Cursor2.Delete = Delete;
56
56
  class Update extends Cursor2 {
57
+ query() {
58
+ return super.query();
59
+ }
57
60
  set(set) {
58
61
  return new Update({ ...this.query(), set });
59
62
  }
@@ -3,7 +3,7 @@ import { Expr } from './Expr';
3
3
  import { Formatter } from './Formatter';
4
4
  import { Query } from './Query';
5
5
  import { SchemaInstructions } from './Schema';
6
- import { CompiledStatement } from './Statement';
6
+ import { Statement } from './Statement';
7
7
  import { Table } from './Table';
8
8
  declare class Callable extends Function {
9
9
  constructor(fn: Function);
@@ -11,7 +11,7 @@ declare class Callable extends Function {
11
11
  declare abstract class DriverBase extends Callable {
12
12
  formatter: Formatter;
13
13
  constructor(formatter: Formatter);
14
- compile<T extends Array<Expr<any>>, R>(create: (...params: T) => Cursor<R>): [Query<T>, CompiledStatement];
14
+ compile<T extends Array<Expr<any>>, R>(create: (...params: T) => Cursor<R>): [Query<T>, Statement];
15
15
  all(...args: Array<any>): any;
16
16
  get(...args: Array<any>): any;
17
17
  sql(strings: TemplateStringsArray, ...params: Array<any>): Cursor<unknown>;
@@ -30,7 +30,7 @@ interface SyncDriver {
30
30
  }
31
31
  declare abstract class SyncDriver extends DriverBase {
32
32
  transactionId: number;
33
- abstract prepareStatement(stmt: CompiledStatement): SyncPreparedStatement;
33
+ abstract prepareStatement(stmt: Statement, discardAfter: boolean): SyncPreparedStatement;
34
34
  abstract schemaInstructions(tableName: string): SchemaInstructions | undefined;
35
35
  prepare<T extends Array<Expr<any>>, R>(create: (...params: T) => Cursor<R>): (...params: ParamTypes<T>) => R;
36
36
  migrateSchema(...tables: Array<Table<any>>): unknown;
@@ -62,7 +62,7 @@ interface AsyncDriver {
62
62
  declare abstract class AsyncDriver extends DriverBase {
63
63
  transactionId: number;
64
64
  abstract isolate(): [connection: AsyncDriver, release: () => Promise<void>];
65
- abstract prepareStatement(stmt: CompiledStatement): AsyncPreparedStatement;
65
+ abstract prepareStatement(stmt: Statement, discardAfter: boolean): AsyncPreparedStatement;
66
66
  abstract schemaInstructions(tableName: string): Promise<SchemaInstructions | undefined>;
67
67
  prepare<T extends Array<Expr<any>>, R>(create: (...params: T) => Cursor<R>): (...params: ParamTypes<T>) => Promise<R>;
68
68
  migrateSchema(...tables: Array<Table<any>>): Promise<unknown>;
@@ -81,7 +81,7 @@ declare class SyncWrapper extends AsyncDriver {
81
81
  lock: Promise<void> | undefined;
82
82
  constructor(sync: SyncDriver);
83
83
  executeQuery<T>(query: Query<T>, stmt?: AsyncPreparedStatement, params?: Array<any>): Promise<T>;
84
- prepareStatement(stmt: CompiledStatement): AsyncPreparedStatement;
84
+ prepareStatement(stmt: Statement, discardAfter: boolean): AsyncPreparedStatement;
85
85
  schemaInstructions(tableName: string): Promise<SchemaInstructions | undefined>;
86
86
  isolate(): [connection: AsyncDriver, release: () => Promise<void>];
87
87
  }
@@ -70,7 +70,7 @@ var SyncDriver = class extends DriverBase {
70
70
  transactionId = 0;
71
71
  prepare(create) {
72
72
  const [query, compiled] = this.compile(create);
73
- const prepared = this.prepareStatement(compiled);
73
+ const prepared = this.prepareStatement(compiled, false);
74
74
  return (...params) => {
75
75
  const namedParams = Object.fromEntries(
76
76
  params.map((value, i) => [`p${i}`, value])
@@ -109,7 +109,7 @@ var SyncDriver = class extends DriverBase {
109
109
  });
110
110
  default:
111
111
  const compiled = stmt ? void 0 : this.formatter.compile(query);
112
- stmt = stmt || this.prepareStatement(compiled);
112
+ stmt = stmt || this.prepareStatement(compiled, true);
113
113
  params = params || compiled.params();
114
114
  if ("selection" in query) {
115
115
  const res = stmt.all(params).map((row) => JSON.parse(row.result).result);
@@ -142,7 +142,10 @@ var SyncDriver = class extends DriverBase {
142
142
  return super.get(...args);
143
143
  }
144
144
  *iterate(cursor) {
145
- const stmt = this.prepareStatement(this.formatter.compile(cursor.query()));
145
+ const stmt = this.prepareStatement(
146
+ this.formatter.compile(cursor.query()),
147
+ true
148
+ );
146
149
  for (const row of stmt.iterate()) {
147
150
  yield JSON.parse(row.result).result;
148
151
  }
@@ -173,7 +176,7 @@ var AsyncDriver = class extends DriverBase {
173
176
  transactionId = 0;
174
177
  prepare(create) {
175
178
  const [query, compiled] = this.compile(create);
176
- const prepared = this.prepareStatement(compiled);
179
+ const prepared = this.prepareStatement(compiled, false);
177
180
  return (...params) => {
178
181
  const namedParams = Object.fromEntries(
179
182
  params.map((value, i) => [`p${i}`, value])
@@ -212,7 +215,7 @@ var AsyncDriver = class extends DriverBase {
212
215
  });
213
216
  default:
214
217
  const compiled = stmt ? void 0 : this.formatter.compile(query);
215
- stmt = stmt || this.prepareStatement(compiled);
218
+ stmt = stmt || this.prepareStatement(compiled, true);
216
219
  params = params || compiled.params();
217
220
  if ("selection" in query) {
218
221
  const res = (await stmt.all(params)).map(
@@ -247,7 +250,10 @@ var AsyncDriver = class extends DriverBase {
247
250
  return super.get(...args);
248
251
  }
249
252
  async *iterate(cursor) {
250
- const stmt = this.prepareStatement(this.formatter.compile(cursor.query()));
253
+ const stmt = this.prepareStatement(
254
+ this.formatter.compile(cursor.query()),
255
+ true
256
+ );
251
257
  for await (const row of stmt.iterate()) {
252
258
  yield JSON.parse(row.result).result;
253
259
  }
@@ -305,8 +311,10 @@ var SyncWrapper = class extends AsyncDriver {
305
311
  await this.lock;
306
312
  return super.executeQuery(query, stmt, params);
307
313
  }
308
- prepareStatement(stmt) {
309
- return new SyncPreparedStatementWrapper(this.sync.prepareStatement(stmt));
314
+ prepareStatement(stmt, discardAfter) {
315
+ return new SyncPreparedStatementWrapper(
316
+ this.sync.prepareStatement(stmt, discardAfter)
317
+ );
310
318
  }
311
319
  async schemaInstructions(tableName) {
312
320
  return this.sync.schemaInstructions(tableName);
@@ -19,15 +19,16 @@ export interface FormatContext {
19
19
  /** Inline all parameters */
20
20
  forceInline?: boolean;
21
21
  formatAsJson?: boolean;
22
- formatSubject?: (mkSubject: () => void) => void;
22
+ topLevel?: boolean;
23
23
  }
24
+ type FormatSubject = (stmt: Statement, mkSubject: () => void) => void;
24
25
  export declare abstract class Formatter implements Sanitizer {
25
26
  constructor();
26
27
  abstract escapeValue(value: any): string;
27
28
  abstract escapeIdentifier(ident: string): string;
28
29
  abstract formatParamValue(paramValue: any): any;
29
30
  abstract formatAccess(ctx: FormatContext, mkSubject: () => void, field: string): Statement;
30
- compile<T>(query: Query<T>, formatInline?: boolean): import("./Statement").CompiledStatement;
31
+ compile<T>(query: Query<T>): Statement;
31
32
  format<T>(ctx: FormatContext, query: Query<T>): Statement;
32
33
  formatSelect(ctx: FormatContext, query: Query.Select): Statement;
33
34
  formatInsert(ctx: FormatContext, query: Query.Insert): Statement;
@@ -51,7 +52,7 @@ export declare abstract class Formatter implements Sanitizer {
51
52
  formatGroupBy(ctx: FormatContext, groupBy: Array<ExprData> | undefined): Statement;
52
53
  formatOrderBy(ctx: FormatContext, orderBy: Array<OrderBy> | undefined): Statement;
53
54
  formatLimit(ctx: FormatContext, { limit, offset, singleResult }: Query.QueryBase): Statement;
54
- formatSelection(ctx: FormatContext, selection: ExprData): Statement;
55
+ formatSelection(ctx: FormatContext, selection: ExprData, formatSubject?: FormatSubject): Statement;
55
56
  formatExprJson(ctx: FormatContext, expr: ExprData): Statement;
56
57
  formatExprValue(ctx: FormatContext, expr: ExprData): Statement;
57
58
  formatIn(ctx: FormatContext, expr: ExprData): Statement;
@@ -62,3 +63,4 @@ export declare abstract class Formatter implements Sanitizer {
62
63
  formatValue(ctx: FormatContext, rawValue: any): Statement;
63
64
  formatExpr(ctx: FormatContext, expr: ExprData): Statement;
64
65
  }
66
+ export {};
@@ -31,23 +31,17 @@ var joins = {
31
31
  left: "left",
32
32
  inner: "inner"
33
33
  };
34
+ function formatAsResultObject(stmt, mkSubject) {
35
+ stmt.raw("json_object('result', ");
36
+ mkSubject();
37
+ stmt.raw(")");
38
+ }
34
39
  var Formatter = class {
35
40
  constructor() {
36
41
  }
37
- compile(query, formatInline = false) {
38
- const stmt = new Statement();
39
- const result = this.format(
40
- {
41
- stmt,
42
- formatSubject: (mkSubject) => {
43
- stmt.raw("json_object('result', ");
44
- mkSubject();
45
- stmt.raw(")");
46
- },
47
- nameResult: "result"
48
- },
49
- query
50
- ).compile(this, formatInline);
42
+ compile(query) {
43
+ const stmt = new Statement(this);
44
+ const result = this.format({ stmt, topLevel: true }, query);
51
45
  return result;
52
46
  }
53
47
  format(ctx, query) {
@@ -77,9 +71,13 @@ var Formatter = class {
77
71
  }
78
72
  }
79
73
  formatSelect(ctx, query) {
80
- const { stmt } = ctx;
74
+ const { stmt, topLevel } = ctx;
81
75
  stmt.add("SELECT").space();
82
- this.formatSelection(ctx, query.selection);
76
+ this.formatSelection(
77
+ { ...ctx, topLevel: false },
78
+ query.selection,
79
+ topLevel ? formatAsResultObject : void 0
80
+ );
83
81
  stmt.addLine("FROM").space();
84
82
  this.formatTarget(ctx, query.from);
85
83
  this.formatWhere(ctx, query.where);
@@ -102,7 +100,7 @@ var Formatter = class {
102
100
  this.formatInsertRow(ctx, query.into.columns, row);
103
101
  if (query.selection) {
104
102
  stmt.add("RETURNING").space();
105
- this.formatSelection(ctx, query.selection);
103
+ this.formatSelection(ctx, query.selection, formatAsResultObject);
106
104
  }
107
105
  return stmt;
108
106
  }
@@ -341,7 +339,7 @@ var Formatter = class {
341
339
  const { stmt } = ctx;
342
340
  if (!expr)
343
341
  return stmt;
344
- stmt.newline().raw("WHERE");
342
+ stmt.newline().raw("WHERE").space();
345
343
  this.formatExprValue(ctx, expr);
346
344
  return stmt;
347
345
  }
@@ -382,22 +380,20 @@ var Formatter = class {
382
380
  stmt.raw("OFFSET").addValue(offset);
383
381
  return stmt;
384
382
  }
385
- formatSelection(ctx, selection) {
386
- const { stmt, formatSubject } = ctx;
383
+ formatSelection(ctx, selection, formatSubject) {
384
+ const { stmt } = ctx;
387
385
  const mkSubject = () => this.formatExpr(
388
386
  {
389
387
  ...ctx,
390
- formatSubject: void 0,
391
388
  formatAsJson: true
392
389
  },
393
390
  selection
394
391
  );
395
392
  if (formatSubject)
396
- formatSubject(mkSubject);
393
+ formatSubject(stmt, mkSubject);
397
394
  else
398
395
  mkSubject();
399
- if (ctx.nameResult)
400
- stmt.add("AS").addIdentifier(ctx.nameResult);
396
+ stmt.add("AS").addIdentifier("result");
401
397
  return stmt;
402
398
  }
403
399
  formatExprJson(ctx, expr) {
@@ -562,11 +558,11 @@ var Formatter = class {
562
558
  }
563
559
  if (expr.query.singleResult) {
564
560
  stmt.raw("json").openParenthesis().openParenthesis();
565
- this.format({ ...ctx, nameResult: "result" }, expr.query);
561
+ this.format(ctx, expr.query);
566
562
  return stmt.closeParenthesis().closeParenthesis();
567
563
  }
568
564
  stmt.openParenthesis().raw("SELECT json_group_array(json(result))").newline().raw("FROM").openParenthesis();
569
- this.format({ ...ctx, nameResult: "result" }, expr.query);
565
+ this.format(ctx, expr.query);
570
566
  return stmt.closeParenthesis().closeParenthesis();
571
567
  case ExprType.Row:
572
568
  switch (expr.target.type) {
@@ -576,17 +572,14 @@ var Formatter = class {
576
572
  throw new Error(`Cannot select empty target`);
577
573
  if (ctx.tableAsExpr)
578
574
  return stmt.identifier(table.alias || table.name);
579
- return this.formatExpr(
580
- ctx,
581
- ExprData.Record(
582
- Object.fromEntries(
583
- Object.entries(table.columns).map(([key, column]) => [
584
- key,
585
- ExprData.Field(ExprData.Row(expr.target), column.name)
586
- ])
587
- )
588
- )
589
- );
575
+ stmt.identifier("json_object");
576
+ for (const [key, column] of stmt.call(
577
+ Object.entries(table.columns)
578
+ )) {
579
+ this.formatString(ctx, key).raw(", ");
580
+ this.formatField(ctx, expr, column.name);
581
+ }
582
+ return stmt;
590
583
  case TargetType.Query:
591
584
  case TargetType.Expr:
592
585
  return stmt.identifier(expr.target.alias).raw(".value");
package/dist/lib/Id.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export type Id<T extends {
1
+ export type Id<T> = T extends {
2
2
  id: any;
3
- }> = T['id'];
3
+ } ? T['id'] : never;
@@ -29,9 +29,9 @@ var Schema;
29
29
  res.push(Query.AlterTable({ table: schema, dropColumn: columnName }));
30
30
  } else {
31
31
  const { sql: instruction } = formatter.formatColumn(
32
- { stmt: new Statement() },
32
+ { stmt: new Statement(formatter) },
33
33
  { ...schemaCol, references: void 0 }
34
- ).compile(formatter);
34
+ );
35
35
  if (removeLeadingWhitespace(localInstruction) !== removeLeadingWhitespace(instruction)) {
36
36
  res.push(Query.AlterTable({ table: schema, alterColumn: schemaCol }));
37
37
  }
@@ -49,10 +49,9 @@ var Schema;
49
49
  } else if (!schemaIndex) {
50
50
  res.unshift(Query.DropIndex({ table: schema, name: indexName }));
51
51
  } else {
52
- const { sql: instruction } = formatter.formatCreateIndex(
53
- { stmt: new Statement() },
52
+ const { sql: instruction } = formatter.compile(
54
53
  Query.CreateIndex({ table: schema, index: schemaIndex })
55
- ).compile(formatter);
54
+ );
56
55
  if (removeLeadingWhitespace(localInstruction) !== removeLeadingWhitespace(instruction)) {
57
56
  res.unshift(Query.DropIndex({ table: schema, name: indexName }));
58
57
  res.push(Query.CreateIndex({ table: schema, index: schemaIndex }));
@@ -1,39 +1,17 @@
1
1
  import { ParamData } from './Param';
2
2
  import { Sanitizer } from './Sanitizer';
3
- declare enum TokenType {
4
- Raw = "Raw",
5
- Identifier = "Identifier",
6
- Value = "Value",
7
- Param = "Param",
8
- Indent = "Indent",
9
- Dedent = "Dedent"
10
- }
11
- declare class Token {
12
- type: TokenType;
13
- data: any;
14
- constructor(type: TokenType, data: any);
15
- static Raw(data: string): Token;
16
- static Indent(): Token;
17
- static Dedent(): Token;
18
- static Identifier(data: string): Token;
19
- static Value(data: any): Token;
20
- static Param(name: string): Token;
21
- }
22
- export interface CompileOptions {
23
- formatInline?: boolean;
24
- spaces?: number;
25
- }
26
3
  export declare class Statement {
27
- tokens: Array<Token>;
28
- constructor(tokens?: Array<Token>);
29
- concat(...tokens: Array<Token>): this;
30
- static tag(strings: ReadonlyArray<string>, params: Array<Statement>): Statement;
4
+ sanitizer: Sanitizer;
5
+ sql: string;
6
+ private paramData;
7
+ currentIndent: string;
8
+ constructor(sanitizer: Sanitizer, sql?: string, paramData?: Array<ParamData>);
31
9
  space(): this;
32
10
  add(addition: undefined | string): this;
33
11
  addLine(addition: undefined | string): this;
34
12
  indent(): this;
35
13
  dedent(): this;
36
- newline(ignore?: boolean): this;
14
+ newline(): this;
37
15
  identifier(name: string): this;
38
16
  addIdentifier(name: string): this;
39
17
  value(value: any): this;
@@ -46,14 +24,6 @@ export declare class Statement {
46
24
  call<T>(parts: Array<T>, separator?: string): Generator<T, this | undefined, unknown>;
47
25
  separate<T>(parts: Array<T>, separator?: string): Generator<T, void, unknown>;
48
26
  isEmpty(): boolean;
49
- compile(sanitizer: Sanitizer, formatInline?: boolean): CompiledStatement;
50
- }
51
- export declare class CompiledStatement {
52
- sanitizer: Sanitizer;
53
- sql: string;
54
- private paramData;
55
- constructor(sanitizer: Sanitizer, sql: string, paramData: Array<ParamData>);
56
27
  params(input?: Record<string, any>): Array<any>;
57
28
  toString(): string;
58
29
  }
59
- export {};
@@ -1,50 +1,18 @@
1
1
  // src/lib/Statement.ts
2
2
  import { ParamData, ParamType } from "./Param.js";
3
- var Token = class {
4
- constructor(type, data) {
5
- this.type = type;
6
- this.data = data;
7
- }
8
- static Raw(data) {
9
- return new Token("Raw" /* Raw */, data);
10
- }
11
- static Indent() {
12
- return new Token("Indent" /* Indent */, null);
13
- }
14
- static Dedent() {
15
- return new Token("Dedent" /* Dedent */, null);
16
- }
17
- static Identifier(data) {
18
- return new Token("Identifier" /* Identifier */, data);
19
- }
20
- static Value(data) {
21
- return new Token("Value" /* Value */, data);
22
- }
23
- static Param(name) {
24
- return new Token("Param" /* Param */, name);
25
- }
26
- };
27
3
  var SEPARATE = ", ";
28
4
  var WHITESPACE = " ";
29
5
  var NEWLINE = "\n";
6
+ var INSERT_PARAM = "?";
30
7
  var Statement = class {
31
- constructor(tokens = []) {
32
- this.tokens = tokens;
33
- }
34
- concat(...tokens) {
35
- this.tokens.push(...tokens);
36
- return this;
37
- }
38
- static tag(strings, params) {
39
- return new Statement(
40
- strings.flatMap((s, i) => {
41
- const param = params[i];
42
- return [Token.Raw(s)].concat(param ? param.tokens : []);
43
- })
44
- );
8
+ constructor(sanitizer, sql = "", paramData = []) {
9
+ this.sanitizer = sanitizer;
10
+ this.sql = sql;
11
+ this.paramData = paramData;
45
12
  }
13
+ currentIndent = "";
46
14
  space() {
47
- if (this.tokens.length === 0)
15
+ if (this.sql === "")
48
16
  return this;
49
17
  return this.raw(WHITESPACE);
50
18
  }
@@ -59,30 +27,32 @@ var Statement = class {
59
27
  return this.newline().add(addition);
60
28
  }
61
29
  indent() {
62
- return this.concat(Token.Indent());
30
+ this.currentIndent = this.currentIndent + " ";
31
+ return this;
63
32
  }
64
33
  dedent() {
65
- return this.concat(Token.Dedent());
34
+ this.currentIndent = this.currentIndent.slice(0, -2);
35
+ return this;
66
36
  }
67
- newline(ignore = false) {
68
- if (ignore)
69
- return this;
70
- return this.raw(NEWLINE);
37
+ newline() {
38
+ return this.raw(NEWLINE + this.currentIndent);
71
39
  }
72
40
  identifier(name) {
73
- return this.concat(Token.Identifier(name));
41
+ return this.raw(this.sanitizer.escapeIdentifier(name));
74
42
  }
75
43
  addIdentifier(name) {
76
44
  return this.space().identifier(name);
77
45
  }
78
46
  value(value) {
79
- return this.concat(Token.Value(value));
47
+ this.paramData.push(ParamData.Value(value));
48
+ return this.raw(INSERT_PARAM);
80
49
  }
81
50
  addValue(value) {
82
51
  return this.space().value(value);
83
52
  }
84
53
  param(name) {
85
- return this.concat(Token.Param(name));
54
+ this.paramData.push(ParamData.Named(name));
55
+ return this.raw(INSERT_PARAM);
86
56
  }
87
57
  addParam(name) {
88
58
  return this.space().param(name);
@@ -90,7 +60,8 @@ var Statement = class {
90
60
  raw(query) {
91
61
  if (!query)
92
62
  return this;
93
- return this.concat(Token.Raw(query));
63
+ this.sql += query;
64
+ return this;
94
65
  }
95
66
  openParenthesis() {
96
67
  return this.raw("(").indent().newline();
@@ -113,49 +84,7 @@ var Statement = class {
113
84
  }
114
85
  }
115
86
  isEmpty() {
116
- return this.tokens.length === 0 || this.tokens.length === 1 && this.tokens[0].type === "Raw" /* Raw */ && this.tokens[0].data === "";
117
- }
118
- compile(sanitizer, formatInline = false) {
119
- let sql = "", paramData = [], indent = "";
120
- for (const token of this.tokens) {
121
- switch (token.type) {
122
- case "Raw" /* Raw */:
123
- if (token.data === NEWLINE)
124
- sql += NEWLINE + indent;
125
- else
126
- sql += token.data;
127
- break;
128
- case "Identifier" /* Identifier */:
129
- sql += sanitizer.escapeIdentifier(token.data);
130
- break;
131
- case "Value" /* Value */:
132
- if (formatInline) {
133
- sql += sanitizer.escapeValue(token.data);
134
- } else {
135
- sql += "?";
136
- paramData.push(ParamData.Value(token.data));
137
- }
138
- break;
139
- case "Param" /* Param */:
140
- sql += "?";
141
- paramData.push(ParamData.Named(token.data));
142
- break;
143
- case "Indent" /* Indent */:
144
- indent += " ";
145
- break;
146
- case "Dedent" /* Dedent */:
147
- indent = indent.slice(0, -2);
148
- break;
149
- }
150
- }
151
- return new CompiledStatement(sanitizer, sql, paramData);
152
- }
153
- };
154
- var CompiledStatement = class {
155
- constructor(sanitizer, sql, paramData) {
156
- this.sanitizer = sanitizer;
157
- this.sql = sql;
158
- this.paramData = paramData;
87
+ return this.sql === "";
159
88
  }
160
89
  params(input) {
161
90
  return this.paramData.map((param) => {
@@ -172,6 +101,5 @@ var CompiledStatement = class {
172
101
  }
173
102
  };
174
103
  export {
175
- CompiledStatement,
176
104
  Statement
177
105
  };
@@ -1,17 +1,12 @@
1
1
  // src/sqlite/SqliteFormatter.ts
2
2
  import { ExprType } from "../lib/Expr.js";
3
3
  import { Formatter } from "../lib/Formatter.js";
4
- function escapeWithin(input, outer) {
5
- let buf = outer;
6
- for (const char of input) {
7
- if (char === outer)
8
- buf += outer + outer;
9
- else
10
- buf += char;
11
- }
12
- buf += outer;
13
- return buf;
14
- }
4
+ var BACKTICK = "`";
5
+ var ESCAPE_BACKTICK = "``";
6
+ var SINGLE_QUOTE = "'";
7
+ var ESCAPE_SINGLE_QUOTE = "''";
8
+ var MATCH_BACKTICK = /`/g;
9
+ var MATCH_SINGLE_QUOTE = /'/g;
15
10
  var SqliteFormatter = class extends Formatter {
16
11
  formatParamValue(paramValue) {
17
12
  if (paramValue === null || paramValue === void 0)
@@ -26,7 +21,7 @@ var SqliteFormatter = class extends Formatter {
26
21
  }
27
22
  escapeValue(value) {
28
23
  if (value === null || value === void 0)
29
- return "null";
24
+ return "NULL";
30
25
  if (typeof value === "boolean")
31
26
  return value ? "1" : "0";
32
27
  if (typeof value === "number")
@@ -36,10 +31,10 @@ var SqliteFormatter = class extends Formatter {
36
31
  return "json(" + this.escapeString(JSON.stringify(value)) + ")";
37
32
  }
38
33
  escapeIdentifier(input) {
39
- return escapeWithin(input, "`");
34
+ return BACKTICK + input.replace(MATCH_BACKTICK, ESCAPE_BACKTICK) + BACKTICK;
40
35
  }
41
36
  escapeString(input) {
42
- return escapeWithin(input, "'");
37
+ return SINGLE_QUOTE + input.replace(MATCH_SINGLE_QUOTE, ESCAPE_SINGLE_QUOTE) + SINGLE_QUOTE;
43
38
  }
44
39
  formatAccess(ctx, mkSubject, field) {
45
40
  const { stmt, formatAsJson } = ctx;
@@ -25,7 +25,7 @@ var SqliteSchema;
25
25
  }
26
26
  SqliteSchema2.createInstructions = createInstructions;
27
27
  function columnInstruction(column) {
28
- const stmt = new Statement();
28
+ const stmt = new Statement(formatter);
29
29
  stmt.identifier(column.name).add(column.type);
30
30
  if (column.pk === 1)
31
31
  stmt.add("PRIMARY KEY");
@@ -34,7 +34,7 @@ var SqliteSchema;
34
34
  if (column.dflt_value !== null) {
35
35
  stmt.add("DEFAULT").space().openParenthesis().raw(column.dflt_value).closeParenthesis();
36
36
  }
37
- return [column.name, stmt.compile(formatter).sql];
37
+ return [column.name, stmt.sql];
38
38
  }
39
39
  SqliteSchema2.columnInstruction = columnInstruction;
40
40
  function indexInstruction(index) {
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "rado",
3
- "version": "0.1.40",
3
+ "version": "0.1.42",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
7
7
  ".": "./dist/index.js",
8
- "./*": "./dist/*.js"
8
+ "./*": "./dist/*.js",
9
+ "./driver/bun:sqlite": "./dist/driver/bun-sqlite.js"
9
10
  },
10
11
  "files": [
11
12
  "dist"
@@ -13,6 +14,9 @@
13
14
  "sideEffects": false,
14
15
  "typesVersions": {
15
16
  "*": {
17
+ "driver/bun:sqlite": [
18
+ "./dist/driver/bun-sqlite.d.ts"
19
+ ],
16
20
  "*": [
17
21
  "./dist/*"
18
22
  ]
@@ -21,6 +25,8 @@
21
25
  "scripts": {
22
26
  "build": "tsc -p tsconfig.build.json && tsx build.ts",
23
27
  "test": "tsx test",
28
+ "test:bun": "bun test/index.ts --driver=bun:sqlite",
29
+ "profile": "cross-env PROFILE=true tsx build.ts && cd bin && (rimraf CPU*.cpuprofile || true) && node --cpu-prof --cpu-prof-interval=100 test && speedscope CPU*.cpuprofile",
24
30
  "prepublishOnly": "tsc -p tsconfig.build.json && tsx build.ts"
25
31
  },
26
32
  "devDependencies": {
@@ -28,9 +34,13 @@
28
34
  "@types/glob": "^8.0.0",
29
35
  "@types/sql.js": "^1.4.2",
30
36
  "better-sqlite3": "^7.5.1",
37
+ "bun-types": "^0.5.0",
38
+ "cross-env": "^7.0.3",
31
39
  "esbuild": "^0.16.16",
32
40
  "glob": "^8.0.3",
41
+ "rimraf": "^4.1.2",
33
42
  "sade": "^1.8.1",
43
+ "speedscope": "^1.15.0",
34
44
  "sql.js": "^1.8.0",
35
45
  "sqlite3": "^5.1.4",
36
46
  "tsx": "^3.12.1",