tina4-nodejs 3.13.139 → 3.13.141

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.
@@ -3574,14 +3574,72 @@ var init_cachedDatabase = __esm({
3574
3574
  }
3575
3575
  });
3576
3576
 
3577
+ // ../orm/src/adapters/sqlCrud.ts
3578
+ function buildInsertRow(dialect, table2, data, suffix = "", options = {}) {
3579
+ const keys = Object.keys(data);
3580
+ const sql = buildInsert(dialect, table2, keys, suffix, options.startAt ?? 1);
3581
+ return { sql, values: Object.values(data) };
3582
+ }
3583
+ function buildInsertRows(dialect, table2, rows) {
3584
+ if (rows.length === 0) return null;
3585
+ const keys = Object.keys(rows[0]);
3586
+ const sql = buildInsert(dialect, table2, keys);
3587
+ const paramsList = rows.map((row) => keys.map((k) => row[k]));
3588
+ return { sql, paramsList };
3589
+ }
3590
+ function buildUpdate(dialect, table2, data, filter, params, options = {}) {
3591
+ const startAt = options.startAt ?? 1;
3592
+ const convertFragment = options.convertFragment ?? identityFragment;
3593
+ const dataKeys = Object.keys(data);
3594
+ const setClauses = buildSetClause(dialect, dataKeys, startAt);
3595
+ const whereStart = startAt + dataKeys.length;
3596
+ if (typeof filter === "string") {
3597
+ const where = filter ? ` WHERE ${convertFragment(filter, whereStart)}` : "";
3598
+ return {
3599
+ sql: `UPDATE ${dialect.quote(table2)} SET ${setClauses}${where}`,
3600
+ values: [...Object.values(data), ...params ?? []]
3601
+ };
3602
+ }
3603
+ const whereClauses = buildWhereClause(dialect, Object.keys(filter), whereStart);
3604
+ return {
3605
+ sql: `UPDATE ${dialect.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`,
3606
+ values: [...Object.values(data), ...Object.values(filter)]
3607
+ };
3608
+ }
3609
+ function buildDelete(dialect, table2, filter, params, options = {}) {
3610
+ const startAt = options.startAt ?? 1;
3611
+ const convertFragment = options.convertFragment ?? identityFragment;
3612
+ if (typeof filter === "string") {
3613
+ const where = filter ? ` WHERE ${convertFragment(filter, startAt)}` : "";
3614
+ return {
3615
+ sql: `DELETE FROM ${dialect.quote(table2)}${where}`,
3616
+ values: params ?? []
3617
+ };
3618
+ }
3619
+ const whereClauses = buildWhereClause(dialect, Object.keys(filter), startAt);
3620
+ return {
3621
+ sql: `DELETE FROM ${dialect.quote(table2)} WHERE ${whereClauses}`,
3622
+ values: Object.values(filter)
3623
+ };
3624
+ }
3625
+ var identityFragment;
3626
+ var init_sqlCrud = __esm({
3627
+ "../orm/src/adapters/sqlCrud.ts"() {
3628
+ "use strict";
3629
+ init_sqlDialect();
3630
+ identityFragment = (fragment) => fragment;
3631
+ }
3632
+ });
3633
+
3577
3634
  // ../orm/src/adapters/sqlite.ts
3578
3635
  var sqlite_exports = {};
3579
3636
  __export(sqlite_exports, {
3580
- SQLiteAdapter: () => SQLiteAdapter
3637
+ SQLiteAdapter: () => SQLiteAdapter,
3638
+ resolveSqlitePath: () => resolveSqlitePath
3581
3639
  });
3582
3640
  import { DatabaseSync } from "node:sqlite";
3583
3641
  import { mkdirSync as mkdirSync2 } from "node:fs";
3584
- import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve2 } from "node:path";
3642
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, resolve as resolve2, sep } from "node:path";
3585
3643
  function isIdentifier(str) {
3586
3644
  return /^[A-Za-z_][A-Za-z0-9_]*$/.test(str);
3587
3645
  }
@@ -3612,17 +3670,20 @@ function sqliteVersionAtLeast(major, minor, patch2) {
3612
3670
  }
