forge-sql-orm 2.1.0 → 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.
@@ -1,32 +1,78 @@
1
1
  import {
2
- MySqlRemoteDatabase,
3
- MySqlRemotePreparedQueryHKT,
4
- MySqlRemoteQueryResultHKT,
2
+ MySqlRawQueryResult,
3
+ MySqlRemoteDatabase,
4
+ MySqlRemotePreparedQueryHKT,
5
+ MySqlRemoteQueryResultHKT,
5
6
  } from "drizzle-orm/mysql-proxy";
6
- import type { SelectedFields } from "drizzle-orm/mysql-core/query-builders/select.types";
7
- import { applyFromDriverTransform, ForgeSqlOrmOptions, mapSelectFieldsWithAlias } from "../../..";
8
- import { MySqlSelectBuilder } from "drizzle-orm/mysql-core";
9
- import type { MySqlTable } from "drizzle-orm/mysql-core/table";
10
- import {
11
- MySqlDeleteBase,
12
- MySqlInsertBuilder,
13
- MySqlUpdateBuilder,
14
- } from "drizzle-orm/mysql-core/query-builders";
15
- import { clearCache, getFromCache, setCacheResult } from "../../../utils/cacheUtils";
7
+
8
+ import {SelectedFields} from "drizzle-orm/mysql-core/query-builders/select.types";
9
+ import {applyFromDriverTransform, ForgeSqlOrmOptions, mapSelectFieldsWithAlias} from "../../..";
10
+ import {MySqlSelectBase, MySqlSelectBuilder} from "drizzle-orm/mysql-core";
11
+ import type {MySqlTable} from "drizzle-orm/mysql-core/table";
12
+ import {MySqlDeleteBase, MySqlInsertBuilder, MySqlUpdateBuilder,} from "drizzle-orm/mysql-core/query-builders";
13
+ import {clearCache, getFromCache, setCacheResult} from "../../../utils/cacheUtils";
16
14
  import {
17
- cacheApplicationContext,
18
- evictLocalCacheQuery,
19
- getQueryLocalCacheQuery,
20
- saveTableIfInsideCacheContext,
21
- saveQueryLocalCacheQuery,
15
+ cacheApplicationContext,
16
+ evictLocalCacheQuery,
17
+ getQueryLocalCacheQuery,
18
+ saveQueryLocalCacheQuery,
19
+ saveTableIfInsideCacheContext,
22
20
  } from "../../../utils/cacheContextUtils";
21
+ import {BuildQueryConfig, isSQLWrapper, SQLWrapper} from "drizzle-orm/sql/sql";
22
+ import type {MySqlQueryResultKind} from "drizzle-orm/mysql-core/session";
23
+ import {getTableColumns, Query} from "drizzle-orm";
24
+ import {MySqlDialect} from "drizzle-orm/mysql-core/dialect";
25
+ import type {GetSelectTableName, GetSelectTableSelection} from "drizzle-orm/query-builders/select.types";
26
+
27
+ // ============================================================================
28
+ // TYPES AND INTERFACES
29
+ // ============================================================================
23
30
 
24
- // Types for better type safety
25
- type QueryBuilder = {
31
+ /**
32
+ * Base interface for query builders that can be executed
33
+ */
34
+ interface QueryBuilder {
26
35
  execute: (...args: any[]) => Promise<any>;
27
36
  then?: (onfulfilled?: any, onrejected?: any) => Promise<any>;
28
37
  toSQL?: () => any;
29
- };
38
+ }
39
+
40
+ /**
41
+ * Error codes that should not trigger cache clearing
42
+ */
43
+ const NON_CACHE_CLEARING_ERROR_CODES = [
44
+ "VALIDATION_ERROR",
45
+ "CONSTRAINT_ERROR"
46
+ ] as const;
47
+
48
+ /**
49
+ * Error codes that should trigger cache clearing
50
+ */
51
+ const CACHE_CLEARING_ERROR_CODES = [
52
+ "DEADLOCK",
53
+ "LOCK_WAIT_TIMEOUT",
54
+ "CONNECTION_ERROR"
55
+ ] as const;
56
+
57
+ /**
58
+ * Error message patterns that should not trigger cache clearing
59
+ */
60
+ const NON_CACHE_CLEARING_PATTERNS = [
61
+ /validation/i,
62
+ /constraint/i
63
+ ] as const;
64
+
65
+ /**
66
+ * Error message patterns that should trigger cache clearing
67
+ */
68
+ const CACHE_CLEARING_PATTERNS = [
69
+ /timeout/i,
70
+ /connection/i
71
+ ] as const;
72
+
73
+ // ============================================================================
74
+ // CACHE MANAGEMENT UTILITIES
75
+ // ============================================================================
30
76
 
