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
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
+
MySqlRawQueryResult,
|
|
2
3
|
MySqlRemoteDatabase,
|
|
3
4
|
MySqlRemotePreparedQueryHKT,
|
|
4
5
|
MySqlRemoteQueryResultHKT,
|
|
5
6
|
} from "drizzle-orm/mysql-proxy";
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
import { SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
7
9
|
import { applyFromDriverTransform, ForgeSqlOrmOptions, mapSelectFieldsWithAlias } from "../../..";
|
|
8
|
-
import { MySqlSelectBuilder } from "drizzle-orm/mysql-core";
|
|
10
|
+
import { MySqlSelectBase, MySqlSelectBuilder } from "drizzle-orm/mysql-core";
|
|
9
11
|
import type { MySqlTable } from "drizzle-orm/mysql-core/table";
|
|
10
12
|
import {
|
|
11
13
|
MySqlDeleteBase,
|
|
@@ -17,16 +19,54 @@ import {
|
|
|
17
19
|
cacheApplicationContext,
|
|
18
20
|
evictLocalCacheQuery,
|
|
19
21
|
getQueryLocalCacheQuery,
|
|
20
|
-
saveTableIfInsideCacheContext,
|
|
21
22
|
saveQueryLocalCacheQuery,
|
|
23
|
+
saveTableIfInsideCacheContext,
|
|
22
24
|
} from "../../../utils/cacheContextUtils";
|
|
25
|
+
import { BuildQueryConfig, isSQLWrapper, SQLWrapper } from "drizzle-orm/sql/sql";
|
|
26
|
+
import type { MySqlQueryResultKind } from "drizzle-orm/mysql-core/session";
|
|
27
|
+
import { getTableColumns, Query } from "drizzle-orm";
|
|
28
|
+
import { MySqlDialect } from "drizzle-orm/mysql-core/dialect";
|
|
29
|
+
import type {
|
|
30
|
+
GetSelectTableName,
|
|
31
|
+
GetSelectTableSelection,
|
|
32
|
+
} from "drizzle-orm/query-builders/select.types";
|
|
33
|
+
|
|
34
|
+
// ============================================================================
|
|
35
|
+
// TYPES AND INTERFACES
|
|
36
|
+
// ============================================================================
|
|
23
37
|
|
|
24
|
-
|
|
25
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Base interface for query builders that can be executed
|
|
40
|
+
*/
|
|
41
|
+
interface QueryBuilder {
|
|
26
42
|
execute: (...args: any[]) => Promise<any>;
|
|
27
43
|
then?: (onfulfilled?: any, onrejected?: any) => Promise<any>;
|
|
28
44
|
toSQL?: () => any;
|
|
29
|
-
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Error codes that should not trigger cache clearing
|
|
49
|
+
*/
|
|
50
|
+
const NON_CACHE_CLEARING_ERROR_CODES = ["VALIDATION_ERROR", "CONSTRAINT_ERROR"] as const;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Error codes that should trigger cache clearing
|
|
54
|
+
*/
|
|
55
|
+
const CACHE_CLEARING_ERROR_CODES = ["DEADLOCK", "LOCK_WAIT_TIMEOUT", "CONNECTION_ERROR"] as const;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Error message patterns that should not trigger cache clearing
|
|
59
|
+
*/
|
|
60
|
+
const NON_CACHE_CLEARING_PATTERNS = [/validation/i, /constraint/i] as const;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Error message patterns that should trigger cache clearing
|
|
64
|
+
*/
|
|
65
|
+
const CACHE_CLEARING_PATTERNS = [/timeout/i, /connection/i] as const;
|
|
66
|
+
|
|
67
|
+
// ============================================================================
|
|
68
|
+
// CACHE MANAGEMENT UTILITIES
|
|
69
|
+
// ============================================================================
|
|
30
70
|
|
|
31
71
|
/**
|
|
32
72
|
* Determines whether cache should be cleared based on the error type.
|
|
@@ -37,22 +77,23 @@ type QueryBuilder = {
|
|
|
37
77
|
*/
|
|
38
78
|
function shouldClearCacheOnError(error: any): boolean {
|
|
39
79
|
// Don't clear cache for client-side errors (validation, etc.)
|
|
80
|
+
if (error?.code && NON_CACHE_CLEARING_ERROR_CODES.includes(error.code)) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
|
|
40
84
|
if (
|
|
41
|
-
error?.
|
|
42
|
-
|
|
43
|
-
(error?.message && /validation/i.exec(error.message))
|
|
85
|
+
error?.message &&
|
|
86
|
+
NON_CACHE_CLEARING_PATTERNS.some((pattern) => pattern.test(error.message))
|
|
44
87
|
) {
|
|
45
88
|
return false;
|
|
46
89
|
}
|
|
47
90
|
|
|
48
91
|
// Clear cache for database-level errors that might affect data consistency
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
(error?.message && /connection/i.exec(error.message))
|
|
55
|
-
) {
|
|
92
|
+
if (error?.code && CACHE_CLEARING_ERROR_CODES.includes(error.code)) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (error?.message && CACHE_CLEARING_PATTERNS.some((pattern) => pattern.test(error.message))) {
|
|
56
97
|
return true;
|
|
57
98
|
}
|
|
58
99
|
|
|
@@ -60,30 +101,138 @@ function shouldClearCacheOnError(error: any): boolean {
|
|
|
60
101
|
return true;
|
|
61
102
|
}
|
|
62
103
|
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// EXPORTED TYPES
|
|
106
|
+
// ============================================================================
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Type for select queries with field aliasing
|
|
110
|
+
*/
|
|
63
111
|
export type SelectAliasedType = <TSelection extends SelectedFields>(
|
|
64
112
|
fields: TSelection,
|
|
65
113
|
) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
|
|
66
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Type for select distinct queries with field aliasing
|
|
117
|
+
*/
|
|
67
118
|
export type SelectAliasedDistinctType = <TSelection extends SelectedFields>(
|
|
68
119
|
fields: TSelection,
|
|
69
120
|
) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
|
|
70
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Type for select queries with field aliasing and caching
|
|
124
|
+
*/
|
|
71
125
|
export type SelectAliasedCacheableType = <TSelection extends SelectedFields>(
|
|
72
126
|
fields: TSelection,
|
|
73
127
|
cacheTtl?: number,
|
|
74
128
|
) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
|
|
75
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Type for select distinct queries with field aliasing and caching
|
|
132
|
+
*/
|
|
76
133
|
export type SelectAliasedDistinctCacheableType = <TSelection extends SelectedFields>(
|
|
77
134
|
fields: TSelection,
|
|
78
135
|
cacheTtl?: number,
|
|
79
136
|
) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
|
|
80
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Type for select queries from table with field aliasing
|
|
140
|
+
*/
|
|
141
|
+
export type SelectAllFromAliasedType = <T extends MySqlTable>(
|
|
142
|
+
table: T,
|
|
143
|
+
) => MySqlSelectBase<
|
|
144
|
+
GetSelectTableName<T>,
|
|
145
|
+
T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
|
|
146
|
+
T["_"]["columns"] extends undefined ? "single" : "partial",
|
|
147
|
+
MySqlRemotePreparedQueryHKT,
|
|
148
|
+
GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
|
|
149
|
+
false,
|
|
150
|
+
never,
|
|
151
|
+
any
|
|
152
|
+
>;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Type for select distinct queries from table with field aliasing
|
|
156
|
+
*/
|
|
157
|
+
export type SelectAllDistinctFromAliasedType = <T extends MySqlTable>(
|
|
158
|
+
table: T,
|
|
159
|
+
) => MySqlSelectBase<
|
|
160
|
+
GetSelectTableName<T>,
|
|
161
|
+
T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
|
|
162
|
+
T["_"]["columns"] extends undefined ? "single" : "partial",
|
|
163
|
+
MySqlRemotePreparedQueryHKT,
|
|
164
|
+
GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
|
|
165
|
+
false,
|
|
166
|
+
never,
|
|
167
|
+
any
|
|
168
|
+
>;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Type for select queries from table with field aliasing and caching
|
|
172
|
+
*/
|
|
173
|
+
export type SelectAllFromCacheableAliasedType = <T extends MySqlTable>(
|
|
174
|
+
table: T,
|
|
175
|
+
cacheTtl?: number,
|
|
176
|
+
) => MySqlSelectBase<
|
|
177
|
+
GetSelectTableName<T>,
|
|
178
|
+
T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
|
|
179
|
+
T["_"]["columns"] extends undefined ? "single" : "partial",
|
|
180
|
+
MySqlRemotePreparedQueryHKT,
|
|
181
|
+
GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
|
|
182
|
+
false,
|
|
183
|
+
never,
|
|
184
|
+
any
|
|
185
|
+
>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Type for select distinct queries from table with field aliasing and caching
|
|
189
|
+
*/
|
|
190
|
+
export type SelectAllDistinctFromCacheableAliasedType = <T extends MySqlTable>(
|
|
191
|
+
table: T,
|
|
192
|
+
cacheTtl?: number,
|
|
193
|
+
) => MySqlSelectBase<
|
|
194
|
+
GetSelectTableName<T>,
|
|
195
|
+
T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"],
|
|
196
|
+
T["_"]["columns"] extends undefined ? "single" : "partial",
|
|
197
|
+
MySqlRemotePreparedQueryHKT,
|
|
198
|
+
GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {},
|
|
199
|
+
false,
|
|
200
|
+
never,
|
|
201
|
+
any
|
|
202
|
+
>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Type for executing raw SQL queries with local cache
|
|
206
|
+
*/
|
|
207
|
+
export type ExecuteQuery = (
|
|
208
|
+
query: SQLWrapper | string,
|
|
209
|
+
) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Type for executing raw SQL queries with local and global cache
|
|
213
|
+
*/
|
|
214
|
+
export type ExecuteQueryCacheable = (
|
|
215
|
+
query: SQLWrapper | string,
|
|
216
|
+
cacheTtl?: number,
|
|
217
|
+
) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Type for insert operations with cache eviction
|
|
221
|
+
*/
|
|
81
222
|
export type InsertAndEvictCacheType = <TTable extends MySqlTable>(
|
|
82
223
|
table: TTable,
|
|
83
224
|
) => MySqlInsertBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Type for update operations with cache eviction
|
|
228
|
+
*/
|
|
84
229
|
export type UpdateAndEvictCacheType = <TTable extends MySqlTable>(
|
|
85
230
|
table: TTable,
|
|
86
231
|
) => MySqlUpdateBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Type for delete operations with cache eviction
|
|
235
|
+
*/
|
|
87
236
|
export type DeleteAndEvictCacheType = <TTable extends MySqlTable>(
|
|
88
237
|
table: TTable,
|
|
89
238
|
) => MySqlDeleteBase<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
|
|
@@ -295,7 +444,7 @@ async function handleCachedQuery(
|
|
|
295
444
|
onrejected?: any,
|
|
296
445
|
): Promise<any> {
|
|
297
446
|
try {
|
|
298
|
-
const localCached = await getQueryLocalCacheQuery(target);
|
|
447
|
+
const localCached = await getQueryLocalCacheQuery(target, options);
|
|
299
448
|
if (localCached) {
|
|
300
449
|
return onfulfilled?.(localCached);
|
|
301
450
|
}
|
|
@@ -305,7 +454,7 @@ async function handleCachedQuery(
|
|
|
305
454
|
}
|
|
306
455
|
const rows = await target.execute();
|
|
307
456
|
const transformed = applyFromDriverTransform(rows, selections, aliasMap);
|
|
308
|
-
await saveQueryLocalCacheQuery(target, transformed);
|
|
457
|
+
await saveQueryLocalCacheQuery(target, transformed, options);
|
|
309
458
|
await setCacheResult(target, options, transformed, cacheTtl).catch((cacheError) => {
|
|
310
459
|
// Log cache error but don't fail the query
|
|
311
460
|
console.warn("Cache set error:", cacheError);
|
|
@@ -321,6 +470,7 @@ async function handleCachedQuery(
|
|
|
321
470
|
* Handles non-cached query execution.
|
|
322
471
|
*
|
|
323
472
|
* @param target - The query target
|
|
473
|
+
* @param options - ForgeSQL ORM options
|
|
324
474
|
* @param selections - Field selections
|
|
325
475
|
* @param aliasMap - Field alias mapping
|
|
326
476
|
* @param onfulfilled - Success callback
|
|
@@ -329,19 +479,20 @@ async function handleCachedQuery(
|
|
|
329
479
|
*/
|
|
330
480
|
async function handleNonCachedQuery(
|
|
331
481
|
target: any,
|
|
482
|
+
options: any,
|
|
332
483
|
selections: any,
|
|
333
484
|
aliasMap: any,
|
|
334
485
|
onfulfilled?: any,
|
|
335
486
|
onrejected?: any,
|
|
336
487
|
): Promise<any> {
|
|
337
488
|
try {
|
|
338
|
-
const localCached = await getQueryLocalCacheQuery(target);
|
|
489
|
+
const localCached = await getQueryLocalCacheQuery(target, options);
|
|
339
490
|
if (localCached) {
|
|
340
491
|
return onfulfilled?.(localCached);
|
|
341
492
|
}
|
|
342
493
|
const rows = await target.execute();
|
|
343
494
|
const transformed = applyFromDriverTransform(rows, selections, aliasMap);
|
|
344
|
-
await saveQueryLocalCacheQuery(target, transformed);
|
|
495
|
+
await saveQueryLocalCacheQuery(target, transformed, options);
|
|
345
496
|
return onfulfilled?.(transformed);
|
|
346
497
|
} catch (error) {
|
|
347
498
|
return onrejected?.(error);
|
|
@@ -394,7 +545,14 @@ function createAliasedSelectBuilder<TSelection extends SelectedFields>(
|
|
|
394
545
|
onrejected,
|
|
395
546
|
);
|
|
396
547
|
} else {
|
|
397
|
-
return handleNonCachedQuery(
|
|
548
|
+
return handleNonCachedQuery(
|
|
549
|
+
target,
|
|
550
|
+
options,
|
|
551
|
+
selections,
|
|
552
|
+
aliasMap,
|
|
553
|
+
onfulfilled,
|
|
554
|
+
onrejected,
|
|
555
|
+
);
|
|
398
556
|
}
|
|
399
557
|
};
|
|
400
558
|
}
|
|
@@ -421,7 +579,13 @@ function createAliasedSelectBuilder<TSelection extends SelectedFields>(
|
|
|
421
579
|
return wrapBuilder(builder);
|
|
422
580
|
}
|
|
423
581
|
|
|
424
|
-
//
|
|
582
|
+
// ============================================================================
|
|
583
|
+
// CONFIGURATION AND CONSTANTS
|
|
584
|
+
// ============================================================================
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Default options for ForgeSQL ORM
|
|
588
|
+
*/
|
|
425
589
|
const DEFAULT_OPTIONS: ForgeSqlOrmOptions = {
|
|
426
590
|
logRawSqlQuery: false,
|
|
427
591
|
disableOptimisticLocking: false,
|
|
@@ -430,7 +594,77 @@ const DEFAULT_OPTIONS: ForgeSqlOrmOptions = {
|
|
|
430
594
|
cacheEntityQueryName: "sql",
|
|
431
595
|
cacheEntityExpirationName: "expiration",
|
|
432
596
|
cacheEntityDataName: "data",
|
|
433
|
-
};
|
|
597
|
+
} as const;
|
|
598
|
+
|
|
599
|
+
// ============================================================================
|
|
600
|
+
// QUERY BUILDER FACTORIES
|
|
601
|
+
// ============================================================================
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Creates a raw SQL query executor with caching support
|
|
605
|
+
*/
|
|
606
|
+
function createRawQueryExecutor(
|
|
607
|
+
db: MySqlRemoteDatabase<any>,
|
|
608
|
+
options: ForgeSqlOrmOptions,
|
|
609
|
+
useGlobalCache: boolean = false,
|
|
610
|
+
) {
|
|
611
|
+
return async function <T extends { [column: string]: any }>(
|
|
612
|
+
query: SQLWrapper | string,
|
|
613
|
+
cacheTtl?: number,
|
|
614
|
+
): Promise<MySqlRawQueryResult> {
|
|
615
|
+
let sql: Query;
|
|
616
|
+
|
|
617
|
+
if (isSQLWrapper(query)) {
|
|
618
|
+
const sqlWrapper = query as SQLWrapper;
|
|
619
|
+
sql = sqlWrapper
|
|
620
|
+
.getSQL()
|
|
621
|
+
.toQuery(
|
|
622
|
+
(db as unknown as { dialect: MySqlDialect }).dialect as unknown as BuildQueryConfig,
|
|
623
|
+
);
|
|
624
|
+
} else {
|
|
625
|
+
sql = {
|
|
626
|
+
sql: query,
|
|
627
|
+
params: [],
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
// Check local cache first
|
|
632
|
+
const localCacheResult = await getQueryLocalCacheQuery(sql, options);
|
|
633
|
+
if (localCacheResult) {
|
|
634
|
+
return localCacheResult as MySqlRawQueryResult;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Check global cache if enabled
|
|
638
|
+
if (useGlobalCache) {
|
|
639
|
+
const cacheResult = await getFromCache({ toSQL: () => sql }, options);
|
|
640
|
+
if (cacheResult) {
|
|
641
|
+
return cacheResult as MySqlRawQueryResult;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Execute query
|
|
646
|
+
const results = await db.execute<T>(query);
|
|
647
|
+
|
|
648
|
+
// Save to local cache
|
|
649
|
+
await saveQueryLocalCacheQuery(sql, results, options);
|
|
650
|
+
|
|
651
|
+
// Save to global cache if enabled
|
|
652
|
+
if (useGlobalCache) {
|
|
653
|
+
await setCacheResult(
|
|
654
|
+
{ toSQL: () => sql },
|
|
655
|
+
options,
|
|
656
|
+
results,
|
|
657
|
+
cacheTtl ?? options.cacheTTL ?? 120,
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
return results;
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// ============================================================================
|
|
666
|
+
// MAIN PATCH FUNCTION
|
|
667
|
+
// ============================================================================
|
|
434
668
|
|
|
435
669
|
/**
|
|
436
670
|
* Patches a Drizzle database instance with additional methods for aliased selects and cache management.
|
|
@@ -465,6 +699,10 @@ export function patchDbWithSelectAliased(
|
|
|
465
699
|
} {
|
|
466
700
|
const newOptions = { ...DEFAULT_OPTIONS, ...options };
|
|
467
701
|
|
|
702
|
+
// ============================================================================
|
|
703
|
+
// SELECT METHODS WITH FIELD ALIASING
|
|
704
|
+
// ============================================================================
|
|
705
|
+
|
|
468
706
|
// Select aliased without cache
|
|
469
707
|
db.selectAliased = function <TSelection extends SelectedFields>(fields: TSelection) {
|
|
470
708
|
return createAliasedSelectBuilder(
|
|
@@ -476,17 +714,6 @@ export function patchDbWithSelectAliased(
|
|
|
476
714
|
);
|
|
477
715
|
};
|
|
478
716
|
|
|
479
|
-
// Select aliased distinct without cache
|
|
480
|
-
db.selectAliasedDistinct = function <TSelection extends SelectedFields>(fields: TSelection) {
|
|
481
|
-
return createAliasedSelectBuilder(
|
|
482
|
-
db,
|
|
483
|
-
fields,
|
|
484
|
-
(selections) => db.selectDistinct(selections),
|
|
485
|
-
false,
|
|
486
|
-
newOptions,
|
|
487
|
-
);
|
|
488
|
-
};
|
|
489
|
-
|
|
490
717
|
// Select aliased with cache
|
|
491
718
|
db.selectAliasedCacheable = function <TSelection extends SelectedFields>(
|
|
492
719
|
fields: TSelection,
|
|
@@ -502,6 +729,17 @@ export function patchDbWithSelectAliased(
|
|
|
502
729
|
);
|
|
503
730
|
};
|
|
504
731
|
|
|
732
|
+
// Select aliased distinct without cache
|
|
733
|
+
db.selectAliasedDistinct = function <TSelection extends SelectedFields>(fields: TSelection) {
|
|
734
|
+
return createAliasedSelectBuilder(
|
|
735
|
+
db,
|
|
736
|
+
fields,
|
|
737
|
+
(selections) => db.selectDistinct(selections),
|
|
738
|
+
false,
|
|
739
|
+
newOptions,
|
|
740
|
+
);
|
|
741
|
+
};
|
|
742
|
+
|
|
505
743
|
// Select aliased distinct with cache
|
|
506
744
|
db.selectAliasedDistinctCacheable = function <TSelection extends SelectedFields>(
|
|
507
745
|
fields: TSelection,
|
|
@@ -517,10 +755,81 @@ export function patchDbWithSelectAliased(
|
|
|
517
755
|
);
|
|
518
756
|
};
|
|
519
757
|
|
|
758
|
+
// ============================================================================
|
|
759
|
+
// TABLE-BASED SELECT METHODS
|
|
760
|
+
// ============================================================================
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* Creates a select query builder for all columns from a table with field aliasing support.
|
|
764
|
+
* This is a convenience method that automatically selects all columns from the specified table.
|
|
765
|
+
*
|
|
766
|
+
* @param table - The table to select from
|
|
767
|
+
* @returns Select query builder with all table columns and field aliasing support
|
|
768
|
+
* @example
|
|
769
|
+
* ```typescript
|
|
770
|
+
* const users = await db.selectFrom(userTable).where(eq(userTable.id, 1));
|
|
771
|
+
* ```
|
|
772
|
+
*/
|
|
773
|
+
db.selectFrom = function <T extends MySqlTable>(table: T) {
|
|
774
|
+
return db.selectAliased(getTableColumns(table)).from(table);
|
|
775
|
+
};
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* Creates a select query builder for all columns from a table with field aliasing and caching support.
|
|
779
|
+
* This is a convenience method that automatically selects all columns from the specified table with caching enabled.
|
|
780
|
+
*
|
|
781
|
+
* @param table - The table to select from
|
|
782
|
+
* @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
|
|
783
|
+
* @returns Select query builder with all table columns, field aliasing, and caching support
|
|
784
|
+
* @example
|
|
785
|
+
* ```typescript
|
|
786
|
+
* const users = await db.selectFromCacheable(userTable, 300).where(eq(userTable.id, 1));
|
|
787
|
+
* ```
|
|
788
|
+
*/
|
|
789
|
+
db.selectFromCacheable = function <T extends MySqlTable>(table: T, cacheTtl?: number) {
|
|
790
|
+
return db.selectAliasedCacheable(getTableColumns(table), cacheTtl).from(table);
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Creates a select distinct query builder for all columns from a table with field aliasing support.
|
|
795
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table.
|
|
796
|
+
*
|
|
797
|
+
* @param table - The table to select from
|
|
798
|
+
* @returns Select distinct query builder with all table columns and field aliasing support
|
|
799
|
+
* @example
|
|
800
|
+
* ```typescript
|
|
801
|
+
* const uniqueUsers = await db.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
|
|
802
|
+
* ```
|
|
803
|
+
*/
|
|
804
|
+
db.selectDistinctFrom = function <T extends MySqlTable>(table: T) {
|
|
805
|
+
return db.selectAliasedDistinct(getTableColumns(table)).from(table);
|
|
806
|
+
};
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* Creates a select distinct query builder for all columns from a table with field aliasing and caching support.
|
|
810
|
+
* This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
|
|
811
|
+
*
|
|
812
|
+
* @param table - The table to select from
|
|
813
|
+
* @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
|
|
814
|
+
* @returns Select distinct query builder with all table columns, field aliasing, and caching support
|
|
815
|
+
* @example
|
|
816
|
+
* ```typescript
|
|
817
|
+
* const uniqueUsers = await db.selectDistinctFromCacheable(userTable, 300).where(eq(userTable.status, 'active'));
|
|
818
|
+
* ```
|
|
819
|
+
*/
|
|
820
|
+
db.selectDistinctFromCacheable = function <T extends MySqlTable>(table: T, cacheTtl?: number) {
|
|
821
|
+
return db.selectAliasedDistinctCacheable(getTableColumns(table), cacheTtl).from(table);
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
// ============================================================================
|
|
825
|
+
// CACHE-AWARE MODIFY OPERATIONS
|
|
826
|
+
// ============================================================================
|
|
827
|
+
|
|
520
828
|
// Insert with cache context support (participates in cache clearing when used within cache context)
|
|
521
829
|
db.insertWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
|
|
522
830
|
return insertAndEvictCacheBuilder(db, table, newOptions, false);
|
|
523
831
|
};
|
|
832
|
+
|
|
524
833
|
// Insert with cache eviction
|
|
525
834
|
db.insertAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
|
|
526
835
|
return insertAndEvictCacheBuilder(db, table, newOptions, true);
|
|
@@ -530,6 +839,7 @@ export function patchDbWithSelectAliased(
|
|
|
530
839
|
db.updateWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
|
|
531
840
|
return updateAndEvictCacheBuilder(db, table, newOptions, false);
|
|
532
841
|
};
|
|
842
|
+
|
|
533
843
|
// Update with cache eviction
|
|
534
844
|
db.updateAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
|
|
535
845
|
return updateAndEvictCacheBuilder(db, table, newOptions, true);
|
|
@@ -539,10 +849,53 @@ export function patchDbWithSelectAliased(
|
|
|
539
849
|
db.deleteWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
|
|
540
850
|
return deleteAndEvictCacheBuilder(db, table, newOptions, false);
|
|
541
851
|
};
|
|
852
|
+
|
|
542
853
|
// Delete with cache eviction
|
|
543
854
|
db.deleteAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
|
|
544
855
|
return deleteAndEvictCacheBuilder(db, table, newOptions, true);
|
|
545
856
|
};
|
|
546
857
|
|
|
858
|
+
// ============================================================================
|
|
859
|
+
// RAW SQL QUERY EXECUTORS
|
|
860
|
+
// ============================================================================
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Executes a raw SQL query with local cache support.
|
|
864
|
+
* This method provides local caching for raw SQL queries within the current invocation context.
|
|
865
|
+
* Results are cached locally and will be returned from cache on subsequent identical queries.
|
|
866
|
+
*
|
|
867
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
868
|
+
* @returns Promise with query results
|
|
869
|
+
* @example
|
|
870
|
+
* ```typescript
|
|
871
|
+
* // Using SQLWrapper
|
|
872
|
+
* const result = await db.executeQuery(sql`SELECT * FROM users WHERE id = ${userId}`);
|
|
873
|
+
*
|
|
874
|
+
* // Using string
|
|
875
|
+
* const result = await db.executeQuery("SELECT * FROM users WHERE status = 'active'");
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
db.executeQuery = createRawQueryExecutor(db, newOptions, false);
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Executes a raw SQL query with both local and global cache support.
|
|
882
|
+
* This method provides comprehensive caching for raw SQL queries:
|
|
883
|
+
* - Local cache: Within the current invocation context
|
|
884
|
+
* - Global cache: Cross-invocation caching using @forge/kvs
|
|
885
|
+
*
|
|
886
|
+
* @param query - The SQL query to execute (SQLWrapper or string)
|
|
887
|
+
* @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
|
|
888
|
+
* @returns Promise with query results
|
|
889
|
+
* @example
|
|
890
|
+
* ```typescript
|
|
891
|
+
* // Using SQLWrapper with custom TTL
|
|
892
|
+
* const result = await db.executeQueryCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
|
|
893
|
+
*
|
|
894
|
+
* // Using string with default TTL
|
|
895
|
+
* const result = await db.executeQueryCacheable("SELECT * FROM users WHERE status = 'active'");
|
|
896
|
+
* ```
|
|
897
|
+
*/
|
|
898
|
+
db.executeQueryCacheable = createRawQueryExecutor(db, newOptions, true);
|
|
899
|
+
|
|
547
900
|
return db;
|
|
548
901
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
DeleteAndEvictCacheType,
|
|
3
|
+
ExecuteQuery,
|
|
4
|
+
ExecuteQueryCacheable,
|
|
3
5
|
InsertAndEvictCacheType,
|
|
4
6
|
SelectAliasedCacheableType,
|
|
5
7
|
SelectAliasedDistinctCacheableType,
|
|
6
8
|
SelectAliasedDistinctType,
|
|
7
9
|
SelectAliasedType,
|
|
10
|
+
SelectAllDistinctFromAliasedType,
|
|
11
|
+
SelectAllDistinctFromCacheableAliasedType,
|
|
12
|
+
SelectAllFromAliasedType,
|
|
13
|
+
SelectAllFromCacheableAliasedType,
|
|
8
14
|
UpdateAndEvictCacheType,
|
|
9
15
|
} from "./additionalActions";
|
|
10
16
|
|
|
@@ -20,6 +26,21 @@ declare module "drizzle-orm/mysql-proxy" {
|
|
|
20
26
|
*/
|
|
21
27
|
selectAliasedDistinct: SelectAliasedDistinctType;
|
|
22
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Select with field aliasing support for all table columns
|
|
31
|
+
*/
|
|
32
|
+
selectFrom: SelectAllFromAliasedType;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Select distinct with field aliasing support for all table columns
|
|
36
|
+
*/
|
|
37
|
+
selectDistinctFrom: SelectAllDistinctFromAliasedType;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Execute raw SQL query with local cache support
|
|
41
|
+
*/
|
|
42
|
+
executeQuery: ExecuteQuery;
|
|
43
|
+
|
|
23
44
|
/**
|
|
24
45
|
* Select with field aliasing and caching support
|
|
25
46
|
*/
|
|
@@ -30,6 +51,21 @@ declare module "drizzle-orm/mysql-proxy" {
|
|
|
30
51
|
*/
|
|
31
52
|
selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
|
|
32
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Select with field aliasing and caching support for all table columns
|
|
56
|
+
*/
|
|
57
|
+
selectFromCacheable: SelectAllFromCacheableAliasedType;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Select distinct with field aliasing and caching support for all table columns
|
|
61
|
+
*/
|
|
62
|
+
selectDistinctFromCacheable: SelectAllDistinctFromCacheableAliasedType;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Execute raw SQL query with both local and global cache support
|
|
66
|
+
*/
|
|
67
|
+
executeQueryCacheable: ExecuteQueryCacheable;
|
|
68
|
+
|
|
33
69
|
/**
|
|
34
70
|
* Insert operation with cache context support.
|
|
35
71
|
* Participates in cache clearing when used within executeWithCacheContext().
|