3613
3671
  function resolveSqlitePath(dbPath) {
3614
3672
  if (dbPath === ":memory:") return dbPath;
3615
- let path10 = dbPath;
3616
- if (!isAbsolute2(path10)) {
3617
- path10 = join4(process.cwd(), path10);
3618
- mkdirSync2(dirname3(path10), { recursive: true });
3619
- } else {
3620
- const cwd = resolve2(process.cwd());
3621
- const abs = resolve2(path10);
3622
- if (abs.startsWith(cwd + "/") || abs === cwd) {
3623
- mkdirSync2(dirname3(abs), { recursive: true });
3624
- }
3673
+ const isWindowsAbs = /^[A-Za-z]:[\\/]/.test(dbPath);
3674
+ if (isAbsolute2(dbPath) || isWindowsAbs) {
3675
+ return dbPath;
3676
+ }
3677
+ const cwd = resolve2(process.cwd());
3678
+ const path10 = join4(cwd, dbPath);
3679
+ const parent = dirname3(path10);
3680
+ const absParent = resolve2(parent);
3681
+ if (absParent !== cwd && !absParent.startsWith(cwd + sep)) {
3682
+ throw new Error(
3683
+ `SQLite path "${dbPath}" resolves outside the project directory: "${absParent}" is not within "${cwd}". Tina4 refuses to create directories outside the project (ADR-0086). Use an absolute path for a database that lives outside the project.`
3684
+ );
3625
3685
  }
3686
+ mkdirSync2(parent, { recursive: true, mode: 509 });
3626
3687
  return path10;
3627
3688
  }
3628
3689
  function fieldTypeToSQLite(def) {
@@ -3658,6 +3719,7 @@ var init_sqlite = __esm({
3658
3719
  "../orm/src/adapters/sqlite.ts"() {
3659
3720
  "use strict";
3660
3721
  init_sqlDialect();
3722
+ init_sqlCrud();
3661
3723
  init_sqlTranslator();
3662
3724
  _sqliteVersionInfo = null;
3663
3725
  SQLiteAdapter = class {
@@ -3778,16 +3840,12 @@ var init_sqlite = __esm({
3778
3840
  }
3779
3841
  insert(table2, data) {
3780
3842
  if (Array.isArray(data)) {
3781
- if (data.length === 0) return { success: true, affectedRows: 0 };
3782
- const keys2 = Object.keys(data[0]);
3783
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
3784
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
3785
- const result = this.executeMany(sql2, paramsList);
3843
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
3844
+ if (!batch) return { success: true, affectedRows: 0 };
3845
+ const result = this.executeMany(batch.sql, batch.paramsList);
3786
3846
  return { success: true, affectedRows: result.affectedRows, lastId: result.lastId };
3787
3847
  }
3788
- const keys = Object.keys(data);
3789
- const sql = buildInsert(ANSI_DIALECT, table2, keys);
3790
- const values = Object.values(data);
3848
+ const { sql, values } = buildInsertRow(ANSI_DIALECT, table2, data);
3791
3849
  try {
3792
3850
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3793
3851
  this._lastInsertId = result.lastInsertRowid;
@@ -3797,21 +3855,7 @@ var init_sqlite = __esm({
3797
3855
  }
3798
3856
  }
3799
3857
  update(table2, data, filter, params) {
3800
- const setClauses = buildSetClause(ANSI_DIALECT, Object.keys(data));
3801
- if (typeof filter === "string") {
3802
- const where = filter ? ` WHERE ${filter}` : "";
3803
- const sql2 = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses}${where}`;
3804
- const values2 = [...Object.values(data), ...params ?? []];
3805
- try {
3806
- const result = this.db.prepare(sql2).run(...toSqlParams(values2));
3807
- return { success: true, affectedRows: Number(result.changes) };
3808
- } catch (e) {
3809
- return { success: false, affectedRows: 0, error: e.message };
3810
- }
3811
- }
3812
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
3813
- const sql = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
3814
- const values = [...Object.values(data), ...Object.values(filter)];
3858
+ const { sql, values } = buildUpdate(ANSI_DIALECT, table2, data, filter, params);
3815
3859
  try {
3816
3860
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3817
3861
  return { success: true, affectedRows: Number(result.changes) };
@@ -3828,18 +3872,7 @@ var init_sqlite = __esm({
3828
3872
  }
3829
3873
  return { success: true, affectedRows: totalAffected };
3830
3874
  }
3831
- if (typeof filter === "string") {
3832
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${filter}` : `DELETE FROM "${table2}"`;
3833
- try {
3834
- const result = this.db.prepare(sql2).run(...toSqlParams(params ?? []));
3835
- return { success: true, affectedRows: Number(result.changes) };
3836
- } catch (e) {
3837
- return { success: false, affectedRows: 0, error: e.message };
3838
- }
3839
- }
3840
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
3841
- const sql = `DELETE FROM ${ANSI_DIALECT.quote(table2)} WHERE ${whereClauses}`;
3842
- const values = Object.values(filter);
3875
+ const { sql, values } = buildDelete(ANSI_DIALECT, table2, filter, params);
3843
3876
  try {
3844
3877
  const result = this.db.prepare(sql).run(...toSqlParams(values));
3845
3878
  return { success: true, affectedRows: Number(result.changes) };
@@ -4131,6 +4164,7 @@ var init_postgres = __esm({
4131
4164
  "../orm/src/adapters/postgres.ts"() {
4132
4165
  "use strict";
4133
4166
  init_sqlDialect();
4167
+ init_sqlCrud();
4134
4168
  init_sqlTranslator();
4135
4169
  init_connectTimeout();
4136
4170
  pg = null;
@@ -4332,21 +4366,17 @@ var init_postgres = __esm({
4332
4366
  async insertAsync(table2, data) {
4333
4367
  this.ensureConnected();
4334
4368
  if (Array.isArray(data)) {
4335
- if (data.length === 0) return { success: true, affectedRows: 0 };
4336
- const keys2 = Object.keys(data[0]);
4337
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
4338
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
4369
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
4370
+ if (!batch) return { success: true, affectedRows: 0 };
4339
4371
  try {
4340
- const result = await this.executeManyAsync(sql2, paramsList);
4372
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
4341
4373
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
4342
4374
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
4343
4375
  } catch (e) {
4344
4376
  return { success: false, affectedRows: 0, error: e.message };
4345
4377
  }
4346
4378
  }
4347
- const keys = Object.keys(data);
4348
- const sql = buildInsert(POSTGRES_DIALECT, table2, keys, " RETURNING *");
4349
- const values = Object.values(data);
4379
+ const { sql, values } = buildInsertRow(POSTGRES_DIALECT, table2, data, " RETURNING *");
4350
4380
  try {
4351
4381
  const result = await this.client.query(sql, values);
4352
4382
  const insertedRow = result.rows[0];
@@ -4366,26 +4396,10 @@ var init_postgres = __esm({
4366
4396
  }
4367
4397
  async updateAsync(table2, data, filter, params) {
4368
4398
  this.ensureConnected();
4369
- const dataKeys = Object.keys(data);
4370
- let paramIndex = 1;
4371
- const setClauses = buildSetClause(POSTGRES_DIALECT, dataKeys, paramIndex);
4372
- paramIndex += dataKeys.length;
4373
- if (typeof filter === "string") {
4374
- const where = filter ? ` WHERE ${this.convertPlaceholders(filter, paramIndex)}` : "";
4375
- const sql2 = `UPDATE ${POSTGRES_DIALECT.quote(table2)} SET ${setClauses}${where}`;
4376
- const values2 = [...Object.values(data), ...params ?? []];
4377
- try {
4378
- const result = await this.client.query(sql2, values2);
4379
- return { success: true, affectedRows: result.rowCount ?? 0 };
4380
- } catch (e) {
4381
- return { success: false, affectedRows: 0, error: e.message };
4382
- }
4383
- }
4384
- const filterKeys = Object.keys(filter);
4385
- const whereClauses = buildWhereClause(POSTGRES_DIALECT, filterKeys, paramIndex);
4386
- paramIndex += filterKeys.length;
4387
- const sql = `UPDATE ${POSTGRES_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
4388
- const values = [...Object.values(data), ...Object.values(filter)];
4399
+ const { sql, values } = buildUpdate(POSTGRES_DIALECT, table2, data, filter, params, {
4400
+ startAt: 1,
4401
+ convertFragment: (fragment, startAt) => this.convertPlaceholders(fragment, startAt)
4402
+ });
4389
4403
  try {
4390
4404
  const result = await this.client.query(sql, values);
4391
4405
  return { success: true, affectedRows: result.rowCount ?? 0 };
@@ -4398,21 +4412,10 @@ var init_postgres = __esm({
4398
4412
  }
4399
4413
  async deleteAsync(table2, filter, params) {
4400
4414
  this.ensureConnected();
4401
- if (typeof filter === "string") {
4402
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${this.bindable(filter, params)}` : `DELETE FROM "${table2}"`;
4403
- try {
4404
- const result = await this.client.query(sql2, params ?? []);
4405
- return { success: true, affectedRows: result.rowCount ?? 0 };
4406
- } catch (e) {
4407
- return { success: false, affectedRows: 0, error: e.message };
4408
- }
4409
- }
4410
- const filterKeys = Object.keys(filter);
4411
- let paramIndex = 1;
4412
- const whereClauses = buildWhereClause(POSTGRES_DIALECT, filterKeys, paramIndex);
4413
- paramIndex += filterKeys.length;
4414
- const sql = `DELETE FROM ${POSTGRES_DIALECT.quote(table2)} WHERE ${whereClauses}`;
4415
- const values = Object.values(filter);
4415
+ const { sql, values } = buildDelete(POSTGRES_DIALECT, table2, filter, params, {
4416
+ startAt: 1,
4417
+ convertFragment: (fragment) => this.bindable(fragment, params)
4418
+ });
4416
4419
  try {
4417
4420
  const result = await this.client.query(sql, values);
4418
4421
  return { success: true, affectedRows: result.rowCount ?? 0 };
@@ -4586,6 +4589,7 @@ var init_mysql = __esm({
4586
4589
  "../orm/src/adapters/mysql.ts"() {
4587
4590
  "use strict";
4588
4591
  init_sqlDialect();
4592
+ init_sqlCrud();
4589
4593
  init_sqlTranslator();
4590
4594
  init_connectTimeout();
4591
4595
  mysql2 = null;
@@ -4767,21 +4771,17 @@ var init_mysql = __esm({
4767
4771
  async insertAsync(table2, data) {
4768
4772
  this.ensureConnected();
4769
4773
  if (Array.isArray(data)) {
4770
- if (data.length === 0) return { success: true, affectedRows: 0 };
4771
- const keys2 = Object.keys(data[0]);
4772
- const sql2 = buildInsert(MYSQL_DIALECT, table2, keys2);
4773
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
4774
+ const batch = buildInsertRows(MYSQL_DIALECT, table2, data);
4775
+ if (!batch) return { success: true, affectedRows: 0 };
4774
4776
  try {
4775
- const result = await this.executeManyAsync(sql2, paramsList);
4777
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
4776
4778
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
4777
4779
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
4778
4780
  } catch (e) {
4779
4781
  return { success: false, affectedRows: 0, error: e.message };
4780
4782
  }
4781
4783
  }
4782
- const keys = Object.keys(data);
4783
- const sql = buildInsert(MYSQL_DIALECT, table2, keys);
4784
- const values = Object.values(data);
4784
+ const { sql, values } = buildInsertRow(MYSQL_DIALECT, table2, data);
4785
4785
  try {
4786
4786
  const result = await this.queryPromise(sql, values);
4787
4787
  this._lastInsertId = result.insertId ?? null;
@@ -4799,21 +4799,7 @@ var init_mysql = __esm({
4799
4799
  }
4800
4800
  async updateAsync(table2, data, filter, params) {
4801
4801
  this.ensureConnected();
4802
- const setClauses = buildSetClause(MYSQL_DIALECT, Object.keys(data));
4803
- if (typeof filter === "string") {
4804
- const where = filter ? ` WHERE ${filter}` : "";
4805
- const sql2 = `UPDATE ${MYSQL_DIALECT.quote(table2)} SET ${setClauses}${where}`;
4806
- const values2 = [...Object.values(data), ...params ?? []];
4807
- try {
4808
- const result = await this.queryPromise(sql2, values2);
4809
- return { success: true, affectedRows: result.affectedRows ?? 0 };
4810
- } catch (e) {
4811
- return { success: false, affectedRows: 0, error: e.message };
4812
- }
4813
- }
4814
- const whereClauses = buildWhereClause(MYSQL_DIALECT, Object.keys(filter));
4815
- const sql = `UPDATE ${MYSQL_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
4816
- const values = [...Object.values(data), ...Object.values(filter)];
4802
+ const { sql, values } = buildUpdate(MYSQL_DIALECT, table2, data, filter, params);
4817
4803
  try {
4818
4804
  const result = await this.queryPromise(sql, values);
4819
4805
  return { success: true, affectedRows: result.affectedRows ?? 0 };
@@ -4826,18 +4812,7 @@ var init_mysql = __esm({
4826
4812
  }
4827
4813
  async deleteAsync(table2, filter, params) {
4828
4814
  this.ensureConnected();
4829
- if (typeof filter === "string") {
4830
- const sql2 = filter ? `DELETE FROM \`${table2}\` WHERE ${filter}` : `DELETE FROM \`${table2}\``;
4831
- try {
4832
- const result = await this.queryPromise(sql2, params ?? []);
4833
- return { success: true, affectedRows: result.affectedRows ?? 0 };
4834
- } catch (e) {
4835
- return { success: false, affectedRows: 0, error: e.message };
4836
- }
4837
- }
4838
- const whereClauses = buildWhereClause(MYSQL_DIALECT, Object.keys(filter));
4839
- const sql = `DELETE FROM ${MYSQL_DIALECT.quote(table2)} WHERE ${whereClauses}`;
4840
- const values = Object.values(filter);
4815
+ const { sql, values } = buildDelete(MYSQL_DIALECT, table2, filter, params);
4841
4816
  try {
4842
4817
  const result = await this.queryPromise(sql, values);
4843
4818
  return { success: true, affectedRows: result.affectedRows ?? 0 };
@@ -4989,6 +4964,7 @@ var init_mssql = __esm({
4989
4964
  "../orm/src/adapters/mssql.ts"() {
4990
4965
  "use strict";
4991
4966
  init_sqlDialect();
4967
+ init_sqlCrud();
4992
4968
  init_sqlTranslator();
4993
4969
  init_connectTimeout();
4994
4970
  tedious = null;
@@ -5245,21 +5221,17 @@ var init_mssql = __esm({
5245
5221
  async insertAsync(table2, data) {
5246
5222
  this.ensureConnected();
5247
5223
  if (Array.isArray(data)) {
5248
- if (data.length === 0) return { success: true, affectedRows: 0 };
5249
- const keys2 = Object.keys(data[0]);
5250
- const sql2 = buildInsert({ quote: MSSQL_DIALECT.quote, marker: ANSI_DIALECT.marker }, table2, keys2);
5251
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
5224
+ const batch = buildInsertRows({ quote: MSSQL_DIALECT.quote, marker: ANSI_DIALECT.marker }, table2, data);
5225
+ if (!batch) return { success: true, affectedRows: 0 };
5252
5226
  try {
5253
- const result = await this.executeManyAsync(sql2, paramsList);
5227
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
5254
5228
  if (result.lastId !== void 0) this._lastInsertId = result.lastId;
5255
5229
  return { success: true, affectedRows: result.totalAffected, lastId: result.lastId };
5256
5230
  } catch (e) {
5257
5231
  return { success: false, affectedRows: 0, error: e.message };
5258
5232
  }
5259
5233
  }
5260
- const keys = Object.keys(data);
5261
- const sql = buildInsert(MSSQL_DIALECT, table2, keys, "; SELECT SCOPE_IDENTITY() AS id", 0);
5262
- const values = Object.values(data);
5234
+ const { sql, values } = buildInsertRow(MSSQL_DIALECT, table2, data, "; SELECT SCOPE_IDENTITY() AS id", { startAt: 0 });
5263
5235
  try {
5264
5236
  const result = await this.execSqlPromise(sql, values);
5265
5237
  const id = result.rows[0]?.id ?? null;
@@ -5282,26 +5254,10 @@ var init_mssql = __esm({
5282
5254
  }
5283
5255
  async updateAsync(table2, data, filter, params) {
5284
5256
  this.ensureConnected();
5285
- const dataKeys = Object.keys(data);
5286
- let paramIndex = 0;
5287
- const setClauses = buildSetClause(MSSQL_DIALECT, dataKeys, paramIndex);
5288
- paramIndex += dataKeys.length;
5289
- if (typeof filter === "string") {
5290
- const where = filter ? ` WHERE ${this.convertPlaceholders(filter, paramIndex)}` : "";
5291
- const sql2 = `UPDATE ${MSSQL_DIALECT.quote(table2)} SET ${setClauses}${where}`;
5292
- const values2 = [...Object.values(data), ...params ?? []];
5293
- try {
5294
- const result = await this.execSqlPromise(sql2, values2);
5295
- return { success: true, affectedRows: result.rowCount };
5296
- } catch (e) {
5297
- return { success: false, affectedRows: 0, error: e.message };
5298
- }
5299
- }
5300
- const filterKeys = Object.keys(filter);
5301
- const whereClauses = buildWhereClause(MSSQL_DIALECT, filterKeys, paramIndex);
5302
- paramIndex += filterKeys.length;
5303
- const sql = `UPDATE ${MSSQL_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
5304
- const values = [...Object.values(data), ...Object.values(filter)];
5257
+ const { sql, values } = buildUpdate(MSSQL_DIALECT, table2, data, filter, params, {
5258
+ startAt: 0,
5259
+ convertFragment: (fragment, startAt) => this.convertPlaceholders(fragment, startAt)
5260
+ });
5305
5261
  try {
5306
5262
  const result = await this.execSqlPromise(sql, values);
5307
5263
  return { success: true, affectedRows: result.rowCount };
@@ -5314,21 +5270,10 @@ var init_mssql = __esm({
5314
5270
  }
5315
5271
  async deleteAsync(table2, filter, params) {
5316
5272
  this.ensureConnected();
5317
- if (typeof filter === "string") {
5318
- const sql2 = filter ? `DELETE FROM [${table2}] WHERE ${this.bindable(filter, params)}` : `DELETE FROM [${table2}]`;
5319
- try {
5320
- const result = await this.execSqlPromise(sql2, params ?? []);
5321
- return { success: true, affectedRows: result.rowCount };
5322
- } catch (e) {
5323
- return { success: false, affectedRows: 0, error: e.message };
5324
- }
5325
- }
5326
- const filterKeys = Object.keys(filter);
5327
- let paramIndex = 0;
5328
- const whereClauses = buildWhereClause(MSSQL_DIALECT, filterKeys, paramIndex);
5329
- paramIndex += filterKeys.length;
5330
- const sql = `DELETE FROM ${MSSQL_DIALECT.quote(table2)} WHERE ${whereClauses}`;
5331
- const values = Object.values(filter);
5273
+ const { sql, values } = buildDelete(MSSQL_DIALECT, table2, filter, params, {
5274
+ startAt: 0,
5275
+ convertFragment: (fragment) => this.bindable(fragment, params)
5276
+ });
5332
5277
  try {
5333
5278
  const result = await this.execSqlPromise(sql, values);
5334
5279
  return { success: true, affectedRows: result.rowCount };
@@ -5581,6 +5526,7 @@ var init_firebird = __esm({
5581
5526
  "../orm/src/adapters/firebird.ts"() {
5582
5527
  "use strict";
5583
5528
  init_sqlDialect();
5529
+ init_sqlCrud();
5584
5530
  init_sqlTranslator();
5585
5531
  init_connectTimeout();
5586
5532
  firebird = null;
@@ -5951,17 +5897,13 @@ var init_firebird = __esm({
5951
5897
  async insertAsync(table2, data) {
5952
5898
  this.ensureConnected();
5953
5899
  if (Array.isArray(data)) {
5954
- if (data.length === 0) return { success: true, affectedRows: 0 };
5955
- const keys2 = Object.keys(data[0]);
5956
- const sql2 = buildInsert(FB_DIALECT, table2, keys2);
5957
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
5958
- const result = await this.executeManyAsync(sql2, paramsList);
5900
+ const batch = buildInsertRows(FB_DIALECT, table2, data);
5901
+ if (!batch) return { success: true, affectedRows: 0 };
5902
+ const result = await this.executeManyAsync(batch.sql, batch.paramsList);
5959
5903
  const lastId2 = await this.readGeneratorId(table2) ?? result.lastId;
5960
5904
  return { success: true, affectedRows: result.totalAffected, lastId: lastId2 ?? void 0 };
5961
5905
  }
5962
- const keys = Object.keys(data);
5963
- const sql = buildInsert(FB_DIALECT, table2, keys);
5964
- const values = Object.values(data);
5906
+ const { sql, values } = buildInsertRow(FB_DIALECT, table2, data);
5965
5907
  await this.executePromise(sql, values);
5966
5908
  const lastId = await this.readGeneratorId(table2);
5967
5909
  return { success: true, affectedRows: 1, lastId: lastId ?? void 0 };
@@ -5971,18 +5913,7 @@ var init_firebird = __esm({
5971
5913
  }
5972
5914
  async updateAsync(table2, data, filter, params) {
5973
5915
  this.ensureConnected();
5974
- const setClauses = buildSetClause(FB_DIALECT, Object.keys(data));
5975
- if (typeof filter === "string") {
5976
- const where = filter ? ` WHERE ${filter}` : "";
5977
- const affected2 = await this.executeReturningCount(
5978
- `UPDATE ${fbQuote(table2)} SET ${setClauses}${where}`,
5979
- [...Object.values(data), ...params ?? []]
5980
- );
5981
- return { success: true, affectedRows: affected2 };
5982
- }
5983
- const whereClauses = buildWhereClause(FB_DIALECT, Object.keys(filter));
5984
- const sql = `UPDATE ${FB_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereClauses}`;
5985
- const values = [...Object.values(data), ...Object.values(filter)];
5916
+ const { sql, values } = buildUpdate(FB_DIALECT, table2, data, filter, params);
5986
5917
  const affected = await this.executeReturningCount(sql, values);
5987
5918
  return { success: true, affectedRows: affected };
5988
5919
  }
@@ -5991,14 +5922,7 @@ var init_firebird = __esm({
5991
5922
  }
5992
5923
  async deleteAsync(table2, filter, params) {
5993
5924
  this.ensureConnected();
5994
- if (typeof filter === "string") {
5995
- const where = filter ? ` WHERE ${filter}` : "";
5996
- const affected2 = await this.executeReturningCount(`DELETE FROM ${fbQuote(table2)}${where}`, params ?? []);
5997
- return { success: true, affectedRows: affected2 };
5998
- }
5999
- const whereClauses = buildWhereClause(FB_DIALECT, Object.keys(filter));
6000
- const sql = `DELETE FROM ${FB_DIALECT.quote(table2)} WHERE ${whereClauses}`;
6001
- const values = Object.values(filter);
5925
+ const { sql, values } = buildDelete(FB_DIALECT, table2, filter, params);
6002
5926
  const affected = await this.executeReturningCount(sql, values);
6003
5927
  return { success: true, affectedRows: affected };
6004
5928
  }
@@ -6830,6 +6754,7 @@ var init_odbc = __esm({
6830
6754
  "../orm/src/adapters/odbc.ts"() {
6831
6755
  "use strict";
6832
6756
  init_sqlDialect();
6757
+ init_sqlCrud();
6833
6758
  init_sqlTranslator();
6834
6759
  init_connectTimeout();
6835
6760
  odbcModule = null;
@@ -7029,16 +6954,12 @@ var init_odbc = __esm({
7029
6954
  async insertAsync(table2, data) {
7030
6955
  this.ensureConnected();
7031
6956
  if (Array.isArray(data)) {
7032
- if (data.length === 0) return { success: true, affectedRows: 0 };
7033
- const keys2 = Object.keys(data[0]);
7034
- const sql2 = buildInsert(ANSI_DIALECT, table2, keys2);
7035
- const paramsList = data.map((row) => keys2.map((k) => row[k]));
7036
- const { totalAffected } = await this.executeManyAsync(sql2, paramsList);
6957
+ const batch = buildInsertRows(ANSI_DIALECT, table2, data);
6958
+ if (!batch) return { success: true, affectedRows: 0 };
6959
+ const { totalAffected } = await this.executeManyAsync(batch.sql, batch.paramsList);
7037
6960
  return { success: true, affectedRows: totalAffected };
7038
6961
  }
7039
- const keys = Object.keys(data);
7040
- const sql = buildInsert(ANSI_DIALECT, table2, keys);
7041
- const values = Object.values(data);
6962
+ const { sql, values } = buildInsertRow(ANSI_DIALECT, table2, data);
7042
6963
  try {
7043
6964
  const result = await this.connection.query(sql, values);
7044
6965
  return { success: true, affectedRows: this.affectedCount(result), lastId: this._lastInsertId ?? void 0 };
@@ -7049,17 +6970,7 @@ var init_odbc = __esm({
7049
6970
  /** Update rows in a table matching filter. */
7050
6971
  async updateAsync(table2, data, filter, params) {
7051
6972
  this.ensureConnected();
7052
- const setClauses = buildSetClause(ANSI_DIALECT, Object.keys(data));
7053
- let whereSql;
7054
- let values;
7055
- if (typeof filter === "string") {
7056
- whereSql = filter;
7057
- values = [...Object.values(data), ...params ?? []];
7058
- } else {
7059
- whereSql = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
7060
- values = [...Object.values(data), ...Object.values(filter)];
7061
- }
7062
- const sql = `UPDATE ${ANSI_DIALECT.quote(table2)} SET ${setClauses} WHERE ${whereSql}`;
6973
+ const { sql, values } = buildUpdate(ANSI_DIALECT, table2, data, filter, params);
7063
6974
  try {
7064
6975
  const result = await this.connection.query(sql, values);
7065
6976
  return { success: true, affectedRows: this.affectedCount(result) };
@@ -7078,18 +6989,7 @@ var init_odbc = __esm({
7078
6989
  }
7079
6990
  return { success: true, affectedRows: totalAffected };
7080
6991
  }
7081
- if (typeof filter === "string") {
7082
- const sql2 = filter ? `DELETE FROM "${table2}" WHERE ${filter}` : `DELETE FROM "${table2}"`;
7083
- try {
7084
- const result = await this.connection.query(sql2, params ?? []);
7085
- return { success: true, affectedRows: this.affectedCount(result) };
7086
- } catch (e) {
7087
- return { success: false, affectedRows: 0, error: e.message };
7088
- }
7089
- }
7090
- const whereClauses = buildWhereClause(ANSI_DIALECT, Object.keys(filter));
7091
- const sql = `DELETE FROM ${ANSI_DIALECT.quote(table2)} WHERE ${whereClauses}`;
7092
- const values = Object.values(filter);
6992
+ const { sql, values } = buildDelete(ANSI_DIALECT, table2, filter, params);
7093
6993
  try {
7094
6994
  const result = await this.connection.query(sql, values);
7095
6995
  return { success: true, affectedRows: this.affectedCount(result) };
@@ -14500,7 +14400,7 @@ var init_attachment = __esm({
14500
14400
  // ../orm/src/realtime/storage.ts
14501
14401
  import { randomBytes as randomBytes3 } from "node:crypto";
14502
14402
  import { mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, statSync as statSync4 } from "node:fs";
14503
- import { resolve as resolve5, sep } from "node:path";
14403
+ import { resolve as resolve5, sep as sep2 } from "node:path";
14504
14404
  import { createRequire as createRequire6 } from "node:module";
14505
14405
  function loadAwsSdk(packageName) {
14506
14406
  try {
@@ -14553,7 +14453,7 @@ var init_storage = __esm({
14553
14453
  // Resolve inside the root and reject any traversal attempt.
14554
14454
  pathFor(key) {
14555
14455
  const target = resolve5(this.directory, key);
14556
- if (target !== this.directory && !target.startsWith(this.directory + sep)) {
14456
+ if (target !== this.directory && !target.startsWith(this.directory + sep2)) {
14557
14457
  throw new Error(`unsafe storage key: ${JSON.stringify(key)}`);
14558
14458
  }
14559
14459
  return target;
@@ -15070,6 +14970,7 @@ __export(src_exports, {
15070
14970
  resolveDbPool: () => resolveDbPool,
15071
14971
  resolveFirebirdCharset: () => resolveFirebirdCharset,
15072
14972
  resolveGraphConnectTimeout: () => resolveGraphConnectTimeout,
14973
+ resolveSqlitePath: () => resolveSqlitePath,
15073
14974
  rollback: () => rollback,
15074
14975
  seedModels: () => seedModels,
15075
14976
  seedOrm: () => seedOrm,
@@ -17544,7 +17445,7 @@ __export(engine_exports, {
17544
17445
  });
17545
17446
  import { createHash as createHash3, createHmac as createHmac3, randomBytes as randomBytes4 } from "node:crypto";
17546
17447
  import { readFileSync as readFileSync6, existsSync as existsSync7, statSync as statSync6, realpathSync } from "node:fs";
17547
- import { join as join10, resolve as resolve6, isAbsolute as isAbsolute4, sep as sep2 } from "node:path";
17448
+ import { join as join10, resolve as resolve6, isAbsolute as isAbsolute4, sep as sep3 } from "node:path";
17548
17449
  function jsonText(value) {
17549
17450
  try {
17550
17451
  const text = JSON.stringify(value);
@@ -17885,15 +17786,15 @@ function findOutsideQuotes(expr, needle) {
17885
17786
  }
17886
17787
  return -1;
17887
17788
  }
17888
- function splitOutsideQuotes(expr, sep8) {
17889
- if (!expr.includes(sep8)) return [expr];
17789
+ function splitOutsideQuotes(expr, sep9) {
17790
+ if (!expr.includes(sep9)) return [expr];
17890
17791
  const parts = [];
17891
17792
  let currentStart = 0;
17892
17793
  let inQuote = null;
17893
17794
  let depth = 0;
17894
17795
  let bracketDepth = 0;
17895
17796
  let i = 0;
17896
- const sepLen = sep8.length;
17797
+ const sepLen = sep9.length;
17897
17798
  const lastStart = expr.length - sepLen;
17898
17799
  while (i <= lastStart) {
17899
17800
  const ch = expr[i];
@@ -17914,7 +17815,7 @@ function splitOutsideQuotes(expr, sep8) {
17914
17815
  else if (ch === ")") depth--;
17915
17816
  else if (ch === "[") bracketDepth++;
17916
17817
  else if (ch === "]") bracketDepth--;
17917
- if (depth === 0 && bracketDepth === 0 && expr.startsWith(sep8, i)) {
17818
+ if (depth === 0 && bracketDepth === 0 && expr.startsWith(sep9, i)) {
17918
17819
  parts.push(expr.slice(currentStart, i));
17919
17820
  i += sepLen;
17920
17821
  currentStart = i;
@@ -18867,8 +18768,8 @@ var init_engine = __esm({
18867
18768
  },
18868
18769
  first: (v) => Array.isArray(v) ? v[0] ?? null : null,
18869
18770
  last: (v) => Array.isArray(v) ? v[v.length - 1] ?? null : null,
18870
- join: (v, sep8) => Array.isArray(v) ? v.map(String).join(sep8 !== void 0 ? String(sep8) : ", ") : String(v),
18871
- split: (v, sep8) => String(v).split(sep8 !== void 0 ? String(sep8) : " "),
18771
+ join: (v, sep9) => Array.isArray(v) ? v.map(String).join(sep9 !== void 0 ? String(sep9) : ", ") : String(v),
18772
+ split: (v, sep9) => String(v).split(sep9 !== void 0 ? String(sep9) : " "),
18872
18773
  replace: (v, from, to) => {
18873
18774
  const s = String(v);
18874
18775
  if (from !== void 0 && typeof from === "object" && from !== null && !Array.isArray(from)) {
@@ -19272,7 +19173,7 @@ var init_engine = __esm({
19272
19173
  }
19273
19174
  const root = realpathSync(this.templateDir);
19274
19175
  const real = realpathSync(filePath);
19275
- if (real !== root && !real.startsWith(root + sep2)) {
19176
+ if (real !== root && !real.startsWith(root + sep3)) {
19276
19177
  throw new Error(`Template path escapes the templates directory: ${name}`);
19277
19178
  }
19278
19179
  return readFileSync6(real, "utf-8");
@@ -24642,7 +24543,7 @@ var init_dispatchPipeline = __esm({
24642
24543
 
24643
24544
  // src/static.ts
24644
24545
  import { readFileSync as readFileSync9, realpathSync as realpathSync3, statSync as statSync8 } from "node:fs";
24645
- import { join as join15, extname as extname3, sep as sep3 } from "node:path";
24546
+ import { join as join15, extname as extname3, sep as sep4 } from "node:path";
24646
24547
  import { gzipSync as gzipSync2 } from "node:zlib";
24647
24548
  function isCompressible(contentType) {
24648
24549
  return COMPRESSIBLE_PREFIXES2.some((prefix) => contentType.includes(prefix));
@@ -24673,8 +24574,8 @@ function tryServeStatic(staticDir, req2, res) {
24673
24574
  }
24674
24575
  const stat = statSync8(realPath);
24675
24576
  if (!stat.isFile()) continue;
24676
- if (realPath !== realDir && !realPath.startsWith(realDir + sep3)) continue;
24677
- if (hasHiddenSegment(realPath.slice(realDir.length + 1), sep3)) continue;
24577
+ if (realPath !== realDir && !realPath.startsWith(realDir + sep4)) continue;
24578
+ if (hasHiddenSegment(realPath.slice(realDir.length + 1), sep4)) continue;
24678
24579
  const ext = extname3(realPath);
24679
24580
  const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
24680
24581
  const etag = `W/"${stat.size}-${Math.floor(stat.mtimeMs / 1e3)}"`;
@@ -25657,7 +25558,7 @@ __export(generate_exports, {
25657
25558
  toTableName: () => toTableName
25658
25559
  });
25659
25560
  import { existsSync as existsSync15, mkdirSync as mkdirSync12, writeFileSync as writeFileSync9 } from "node:fs";
25660
- import { join as join20, relative as relative2, resolve as resolve10, sep as sep4 } from "node:path";
25561
+ import { join as join20, relative as relative2, resolve as resolve10, sep as sep5 } from "node:path";
25661
25562
  function ensureDir(dir) {
25662
25563
  if (__resolution.dryRun) return;
25663
25564
  if (!existsSync15(dir)) {
@@ -25783,7 +25684,7 @@ function toRelPath(absPath) {
25783
25684
  const cwd = process.cwd();
25784
25685
  const rel = relative2(cwd, absPath);
25785
25686
  if (!rel) return absPath;
25786
- return sep4 === "/" ? rel : rel.split(sep4).join("/");
25687
+ return sep5 === "/" ? rel : rel.split(sep5).join("/");
25787
25688
  }
25788
25689
  function captureEditHints(absPath, content) {
25789
25690
  if (!/\.(ts|tsx|js|mjs|cjs|jsx|sql|twig|html\.twig)$/.test(absPath)) return;
@@ -25855,12 +25756,6 @@ function printResolution() {
25855
25756
  lines.push("");
25856
25757
  process.stderr.write(lines.join("\n"));
25857
25758
  }
25858
- function toPlural(name) {
25859
- const lower = name.toLowerCase();
25860
- if (lower.endsWith("s")) return lower;
25861
- if (lower.endsWith("y") && !/[aeiou]y$/i.test(lower)) return lower.slice(0, -1) + "ies";
25862
- return lower + "s";
25863
- }
25864
25759
  function toCamel(name) {
25865
25760
  return name.charAt(0).toLowerCase() + name.slice(1);
25866
25761
  }
@@ -26293,7 +26188,7 @@ ${aiFill(`delete_${singular}`, {
26293
26188
  }
26294
26189
  function generateCrud(name, flags) {
26295
26190
  const table2 = resolveTable(name, flags, { announce: false });
26296
- const routeName = toPlural(table2);
26191
+ const routeName = pluralizeReserved(toSnake(name));
26297
26192
  const isPublic = Boolean(flags.public);
26298
26193
  if (!__resolution.jsonMode) console.log(`
26299
26194
  Generating CRUD for ${name}...
@@ -26547,7 +26442,7 @@ void test${titleName};
26547
26442
  function generateForm(name, flags) {
26548
26443
  const fields = fieldsOrDefault(flags.fields || "");
26549
26444
  const table2 = resolveTable(name, flags, { announce: false });
26550
- const routeName = toPlural(table2);
26445
+ const routeName = pluralizeReserved(toSnake(name));
26551
26446
  const inputTypes = {
26552
26447
  string: "text",
26553
26448
  str: "text",
@@ -26613,7 +26508,7 @@ function generateForm(name, flags) {
26613
26508
  function generateView(name, flags) {
26614
26509
  const fields = fieldsOrDefault(flags.fields || "");
26615
26510
  const table2 = resolveTable(name, flags, { announce: false });
26616
- const routeName = toPlural(table2);
26511
+ const routeName = pluralizeReserved(toSnake(name));
26617
26512
  const cols = fields.map(([f]) => f);
26618
26513
  const dir = resolve10("src/templates/pages");
26619
26514
  ensureDir(dir);
@@ -27625,7 +27520,7 @@ var init_generate = __esm({
27625
27520
  crud: ({ name, table: table2 }) => [
27626
27521
  `Apply the migration: npx tina4nodejs migrate`,
27627
27522
  `Serve and try: npx tina4nodejs serve -> visit /swagger`,
27628
- `Run the gate test: npx tsx tests/${toPlural(table2)}.test.ts`,
27523
+ `Run the gate test: npx tsx tests/${pluralizeReserved(toSnake(name))}.test.ts`,
27629
27524
  `Change fields: edit src/models/${name}.ts then re-run generate crud`
27630
27525
  ],
27631
27526
  migration: () => [
@@ -27643,10 +27538,10 @@ var init_generate = __esm({
27643
27538
  ],
27644
27539
  form: ({ name, table: table2 }) => [
27645
27540
  `Render from a route: res.render("forms/${table2}.twig", { item })`,
27646
- `Add the POST route: npx tina4nodejs generate route ${toPlural(table2)} --model ${name}`
27541
+ `Add the POST route: npx tina4nodejs generate route ${pluralizeReserved(toSnake(name))} --model ${name}`
27647
27542
  ],
27648
- view: ({ table: table2 }) => [
27649
- `Wire routes to render list -> ${toPlural(table2)}.twig, detail -> ${table2}.twig`,
27543
+ view: ({ name, table: table2 }) => [
27544
+ `Wire routes to render list -> ${pluralizeReserved(toSnake(name))}.twig, detail -> ${table2}.twig`,
27650
27545
  `Customize the templates in src/templates/pages/`
27651
27546
  ],
27652
27547
  auth: () => [
@@ -36000,7 +35895,7 @@ ${end}
36000
35895
  // src/devAdmin.ts
36001
35896
  import { cpus as osCpus } from "node:os";
36002
35897
  import { readFileSync as readFileSync20, writeFileSync as writeFileSync15, existsSync as existsSync22, readdirSync as readdirSync15, mkdirSync as mkdirSync18, copyFileSync, statSync as statSync17, openSync as openSync4, closeSync as closeSync4, fstatSync as fstatSync2, fchmodSync as fchmodSync2, ftruncateSync, constants as constants3, realpathSync as realpathSync6, lstatSync } from "node:fs";
36003
- import { join as join27, dirname as dirname12, resolve as resolve16, relative as relative9, sep as sep7, basename as basename5 } from "node:path";
35898
+ import { join as join27, dirname as dirname12, resolve as resolve16, relative as relative9, sep as sep8, basename as basename5 } from "node:path";
36004
35899
  import { fileURLToPath as fileURLToPath5 } from "node:url";
36005
35900
  import { timingSafeEqual as timingSafeEqual2 } from "node:crypto";
36006
35901
  function escapeHtml(value) {
@@ -36391,7 +36286,7 @@ function safeJoin(projectRoot3, rel, extraRoots = []) {
36391
36286
  const resolved = realPathOf(resolve16(root, rel));
36392
36287
  const roots = [root, ...extraRoots.filter(Boolean).map((r) => realPathOf(resolve16(r)))];
36393
36288
  for (const r of roots) {
36394
- if (resolved === r || resolved.startsWith(r.endsWith(sep7) ? r : r + sep7)) return resolved;
36289
+ if (resolved === r || resolved.startsWith(r.endsWith(sep8) ? r : r + sep8)) return resolved;
36395
36290
  }
36396
36291
  } catch {
36397
36292
  }
@@ -39930,8 +39825,8 @@ function writeMcpDiscovery(projectRoot3, port) {
39930
39825
  const lines = contents.split(/\r?\n/);
39931
39826
  const already = lines.some((l) => l.trim() === GITIGNORE_LINE || l.trim() === ".tina4");
39932
39827
  if (!already) {
39933
- const sep8 = contents.endsWith("\n") || contents === "" ? "" : "\n";
39934
- fs9.writeFileSync(gitignorePath, `${contents}${sep8}${GITIGNORE_LINE}
39828
+ const sep9 = contents.endsWith("\n") || contents === "" ? "" : "\n";
39829
+ fs9.writeFileSync(gitignorePath, `${contents}${sep9}${GITIGNORE_LINE}
39935
39830
  `, "utf-8");
39936
39831
  }
39937
39832
  }