sqlite-zod-orm 3.20.0 → 3.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4493,6 +4493,12 @@ class QueryBuilder {
4493
4493
  first() {
4494
4494
  return this.get();
4495
4495
  }
4496
+ firstOrFail() {
4497
+ const row = this.get();
4498
+ if (row === null)
4499
+ throw new Error("No matching row found");
4500
+ return row;
4501
+ }
4496
4502
  exists() {
4497
4503
  const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4498
4504
  const existsSql = selectSql.replace(/^SELECT .+? FROM/, "SELECT 1 FROM").replace(/ LIMIT \d+/, "") + " LIMIT 1";
@@ -4572,6 +4578,20 @@ class QueryBuilder {
4572
4578
  const aggSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT ${groupCols}, COUNT(*) as count FROM`);
4573
4579
  return this.executor(aggSql, params, true);
4574
4580
  }
4581
+ toSQL() {
4582
+ return compileIQO(this.tableName, this.iqo);
4583
+ }
4584
+ pluck(column) {
4585
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4586
+ const pluckSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT "${column}" FROM`);
4587
+ const results = this.executor(pluckSql, params, true);
4588
+ return results.map((r) => r[column]);
4589
+ }
4590
+ clone() {
4591
+ const cloned = new QueryBuilder(this.tableName, this.executor, this.singleExecutor, this.joinResolver, this.conditionResolver, this.eagerLoader);
4592
+ cloned.iqo = JSON.parse(JSON.stringify(this.iqo));
4593
+ return cloned;
4594
+ }
4575
4595
  updateAll(data) {
4576
4596
  const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
4577
4597
  const whereMatch = selectSql.match(/WHERE (.+?)(?:\s+ORDER|\s+LIMIT|\s+GROUP|\s+HAVING|$)/s);
@@ -5235,7 +5255,8 @@ class _Database {
5235
5255
  _pollInterval;
5236
5256
  constructor(dbFile, schemas, options = {}) {
5237
5257
  this.db = new SqliteDatabase(dbFile);
5238
- this.db.run("PRAGMA journal_mode = WAL");
5258
+ if (options.wal !== false)
5259
+ this.db.run("PRAGMA journal_mode = WAL");
5239
5260
  this.db.run("PRAGMA foreign_keys = ON");
5240
5261
  this.schemas = schemas;
5241
5262
  this.options = options;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlite-zod-orm",
3
- "version": "3.20.0",
3
+ "version": "3.22.0",
4
4
  "description": "Type-safe SQLite ORM for Bun — Zod schemas, fluent queries, auto relationships, zero SQL",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/builder.ts CHANGED
@@ -330,6 +330,19 @@ export class QueryBuilder<T extends Record<string, any>, TResult extends Record<
330
330
  return this.get();
331
331
  }
332
332
 
333
+ /**
334
+ * Return the first matching row or throw if none found.
335
+ * ```ts
336
+ * const user = db.users.select().where({ id: 1 }).firstOrFail();
337
+ * // throws Error('No matching row found') if id=1 doesn't exist
338
+ * ```
339
+ */
340
+ firstOrFail(): TResult {
341
+ const row = this.get();
342
+ if (row === null) throw new Error('No matching row found');
343
+ return row;
344
+ }
345
+
333
346
  /** Returns true if at least one row matches the query. */
334
347
  exists(): boolean {
335
348
  const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
@@ -465,6 +478,49 @@ export class QueryBuilder<T extends Record<string, any>, TResult extends Record<
465
478
  return this.executor(aggSql, params, true) as any;
466
479
  }
467
480
 
481
+ // ---------- Query Inspection ----------
482
+
483
+ /**
484
+ * Compile and return the SQL string + params without executing.
485
+ * ```ts
486
+ * db.users.select().where({ role: 'admin' }).toSQL()
487
+ * // → { sql: 'SELECT * FROM "users" WHERE "role" = ?', params: ['admin'] }
488
+ * ```
489
+ */
490
+ toSQL(): { sql: string; params: any[] } {
491
+ return compileIQO(this.tableName, this.iqo);
492
+ }
493
+
494
+ // ---------- Convenience Methods ----------
495
+
496
+ /**
497
+ * Return a flat array of values for a single column.
498
+ * ```ts
499
+ * db.users.select().pluck('name') // → ['Alice', 'Bob', 'Charlie']
500
+ * ```
501
+ */
502
+ pluck(column: keyof T & string): any[] {
503
+ const { sql: selectSql, params } = compileIQO(this.tableName, this.iqo);
504
+ const pluckSql = selectSql.replace(/^SELECT .+? FROM/, `SELECT "${column}" FROM`);
505
+ const results = this.executor(pluckSql, params, true);
506
+ return results.map((r: any) => r[column]);
507
+ }
508
+
509
+ /** Clone this QueryBuilder so you can fork a query. */
510
+ clone(): QueryBuilder<T, TResult> {
511
+ const cloned = new QueryBuilder<T, TResult>(
512
+ this.tableName,
513
+ this.executor,
514
+ this.singleExecutor,
515
+ this.joinResolver,
516
+ this.conditionResolver,
517
+ this.eagerLoader,
518
+ );
519
+ // Deep-copy the IQO state
520
+ (cloned as any).iqo = JSON.parse(JSON.stringify(this.iqo));
521
+ return cloned;
522
+ }
523
+
468
524
  // ---------- Batch Mutations ----------
469
525
 
470
526
  /**
package/src/database.ts CHANGED
@@ -65,7 +65,7 @@ class _Database<Schemas extends SchemaMap> {
65
65
 
66
66
  constructor(dbFile: string, schemas: Schemas, options: DatabaseOptions = {}) {
67
67
  this.db = new SqliteDatabase(dbFile);
68
- this.db.run('PRAGMA journal_mode = WAL');
68
+ if (options.wal !== false) this.db.run('PRAGMA journal_mode = WAL');
69
69
  this.db.run('PRAGMA foreign_keys = ON');
70
70
  this.schemas = schemas;
71
71
  this.options = options;
package/src/types.ts CHANGED
@@ -75,6 +75,12 @@ export type DatabaseOptions<R extends RelationsConfig = RelationsConfig> = {
75
75
  * Default: `false`.
76
76
  */
77
77
  debug?: boolean;
78
+ /**
79
+ * Enable WAL (Write-Ahead Logging) journal mode for better
80
+ * concurrent read/write performance. Recommended for production.
81
+ * Default: `false`.
82
+ */
83
+ wal?: boolean;
78
84
  /**
79
85
  * Lifecycle hooks per table. Each hook receives data and can transform it.
80
86
  *