forge-sql-orm 2.0.20 → 2.0.22
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 +49 -0
- package/dist/ForgeSQLORM.js +12 -0
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +12 -0
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/utils/sqlUtils.d.ts +2 -0
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/utils/sqlUtils.ts +12 -0
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.
|
package/dist/ForgeSQLORM.js
CHANGED
|
@@ -131,6 +131,7 @@ function generateDropTableStatements(tables) {
|
|
|
131
131
|
const dropStatements = [];
|
|
132
132
|
tables.forEach((tableName) => {
|
|
133
133
|
dropStatements.push(`DROP TABLE IF EXISTS \`${tableName}\`;`);
|
|
134
|
+
dropStatements.push(`DROP SEQUENCE IF EXISTS \`${tableName}\`;`);
|
|
134
135
|
});
|
|
135
136
|
return dropStatements;
|
|
136
137
|
}
|
|
@@ -269,6 +270,15 @@ function processNullBranches(obj) {
|
|
|
269
270
|
}
|
|
270
271
|
return allNull ? null : result;
|
|
271
272
|
}
|
|
273
|
+
function formatLimitOffset(limitOrOffset) {
|
|
274
|
+
if (typeof limitOrOffset !== "number" || isNaN(limitOrOffset)) {
|
|
275
|
+
throw new Error("limitOrOffset must be a valid number");
|
|
276
|
+
}
|
|
277
|
+
return drizzleOrm.sql.raw(`${limitOrOffset}`);
|
|
278
|
+
}
|
|
279
|
+
function nextVal(sequenceName) {
|
|
280
|
+
return drizzleOrm.sql.raw(`NEXTVAL(${sequenceName})`);
|
|
281
|
+
}
|
|
272
282
|
class ForgeSQLCrudOperations {
|
|
273
283
|
forgeOperations;
|
|
274
284
|
options;
|
|
@@ -1338,6 +1348,7 @@ exports.forgeDriver = forgeDriver;
|
|
|
1338
1348
|
exports.forgeSystemTables = forgeSystemTables;
|
|
1339
1349
|
exports.forgeTimeString = forgeTimeString;
|
|
1340
1350
|
exports.forgeTimestampString = forgeTimestampString;
|
|
1351
|
+
exports.formatLimitOffset = formatLimitOffset;
|
|
1341
1352
|
exports.generateDropTableStatements = generateDropTableStatements;
|
|
1342
1353
|
exports.getHttpResponse = getHttpResponse;
|
|
1343
1354
|
exports.getPrimaryKeys = getPrimaryKeys;
|
|
@@ -1346,6 +1357,7 @@ exports.getTables = getTables;
|
|
|
1346
1357
|
exports.mapSelectAllFieldsToAlias = mapSelectAllFieldsToAlias;
|
|
1347
1358
|
exports.mapSelectFieldsWithAlias = mapSelectFieldsWithAlias;
|
|
1348
1359
|
exports.migrations = migrations;
|
|
1360
|
+
exports.nextVal = nextVal;
|
|
1349
1361
|
exports.parseDateTime = parseDateTime;
|
|
1350
1362
|
exports.patchDbWithSelectAliased = patchDbWithSelectAliased;
|
|
1351
1363
|
//# sourceMappingURL=ForgeSQLORM.js.map
|