forge-sql-orm 2.0.30 → 2.1.1
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 +1410 -81
- package/dist/ForgeSQLORM.js +1456 -60
- package/dist/ForgeSQLORM.js.map +1 -1
- package/dist/ForgeSQLORM.mjs +1440 -61
- package/dist/ForgeSQLORM.mjs.map +1 -1
- package/dist/core/ForgeSQLAnalyseOperations.d.ts +1 -1
- package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLCacheOperations.d.ts +119 -0
- package/dist/core/ForgeSQLCacheOperations.d.ts.map +1 -0
- package/dist/core/ForgeSQLCrudOperations.d.ts +38 -22
- package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
- package/dist/core/ForgeSQLORM.d.ts +248 -13
- package/dist/core/ForgeSQLORM.d.ts.map +1 -1
- package/dist/core/ForgeSQLQueryBuilder.d.ts +394 -19
- package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/drizzle/extensions/additionalActions.d.ts +90 -0
- package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -0
- package/dist/utils/cacheContextUtils.d.ts +123 -0
- package/dist/utils/cacheContextUtils.d.ts.map +1 -0
- package/dist/utils/cacheUtils.d.ts +56 -0
- package/dist/utils/cacheUtils.d.ts.map +1 -0
- package/dist/utils/sqlUtils.d.ts +8 -0
- package/dist/utils/sqlUtils.d.ts.map +1 -1
- package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts +46 -0
- package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -0
- package/dist/webtriggers/index.d.ts +1 -0
- package/dist/webtriggers/index.d.ts.map +1 -1
- package/package.json +15 -12
- package/src/core/ForgeSQLAnalyseOperations.ts +1 -1
- package/src/core/ForgeSQLCacheOperations.ts +195 -0
- package/src/core/ForgeSQLCrudOperations.ts +49 -40
- package/src/core/ForgeSQLORM.ts +743 -34
- package/src/core/ForgeSQLQueryBuilder.ts +456 -20
- package/src/index.ts +1 -1
- package/src/lib/drizzle/extensions/additionalActions.ts +852 -0
- package/src/lib/drizzle/extensions/types.d.ts +99 -10
- package/src/utils/cacheContextUtils.ts +212 -0
- package/src/utils/cacheUtils.ts +403 -0
- package/src/utils/sqlUtils.ts +42 -0
- package/src/webtriggers/clearCacheSchedulerTrigger.ts +79 -0
- package/src/webtriggers/index.ts +1 -0
- package/dist/lib/drizzle/extensions/selectAliased.d.ts +0 -9
- package/dist/lib/drizzle/extensions/selectAliased.d.ts.map +0 -1
- package/src/lib/drizzle/extensions/selectAliased.ts +0 -72
|
@@ -1,14 +1,103 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
DeleteAndEvictCacheType, ExecuteQuery, ExecuteQueryCacheable,
|
|
3
|
+
InsertAndEvictCacheType,
|
|
4
|
+
SelectAliasedCacheableType,
|
|
5
|
+
SelectAliasedDistinctCacheableType,
|
|
6
|
+
SelectAliasedDistinctType,
|
|
7
|
+
SelectAliasedType, SelectAllDistinctFromAliasedType,
|
|
8
|
+
SelectAllDistinctFromCacheableAliasedType, SelectAllFromAliasedType, SelectAllFromCacheableAliasedType,
|
|
9
|
+
UpdateAndEvictCacheType,
|
|
10
|
+
} from "./additionalActions";
|
|
4
11
|
|
|
5
12
|
declare module "drizzle-orm/mysql-proxy" {
|
|
6
|
-
interface MySqlRemoteDatabase
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
interface MySqlRemoteDatabase {
|
|
14
|
+
/**
|
|
15
|
+
* Select with field aliasing support
|
|
16
|
+
*/
|
|
17
|
+
selectAliased: SelectAliasedType;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Select distinct with field aliasing support
|
|
21
|
+
*/
|
|
22
|
+
selectAliasedDistinct: SelectAliasedDistinctType;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Select with field aliasing support for all table columns
|
|
26
|
+
*/
|
|
27
|
+
selectFrom: SelectAllFromAliasedType;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Select distinct with field aliasing support for all table columns
|
|
31
|
+
*/
|
|
32
|
+
selectDistinctFrom: SelectAllDistinctFromAliasedType;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Execute raw SQL query with local cache support
|
|
36
|
+
*/
|
|
37
|
+
executeQuery: ExecuteQuery;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Select with field aliasing and caching support
|
|
41
|
+
*/
|
|
42
|
+
selectAliasedCacheable: SelectAliasedCacheableType;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Select distinct with field aliasing and caching support
|
|
46
|
+
*/
|
|
47
|
+
selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Select with field aliasing and caching support for all table columns
|
|
51
|
+
*/
|
|
52
|
+
selectFromCacheable: SelectAllFromCacheableAliasedType;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Select distinct with field aliasing and caching support for all table columns
|
|
56
|
+
*/
|
|
57
|
+
selectDistinctFromCacheable: SelectAllDistinctFromCacheableAliasedType;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Execute raw SQL query with both local and global cache support
|
|
61
|
+
*/
|
|
62
|
+
executeQueryCacheable: ExecuteQueryCacheable;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Insert operation with cache context support.
|
|
66
|
+
* Participates in cache clearing when used within executeWithCacheContext().
|
|
67
|
+
* Does not immediately clear cache, but marks table for batch cache clearing.
|
|
68
|
+
*/
|
|
69
|
+
insertWithCacheContext: InsertAndEvictCacheType;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Insert operation that automatically evicts cache immediately after execution.
|
|
73
|
+
* Always clears cache for the affected table, regardless of cache context.
|
|
74
|
+
*/
|
|
75
|
+
insertAndEvictCache: InsertAndEvictCacheType;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Update operation with cache context support.
|
|
79
|
+
* Participates in cache clearing when used within executeWithCacheContext().
|
|
80
|
+
* Does not immediately clear cache, but marks table for batch cache clearing.
|
|
81
|
+
*/
|
|
82
|
+
updateWithCacheContext: UpdateAndEvictCacheType;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Update operation that automatically evicts cache immediately after execution.
|
|
86
|
+
* Always clears cache for the affected table, regardless of cache context.
|
|
87
|
+
*/
|
|
88
|
+
updateAndEvictCache: UpdateAndEvictCacheType;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Delete operation with cache context support.
|
|
92
|
+
* Participates in cache clearing when used within executeWithCacheContext().
|
|
93
|
+
* Does not immediately clear cache, but marks table for batch cache clearing.
|
|
94
|
+
*/
|
|
95
|
+
deleteWithCacheContext: DeleteAndEvictCacheType;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Delete operation that automatically evicts cache immediately after execution.
|
|
99
|
+
* Always clears cache for the affected table, regardless of cache context.
|
|
100
|
+
*/
|
|
101
|
+
deleteAndEvictCache: DeleteAndEvictCacheType;
|
|
13
102
|
}
|
|
14
103
|
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { AnyMySqlSelectQueryBuilder, AnyMySqlTable } from "drizzle-orm/mysql-core";
|
|
3
|
+
import { getTableName } from "drizzle-orm/table";
|
|
4
|
+
import { ForgeSqlOrmOptions } from "../core/ForgeSQLQueryBuilder";
|
|
5
|
+
import { MySqlSelectDynamic } from "drizzle-orm/mysql-core/query-builders/select.types";
|
|
6
|
+
import { hashKey } from "./cacheUtils";
|
|
7
|
+
import { Query } from "drizzle-orm/sql/sql";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Interface representing the cache application context.
|
|
11
|
+
* Stores information about tables that are being processed within a cache context.
|
|
12
|
+
*/
|
|
13
|
+
export interface CacheApplicationContext {
|
|
14
|
+
/** Set of table names (in lowercase) that are being processed within the cache context */
|
|
15
|
+
tables: Set<string>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Interface representing the local cache application context.
|
|
20
|
+
* Stores cached query results in memory for the duration of a local cache context.
|
|
21
|
+
*
|
|
22
|
+
* @interface LocalCacheApplicationContext
|
|
23
|
+
*/
|
|
24
|
+
export interface LocalCacheApplicationContext {
|
|
25
|
+
/**
|
|
26
|
+
* Cache object mapping query hash keys to cached results
|
|
27
|
+
* @property {Record<string, {sql: string, data: unknown[]}>} cache - Map of query keys to cached data
|
|
28
|
+
*/
|
|
29
|
+
cache: Record<
|
|
30
|
+
string,
|
|
31
|
+
{
|
|
32
|
+
sql: string;
|
|
33
|
+
data: unknown[];
|
|
34
|
+
}
|
|
35
|
+
>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* AsyncLocalStorage instance for managing cache context across async operations.
|
|
40
|
+
* This allows tracking which tables are being processed within a cache context
|
|
41
|
+
* without explicitly passing context through function parameters.
|
|
42
|
+
*/
|
|
43
|
+
export const cacheApplicationContext = new AsyncLocalStorage<CacheApplicationContext>();
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* AsyncLocalStorage instance for managing local cache context across async operations.
|
|
47
|
+
* This allows storing and retrieving cached query results within a local cache context
|
|
48
|
+
* without explicitly passing context through function parameters.
|
|
49
|
+
*/
|
|
50
|
+
export const localCacheApplicationContext = new AsyncLocalStorage<LocalCacheApplicationContext>();
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Saves a table name to the current cache context if one exists.
|
|
54
|
+
* This function is used to track which tables are being processed within
|
|
55
|
+
* a cache context for proper cache invalidation.
|
|
56
|
+
*
|
|
57
|
+
* @param table - The Drizzle table schema to track
|
|
58
|
+
* @returns Promise that resolves when the table is saved to context
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* await saveTableIfInsideCacheContext(usersTable);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export async function saveTableIfInsideCacheContext<T extends AnyMySqlTable>(
|
|
66
|
+
table: T,
|
|
67
|
+
): Promise<void> {
|
|
68
|
+
const context = cacheApplicationContext.getStore();
|
|
69
|
+
if (context) {
|
|
70
|
+
const tableName = getTableName(table).toLowerCase();
|
|
71
|
+
context.tables.add(tableName);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Saves a query result to the local cache context.
|
|
77
|
+
* This function stores query results in memory for the duration of the local cache context.
|
|
78
|
+
*
|
|
79
|
+
* @param query - The Drizzle query to cache
|
|
80
|
+
* @param rows - The query result data to cache
|
|
81
|
+
* @returns Promise that resolves when the data is saved to local cache
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* const query = db.select({ id: users.id, name: users.name }).from(users);
|
|
86
|
+
* const results = await query.execute();
|
|
87
|
+
* await saveQueryLocalCacheQuery(query, results);
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export async function saveQueryLocalCacheQuery<
|
|
91
|
+
T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>,
|
|
92
|
+
>(query: T, rows: unknown[]): Promise<void> {
|
|
93
|
+
const context = localCacheApplicationContext.getStore();
|
|
94
|
+
if (context) {
|
|
95
|
+
if (!context.cache) {
|
|
96
|
+
context.cache = {};
|
|
97
|
+
}
|
|
98
|
+
const sql = query as { toSQL: () => Query };
|
|
99
|
+
const key = hashKey(sql.toSQL());
|
|
100
|
+
context.cache[key] = {
|
|
101
|
+
sql: sql.toSQL().sql.toLowerCase(),
|
|
102
|
+
data: rows,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves a query result from the local cache context.
|
|
109
|
+
* This function checks if a query result is already cached in memory.
|
|
110
|
+
*
|
|
111
|
+
* @param query - The Drizzle query to check for cached results
|
|
112
|
+
* @returns Promise that resolves to cached data if found, undefined otherwise
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```typescript
|
|
116
|
+
* const query = db.select({ id: users.id, name: users.name }).from(users);
|
|
117
|
+
* const cachedResult = await getQueryLocalCacheQuery(query);
|
|
118
|
+
* if (cachedResult) {
|
|
119
|
+
* return cachedResult; // Use cached data
|
|
120
|
+
* }
|
|
121
|
+
* // Execute query and cache result
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export async function getQueryLocalCacheQuery<
|
|
125
|
+
T extends MySqlSelectDynamic<AnyMySqlSelectQueryBuilder>,
|
|
126
|
+
>(query: T): Promise<unknown[] | undefined> {
|
|
127
|
+
const context = localCacheApplicationContext.getStore();
|
|
128
|
+
if (context) {
|
|
129
|
+
if (!context.cache) {
|
|
130
|
+
context.cache = {};
|
|
131
|
+
}
|
|
132
|
+
const sql = query as { toSQL: () => Query };
|
|
133
|
+
const key = hashKey(sql.toSQL());
|
|
134
|
+
if (context.cache[key] && context.cache[key].sql === sql.toSQL().sql.toLowerCase()) {
|
|
135
|
+
return context.cache[key].data;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Evicts cached queries from the local cache context that involve the specified table.
|
|
145
|
+
* This function removes cached query results that contain the given table name.
|
|
146
|
+
*
|
|
147
|
+
* @param table - The Drizzle table schema to evict cache for
|
|
148
|
+
* @param options - ForgeSQL ORM options containing cache configuration
|
|
149
|
+
* @returns Promise that resolves when cache eviction is complete
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```typescript
|
|
153
|
+
* // After inserting/updating/deleting from users table
|
|
154
|
+
* await evictLocalCacheQuery(usersTable, forgeSqlOptions);
|
|
155
|
+
* // All cached queries involving users table are now removed
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
export async function evictLocalCacheQuery<T extends AnyMySqlTable>(
|
|
159
|
+
table: T,
|
|
160
|
+
options: ForgeSqlOrmOptions,
|
|
161
|
+
): Promise<void> {
|
|
162
|
+
const context = localCacheApplicationContext.getStore();
|
|
163
|
+
if (context) {
|
|
164
|
+
if (!context.cache) {
|
|
165
|
+
context.cache = {};
|
|
166
|
+
}
|
|
167
|
+
const tableName = getTableName(table);
|
|
168
|
+
const searchString = options.cacheWrapTable ? `\`${tableName}\`` : tableName;
|
|
169
|
+
const keyToEvicts: string[] = [];
|
|
170
|
+
Object.keys(context.cache).forEach((key) => {
|
|
171
|
+
if (context.cache[key].sql.includes(searchString)) {
|
|
172
|
+
keyToEvicts.push(key);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
keyToEvicts.forEach((key) => delete context.cache[key]);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Checks if the given SQL query contains any tables that are currently being processed
|
|
181
|
+
* within a cache context. This is used to determine if cache should be bypassed
|
|
182
|
+
* for queries that affect tables being modified within the context.
|
|
183
|
+
*
|
|
184
|
+
* @param sql - The SQL query string to check
|
|
185
|
+
* @param options - ForgeSQL ORM options containing cache configuration
|
|
186
|
+
* @returns Promise that resolves to true if the SQL contains tables in cache context
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* ```typescript
|
|
190
|
+
* const shouldBypassCache = await isTableContainsTableInCacheContext(
|
|
191
|
+
* "SELECT * FROM users WHERE id = 1",
|
|
192
|
+
* forgeSqlOptions
|
|
193
|
+
* );
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export async function isTableContainsTableInCacheContext(
|
|
197
|
+
sql: string,
|
|
198
|
+
options: ForgeSqlOrmOptions,
|
|
199
|
+
): Promise<boolean> {
|
|
200
|
+
const context = cacheApplicationContext.getStore();
|
|
201
|
+
if (!context) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const tables = Array.from(context.tables);
|
|
206
|
+
const lowerSql = sql.toLowerCase();
|
|
207
|
+
|
|
208
|
+
return tables.some((table) => {
|
|
209
|
+
const tablePattern = options.cacheWrapTable ? `\`${table}\`` : table;
|
|
210
|
+
return lowerSql.includes(tablePattern);
|
|
211
|
+
});
|
|
212
|
+
}
|