forge-sql-orm 2.1.0 → 2.1.2
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 +337 -17
- package/dist/ForgeSQLORM.js +424 -34
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +425 -35
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +144 -0
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +149 -2
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/lib/drizzle/extensions/additionalActions.d.ts +50 -2
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -1
- package/dist/utils/cacheContextUtils.d.ts +4 -2
- package/dist/utils/cacheContextUtils.d.ts.map +1 -1
- package/dist/utils/sqlUtils.d.ts +6 -6
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/core/ForgeSQLORM.ts +319 -13
- package/src/core/ForgeSQLQueryBuilder.ts +218 -0
- package/src/lib/drizzle/extensions/additionalActions.ts +387 -34
- package/src/lib/drizzle/extensions/types.d.ts +36 -0
- package/src/utils/cacheContextUtils.ts +16 -2
- package/src/utils/sqlUtils.ts +34 -9
package/README.md
CHANGED
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
- ✅ **Global Cache System (Level 2)** with cross-invocation caching, automatic cache invalidation and context-aware operations (using [@forge/kvs](https://developer.atlassian.com/platform/forge/storage-reference/storage-api-custom-entities/) )
|
|
22
22
|
- ✅ **Type-Safe Query Building**: Write SQL queries with full TypeScript support
|
|
23
23
|
- ✅ **Supports complex SQL queries** with joins and filtering using Drizzle ORM
|
|
24
|
+
- ✅ **Advanced Query Methods**: `selectFrom()`, `selectDistinctFrom()`, `selectCacheableFrom()`, `selectDistinctCacheableFrom()` for all-column queries with field aliasing
|
|
25
|
+
- ✅ **Raw SQL Execution**: `execute()` and `executeCacheable()` methods for direct SQL queries with local and global caching
|
|
26
|
+
- ✅ **Common Table Expressions (CTEs)**: `with()` method for complex queries with subqueries
|
|
24
27
|
- ✅ **Schema migration support**, allowing automatic schema evolution
|
|
25
28
|
- ✅ **Automatic entity generation** from MySQL/tidb databases
|
|
26
29
|
- ✅ **Automatic migration generation** from MySQL/tidb databases
|
|
@@ -134,6 +137,20 @@ await forgeSQL.executeWithLocalContext(async () => {
|
|
|
134
137
|
// This query will use local cache (no database call)
|
|
135
138
|
const cachedUsers = await forgeSQL.select({ id: users.id, name: users.name })
|
|
136
139
|
.from(users).where(eq(users.active, true));
|
|
140
|
+
|
|
141
|
+
// Using new methods for better performance
|
|
142
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
143
|
+
.where(eq(users.active, true));
|
|
144
|
+
|
|
145
|
+
// This will use local cache (no database call)
|
|
146
|
+
const cachedUsersFrom = await forgeSQL.selectFrom(users)
|
|
147
|
+
.where(eq(users.active, true));
|
|
148
|
+
|
|
149
|
+
// Raw SQL with local caching
|
|
150
|
+
const rawUsers = await forgeSQL.execute(
|
|
151
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
152
|
+
[true]
|
|
153
|
+
);
|
|
137
154
|
});
|
|
138
155
|
```
|
|
139
156
|
Best for: Performance optimization of repeated queries within resolvers or single invocation contexts.
|
|
@@ -240,6 +257,16 @@ await forgeSQL.executeWithLocalContext(async () => {
|
|
|
240
257
|
// This query will use local cache (no database call)
|
|
241
258
|
const cachedUsers = await forgeSQL.select({ id: users.id, name: users.name })
|
|
242
259
|
.from(users).where(eq(users.active, true));
|
|
260
|
+
|
|
261
|
+
// Using new methods for better performance
|
|
262
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
263
|
+
.where(eq(users.active, true));
|
|
264
|
+
|
|
265
|
+
// Raw SQL with local caching
|
|
266
|
+
const rawUsers = await forgeSQL.execute(
|
|
267
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
268
|
+
[true]
|
|
269
|
+
);
|
|
243
270
|
});
|
|
244
271
|
```
|
|
245
272
|
|
|
@@ -277,6 +304,42 @@ await forgeSQL.update(Users).set(updateData).where(eq(Users.id, 1));
|
|
|
277
304
|
// Direct Drizzle access
|
|
278
305
|
const db = forgeSQL.getDrizzleQueryBuilder();
|
|
279
306
|
const users = await db.select().from(users);
|
|
307
|
+
|
|
308
|
+
// Using new methods for enhanced functionality
|
|
309
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
310
|
+
.where(eq(users.active, true));
|
|
311
|
+
|
|
312
|
+
const usersDistinct = await forgeSQL.selectDistinctFrom(users)
|
|
313
|
+
.where(eq(users.active, true));
|
|
314
|
+
|
|
315
|
+
const usersCacheable = await forgeSQL.selectCacheableFrom(users)
|
|
316
|
+
.where(eq(users.active, true));
|
|
317
|
+
|
|
318
|
+
// Raw SQL execution
|
|
319
|
+
const rawUsers = await forgeSQL.execute(
|
|
320
|
+
"SELECT * FROM users WHERE active = ?",
|
|
321
|
+
[true]
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
// Raw SQL with caching
|
|
325
|
+
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
326
|
+
"SELECT * FROM users WHERE active = ?",
|
|
327
|
+
[true],
|
|
328
|
+
300
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
// Common Table Expressions (CTEs)
|
|
332
|
+
const userStats = await forgeSQL
|
|
333
|
+
.with(
|
|
334
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true)).as('activeUsers'),
|
|
335
|
+
forgeSQL.selectFrom(orders).where(eq(orders.status, 'completed')).as('completedOrders')
|
|
336
|
+
)
|
|
337
|
+
.select({
|
|
338
|
+
totalActiveUsers: sql`COUNT(au.id)`,
|
|
339
|
+
totalCompletedOrders: sql`COUNT(co.id)`
|
|
340
|
+
})
|
|
341
|
+
.from(sql`activeUsers au`)
|
|
342
|
+
.leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`));
|
|
280
343
|
```
|
|
281
344
|
|
|
282
345
|
This approach gives you direct access to all Drizzle ORM features while still using the @forge/sql backend with enhanced caching and versioning capabilities.
|
|
@@ -315,6 +378,29 @@ await forgeSQL.executeWithCacheContext(async () => {
|
|
|
315
378
|
const users = await db.selectAliasedCacheable(getTableColumns(users)).from(users);
|
|
316
379
|
// Cache is cleared only once at the end for all affected tables
|
|
317
380
|
});
|
|
381
|
+
|
|
382
|
+
// Using new methods with direct drizzle
|
|
383
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
384
|
+
.where(eq(users.active, true));
|
|
385
|
+
|
|
386
|
+
const usersDistinct = await forgeSQL.selectDistinctFrom(users)
|
|
387
|
+
.where(eq(users.active, true));
|
|
388
|
+
|
|
389
|
+
const usersCacheable = await forgeSQL.selectCacheableFrom(users)
|
|
390
|
+
.where(eq(users.active, true));
|
|
391
|
+
|
|
392
|
+
// Raw SQL execution
|
|
393
|
+
const rawUsers = await forgeSQL.execute(
|
|
394
|
+
"SELECT * FROM users WHERE active = ?",
|
|
395
|
+
[true]
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
// Raw SQL with caching
|
|
399
|
+
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
400
|
+
"SELECT * FROM users WHERE active = ?",
|
|
401
|
+
[true],
|
|
402
|
+
300
|
|
403
|
+
);
|
|
318
404
|
```
|
|
319
405
|
|
|
320
406
|
## Setting Up Caching with @forge/kvs (Optional)
|
|
@@ -622,6 +708,20 @@ const optimizedData = await forgeSQL.executeWithLocalCacheContextAndReturnValue(
|
|
|
622
708
|
const cachedUsers = await forgeSQL.select({id: users.id, name: users.name})
|
|
623
709
|
.from(users).where(eq(users.active, true));
|
|
624
710
|
|
|
711
|
+
// Using new methods for better performance
|
|
712
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
713
|
+
.where(eq(users.active, true));
|
|
714
|
+
|
|
715
|
+
// This will use local cache (no database call)
|
|
716
|
+
const cachedUsersFrom = await forgeSQL.selectFrom(users)
|
|
717
|
+
.where(eq(users.active, true));
|
|
718
|
+
|
|
719
|
+
// Raw SQL with local caching
|
|
720
|
+
const rawUsers = await forgeSQL.execute(
|
|
721
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
722
|
+
[true]
|
|
723
|
+
);
|
|
724
|
+
|
|
625
725
|
// Insert operation - evicts local cache
|
|
626
726
|
await forgeSQL.insert(users).values({name: 'New User', active: true});
|
|
627
727
|
|
|
@@ -629,7 +729,7 @@ const optimizedData = await forgeSQL.executeWithLocalCacheContextAndReturnValue(
|
|
|
629
729
|
const updatedUsers = await forgeSQL.select({id: users.id, name: users.name})
|
|
630
730
|
.from(users).where(eq(users.active, true));
|
|
631
731
|
|
|
632
|
-
return { users, cachedUsers, updatedUsers };
|
|
732
|
+
return { users, cachedUsers, updatedUsers, usersFrom, cachedUsersFrom, rawUsers };
|
|
633
733
|
});
|
|
634
734
|
|
|
635
735
|
```
|
|
@@ -646,6 +746,13 @@ const optimizedData = await forgeSQL.executeWithLocalCacheContextAndReturnValue(
|
|
|
646
746
|
| `updateAndEvictCache()` | Simple updates | ❌ No | ✅ Yes |
|
|
647
747
|
| `deleteAndEvictCache()` | Simple deletes | ❌ No | ✅ Yes |
|
|
648
748
|
| `insert/update/delete` | Basic Drizzle operations | ❌ No | Cache Context |
|
|
749
|
+
| `selectFrom()` | All-column queries with field aliasing | ❌ No | Local Cache |
|
|
750
|
+
| `selectDistinctFrom()` | Distinct all-column queries with field aliasing | ❌ No | Local Cache |
|
|
751
|
+
| `selectCacheableFrom()` | All-column queries with field aliasing and caching | ❌ No | Local + Global Cache |
|
|
752
|
+
| `selectDistinctCacheableFrom()` | Distinct all-column queries with field aliasing and caching | ❌ No | Local + Global Cache |
|
|
753
|
+
| `execute()` | Raw SQL queries with local caching | ❌ No | Local Cache |
|
|
754
|
+
| `executeCacheable()` | Raw SQL queries with local and global caching | ❌ No | Local + Global Cache |
|
|
755
|
+
| `with()` | Common Table Expressions (CTEs) | ❌ No | Local Cache |
|
|
649
756
|
|
|
650
757
|
|
|
651
758
|
## Choosing the Right Method - Direct Drizzle
|
|
@@ -659,6 +766,13 @@ const optimizedData = await forgeSQL.executeWithLocalCacheContextAndReturnValue(
|
|
|
659
766
|
| `updateAndEvictCache()` | Simple updates without conflicts | ❌ No | ✅ Yes |
|
|
660
767
|
| `deleteAndEvictCache()` | Simple deletes without conflicts | ❌ No | ✅ Yes |
|
|
661
768
|
| `insert/update/delete` | Basic Drizzle operations | ❌ No | ❌ No |
|
|
769
|
+
| `selectFrom()` | All-column queries with field aliasing | ❌ No | Local Cache |
|
|
770
|
+
| `selectDistinctFrom()` | Distinct all-column queries with field aliasing | ❌ No | Local Cache |
|
|
771
|
+
| `selectCacheableFrom()` | All-column queries with field aliasing and caching | ❌ No | Local + Global Cache |
|
|
772
|
+
| `selectDistinctCacheableFrom()` | Distinct all-column queries with field aliasing and caching | ❌ No | Local + Global Cache |
|
|
773
|
+
| `execute()` | Raw SQL queries with local caching | ❌ No | Local Cache |
|
|
774
|
+
| `executeCacheable()` | Raw SQL queries with local and global caching | ❌ No | Local + Global Cache |
|
|
775
|
+
| `with()` | Common Table Expressions (CTEs) | ❌ No | Local Cache |
|
|
662
776
|
where Cache context - allows you to batch cache invalidation events and bypass cache reads for affected tables.
|
|
663
777
|
|
|
664
778
|
|
|
@@ -886,6 +1000,34 @@ const user = await forgeSQL
|
|
|
886
1000
|
.selectCacheable({user: users})
|
|
887
1001
|
.from(users);
|
|
888
1002
|
|
|
1003
|
+
// Using forgeSQL.selectFrom() - Select all columns with field aliasing
|
|
1004
|
+
const user = await forgeSQL
|
|
1005
|
+
.selectFrom(users)
|
|
1006
|
+
.where(eq(users.id, 1));
|
|
1007
|
+
|
|
1008
|
+
// Using forgeSQL.selectDistinctFrom() - Select distinct all columns with field aliasing
|
|
1009
|
+
const user = await forgeSQL
|
|
1010
|
+
.selectDistinctFrom(users)
|
|
1011
|
+
.where(eq(users.id, 1));
|
|
1012
|
+
|
|
1013
|
+
// Using forgeSQL.selectCacheableFrom() - Select all columns with field aliasing and caching
|
|
1014
|
+
const user = await forgeSQL
|
|
1015
|
+
.selectCacheableFrom(users)
|
|
1016
|
+
.where(eq(users.id, 1));
|
|
1017
|
+
|
|
1018
|
+
// Using forgeSQL.selectDistinctCacheableFrom() - Select distinct all columns with field aliasing and caching
|
|
1019
|
+
const user = await forgeSQL
|
|
1020
|
+
.selectDistinctCacheableFrom(users)
|
|
1021
|
+
.where(eq(users.id, 1));
|
|
1022
|
+
|
|
1023
|
+
// Using forgeSQL.execute() - Execute raw SQL with local caching
|
|
1024
|
+
const user = await forgeSQL
|
|
1025
|
+
.execute("SELECT * FROM users WHERE id = ?", [1]);
|
|
1026
|
+
|
|
1027
|
+
// Using forgeSQL.executeCacheable() - Execute raw SQL with local and global caching
|
|
1028
|
+
const user = await forgeSQL
|
|
1029
|
+
.executeCacheable("SELECT * FROM users WHERE id = ?", [1], 300);
|
|
1030
|
+
|
|
889
1031
|
// Using forgeSQL.getDrizzleQueryBuilder()
|
|
890
1032
|
const user = await forgeSQL
|
|
891
1033
|
.getDrizzleQueryBuilder()
|
|
@@ -941,6 +1083,31 @@ const orderWithUser = await forgeSQL
|
|
|
941
1083
|
.from(orders)
|
|
942
1084
|
.innerJoin(users, eq(orders.userId, users.id));
|
|
943
1085
|
|
|
1086
|
+
// Using new selectFrom methods with joins
|
|
1087
|
+
const orderWithUser = await forgeSQL
|
|
1088
|
+
.selectFrom(orders)
|
|
1089
|
+
.innerJoin(users, eq(orders.userId, users.id))
|
|
1090
|
+
.where(eq(orders.id, 1));
|
|
1091
|
+
|
|
1092
|
+
// Using selectCacheableFrom with joins and caching
|
|
1093
|
+
const orderWithUser = await forgeSQL
|
|
1094
|
+
.selectCacheableFrom(orders)
|
|
1095
|
+
.innerJoin(users, eq(orders.userId, users.id))
|
|
1096
|
+
.where(eq(orders.id, 1));
|
|
1097
|
+
|
|
1098
|
+
// Using with() for Common Table Expressions (CTEs)
|
|
1099
|
+
const userStats = await forgeSQL
|
|
1100
|
+
.with(
|
|
1101
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true)).as('activeUsers'),
|
|
1102
|
+
forgeSQL.selectFrom(orders).where(eq(orders.status, 'completed')).as('completedOrders')
|
|
1103
|
+
)
|
|
1104
|
+
.select({
|
|
1105
|
+
totalActiveUsers: sql`COUNT(au.id)`,
|
|
1106
|
+
totalCompletedOrders: sql`COUNT(co.id)`
|
|
1107
|
+
})
|
|
1108
|
+
.from(sql`activeUsers au`)
|
|
1109
|
+
.leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`));
|
|
1110
|
+
|
|
944
1111
|
// OR with direct drizzle
|
|
945
1112
|
const db = patchDbWithSelectAliased(drizzle(forgeDriver));
|
|
946
1113
|
const orderWithUser = await db
|
|
@@ -982,6 +1149,28 @@ const userStats = await forgeSQL
|
|
|
982
1149
|
const users = await forgeSQL
|
|
983
1150
|
.fetch()
|
|
984
1151
|
.executeRawSQL<Users>("SELECT * FROM users");
|
|
1152
|
+
|
|
1153
|
+
// Using execute() for raw SQL with local caching
|
|
1154
|
+
const users = await forgeSQL
|
|
1155
|
+
.execute("SELECT * FROM users WHERE active = ?", [true]);
|
|
1156
|
+
|
|
1157
|
+
// Using executeCacheable() for raw SQL with local and global caching
|
|
1158
|
+
const users = await forgeSQL
|
|
1159
|
+
.executeCacheable("SELECT * FROM users WHERE active = ?", [true], 300);
|
|
1160
|
+
|
|
1161
|
+
// Using execute() with complex queries
|
|
1162
|
+
const userStats = await forgeSQL
|
|
1163
|
+
.execute(`
|
|
1164
|
+
SELECT
|
|
1165
|
+
u.id,
|
|
1166
|
+
u.name,
|
|
1167
|
+
COUNT(o.id) as order_count,
|
|
1168
|
+
SUM(o.amount) as total_amount
|
|
1169
|
+
FROM users u
|
|
1170
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
1171
|
+
WHERE u.active = ?
|
|
1172
|
+
GROUP BY u.id, u.name
|
|
1173
|
+
`, [true]);
|
|
985
1174
|
```
|
|
986
1175
|
|
|
987
1176
|
## Modify Operations
|
|
@@ -1264,6 +1453,26 @@ await forgeSQL.executeWithLocalContext(async () => {
|
|
|
1264
1453
|
const cachedUsers = await forgeSQL.select({ id: users.id, name: users.name })
|
|
1265
1454
|
.from(users).where(eq(users.active, true));
|
|
1266
1455
|
|
|
1456
|
+
// Using new selectFrom methods with local caching
|
|
1457
|
+
const usersFrom = await forgeSQL.selectFrom(users)
|
|
1458
|
+
.where(eq(users.active, true));
|
|
1459
|
+
|
|
1460
|
+
// This will use local cache (no database call)
|
|
1461
|
+
const cachedUsersFrom = await forgeSQL.selectFrom(users)
|
|
1462
|
+
.where(eq(users.active, true));
|
|
1463
|
+
|
|
1464
|
+
// Using execute() with local caching
|
|
1465
|
+
const rawUsers = await forgeSQL.execute(
|
|
1466
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
1467
|
+
[true]
|
|
1468
|
+
);
|
|
1469
|
+
|
|
1470
|
+
// This will use local cache (no database call)
|
|
1471
|
+
const cachedRawUsers = await forgeSQL.execute(
|
|
1472
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
1473
|
+
[true]
|
|
1474
|
+
);
|
|
1475
|
+
|
|
1267
1476
|
// Insert operation - evicts local cache for users table
|
|
1268
1477
|
await forgeSQL.insert(users).values({ name: 'New User', active: true });
|
|
1269
1478
|
|
|
@@ -1292,23 +1501,29 @@ const result = await forgeSQL.executeWithLocalCacheContextAndReturnValue(async (
|
|
|
1292
1501
|
// Atlassian forge resolver with local cache optimization
|
|
1293
1502
|
const userResolver = async (req) => {
|
|
1294
1503
|
return await forgeSQL.executeWithLocalCacheContextAndReturnValue(async () => {
|
|
1295
|
-
// Get user details
|
|
1296
|
-
const user = await forgeSQL.
|
|
1297
|
-
.
|
|
1504
|
+
// Get user details using selectFrom (all columns with field aliasing)
|
|
1505
|
+
const user = await forgeSQL.selectFrom(users)
|
|
1506
|
+
.where(eq(users.id, args.userId));
|
|
1507
|
+
|
|
1508
|
+
// Get user's orders using selectCacheableFrom (with caching)
|
|
1509
|
+
const orders = await forgeSQL.selectCacheableFrom(orders)
|
|
1510
|
+
.where(eq(orders.userId, args.userId));
|
|
1298
1511
|
|
|
1299
|
-
// Get user's
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
}).from(orders).where(eq(orders.userId, args.userId));
|
|
1512
|
+
// Get user's profile using raw SQL with execute()
|
|
1513
|
+
const profile = await forgeSQL.execute(
|
|
1514
|
+
"SELECT id, bio, avatar FROM profiles WHERE user_id = ?",
|
|
1515
|
+
[args.userId]
|
|
1516
|
+
);
|
|
1305
1517
|
|
|
1306
|
-
// Get user
|
|
1307
|
-
const
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1518
|
+
// Get user statistics using complex raw SQL
|
|
1519
|
+
const stats = await forgeSQL.execute(`
|
|
1520
|
+
SELECT
|
|
1521
|
+
COUNT(o.id) as total_orders,
|
|
1522
|
+
SUM(o.amount) as total_spent,
|
|
1523
|
+
AVG(o.amount) as avg_order_value
|
|
1524
|
+
FROM orders o
|
|
1525
|
+
WHERE o.user_id = ? AND o.status = 'completed'
|
|
1526
|
+
`, [args.userId]);
|
|
1312
1527
|
|
|
1313
1528
|
// If any of these queries are repeated within the same resolver,
|
|
1314
1529
|
// they will use the local cache instead of hitting the database
|
|
@@ -1316,7 +1531,8 @@ const userResolver = async (req) => {
|
|
|
1316
1531
|
return {
|
|
1317
1532
|
...user[0],
|
|
1318
1533
|
orders,
|
|
1319
|
-
profile: profile[0]
|
|
1534
|
+
profile: profile[0],
|
|
1535
|
+
stats: stats[0]
|
|
1320
1536
|
};
|
|
1321
1537
|
});
|
|
1322
1538
|
};
|
|
@@ -1351,6 +1567,17 @@ await forgeSQL.executeWithLocalContext(async () => {
|
|
|
1351
1567
|
// 3. Database query
|
|
1352
1568
|
const users = await forgeSQL.selectCacheable({ id: users.id, name: users.name })
|
|
1353
1569
|
.from(users).where(eq(users.active, true));
|
|
1570
|
+
|
|
1571
|
+
// Using new methods with multi-level caching
|
|
1572
|
+
const usersFrom = await forgeSQL.selectCacheableFrom(users)
|
|
1573
|
+
.where(eq(users.active, true));
|
|
1574
|
+
|
|
1575
|
+
// Raw SQL with multi-level caching
|
|
1576
|
+
const rawUsers = await forgeSQL.executeCacheable(
|
|
1577
|
+
"SELECT id, name FROM users WHERE active = ?",
|
|
1578
|
+
[true],
|
|
1579
|
+
300 // TTL in seconds
|
|
1580
|
+
);
|
|
1354
1581
|
});
|
|
1355
1582
|
```
|
|
1356
1583
|
|
|
@@ -1387,6 +1614,33 @@ const results = await forgeSQL.modifyWithVersioningAndEvictCache().executeRawSQL
|
|
|
1387
1614
|
[true],
|
|
1388
1615
|
300 // TTL in seconds
|
|
1389
1616
|
);
|
|
1617
|
+
|
|
1618
|
+
// Using new methods for cache-aware operations
|
|
1619
|
+
const usersFrom = await forgeSQL.selectCacheableFrom(Users)
|
|
1620
|
+
.where(eq(Users.active, true));
|
|
1621
|
+
|
|
1622
|
+
const usersDistinct = await forgeSQL.selectDistinctCacheableFrom(Users)
|
|
1623
|
+
.where(eq(Users.active, true));
|
|
1624
|
+
|
|
1625
|
+
// Raw SQL with local and global caching
|
|
1626
|
+
const rawUsers = await forgeSQL.executeCacheable(
|
|
1627
|
+
"SELECT * FROM users WHERE active = ?",
|
|
1628
|
+
[true],
|
|
1629
|
+
300 // TTL in seconds
|
|
1630
|
+
);
|
|
1631
|
+
|
|
1632
|
+
// Using with() for Common Table Expressions with caching
|
|
1633
|
+
const userStats = await forgeSQL
|
|
1634
|
+
.with(
|
|
1635
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true)).as('activeUsers'),
|
|
1636
|
+
forgeSQL.selectFrom(orders).where(eq(orders.status, 'completed')).as('completedOrders')
|
|
1637
|
+
)
|
|
1638
|
+
.select({
|
|
1639
|
+
totalActiveUsers: sql`COUNT(au.id)`,
|
|
1640
|
+
totalCompletedOrders: sql`COUNT(co.id)`
|
|
1641
|
+
})
|
|
1642
|
+
.from(sql`activeUsers au`)
|
|
1643
|
+
.leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`));
|
|
1390
1644
|
```
|
|
1391
1645
|
|
|
1392
1646
|
### Manual Cache Management
|
|
@@ -1728,6 +1982,30 @@ const rawPlan = await analyzeForgeSql.explainRaw(
|
|
|
1728
1982
|
"SELECT * FROM users WHERE id = ?",
|
|
1729
1983
|
[1]
|
|
1730
1984
|
);
|
|
1985
|
+
|
|
1986
|
+
// Analyze new methods
|
|
1987
|
+
const usersFromPlan = await analyzeForgeSql.explain(
|
|
1988
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true))
|
|
1989
|
+
);
|
|
1990
|
+
|
|
1991
|
+
const usersCacheablePlan = await analyzeForgeSql.explain(
|
|
1992
|
+
forgeSQL.selectCacheableFrom(users).where(eq(users.active, true))
|
|
1993
|
+
);
|
|
1994
|
+
|
|
1995
|
+
// Analyze Common Table Expressions (CTEs)
|
|
1996
|
+
const ctePlan = await analyzeForgeSql.explain(
|
|
1997
|
+
forgeSQL
|
|
1998
|
+
.with(
|
|
1999
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true)).as('activeUsers'),
|
|
2000
|
+
forgeSQL.selectFrom(orders).where(eq(orders.status, 'completed')).as('completedOrders')
|
|
2001
|
+
)
|
|
2002
|
+
.select({
|
|
2003
|
+
totalActiveUsers: sql`COUNT(au.id)`,
|
|
2004
|
+
totalCompletedOrders: sql`COUNT(co.id)`
|
|
2005
|
+
})
|
|
2006
|
+
.from(sql`activeUsers au`)
|
|
2007
|
+
.leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`))
|
|
2008
|
+
);
|
|
1731
2009
|
```
|
|
1732
2010
|
|
|
1733
2011
|
This analysis provides insights into:
|
|
@@ -1787,6 +2065,13 @@ This section covers the breaking changes introduced in version 2.1.x and how to
|
|
|
1787
2065
|
- `forgeSQL.insertAndEvictCache()` - Basic Drizzle operations with evict cache after execution
|
|
1788
2066
|
- `forgeSQL.updateAndEvictCache()` - Basic Drizzle operations with evict cache after execution
|
|
1789
2067
|
- `forgeSQL.deleteAndEvictCache()` - Basic Drizzle operations with evict cache after execution
|
|
2068
|
+
- `forgeSQL.selectFrom()` - All-column queries with field aliasing
|
|
2069
|
+
- `forgeSQL.selectDistinctFrom()` - Distinct all-column queries with field aliasing
|
|
2070
|
+
- `forgeSQL.selectCacheableFrom()` - All-column queries with field aliasing and caching
|
|
2071
|
+
- `forgeSQL.selectDistinctCacheableFrom()` - Distinct all-column queries with field aliasing and caching
|
|
2072
|
+
- `forgeSQL.execute()` - Raw SQL queries with local caching
|
|
2073
|
+
- `forgeSQL.executeCacheable()` - Raw SQL queries with local and global caching
|
|
2074
|
+
- `forgeSQL.with()` - Common Table Expressions (CTEs)
|
|
1790
2075
|
|
|
1791
2076
|
**Optional Migration:**
|
|
1792
2077
|
You can optionally migrate to the new API methods for better performance and cache management:
|
|
@@ -1799,6 +2084,41 @@ await forgeSQL.modifyWithVersioning().insert(Users, [userData]);
|
|
|
1799
2084
|
await forgeSQL.insert(Users).values(userData);
|
|
1800
2085
|
// or for versioned operations with cache management
|
|
1801
2086
|
await forgeSQL.modifyWithVersioningAndEvictCache().insert(Users, [userData]);
|
|
2087
|
+
|
|
2088
|
+
// ✅ New query methods for better performance
|
|
2089
|
+
const users = await forgeSQL.selectFrom(Users)
|
|
2090
|
+
.where(eq(Users.active, true));
|
|
2091
|
+
|
|
2092
|
+
const usersDistinct = await forgeSQL.selectDistinctFrom(Users)
|
|
2093
|
+
.where(eq(Users.active, true));
|
|
2094
|
+
|
|
2095
|
+
const usersCacheable = await forgeSQL.selectCacheableFrom(Users)
|
|
2096
|
+
.where(eq(Users.active, true));
|
|
2097
|
+
|
|
2098
|
+
// ✅ Raw SQL execution with caching
|
|
2099
|
+
const rawUsers = await forgeSQL.execute(
|
|
2100
|
+
"SELECT * FROM users WHERE active = ?",
|
|
2101
|
+
[true]
|
|
2102
|
+
);
|
|
2103
|
+
|
|
2104
|
+
const cachedRawUsers = await forgeSQL.executeCacheable(
|
|
2105
|
+
"SELECT * FROM users WHERE active = ?",
|
|
2106
|
+
[true],
|
|
2107
|
+
300
|
|
2108
|
+
);
|
|
2109
|
+
|
|
2110
|
+
// ✅ Common Table Expressions (CTEs)
|
|
2111
|
+
const userStats = await forgeSQL
|
|
2112
|
+
.with(
|
|
2113
|
+
forgeSQL.selectFrom(users).where(eq(users.active, true)).as('activeUsers'),
|
|
2114
|
+
forgeSQL.selectFrom(orders).where(eq(orders.status, 'completed')).as('completedOrders')
|
|
2115
|
+
)
|
|
2116
|
+
.select({
|
|
2117
|
+
totalActiveUsers: sql`COUNT(au.id)`,
|
|
2118
|
+
totalCompletedOrders: sql`COUNT(co.id)`
|
|
2119
|
+
})
|
|
2120
|
+
.from(sql`activeUsers au`)
|
|
2121
|
+
.leftJoin(sql`completedOrders co`, eq(sql`au.id`, sql`co.userId`));
|
|
1802
2122
|
```
|
|
1803
2123
|
|
|
1804
2124
|
#### 3. Automatic Migration Script
|