forge-sql-orm 2.0.6 → 2.0.7

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.
Files changed (2) hide show
  1. package/README.md +281 -1
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -342,4 +342,284 @@ const orderWithUser = await forgeSQL
342
342
  .select({
343
343
  orderId: rawSql`${Orders.id} as \`orderId\``,
344
344
  product: Orders.product,
345
- userName: rawSql`${Users.name} as \`
345
+ userName: rawSql`${Users.name} as \`userName\``
346
+ }).from(Orders)
347
+ .innerJoin(Users, eq(Orders.userId, Users.id))
348
+ .where(eq(Orders.id, 1));
349
+
350
+ // OR with direct drizzle
351
+ const db = drizzle(forgeDriver);
352
+ const orderWithUser = await db
353
+ .select({
354
+ orderId: rawSql`${Orders.id} as \`orderId\``,
355
+ product: Orders.product,
356
+ userName: rawSql`${Users.name} as \`userName\``
357
+ }).from(Orders)
358
+ .innerJoin(Users, eq(Orders.userId, Users.id))
359
+ .where(eq(Orders.id, 1));
360
+ // Returns: { orderId: 1, product: "Product 1", userName: "John Doe" }
361
+ ```
362
+
363
+ ### Complex Queries with Aggregations
364
+
365
+ ```js
366
+ // Finding duplicates
367
+ // With forgeSQL
368
+ const duplicates = await forgeSQL
369
+ .getDrizzleQueryBuilder()
370
+ .select({
371
+ name: Users.name,
372
+ count: rawSql`COUNT(*) as \`count\``
373
+ }).from(Users)
374
+ .groupBy(Users.name)
375
+ .having(rawSql`COUNT(*) > 1`);
376
+
377
+ // OR with direct drizzle
378
+ const db = drizzle(forgeDriver);
379
+ const duplicates = await db
380
+ .select({
381
+ name: Users.name,
382
+ count: rawSql`COUNT(*) as \`count\``
383
+ }).from(Users)
384
+ .groupBy(Users.name)
385
+ .having(rawSql`COUNT(*) > 1`);
386
+ // Returns: { name: "John Doe", count: 2 }
387
+
388
+ // Using executeQueryOnlyOne for unique results
389
+ const userStats = await forgeSQL
390
+ .fetch()
391
+ .executeQueryOnlyOne(
392
+ forgeSQL
393
+ .getDrizzleQueryBuilder()
394
+ .select({
395
+ totalUsers: rawSql`COUNT(*) as \`totalUsers\``,
396
+ uniqueNames: rawSql`COUNT(DISTINCT name) as \`uniqueNames\``
397
+ }).from(Users)
398
+ );
399
+ // Returns: { totalUsers: 100, uniqueNames: 80 }
400
+ // Throws error if multiple records found
401
+ ```
402
+
403
+ ### Raw SQL Queries
404
+
405
+ ```js
406
+ // Using executeRawSQL for direct SQL queries
407
+ const users = await forgeSQL
408
+ .fetch()
409
+ .executeRawSQL<Users>("SELECT * FROM users");
410
+ ```
411
+
412
+ ## CRUD Operations
413
+
414
+ ### Insert Operations
415
+
416
+ ```js
417
+ // Single insert
418
+ const userId = await forgeSQL.crud().insert(Users, [{ id: 1, name: "Smith" }]);
419
+
420
+ // Bulk insert
421
+ await forgeSQL.crud().insert(Users, [
422
+ { id: 2, name: "Smith" },
423
+ { id: 3, name: "Vasyl" },
424
+ ]);
425
+
426
+ // Insert with duplicate handling
427
+ await forgeSQL.crud().insert(
428
+ Users,
429
+ [
430
+ { id: 4, name: "Smith" },
431
+ { id: 4, name: "Vasyl" },
432
+ ],
433
+ true
434
+ );
435
+ ```
436
+
437
+ ### Update Operations
438
+
439
+ ```js
440
+ // Update by ID with optimistic locking
441
+ await forgeSQL.crud().updateById({ id: 1, name: "Smith Updated" }, Users);
442
+
443
+ // Update specific fields
444
+ await forgeSQL.crud().updateById(
445
+ { id: 1, age: 35 },
446
+ Users
447
+ );
448
+
449
+ // Update with custom WHERE condition
450
+ await forgeSQL.crud().updateFields(
451
+ { name: "New Name", age: 35 },
452
+ Users,
453
+ eq(Users.email, "smith@example.com")
454
+ );
455
+ ```
456
+
457
+ ### Delete Operations
458
+
459
+ ```js
460
+ // Delete by ID
461
+ await forgeSQL.crud().deleteById(1, Users);
462
+ ```
463
+
464
+ ## Optimistic Locking
465
+
466
+ 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.
467
+
468
+ ### Supported Version Field Types
469
+
470
+ - `datetime` - Timestamp-based versioning
471
+ - `timestamp` - Timestamp-based versioning
472
+ - `integer` - Numeric version increment
473
+ - `decimal` - Numeric version increment
474
+
475
+ ### Configuration
476
+
477
+ ```typescript
478
+ const options = {
479
+ additionalMetadata: {
480
+ users: {
481
+ tableName: "users",
482
+ versionField: {
483
+ fieldName: "updatedAt",
484
+ }
485
+ }
486
+ }
487
+ };
488
+
489
+ const forgeSQL = new ForgeSQL(options);
490
+ ```
491
+
492
+ ### Example Usage
493
+
494
+ ```typescript
495
+ // The version field will be automatically handled
496
+ await forgeSQL.crud().updateById(
497
+ {
498
+ id: 1,
499
+ name: "Updated Name",
500
+ updatedAt: new Date() // Will be automatically set if not provided
501
+ },
502
+ Users
503
+ );
504
+ ```
505
+
506
+ ## ForgeSqlOrmOptions
507
+
508
+ The `ForgeSqlOrmOptions` object allows customization of ORM behavior:
509
+
510
+ | Option | Type | Description |
511
+ | -------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
512
+ | `logRawSqlQuery` | `boolean` | Enables logging of raw SQL queries in the Atlassian Forge Developer Console. Useful for debugging and monitoring. Defaults to `false`. |
513
+ | `disableOptimisticLocking` | `boolean` | Disables optimistic locking. When set to `true`, no additional condition (e.g., a version check) is added during record updates, which can improve performance. However, this may lead to conflicts when multiple transactions attempt to update the same record concurrently. |
514
+ | `additionalMetadata` | `object` | Allows adding custom metadata to all entities. This is useful for tracking common fields across all tables (e.g., `createdAt`, `updatedAt`, `createdBy`, etc.). The metadata will be automatically added to all generated entities. |
515
+
516
+ ## CLI Commands
517
+
518
+ ```sh
519
+ $ npx forge-sql-orm --help
520
+
521
+ Usage: forge-sql-orm [options] [command]
522
+
523
+ Options:
524
+ -V, --version Output the version number
525
+ -h, --help Display help for command
526
+
527
+ Commands:
528
+ generate:model [options] Generate Drizzle models from the database
529
+ migrations:create [options] Generate an initial migration for the entire database
530
+ migrations:update [options] Generate a migration to update the database schema
531
+ migrations:drop [options] Generate a migration to drop all tables
532
+ help [command] Display help for a specific command
533
+ ```
534
+
535
+ ## Web Triggers for Migrations
536
+
537
+ Forge-SQL-ORM provides two web triggers for managing database migrations in Atlassian Forge:
538
+
539
+ ### 1. Apply Migrations Trigger
540
+
541
+ This trigger allows you to apply database migrations through a web endpoint. It's useful for:
542
+ - Manually triggering migrations
543
+ - Running migrations as part of your deployment process
544
+ - Testing migrations in different environments
545
+
546
+ ```typescript
547
+ // Example usage in your Forge app
548
+ import { applySchemaMigrations } from "forge-sql-orm";
549
+ import migration from "./migration";
550
+
551
+ export const handlerMigration = async () => {
552
+ return applySchemaMigrations(migration);
553
+ };
554
+ ```
555
+
556
+ Configure in `manifest.yml`:
557
+ ```yaml
558
+ webtrigger:
559
+ - key: invoke-schema-migration
560
+ function: runSchemaMigration
561
+ security:
562
+ egress:
563
+ allowDataEgress: false
564
+ allowedResponses:
565
+ - statusCode: 200
566
+ body: '{"body": "Migrations successfully executed"}'
567
+ sql:
568
+ - key: main
569
+ engine: mysql
570
+ function:
571
+ - key: runSchemaMigration
572
+ handler: index.handlerMigration
573
+ ```
574
+
575
+ ### 2. Drop Migrations Trigger
576
+
577
+ ⚠️ **WARNING**: This trigger will permanently delete all data in the specified tables and clear the migrations history. This operation cannot be undone!
578
+
579
+ This trigger allows you to completely reset your database schema. It's useful for:
580
+ - Development environments where you need to start fresh
581
+ - Testing scenarios requiring a clean database
582
+ - Resetting the database before applying new migrations
583
+
584
+ **Important**: The trigger will only drop tables that are defined in your models. Any tables that exist in the database but are not defined in your models will remain untouched.
585
+
586
+ ```typescript
587
+ // Example usage in your Forge app
588
+ import { dropSchemaMigrations } from "forge-sql-orm";
589
+ import * as schema from "./entities/schema";
590
+
591
+ export const dropMigrations = () => {
592
+ return dropSchemaMigrations(Object.values(schema));
593
+ };
594
+ ```
595
+
596
+ Configure in `manifest.yml`:
597
+ ```yaml
598
+ webtrigger:
599
+ - key: drop-schema-migration
600
+ function: dropMigrations
601
+ sql:
602
+ - key: main
603
+ engine: mysql
604
+ function:
605
+ - key: dropMigrations
606
+ handler: index.dropMigrations
607
+ ```
608
+
609
+ ### Important Notes
610
+
611
+ **Security Considerations**:
612
+ - The drop migrations trigger should be restricted to development environments
613
+ - Consider implementing additional authentication for these endpoints
614
+ - Use the `security` section in `manifest.yml` to control access
615
+
616
+ **Best Practices**:
617
+ - Always backup your data before using the drop migrations trigger
618
+ - Test migrations in a development environment first
619
+ - Use these triggers as part of your deployment pipeline
620
+ - Monitor the execution logs in the Forge Developer Console
621
+
622
+
623
+ ## License
624
+ This project is licensed under the **MIT License**.
625
+ Feel free to use it for commercial and personal projects.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-sql-orm",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Drizzle ORM integration for Forge-SQL in Atlassian Forge applications.",
5
5
  "main": "dist/ForgeSQLORM.js",
6
6
  "module": "dist/ForgeSQLORM.mjs",