31
77
  /**
32
78
  * Determines whether cache should be cleared based on the error type.
@@ -37,22 +83,20 @@ type QueryBuilder = {
37
83
  */
38
84
  function shouldClearCacheOnError(error: any): boolean {
39
85
  // Don't clear cache for client-side errors (validation, etc.)
40
- if (
41
- error?.code === "VALIDATION_ERROR" ||
42
- error?.code === "CONSTRAINT_ERROR" ||
43
- (error?.message && /validation/i.exec(error.message))
44
- ) {
86
+ if (error?.code && NON_CACHE_CLEARING_ERROR_CODES.includes(error.code)) {
87
+ return false;
88
+ }
89
+
90
+ if (error?.message && NON_CACHE_CLEARING_PATTERNS.some(pattern => pattern.test(error.message))) {
45
91
  return false;
46
92
  }
47
93
 
48
94
  // Clear cache for database-level errors that might affect data consistency
49
- if (
50
- error?.code === "DEADLOCK" ||
51
- error?.code === "LOCK_WAIT_TIMEOUT" ||
52
- error?.code === "CONNECTION_ERROR" ||
53
- (error?.message && /timeout/i.exec(error.message)) ||
54
- (error?.message && /connection/i.exec(error.message))
55
- ) {
95
+ if (error?.code && CACHE_CLEARING_ERROR_CODES.includes(error.code)) {
96
+ return true;
97
+ }
98
+
99
+ if (error?.message && CACHE_CLEARING_PATTERNS.some(pattern => pattern.test(error.message))) {
56
100
  return true;
57
101
  }
58
102
 
@@ -60,30 +104,97 @@ function shouldClearCacheOnError(error: any): boolean {
60
104
  return true;
61
105
  }
62
106
 
107
+ // ============================================================================
108
+ // EXPORTED TYPES
109
+ // ============================================================================
110
+
111
+ /**
112
+ * Type for select queries with field aliasing
113
+ */
63
114
  export type SelectAliasedType = <TSelection extends SelectedFields>(
64
115
  fields: TSelection,
65
116
  ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
66
117
 
118
+ /**
119
+ * Type for select distinct queries with field aliasing
120
+ */
67
121
  export type SelectAliasedDistinctType = <TSelection extends SelectedFields>(
68
122
  fields: TSelection,
69
123
  ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
70
124
 
125
+ /**
126
+ * Type for select queries with field aliasing and caching
127
+ */
71
128
  export type SelectAliasedCacheableType = <TSelection extends SelectedFields>(
72
129
  fields: TSelection,
73
130
  cacheTtl?: number,
74
131
  ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
75
132
 
133
+ /**
134
+ * Type for select distinct queries with field aliasing and caching
135
+ */
76
136
  export type SelectAliasedDistinctCacheableType = <TSelection extends SelectedFields>(
77
137
  fields: TSelection,
78
138
  cacheTtl?: number,
79
139
  ) => MySqlSelectBuilder<TSelection, MySqlRemotePreparedQueryHKT>;
80
140
 
141
+ /**
142
+ * Type for select queries from table with field aliasing
143
+ */
144
+ export type SelectAllFromAliasedType = <T extends MySqlTable>(
145
+ table: T,
146
+ ) => MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
147
+
148
+ /**
149
+ * Type for select distinct queries from table with field aliasing
150
+ */
151
+ export type SelectAllDistinctFromAliasedType = <T extends MySqlTable>(
152
+ table: T,
153
+ ) => MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
154
+
155
+ /**
156
+ * Type for select queries from table with field aliasing and caching
157
+ */
158
+ export type SelectAllFromCacheableAliasedType = <T extends MySqlTable>(
159
+ table: T,
160
+ cacheTtl?: number,
161
+ ) => MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
162
+
163
+ /**
164
+ * Type for select distinct queries from table with field aliasing and caching
165
+ */
166
+ export type SelectAllDistinctFromCacheableAliasedType = <T extends MySqlTable>(
167
+ table: T,
168
+ cacheTtl?: number,
169
+ ) => MySqlSelectBase<GetSelectTableName<T>, T["_"]["columns"] extends undefined ? GetSelectTableSelection<T> : T["_"]["columns"], T["_"]["columns"] extends undefined ? "single" : "partial", MySqlRemotePreparedQueryHKT, GetSelectTableName<T> extends string ? Record<string & GetSelectTableName<T>, "not-null"> : {}, false, never, any>;
170
+
171
+ /**
172
+ * Type for executing raw SQL queries with local cache
173
+ */
174
+ export type ExecuteQuery = (query: SQLWrapper | string) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
175
+
176
+ /**
177
+ * Type for executing raw SQL queries with local and global cache
178
+ */
179
+ export type ExecuteQueryCacheable = (query: SQLWrapper | string, cacheTtl?: number) => Promise<MySqlQueryResultKind<MySqlRemoteQueryResultHKT, unknown>>;
180
+
181
+ /**
182
+ * Type for insert operations with cache eviction
183
+ */
81
184
  export type InsertAndEvictCacheType = <TTable extends MySqlTable>(
82
185
  table: TTable,
83
186
  ) => MySqlInsertBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
187
+
188
+ /**
189
+ * Type for update operations with cache eviction
190
+ */
84
191
  export type UpdateAndEvictCacheType = <TTable extends MySqlTable>(
85
192
  table: TTable,
86
193
  ) => MySqlUpdateBuilder<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
194
+
195
+ /**
196
+ * Type for delete operations with cache eviction
197
+ */
87
198
  export type DeleteAndEvictCacheType = <TTable extends MySqlTable>(
88
199
  table: TTable,
89
200
  ) => MySqlDeleteBase<TTable, MySqlRemoteQueryResultHKT, MySqlRemotePreparedQueryHKT>;
@@ -421,7 +532,13 @@ function createAliasedSelectBuilder<TSelection extends SelectedFields>(
421
532
  return wrapBuilder(builder);
422
533
  }
423
534
 
424
- // Default options for better type safety
535
+ // ============================================================================
536
+ // CONFIGURATION AND CONSTANTS
537
+ // ============================================================================
538
+
539
+ /**
540
+ * Default options for ForgeSQL ORM
541
+ */
425
542
  const DEFAULT_OPTIONS: ForgeSqlOrmOptions = {
426
543
  logRawSqlQuery: false,
427
544
  disableOptimisticLocking: false,
@@ -430,7 +547,75 @@ const DEFAULT_OPTIONS: ForgeSqlOrmOptions = {
430
547
  cacheEntityQueryName: "sql",
431
548
  cacheEntityExpirationName: "expiration",
432
549
  cacheEntityDataName: "data",
433
- };
550
+ } as const;
551
+
552
+ // ============================================================================
553
+ // QUERY BUILDER FACTORIES
554
+ // ============================================================================
555
+
556
+
557
+ /**
558
+ * Creates a raw SQL query executor with caching support
559
+ */
560
+ function createRawQueryExecutor(
561
+ db: MySqlRemoteDatabase<any>,
562
+ options: ForgeSqlOrmOptions,
563
+ useGlobalCache: boolean = false
564
+ ) {
565
+ return async function <T extends { [column: string]: any }>(
566
+ query: SQLWrapper | string,
567
+ cacheTtl?: number
568
+ ): Promise<MySqlRawQueryResult> {
569
+ let sql: Query;
570
+
571
+ if (isSQLWrapper(query)) {
572
+ const sqlWrapper = query as SQLWrapper;
573
+ sql = sqlWrapper.getSQL()
574
+ .toQuery(((db as unknown as { dialect: MySqlDialect }).dialect) as unknown as BuildQueryConfig);
575
+ } else {
576
+ sql = {
577
+ sql: query,
578
+ params: []
579
+ };
580
+ }
581
+
582
+ // Check local cache first
583
+ const localCacheResult = await getQueryLocalCacheQuery(sql);
584
+ if (localCacheResult) {
585
+ return localCacheResult as MySqlRawQueryResult;
586
+ }
587
+
588
+ // Check global cache if enabled
589
+ if (useGlobalCache) {
590
+ const cacheResult = await getFromCache({ toSQL: () => sql }, options);
591
+ if (cacheResult) {
592
+ return cacheResult as MySqlRawQueryResult;
593
+ }
594
+ }
595
+
596
+ // Execute query
597
+ const results = await db.execute<T>(query);
598
+
599
+ // Save to local cache
600
+ await saveQueryLocalCacheQuery(sql, results);
601
+
602
+ // Save to global cache if enabled
603
+ if (useGlobalCache) {
604
+ await setCacheResult(
605
+ { toSQL: () => sql },
606
+ options,
607
+ results,
608
+ cacheTtl ?? options.cacheTTL ?? 120
609
+ );
610
+ }
611
+
612
+ return results;
613
+ };
614
+ }
615
+
616
+ // ============================================================================
617
+ // MAIN PATCH FUNCTION
618
+ // ============================================================================
434
619
 
435
620
  /**
436
621
  * Patches a Drizzle database instance with additional methods for aliased selects and cache management.
@@ -465,6 +650,10 @@ export function patchDbWithSelectAliased(
465
650
  } {
466
651
  const newOptions = { ...DEFAULT_OPTIONS, ...options };
467
652
 
653
+ // ============================================================================
654
+ // SELECT METHODS WITH FIELD ALIASING
655
+ // ============================================================================
656
+
468
657
  // Select aliased without cache
469
658
  db.selectAliased = function <TSelection extends SelectedFields>(fields: TSelection) {
470
659
  return createAliasedSelectBuilder(
@@ -476,17 +665,6 @@ export function patchDbWithSelectAliased(
476
665
  );
477
666
  };
478
667
 
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
668
  // Select aliased with cache
491
669
  db.selectAliasedCacheable = function <TSelection extends SelectedFields>(
492
670
  fields: TSelection,
@@ -502,6 +680,17 @@ export function patchDbWithSelectAliased(
502
680
  );
503
681
  };
504
682
 
683
+ // Select aliased distinct without cache
684
+ db.selectAliasedDistinct = function <TSelection extends SelectedFields>(fields: TSelection) {
685
+ return createAliasedSelectBuilder(
686
+ db,
687
+ fields,
688
+ (selections) => db.selectDistinct(selections),
689
+ false,
690
+ newOptions,
691
+ );
692
+ };
693
+
505
694
  // Select aliased distinct with cache
506
695
  db.selectAliasedDistinctCacheable = function <TSelection extends SelectedFields>(
507
696
  fields: TSelection,
@@ -517,10 +706,81 @@ export function patchDbWithSelectAliased(
517
706
  );
518
707
  };
519
708
 
709
+ // ============================================================================
710
+ // TABLE-BASED SELECT METHODS
711
+ // ============================================================================
712
+
713
+ /**
714
+ * Creates a select query builder for all columns from a table with field aliasing support.
715
+ * This is a convenience method that automatically selects all columns from the specified table.
716
+ *
717
+ * @param table - The table to select from
718
+ * @returns Select query builder with all table columns and field aliasing support
719
+ * @example
720
+ * ```typescript
721
+ * const users = await db.selectFrom(userTable).where(eq(userTable.id, 1));
722
+ * ```
723
+ */
724
+ db.selectFrom = function <T extends MySqlTable>(table: T) {
725
+ return db.selectAliased(getTableColumns(table)).from(table);
726
+ };
727
+
728
+ /**
729
+ * Creates a select query builder for all columns from a table with field aliasing and caching support.
730
+ * This is a convenience method that automatically selects all columns from the specified table with caching enabled.
731
+ *
732
+ * @param table - The table to select from
733
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
734
+ * @returns Select query builder with all table columns, field aliasing, and caching support
735
+ * @example
736
+ * ```typescript
737
+ * const users = await db.selectFromCacheable(userTable, 300).where(eq(userTable.id, 1));
738
+ * ```
739
+ */
740
+ db.selectFromCacheable = function <T extends MySqlTable>(table: T, cacheTtl?: number) {
741
+ return db.selectAliasedCacheable(getTableColumns(table), cacheTtl).from(table);
742
+ };
743
+
744
+ /**
745
+ * Creates a select distinct query builder for all columns from a table with field aliasing support.
746
+ * This is a convenience method that automatically selects all distinct columns from the specified table.
747
+ *
748
+ * @param table - The table to select from
749
+ * @returns Select distinct query builder with all table columns and field aliasing support
750
+ * @example
751
+ * ```typescript
752
+ * const uniqueUsers = await db.selectDistinctFrom(userTable).where(eq(userTable.status, 'active'));
753
+ * ```
754
+ */
755
+ db.selectDistinctFrom = function <T extends MySqlTable>(table: T) {
756
+ return db.selectAliasedDistinct(getTableColumns(table)).from(table);
757
+ };
758
+
759
+ /**
760
+ * Creates a select distinct query builder for all columns from a table with field aliasing and caching support.
761
+ * This is a convenience method that automatically selects all distinct columns from the specified table with caching enabled.
762
+ *
763
+ * @param table - The table to select from
764
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
765
+ * @returns Select distinct query builder with all table columns, field aliasing, and caching support
766
+ * @example
767
+ * ```typescript
768
+ * const uniqueUsers = await db.selectDistinctFromCacheable(userTable, 300).where(eq(userTable.status, 'active'));
769
+ * ```
770
+ */
771
+ db.selectDistinctFromCacheable = function <T extends MySqlTable>(table: T, cacheTtl?: number) {
772
+ return db.selectAliasedDistinctCacheable(getTableColumns(table), cacheTtl).from(table);
773
+ };
774
+
775
+ // ============================================================================
776
+ // CACHE-AWARE MODIFY OPERATIONS
777
+ // ============================================================================
778
+
520
779
  // Insert with cache context support (participates in cache clearing when used within cache context)
521
780
  db.insertWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
522
781
  return insertAndEvictCacheBuilder(db, table, newOptions, false);
523
782
  };
783
+
524
784
  // Insert with cache eviction
525
785
  db.insertAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
526
786
  return insertAndEvictCacheBuilder(db, table, newOptions, true);
@@ -530,6 +790,7 @@ export function patchDbWithSelectAliased(
530
790
  db.updateWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
531
791
  return updateAndEvictCacheBuilder(db, table, newOptions, false);
532
792
  };
793
+
533
794
  // Update with cache eviction
534
795
  db.updateAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
535
796
  return updateAndEvictCacheBuilder(db, table, newOptions, true);
@@ -539,10 +800,53 @@ export function patchDbWithSelectAliased(
539
800
  db.deleteWithCacheContext = function <TTable extends MySqlTable>(table: TTable) {
540
801
  return deleteAndEvictCacheBuilder(db, table, newOptions, false);
541
802
  };
803
+
542
804
  // Delete with cache eviction
543
805
  db.deleteAndEvictCache = function <TTable extends MySqlTable>(table: TTable) {
544
806
  return deleteAndEvictCacheBuilder(db, table, newOptions, true);
545
807
  };
546
808
 
809
+ // ============================================================================
810
+ // RAW SQL QUERY EXECUTORS
811
+ // ============================================================================
812
+
813
+ /**
814
+ * Executes a raw SQL query with local cache support.
815
+ * This method provides local caching for raw SQL queries within the current invocation context.
816
+ * Results are cached locally and will be returned from cache on subsequent identical queries.
817
+ *
818
+ * @param query - The SQL query to execute (SQLWrapper or string)
819
+ * @returns Promise with query results
820
+ * @example
821
+ * ```typescript
822
+ * // Using SQLWrapper
823
+ * const result = await db.executeQuery(sql`SELECT * FROM users WHERE id = ${userId}`);
824
+ *
825
+ * // Using string
826
+ * const result = await db.executeQuery("SELECT * FROM users WHERE status = 'active'");
827
+ * ```
828
+ */
829
+ db.executeQuery = createRawQueryExecutor(db, newOptions, false);
830
+
831
+ /**
832
+ * Executes a raw SQL query with both local and global cache support.
833
+ * This method provides comprehensive caching for raw SQL queries:
834
+ * - Local cache: Within the current invocation context
835
+ * - Global cache: Cross-invocation caching using @forge/kvs
836
+ *
837
+ * @param query - The SQL query to execute (SQLWrapper or string)
838
+ * @param cacheTtl - Optional cache TTL override (defaults to global cache TTL)
839
+ * @returns Promise with query results
840
+ * @example
841
+ * ```typescript
842
+ * // Using SQLWrapper with custom TTL
843
+ * const result = await db.executeQueryCacheable(sql`SELECT * FROM users WHERE id = ${userId}`, 300);
844
+ *
845
+ * // Using string with default TTL
846
+ * const result = await db.executeQueryCacheable("SELECT * FROM users WHERE status = 'active'");
847
+ * ```
848
+ */
849
+ db.executeQueryCacheable = createRawQueryExecutor(db, newOptions, true);
850
+
547
851
  return db;
548
852
  }
@@ -1,11 +1,12 @@
1
1
  import {
2
- DeleteAndEvictCacheType,
3
- InsertAndEvictCacheType,
4
- SelectAliasedCacheableType,
5
- SelectAliasedDistinctCacheableType,
6
- SelectAliasedDistinctType,
7
- SelectAliasedType,
8
- UpdateAndEvictCacheType,
2
+ DeleteAndEvictCacheType, ExecuteQuery, ExecuteQueryCacheable,
3
+ InsertAndEvictCacheType,
4
+ SelectAliasedCacheableType,
5
+ SelectAliasedDistinctCacheableType,
6
+ SelectAliasedDistinctType,
7
+ SelectAliasedType, SelectAllDistinctFromAliasedType,
8
+ SelectAllDistinctFromCacheableAliasedType, SelectAllFromAliasedType, SelectAllFromCacheableAliasedType,
9
+ UpdateAndEvictCacheType,
9
10
  } from "./additionalActions";
10
11
 
11
12
  declare module "drizzle-orm/mysql-proxy" {
@@ -20,6 +21,21 @@ declare module "drizzle-orm/mysql-proxy" {
20
21
  */
21
22
  selectAliasedDistinct: SelectAliasedDistinctType;
22
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
+
23
39
  /**
24
40
  * Select with field aliasing and caching support
25
41
  */
@@ -30,6 +46,21 @@ declare module "drizzle-orm/mysql-proxy" {
30
46
  */
31
47
  selectAliasedDistinctCacheable: SelectAliasedDistinctCacheableType;
32
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
+
33
64
  /**
34
65
  * Insert operation with cache context support.
35
66
  * Participates in cache clearing when used within executeWithCacheContext().
@@ -138,6 +138,8 @@ export async function getQueryLocalCacheQuery<
138
138
  return undefined;
139
139
  }
140
140
 
141
+
142
+
141
143
  /**
142
144
  * Evicts cached queries from the local cache context that involve the specified table.
143
145
  * This function removes cached query results that contain the given table name.
@@ -75,19 +75,45 @@ export const parseDateTime = (value: string | Date, format: string): Date => {
75
75
  };
76
76
 
77
77
  /**
78
- * Helper function to validate and format Date objects using DateTime
79
- * @param value - Date object to validate and format
80
- * @param format - DateTime format string
81
- * @returns Formatted date string
82
- * @throws Error if date is invalid
78
+ * Helper function to validate and format a date-like value using Luxon DateTime.
79
+ * @param value - Date object, ISO/RFC2822/SQL/HTTP string, or timestamp (number|string).
80
+ * @param format - DateTime format string (Luxon format tokens).
81
+ * @returns Formatted date string.
82
+ * @throws Error if value cannot be parsed as a valid date.
83
83
  */
84
- export function formatDateTime(value: Date, format: string): string {
85
- const fromJSDate = DateTime.fromJSDate(value);
86
- if (fromJSDate.isValid) {
87
- return fromJSDate.toFormat(format);
88
- } else {
89
- throw new Error("Invalid Date");
90
- }
84
+ export function formatDateTime(value: Date | string | number, format: string): string {
85
+ let dt: DateTime|null = null;
86
+
87
+ if (value instanceof Date) {
88
+ dt = DateTime.fromJSDate(value);
89
+ } else if (typeof value === "string") {
90
+ // Перебор парсеров
91
+ for (const parser of [
92
+ DateTime.fromISO,
93
+ DateTime.fromRFC2822,
94
+ DateTime.fromSQL,
95
+ DateTime.fromHTTP,
96
+ ]) {
97
+ dt = parser(value);
98
+ if (dt.isValid) break;
99
+ }
100
+ if (!dt?.isValid) {
101
+ const parsed = Number(value);
102
+ if (!isNaN(parsed)) {
103
+ dt = DateTime.fromMillis(parsed);
104
+ }
105
+ }
106
+ } else if (typeof value === "number") {
107
+ dt = DateTime.fromMillis(value);
108
+ } else {
109
+ throw new Error("Unsupported type");
110
+ }
111
+
112
+ if (!dt?.isValid) {
113
+ throw new Error("Invalid Date");
114
+ }
115
+
116
+ return dt.toFormat(format);
91
117
  }
92
118
 
93
119
  /**