forge-sql-orm 1.0.23 → 1.0.25

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.
@@ -4,23 +4,30 @@ const mysql = require("@mikro-orm/mysql");
4
4
  const sql = require("@forge/sql");
5
5
  const moment = require("moment");
6
6
  const entityGenerator = require("@mikro-orm/entity-generator");
7
- const transformValue = (value) => {
7
+ const wrapIfNeeded = (data, wrap) => {
8
+ return wrap ? `'${data}'` : data;
9
+ };
10
+ const transformValue = (value, wrapValue = false) => {
8
11
  switch (value.type) {
9
12
  case "text":
10
13
  case "string":
11
- return `'${value.value}'`;
14
+ return wrapIfNeeded(`${value.value}`, wrapValue);
12
15
  case "datetime":
13
- return `'${moment(value.value).format("YYYY-MM-DDTHH:mm:ss.SSS")}'`;
16
+ return wrapIfNeeded(`${moment(value.value).format("YYYY-MM-DDTHH:mm:ss.SSS")}`, wrapValue);
14
17
  case "date":
15
- return `'${moment(value.value).format("YYYY-MM-DD")}'`;
18
+ return wrapIfNeeded(`${moment(value.value).format("YYYY-MM-DD")}`, wrapValue);
16
19
  case "time":
17
- return `'${moment(value.value).format("HH:mm:ss.SSS")}'`;
20
+ return wrapIfNeeded(`${moment(value.value).format("HH:mm:ss.SSS")}`, wrapValue);
18
21
  default:
19
22
  return value.value;
20
23
  }
21
24
  };
22
25
  const parseDateTime = (value, format) => {
23
- return moment(value, format).toDate();
26
+ const m = moment(value, format, true);
27
+ if (!m.isValid()) {
28
+ return moment(value).toDate();
29
+ }
30
+ return m.toDate();
24
31
  };
25
32
  class ForgeSQLCrudOperations {
26
33
  forgeOperations;
@@ -30,57 +37,86 @@ class ForgeSQLCrudOperations {
30
37
  this.options = options;
31
38
  }
32
39
  /**
33
- * Generates an SQL insert query with values.
40
+ * Generates an SQL INSERT statement for the provided models.
41
+ * If a version field exists in the schema, its value is set accordingly.
42
+ *
34
43
  * @param schema - The entity schema.
35
44
  * @param models - The list of entities to insert.
36
45
  * @param updateIfExists - Whether to update the row if it already exists.
37
- * @returns An object containing the SQL query, fields, and values.
46
+ * @returns An object containing the SQL query, column names, and values.
38
47
  */
39
48
  async generateInsertScript(schema, models, updateIfExists) {
40
- const fieldNames = /* @__PURE__ */ new Set();
41
- const fieldValueMaps = [];
49
+ const columnNames = /* @__PURE__ */ new Set();
50
+ const modelFieldValues = [];
42
51
  models.forEach((model) => {
43
- const fieldValueMap = {};
44
- schema.meta.props.forEach((p) => {
45
- const modelValue = model[p.name];
46
- if (p.kind === "scalar" && modelValue !== void 0) {
47
- fieldNames.add(p.fieldNames[0] || p.name);
48
- fieldValueMap[p.fieldNames[0]] = {
49
- type: p.type,
50
- value: modelValue
51
- };
52
+ const fieldValues = {};
53
+ schema.meta.props.forEach((prop) => {
54
+ const value = model[prop.name];
55
+ if (prop.kind === "scalar" && value !== void 0) {
56
+ const columnName = this.getRealFieldNameFromSchema(prop);
57
+ columnNames.add(columnName);
58
+ fieldValues[columnName] = { type: prop.type, value };
52
59
  }
53
60
  });
54
- fieldValueMaps.push(fieldValueMap);
61
+ modelFieldValues.push(fieldValues);
55
62
  });
56
- const fields = Array.from(fieldNames);
57
- const values = fieldValueMaps.flatMap(
58
- (fieldValueMap) => fields.map(
59
- (f) => fieldValueMap[f] || {
63
+ const versionField = this.getVersionField(schema);
64
+ if (versionField) {
65
+ modelFieldValues.forEach((mv) => {
66
+ const versionRealName = this.getRealFieldNameFromSchema(versionField);
67
+ if (mv[versionRealName]) {
68
+ mv[versionRealName].value = transformValue(
69
+ { value: this.createVersionField(versionField), type: versionField.name },
70
+ true
71
+ );
72
+ } else {
73
+ mv[versionRealName] = {
74
+ type: versionField.type,
75
+ value: transformValue(
76
+ { value: this.createVersionField(versionField), type: versionField.name },
77
+ true
78
+ )
79
+ };
80
+ columnNames.add(versionField.name);
81
+ }
82
+ });
83
+ }
84
+ const columns = Array.from(columnNames);
85
+ const values = modelFieldValues.flatMap(
86
+ (fieldValueMap) => columns.map(
87
+ (column) => fieldValueMap[column] || {
60
88
  type: "string",
61
89
  value: null
62
90
  }
63
91
  )
64
92
  );
93
+ const insertValues = modelFieldValues.map((fieldValueMap) => {
94
+ const rowValues = columns.map(
95
+ (column) => transformValue(
96
+ fieldValueMap[column] || { type: "string", value: null },
97
+ true
98
+ )
99
+ ).join(",");
100
+ return `(${rowValues})`;
101
+ }).join(", ");
102
+ const insertEmptyValues = modelFieldValues.map(() => {
103
+ const rowValues = columns.map(
104
+ () => "?"
105
+ ).join(",");
106
+ return `(${rowValues})`;
107
+ }).join(", ");
108
+ const updateClause = updateIfExists ? ` ON DUPLICATE KEY UPDATE ${columns.map((col) => `${col} = VALUES(${col})`).join(",")}` : "";
65
109
  return {
66
- sql: `INSERT INTO ${schema.meta.collection} (${fields.join(",")}) VALUES ${fieldValueMaps.map(
67
- (fieldValueMap) => `(${fields.map(
68
- (f) => transformValue(
69
- fieldValueMap[f] || {
70
- type: "string",
71
- value: null
72
- }
73
- )
74
- ).join(",")})`
75
- ).join(
76
- ", "
77
- )} ${updateIfExists ? `ON DUPLICATE KEY UPDATE ${fields.map((f) => `${f} = VALUES(${f})`).join(",")}` : ""}`,
78
- fields,
110
+ sql: `INSERT INTO ${schema.meta.collection} (${columns.join(",")}) VALUES ${insertValues}${updateClause}`,
111
+ query: `INSERT INTO ${schema.meta.collection} (${columns.join(",")}) VALUES ${insertEmptyValues}${updateClause}`,
112
+ fields: columns,
79
113
  values
80
114
  };
81
115
  }
82
116
  /**
83
117
  * Inserts records into the database.
118
+ * If a version field exists in the schema, versioning is applied.
119
+ *
84
120
  * @param schema - The entity schema.
85
121
  * @param models - The list of entities to insert.
86
122
  * @param updateIfExists - Whether to update the row if it already exists.
@@ -90,27 +126,29 @@ class ForgeSQLCrudOperations {
90
126
  if (!models || models.length === 0) return 0;
91
127
  const query = await this.generateInsertScript(schema, models, updateIfExists);
92
128
  if (this.options?.logRawSqlQuery) {
93
- console.debug("INSERT SQL: " + query.sql);
129
+ console.debug("INSERT SQL: " + query.query);
94
130
  }
95
131
  const sqlStatement = sql.sql.prepare(query.sql);
96
- const updateQueryResponseResult = await sqlStatement.execute();
97
- return updateQueryResponseResult.rows.insertId;
132
+ const result = await sqlStatement.execute();
133
+ return result.rows.insertId;
98
134
  }
99
135
  /**
100
- * Retrieves the primary keys for the given entity schema.
136
+ * Retrieves the primary key properties from the entity schema.
137
+ *
101
138
  * @param schema - The entity schema.
102
139
  * @returns An array of primary key properties.
103
140
  * @throws If no primary keys are found.
104
141
  */
105
142
  getPrimaryKeys(schema) {
106
- const primaryKeys = schema.meta.props.filter((p) => p.primary);
143
+ const primaryKeys = schema.meta.props.filter((prop) => prop.primary);
107
144
  if (!primaryKeys.length) {
108
145
  throw new Error(`No primary keys found for schema: ${schema.meta.className}`);
109
146
  }
110
147
  return primaryKeys;
111
148
  }
112
149
  /**
113
- * Deletes a record by its ID.
150
+ * Deletes a record by its primary key.
151
+ *
114
152
  * @param id - The ID of the record to delete.
115
153
  * @param schema - The entity schema.
116
154
  * @returns The number of rows affected.
@@ -126,33 +164,303 @@ class ForgeSQLCrudOperations {
126
164
  queryBuilder.andWhere({ [primaryKey.name]: { $eq: id } });
127
165
  const query = queryBuilder.getFormattedQuery();
128
166
  if (this.options?.logRawSqlQuery) {
129
- console.debug("DELETE SQL: " + query);
167
+ console.debug("DELETE SQL: " + queryBuilder.getQuery());
130
168
  }
131
169
  const sqlStatement = sql.sql.prepare(query);
132
- const updateQueryResponseResult = await sqlStatement.execute();
133
- return updateQueryResponseResult.rows.affectedRows;
170
+ const result = await sqlStatement.execute();
171
+ return result.rows.affectedRows;
134
172
  }
135
173
  /**
136
- * Updates a record by its ID.
174
+ * Retrieves the version field from the entity schema.
175
+ * The version field must be of type datetime, integer, or decimal, not a primary key, and not nullable.
176
+ *
177
+ * @param schema - The entity schema.
178
+ * @returns The version field property if it exists.
179
+ */
180
+ getVersionField(schema) {
181
+ if (this.options.disableOptimisticLocking) {
182
+ return void 0;
183
+ }
184
+ return schema.meta.props.filter((prop) => prop.version).filter((prop) => {
185
+ const validType = prop.type === "datetime" || prop.type === "integer" || prop.type === "decimal";
186
+ if (!validType) {
187
+ console.warn(
188
+ `Version field "${prop.name}" in table ${schema.meta.tableName} must be datetime, integer, or decimal, but is "${prop.type}"`
189
+ );
190
+ }
191
+ return validType;
192
+ }).filter((prop) => {
193
+ if (prop.primary) {
194
+ console.warn(
195
+ `Version field "${prop.name}" in table ${schema.meta.tableName} cannot be a primary key`
196
+ );
197
+ return false;
198
+ }
199
+ return true;
200
+ }).find((prop) => {
201
+ if (prop.nullable) {
202
+ console.warn(
203
+ `Version field "${prop.name}" in table ${schema.meta.tableName} should not be nullable`
204
+ );
205
+ return false;
206
+ }
207
+ return true;
208
+ });
209
+ }
210
+ /**
211
+ * Increments the version field of an entity.
212
+ * For datetime types, sets the current date; for numeric types, increments by 1.
213
+ *
214
+ * @param versionField - The version field property.
215
+ * @param updateModel - The entity to update.
216
+ */
217
+ incrementVersionField(versionField, updateModel) {
218
+ const key = versionField.name;
219
+ switch (versionField.type) {
220
+ case "datetime": {
221
+ updateModel[key] = /* @__PURE__ */ new Date();
222
+ break;
223
+ }
224
+ case "decimal":
225
+ case "integer": {
226
+ updateModel[key] = updateModel[key] + 1;
227
+ break;
228
+ }
229
+ default:
230
+ throw new Error(`Unsupported version field type: ${versionField.type}`);
231
+ }
232
+ }
233
+ /**
234
+ * Creates the initial version field value for an entity.
235
+ * For datetime types, returns the current date; for numeric types, returns 0.
236
+ *
237
+ * @param versionField - The version field property.
238
+ */
239
+ createVersionField(versionField) {
240
+ switch (versionField.type) {
241
+ case "datetime": {
242
+ return /* @__PURE__ */ new Date();
243
+ }
244
+ case "decimal":
245
+ case "integer": {
246
+ return 0;
247
+ }
248
+ default:
249
+ throw new Error(`Unsupported version field type: ${versionField.type}`);
250
+ }
251
+ }
252
+ /**
253
+ * Updates a record by its primary key using the provided entity data.
254
+ *
137
255
  * @param entity - The entity with updated values.
138
256
  * @param schema - The entity schema.
139
- * @throws If the primary key value is missing in the entity.
140
257
  */
141
258
  async updateById(entity, schema) {
259
+ const fields = schema.meta.props.filter((prop) => prop.kind === "scalar").map((prop) => prop.name);
260
+ await this.updateFieldById(entity, fields, schema);
261
+ }
262
+ /**
263
+ * Updates specified fields of records based on provided conditions.
264
+ * If the "where" parameter is not provided, the WHERE clause is built from the entity fields
265
+ * that are not included in the list of fields to update.
266
+ *
267
+ * @param entity - The object containing values to update and potential criteria for filtering.
268
+ * @param fields - Array of field names to update.
269
+ * @param schema - The entity schema.
270
+ * @param where - Optional filtering conditions for the WHERE clause.
271
+ * @returns The number of affected rows.
272
+ * @throws If no filtering criteria are provided (either via "where" or from the remaining entity fields).
273
+ */
274
+ async updateFields(entity, fields, schema, where) {
275
+ const updateData = this.filterEntityFields(entity, fields);
276
+ const updateModel = this.modifyModel(updateData, schema);
277
+ let queryBuilder = this.forgeOperations.createQueryBuilder(schema.meta.class).getKnexQuery();
278
+ queryBuilder.update(updateModel);
279
+ if (where) {
280
+ queryBuilder.where(where);
281
+ } else {
282
+ const filterCriteria = Object.keys(entity).filter((key) => !fields.includes(key)).reduce((criteria, key) => {
283
+ if (entity[key] !== void 0) {
284
+ criteria[key] = entity[key];
285
+ }
286
+ return criteria;
287
+ }, {});
288
+ if (Object.keys(filterCriteria).length === 0) {
289
+ throw new Error(
290
+ "Filtering criteria (WHERE clause) must be provided either via the 'where' parameter or through non-updated entity fields"
291
+ );
292
+ }
293
+ queryBuilder.where(filterCriteria);
294
+ }
295
+ if (this.options?.logRawSqlQuery) {
296
+ console.debug("UPDATE SQL (updateFields): " + queryBuilder.toSQL().sql);
297
+ }
298
+ const sqlQuery = queryBuilder.toQuery();
299
+ const updateQueryResponse = await this.forgeOperations.fetch().executeRawUpdateSQL(sqlQuery);
300
+ return updateQueryResponse.affectedRows;
301
+ }
302
+ /**
303
+ * Updates specific fields of a record identified by its primary key.
304
+ * If a version field exists in the schema, versioning is applied.
305
+ *
306
+ * @param entity - The entity with updated values.
307
+ * @param fields - The list of field names to update.
308
+ * @param schema - The entity schema.
309
+ * @throws If the primary key is not included in the update fields.
310
+ */
311
+ async updateFieldById(entity, fields, schema) {
142
312
  const primaryKeys = this.getPrimaryKeys(schema);
143
- const queryBuilder = this.forgeOperations.createQueryBuilder(schema.meta.class).update(entity);
144
313
  primaryKeys.forEach((pk) => {
145
- const value = entity[pk.name];
146
- if (value === null || value === void 0) {
147
- throw new Error(`Primary Key ${pk.name} must exist in the model`);
314
+ if (!fields.includes(pk.name)) {
315
+ throw new Error("Update fields must include primary key: " + pk.name);
148
316
  }
149
- queryBuilder.andWhere({ [pk.name]: { $eq: value } });
150
317
  });
151
- const query = queryBuilder.getFormattedQuery();
318
+ const updatedEntity = this.filterEntityFields(entity, fields);
319
+ let queryBuilder = this.forgeOperations.createQueryBuilder(schema.meta.class).getKnexQuery();
320
+ const versionField = this.getVersionField(schema);
321
+ const useVersion = Boolean(versionField);
322
+ let updateModel = { ...updatedEntity };
323
+ if (useVersion && versionField) {
324
+ let oldModel = entity;
325
+ if (entity[versionField.name] === void 0 || entity[versionField.name] === null) {
326
+ oldModel = await this.getOldModel(primaryKeys, entity, schema, versionField);
327
+ }
328
+ const primaryFieldNames = primaryKeys.map((pk) => pk.name);
329
+ const fieldsToRetain = primaryFieldNames.concat(versionField.name);
330
+ const fromEntries = Object.fromEntries(fieldsToRetain.map((key) => [key, oldModel[key]]));
331
+ updateModel = { ...updatedEntity, ...fromEntries };
332
+ this.incrementVersionField(versionField, updateModel);
333
+ updateModel = this.modifyModel(updateModel, schema);
334
+ queryBuilder.update(updateModel);
335
+ if (oldModel[versionField.name] !== void 0 || oldModel[versionField.name] !== null && this.isValid(oldModel[versionField.name])) {
336
+ queryBuilder.andWhere(this.optWhere(oldModel, versionField));
337
+ }
338
+ } else {
339
+ updateModel = this.modifyModel(updatedEntity, schema);
340
+ queryBuilder.update(updateModel);
341
+ }
342
+ this.addPrimaryWhere(queryBuilder, primaryKeys, updateModel);
343
+ const sqlQuery = queryBuilder.toQuery();
152
344
  if (this.options?.logRawSqlQuery) {
153
- console.debug("UPDATE SQL: " + query);
345
+ console.debug("UPDATE SQL: " + queryBuilder.toSQL().sql);
346
+ }
347
+ const updateQueryResponse = await this.forgeOperations.fetch().executeRawUpdateSQL(sqlQuery);
348
+ if (versionField && !updateQueryResponse.affectedRows) {
349
+ throw new Error(
350
+ "Optimistic locking failed: the record with primary key(s) " + primaryKeys.map((p) => updateModel[p.name]).join(", ") + " has been modified by another process."
351
+ );
154
352
  }
155
- await this.forgeOperations.fetch().executeRawUpdateSQL(query);
353
+ }
354
+ /**
355
+ * Constructs an optional WHERE clause for the version field.
356
+ *
357
+ * @param updateModel - The model containing the current version field value.
358
+ * @param versionField - The version field property.
359
+ * @returns A filter query for the version field.
360
+ */
361
+ optWhere(updateModel, versionField) {
362
+ const currentVersionValue = transformValue(
363
+ { value: updateModel[versionField.name], type: versionField.type },
364
+ false
365
+ );
366
+ return { [versionField.name]: currentVersionValue };
367
+ }
368
+ /**
369
+ * Retrieves the current state of a record from the database.
370
+ *
371
+ * @param primaryKeys - The primary key properties.
372
+ * @param entity - The entity with updated values.
373
+ * @param schema - The entity schema.
374
+ * @param versionField - The version field property.
375
+ * @returns The existing record from the database.
376
+ * @throws If the record does not exist or if multiple records are found.
377
+ */
378
+ async getOldModel(primaryKeys, entity, schema, versionField) {
379
+ const primaryFieldNames = primaryKeys.map((pk) => pk.name);
380
+ const fieldsToSelect = primaryFieldNames.concat(versionField.name);
381
+ const queryBuilder = this.forgeOperations.createQueryBuilder(schema).select(fieldsToSelect);
382
+ this.addPrimaryWhere(queryBuilder, primaryKeys, entity);
383
+ const formattedQuery = queryBuilder.getFormattedQuery();
384
+ const models = await this.forgeOperations.fetch().executeSchemaSQL(formattedQuery, schema);
385
+ if (!models || models.length === 0) {
386
+ throw new Error(`Cannot modify record because it does not exist in table ${schema.meta.tableName}`);
387
+ }
388
+ if (models.length > 1) {
389
+ throw new Error(
390
+ `Cannot modify record because multiple rows with the same ID were found in table ${schema.meta.tableName}. Please verify the table metadata.`
391
+ );
392
+ }
393
+ return models[0];
394
+ }
395
+ /**
396
+ * Adds primary key conditions to the query builder.
397
+ *
398
+ * @param queryBuilder - The Knex query builder instance.
399
+ * @param primaryKeys - The primary key properties.
400
+ * @param entity - The entity containing primary key values.
401
+ * @throws If any primary key value is missing.
402
+ */
403
+ addPrimaryWhere(queryBuilder, primaryKeys, entity) {
404
+ primaryKeys.forEach((pk) => {
405
+ const fieldName = this.getRealFieldNameFromSchema(pk);
406
+ const value = entity[fieldName];
407
+ if (value === null || value === void 0) {
408
+ throw new Error(`Primary key ${fieldName} must exist in the model`);
409
+ }
410
+ queryBuilder.andWhere({ [fieldName]: value });
411
+ });
412
+ }
413
+ /**
414
+ * Filters the entity to include only the specified fields.
415
+ *
416
+ * @param entity - The original entity.
417
+ * @param fields - The list of fields to retain.
418
+ * @returns A partial entity object containing only the specified fields.
419
+ */
420
+ filterEntityFields = (entity, fields) => fields.reduce((result, field) => {
421
+ if (field in entity) {
422
+ result[field] = entity[field];
423
+ }
424
+ return result;
425
+ }, {});
426
+ /**
427
+ * Transforms and modifies the updated entity model based on the schema.
428
+ *
429
+ * @param updatedEntity - The updated entity.
430
+ * @param schema - The entity schema.
431
+ * @returns The modified entity.
432
+ */
433
+ modifyModel(updatedEntity, schema) {
434
+ const modifiedModel = {};
435
+ schema.meta.props.filter((p) => p.kind === "scalar").forEach((p) => {
436
+ const value = updatedEntity[p.name];
437
+ if (value !== void 0 && value !== null) {
438
+ const fieldName = this.getRealFieldNameFromSchema(p);
439
+ modifiedModel[fieldName] = transformValue({ value, type: p.type }, false);
440
+ }
441
+ });
442
+ return modifiedModel;
443
+ }
444
+ /**
445
+ * Returns the real field name from the entity property based on the schema.
446
+ *
447
+ * @param p - The entity property.
448
+ * @returns The real field name.
449
+ */
450
+ getRealFieldNameFromSchema(p) {
451
+ return p.fieldNames && p.fieldNames.length ? p.fieldNames[0] : p.name;
452
+ }
453
+ /**
454
+ * Validates the provided value.
455
+ *
456
+ * @param value - The value to validate.
457
+ * @returns True if the value is valid, false otherwise.
458
+ */
459
+ isValid(value) {
460
+ if (value instanceof Date) {
461
+ return !isNaN(value.getTime());
462
+ }
463
+ return true;
156
464
  }
157
465
  }
158
466
  class ForgeSQLSelectOperations {
@@ -160,6 +468,16 @@ class ForgeSQLSelectOperations {
160
468
  constructor(options) {
161
469
  this.options = options;
162
470
  }
471
+ async executeSchemaSQLOnlyOne(query, schema) {
472
+ const results = await this.executeSchemaSQL(query, schema);
473
+ if (!results || results.length === 0) {
474
+ return void 0;
475
+ }
476
+ if (results.length > 1) {
477
+ throw new Error("Expected 1 record but returned " + results.length);
478
+ }
479
+ return results[0];
480
+ }
163
481
  /**
164
482
  * Executes a schema-based SQL query and maps the result to the entity schema.
165
483
  * @param query - The SQL query to execute.
@@ -211,13 +529,14 @@ class ForgeSQLSelectOperations {
211
529
  /**
212
530
  * Executes a raw SQL update query.
213
531
  * @param query - The raw SQL update query.
532
+ * @param params - sql parameters.
214
533
  * @returns The update response containing affected rows.
215
534
  */
216
- async executeRawUpdateSQL(query) {
217
- if (this.options.logRawSqlQuery) {
218
- console.debug("Executing update SQL: " + query);
219
- }
535
+ async executeRawUpdateSQL(query, params) {
220
536
  const sqlStatement = sql.sql.prepare(query);
537
+ if (params) {
538
+ sqlStatement.bindParams(params);
539
+ }
221
540
  const updateQueryResponseResults = await sqlStatement.execute();
222
541
  return updateQueryResponseResults.rows;
223
542
  }
@@ -254,7 +573,7 @@ class ForgeSQLORMImpl {
254
573
  preferTs: false,
255
574
  debug: false
256
575
  });
257
- const newOptions = options ?? { logRawSqlQuery: false };
576
+ const newOptions = options ?? { logRawSqlQuery: false, disableOptimisticLocking: false };
258
577
  this.crudOperations = new ForgeSQLCrudOperations(this, newOptions);
259
578
  this.fetchOperations = new ForgeSQLSelectOperations(newOptions);
260
579
  } catch (error) {
@@ -265,11 +584,12 @@ class ForgeSQLORMImpl {
265
584
  /**
266
585
  * Returns the singleton instance of ForgeSQLORMImpl.
267
586
  * @param entities - List of entities (required only on first initialization).
587
+ * @param options - Options for configuring ForgeSQL ORM behavior.
268
588
  * @returns The singleton instance of ForgeSQLORMImpl.
269
589
  */
270
- static getInstance(entities) {
590
+ static getInstance(entities, options) {
271
591
  if (!ForgeSQLORMImpl.instance) {
272
- ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(entities);
592
+ ForgeSQLORMImpl.instance = new ForgeSQLORMImpl(entities, options);
273
593
  }
274
594
  return ForgeSQLORMImpl.instance;
275
595
  }
@@ -298,7 +618,7 @@ class ForgeSQLORMImpl {
298
618
  return this.mikroORM.em.createQueryBuilder(entityName, alias, void 0, loggerContext);
299
619
  }
300
620
  /**
301
- * Provides access to the underlying Knex instance for executing raw queries and building complex query parts.
621
+ * Provides access to the underlying Knex instance for building complex query parts.
302
622
  * enabling advanced query customization and performance tuning.
303
623
  * @returns The Knex instance, which can be used for query building.
304
624
  */
@@ -308,8 +628,8 @@ class ForgeSQLORMImpl {
308
628
  }
309
629
  class ForgeSQLORM {
310
630
  ormInstance;
311
- constructor(entities) {
312
- this.ormInstance = ForgeSQLORMImpl.getInstance(entities);
631
+ constructor(entities, options) {
632
+ this.ormInstance = ForgeSQLORMImpl.getInstance(entities, options);
313
633
  }
314
634
  /**
315
635
  * Proxies the `crud` method from `ForgeSQLORMImpl`.