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.
Files changed (46) hide show
  1. package/README.md +1410 -81
  2. package/dist/ForgeSQLORM.js +1456 -60
  3. package/dist/ForgeSQLORM.js.map +1 -1
  4. package/dist/ForgeSQLORM.mjs +1440 -61
  5. package/dist/ForgeSQLORM.mjs.map +1 -1
  6. package/dist/core/ForgeSQLAnalyseOperations.d.ts +1 -1
  7. package/dist/core/ForgeSQLAnalyseOperations.d.ts.map +1 -1
  8. package/dist/core/ForgeSQLCacheOperations.d.ts +119 -0
  9. package/dist/core/ForgeSQLCacheOperations.d.ts.map +1 -0
  10. package/dist/core/ForgeSQLCrudOperations.d.ts +38 -22
  11. package/dist/core/ForgeSQLCrudOperations.d.ts.map +1 -1
  12. package/dist/core/ForgeSQLORM.d.ts +248 -13
  13. package/dist/core/ForgeSQLORM.d.ts.map +1 -1
  14. package/dist/core/ForgeSQLQueryBuilder.d.ts +394 -19
  15. package/dist/core/ForgeSQLQueryBuilder.d.ts.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/lib/drizzle/extensions/additionalActions.d.ts +90 -0
  19. package/dist/lib/drizzle/extensions/additionalActions.d.ts.map +1 -0
  20. package/dist/utils/cacheContextUtils.d.ts +123 -0
  21. package/dist/utils/cacheContextUtils.d.ts.map +1 -0
  22. package/dist/utils/cacheUtils.d.ts +56 -0
  23. package/dist/utils/cacheUtils.d.ts.map +1 -0
  24. package/dist/utils/sqlUtils.d.ts +8 -0
  25. package/dist/utils/sqlUtils.d.ts.map +1 -1
  26. package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts +46 -0
  27. package/dist/webtriggers/clearCacheSchedulerTrigger.d.ts.map +1 -0
  28. package/dist/webtriggers/index.d.ts +1 -0
  29. package/dist/webtriggers/index.d.ts.map +1 -1
  30. package/package.json +15 -12
  31. package/src/core/ForgeSQLAnalyseOperations.ts +1 -1
  32. package/src/core/ForgeSQLCacheOperations.ts +195 -0
  33. package/src/core/ForgeSQLCrudOperations.ts +49 -40
  34. package/src/core/ForgeSQLORM.ts +743 -34
  35. package/src/core/ForgeSQLQueryBuilder.ts +456 -20
  36. package/src/index.ts +1 -1
  37. package/src/lib/drizzle/extensions/additionalActions.ts +852 -0
  38. package/src/lib/drizzle/extensions/types.d.ts +99 -10
  39. package/src/utils/cacheContextUtils.ts +212 -0
  40. package/src/utils/cacheUtils.ts +403 -0
  41. package/src/utils/sqlUtils.ts +42 -0
  42. package/src/webtriggers/clearCacheSchedulerTrigger.ts +79 -0
  43. package/src/webtriggers/index.ts +1 -0
  44. package/dist/lib/drizzle/extensions/selectAliased.d.ts +0 -9
  45. package/dist/lib/drizzle/extensions/selectAliased.d.ts.map +0 -1
  46. package/src/lib/drizzle/extensions/selectAliased.ts +0 -72
@@ -1,14 +1,103 @@
1
- import { SelectedFields } from "drizzle-orm";
2
- import { MySqlSelectBuilder } from "drizzle-orm/mysql-core";
3
- import { MySqlRemotePreparedQueryHKT } from "drizzle-orm/mysql-proxy";
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
- selectAliased<TSelection extends SelectedFields>(
8
- fields: TSelection,
9
- ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
10
- selectAliasedDistinct<TSelection extends SelectedFields>(
11
- fields: TSelection,
12
- ): MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
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
+ }