forge-sql-orm 2.0.19 → 2.0.21

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/README.md CHANGED
@@ -465,6 +465,20 @@ await forgeSQL.crud().insert(Users, [
465
465
  ],
466
466
  true
467
467
  );
468
+
469
+ // Insert with sequence (nextVal)
470
+ import { nextVal } from "forge-sql-orm";
471
+
472
+ const user = {
473
+ id: nextVal('user_id_seq'),
474
+ name: "user test",
475
+ organization_id: 1
476
+ };
477
+ const id = await forgeSQL.modify().insert(appUser, [user]);
478
+
479
+ // The generated SQL will be:
480
+ // INSERT INTO app_user (id, name, organization_id)
481
+ // VALUES (NEXTVAL(user_id_seq), ?, ?) -- params: ["user test", 1]
468
482
  ```
469
483
 
470
484
  ### Update Operations
@@ -494,6 +508,41 @@ await forgeSQL.crud().updateFields(
494
508
  await forgeSQL.crud().deleteById(1, Users);
495
509
  ```
496
510
 
511
+ ## SQL Utilities
512
+
513
+ ### formatLimitOffset
514
+
515
+ The `formatLimitOffset` utility function is used to safely insert numeric values directly into SQL queries for LIMIT and OFFSET clauses. This is necessary because Atlassian Forge SQL doesn't support parameterized queries for these clauses.
516
+
517
+ ```typescript
518
+ import { formatLimitOffset } from "forge-sql-orm";
519
+
520
+ // Example usage in a query
521
+ const result = await forgeSQL
522
+ .select()
523
+ .from(orderItem)
524
+ .orderBy(asc(orderItem.createdAt))
525
+ .limit(formatLimitOffset(10))
526
+ .offset(formatLimitOffset(350000));
527
+
528
+ // The generated SQL will be:
529
+ // SELECT * FROM order_item
530
+ // ORDER BY created_at ASC
531
+ // LIMIT 10
532
+ // OFFSET 350000
533
+ ```
534
+
535
+ **Important Notes:**
536
+ - The function performs type checking to prevent SQL injection
537
+ - It throws an error if the input is not a valid number
538
+ - Use this function instead of direct parameter binding for LIMIT and OFFSET clauses
539
+ - The function is specifically designed to work with Atlassian Forge SQL's limitations
540
+
541
+ **Security Considerations:**
542
+ - The function includes validation to ensure the input is a valid number
543
+ - This prevents SQL injection by ensuring only numeric values are inserted
544
+ - Always use this function instead of string concatenation for LIMIT and OFFSET values
545
+
497
546
  ## Optimistic Locking
498
547
 
499
548
  Optimistic locking is a concurrency control mechanism that prevents data conflicts when multiple transactions attempt to update the same record concurrently. Instead of using locks, this technique relies on a version field in your entity models.
@@ -269,6 +269,15 @@ function processNullBranches(obj) {
269
269
  }
270
270
  return allNull ? null : result;
271
271
  }
272
+ function formatLimitOffset(limitOrOffset) {
273
+ if (typeof limitOrOffset !== "number" || isNaN(limitOrOffset)) {
274
+ throw new Error("limitOrOffset must be a valid number");
275
+ }
276
+ return drizzleOrm.sql.raw(`${limitOrOffset}`);
277
+ }
278
+ function nextVal(sequenceName) {
279
+ return drizzleOrm.sql`SELECT NEXT VALUE FOR ${sequenceName} AS id`;
280
+ }
272
281
  class ForgeSQLCrudOperations {
273
282
  forgeOperations;
274
283
  options;
@@ -920,10 +929,11 @@ class ForgeSQLAnalyseOperation {
920
929
  * Retrieves and analyzes slow queries from the database.
921
930
  * @returns {Promise<SlowQueryNormalized[]>} The normalized slow query data
922
931
  */
932
+ // CLUSTER_SLOW_QUERY STATISTICS
923
933
  async analyzeSlowQueries() {
924
934
  const results = await this.forgeOperations.fetch().executeRawSQL(`
925
935
  SELECT *
926
- FROM information_schema.slow_query
936
+ FROM information_schema.slow_query
927
937
  ORDER BY time DESC
928
938
  `);
929
939
  return results.map((row) => this.normalizeSlowQuery(row));
@@ -1337,6 +1347,7 @@ exports.forgeDriver = forgeDriver;
1337
1347
  exports.forgeSystemTables = forgeSystemTables;
1338
1348
  exports.forgeTimeString = forgeTimeString;
1339
1349
  exports.forgeTimestampString = forgeTimestampString;
1350
+ exports.formatLimitOffset = formatLimitOffset;
1340
1351
  exports.generateDropTableStatements = generateDropTableStatements;
1341
1352
  exports.getHttpResponse = getHttpResponse;
1342
1353
  exports.getPrimaryKeys = getPrimaryKeys;
@@ -1345,6 +1356,7 @@ exports.getTables = getTables;
1345
1356
  exports.mapSelectAllFieldsToAlias = mapSelectAllFieldsToAlias;
1346
1357
  exports.mapSelectFieldsWithAlias = mapSelectFieldsWithAlias;
1347
1358
  exports.migrations = migrations;
1359
+ exports.nextVal = nextVal;
1348
1360
  exports.parseDateTime = parseDateTime;
1349
1361
  exports.patchDbWithSelectAliased = patchDbWithSelectAliased;
1350
1362
  //# sourceMappingURL=ForgeSQLORM.js.map