@hedystia/db 2.0.2 → 2.0.4

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 (53) hide show
  1. package/dist/cache/manager.cjs +23 -0
  2. package/dist/cache/manager.cjs.map +1 -1
  3. package/dist/cache/manager.d.cts +14 -0
  4. package/dist/cache/manager.d.mts +14 -0
  5. package/dist/cache/manager.mjs +23 -0
  6. package/dist/cache/manager.mjs.map +1 -1
  7. package/dist/cli/commands/migration.cjs +3 -2
  8. package/dist/cli/commands/migration.cjs.map +1 -1
  9. package/dist/cli/commands/migration.mjs +3 -2
  10. package/dist/cli/commands/migration.mjs.map +1 -1
  11. package/dist/core/database.cjs +9 -4
  12. package/dist/core/database.cjs.map +1 -1
  13. package/dist/core/database.d.cts +4 -9
  14. package/dist/core/database.d.mts +4 -9
  15. package/dist/core/database.mjs +9 -4
  16. package/dist/core/database.mjs.map +1 -1
  17. package/dist/core/repository.cjs +32 -10
  18. package/dist/core/repository.cjs.map +1 -1
  19. package/dist/core/repository.d.cts +8 -1
  20. package/dist/core/repository.d.mts +8 -1
  21. package/dist/core/repository.mjs +32 -10
  22. package/dist/core/repository.mjs.map +1 -1
  23. package/dist/drivers/sql-compiler.cjs +6 -0
  24. package/dist/drivers/sql-compiler.cjs.map +1 -1
  25. package/dist/drivers/sql-compiler.mjs +6 -0
  26. package/dist/drivers/sql-compiler.mjs.map +1 -1
  27. package/dist/index.cjs +1 -0
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +3 -3
  30. package/dist/index.d.mts +3 -3
  31. package/dist/index.mjs +2 -2
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/schema/column.cjs +2 -2
  34. package/dist/schema/column.cjs.map +1 -1
  35. package/dist/schema/column.d.cts +2 -2
  36. package/dist/schema/column.d.mts +2 -2
  37. package/dist/schema/column.mjs +2 -2
  38. package/dist/schema/column.mjs.map +1 -1
  39. package/dist/schema/columns/index.cjs +12 -0
  40. package/dist/schema/columns/index.cjs.map +1 -1
  41. package/dist/schema/columns/index.d.cts +10 -2
  42. package/dist/schema/columns/index.d.mts +10 -2
  43. package/dist/schema/columns/index.mjs +12 -1
  44. package/dist/schema/columns/index.mjs.map +1 -1
  45. package/dist/schema/table.cjs +2 -1
  46. package/dist/schema/table.cjs.map +1 -1
  47. package/dist/schema/table.d.cts +4 -2
  48. package/dist/schema/table.d.mts +4 -2
  49. package/dist/schema/table.mjs +2 -1
  50. package/dist/schema/table.mjs.map +1 -1
  51. package/dist/types.d.cts +101 -3
  52. package/dist/types.d.mts +101 -3
  53. package/package.json +1 -1
@@ -127,6 +127,29 @@ var CacheManager = class {
127
127
  get isEnabled() {
128
128
  return this.enabled;
129
129
  }
130
+ /**
131
+ * Get a cached query result or execute the query with per-table cache config override
132
+ * @param {string} table - Table name
133
+ * @param {string} method - Method name (find, findFirst, etc.)
134
+ * @param {unknown} options - Query options
135
+ * @param {() => Promise<T>} executor - Function that executes the query
136
+ * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
137
+ * @returns {Promise<T>} The query result
138
+ */
139
+ async getOrSetWithTableConfig(table, method, options, executor, tableConfig) {
140
+ if (!(tableConfig ? tableConfig.enabled : this.enabled)) return executor();
141
+ const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;
142
+ const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;
143
+ const key = this.buildKey(table, method, options);
144
+ const cached = this.store.get(key);
145
+ if (cached !== void 0) {
146
+ this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);
147
+ return cached;
148
+ }
149
+ const result = await executor();
150
+ this.store.set(key, result, effectiveTtl);
151
+ return result;
152
+ }
130
153
  buildKey(table, method, options) {
131
154
  return `query:${table}:${method}:${require_stable_stringify.stableStringify(options)}`;
132
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.cjs","names":["DEFAULT_CACHE_TTL","DEFAULT_CACHE_MAX_TTL","MemoryStore","DEFAULT_CACHE_MAX_ENTRIES","stableStringify"],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":";;;;;;;AAQA,IAAa,eAAb,MAA0B;CACxB;CACA;CACA;CACA;CAEA,YAAY,QAAgC;AAC1C,MAAI,OAAO,WAAW,WAAW;AAC/B,QAAK,UAAU;AACf,QAAK,UAAUA,kBAAAA;AACf,QAAK,SAASC,kBAAAA;AACd,QAAK,QAAQ,IAAIC,qBAAAA,YAAYC,kBAAAA,0BAA0B;aAC9C,QAAQ;AACjB,QAAK,UAAU,OAAO;AACtB,QAAK,UAAU,OAAO,OAAA;AACtB,QAAK,SAAS,OAAO,UAAA;AACrB,QAAK,QAAQ,IAAID,qBAAAA,YAAY,OAAO,cAAA,IAAwC;SACvE;AACL,QAAK,UAAU;AACf,QAAK,UAAUF,kBAAAA;AACf,QAAK,SAASC,kBAAAA;AACd,QAAK,QAAQ,IAAIC,qBAAAA,aAAa;;;;;;;;;;;CAYlC,MAAM,SACJ,OACA,QACA,SACA,UACY;AACZ,MAAI,CAAC,KAAK,QACR,QAAO,UAAU;EAGnB,MAAM,MAAM,KAAK,SAAS,OAAO,QAAQ,QAAQ;EACjD,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,MAAI,WAAW,KAAA,GAAW;AACxB,QAAK,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK,OAAO;AACpD,UAAO;;EAGT,MAAM,SAAS,MAAM,UAAU;AAC/B,OAAK,MAAM,IAAI,KAAK,QAAQ,KAAK,QAAQ;AACzC,SAAO;;;;;;;;CAST,UAAU,OAAe,IAAqB,MAAqB;AACjE,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;AAC/B,OAAK,MAAM,IAAI,KAAK,MAAM,KAAK,QAAQ;;;;;;;;CASzC,UAAU,OAAe,IAA0C;AACjE,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;EAC/B,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,MAAI,WAAW,KAAA,EACb,MAAK,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK,OAAO;AAEtD,SAAO;;;;;;CAOT,gBAAgB,OAAqB;AACnC,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;AAChD,OAAK,MAAM,mBAAmB,UAAU,MAAM,GAAG;;;;;;;CAQnD,iBAAiB,OAAe,IAA2B;AACzD,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,MAAM,OAAO,UAAU,MAAM,GAAG,KAAK;AAC1C,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;;;;;;;;CASlD,aAAa,OAAe,IAAqB,MAAqC;AACpF,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;EAC/B,MAAM,WAAW,KAAK,MAAM,IAAI,IAAI;AACpC,MAAI,YAAY,OAAO,aAAa,SAClC,MAAK,MAAM,IAAI,KAAK;GAAE,GAAG;GAAU,GAAG;GAAM,EAAE,KAAK,QAAQ;AAE7D,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;;;;;CAMlD,QAAc;AACZ,OAAK,MAAM,OAAO;;;;;;CAOpB,IAAI,OAAe;AACjB,SAAO,KAAK,MAAM;;;;;;CAOpB,IAAI,YAAqB;AACvB,SAAO,KAAK;;CAGd,SAAiB,OAAe,QAAgB,SAA0B;AACxE,SAAO,SAAS,MAAM,GAAG,OAAO,GAAGE,yBAAAA,gBAAgB,QAAQ"}
1
+ {"version":3,"file":"manager.cjs","names":["DEFAULT_CACHE_TTL","DEFAULT_CACHE_MAX_TTL","MemoryStore","DEFAULT_CACHE_MAX_ENTRIES","stableStringify"],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get a cached query result or execute the query with per-table cache config override\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config\n * @returns {Promise<T>} The query result\n */\n async getOrSetWithTableConfig<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n tableConfig?: { enabled: boolean; ttl?: number; maxTtl?: number },\n ): Promise<T> {\n const effectiveEnabled = tableConfig ? tableConfig.enabled : this.enabled;\n if (!effectiveEnabled) {\n return executor();\n }\n\n const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;\n const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, effectiveTtl);\n return result;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":"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"}
@@ -65,6 +65,20 @@ declare class CacheManager {
65
65
  * @returns {boolean} Whether caching is enabled
66
66
  */
67
67
  get isEnabled(): boolean;
68
+ /**
69
+ * Get a cached query result or execute the query with per-table cache config override
70
+ * @param {string} table - Table name
71
+ * @param {string} method - Method name (find, findFirst, etc.)
72
+ * @param {unknown} options - Query options
73
+ * @param {() => Promise<T>} executor - Function that executes the query
74
+ * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
75
+ * @returns {Promise<T>} The query result
76
+ */
77
+ getOrSetWithTableConfig<T>(table: string, method: string, options: unknown, executor: () => Promise<T>, tableConfig?: {
78
+ enabled: boolean;
79
+ ttl?: number;
80
+ maxTtl?: number;
81
+ }): Promise<T>;
68
82
  private buildKey;
69
83
  }
70
84
  //#endregion
@@ -65,6 +65,20 @@ declare class CacheManager {
65
65
  * @returns {boolean} Whether caching is enabled
66
66
  */
67
67
  get isEnabled(): boolean;
68
+ /**
69
+ * Get a cached query result or execute the query with per-table cache config override
70
+ * @param {string} table - Table name
71
+ * @param {string} method - Method name (find, findFirst, etc.)
72
+ * @param {unknown} options - Query options
73
+ * @param {() => Promise<T>} executor - Function that executes the query
74
+ * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
75
+ * @returns {Promise<T>} The query result
76
+ */
77
+ getOrSetWithTableConfig<T>(table: string, method: string, options: unknown, executor: () => Promise<T>, tableConfig?: {
78
+ enabled: boolean;
79
+ ttl?: number;
80
+ maxTtl?: number;
81
+ }): Promise<T>;
68
82
  private buildKey;
69
83
  }
70
84
  //#endregion
@@ -130,6 +130,29 @@ var CacheManager = class {
130
130
  get isEnabled() {
131
131
  return this.enabled;
132
132
  }
133
+ /**
134
+ * Get a cached query result or execute the query with per-table cache config override
135
+ * @param {string} table - Table name
136
+ * @param {string} method - Method name (find, findFirst, etc.)
137
+ * @param {unknown} options - Query options
138
+ * @param {() => Promise<T>} executor - Function that executes the query
139
+ * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config
140
+ * @returns {Promise<T>} The query result
141
+ */
142
+ async getOrSetWithTableConfig(table, method, options, executor, tableConfig) {
143
+ if (!(tableConfig ? tableConfig.enabled : this.enabled)) return executor();
144
+ const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;
145
+ const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;
146
+ const key = this.buildKey(table, method, options);
147
+ const cached = this.store.get(key);
148
+ if (cached !== void 0) {
149
+ this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);
150
+ return cached;
151
+ }
152
+ const result = await executor();
153
+ this.store.set(key, result, effectiveTtl);
154
+ return result;
155
+ }
133
156
  buildKey(table, method, options) {
134
157
  return `query:${table}:${method}:${stableStringify(options)}`;
135
158
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manager.mjs","names":[],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":";;;;;gBAAmG;YAExD;;;;AAM3C,IAAa,eAAb,MAA0B;CACxB;CACA;CACA;CACA;CAEA,YAAY,QAAgC;AAC1C,MAAI,OAAO,WAAW,WAAW;AAC/B,QAAK,UAAU;AACf,QAAK,UAAU;AACf,QAAK,SAAS;AACd,QAAK,QAAQ,IAAI,YAAY,0BAA0B;aAC9C,QAAQ;AACjB,QAAK,UAAU,OAAO;AACtB,QAAK,UAAU,OAAO,OAAA;AACtB,QAAK,SAAS,OAAO,UAAA;AACrB,QAAK,QAAQ,IAAI,YAAY,OAAO,cAAA,IAAwC;SACvE;AACL,QAAK,UAAU;AACf,QAAK,UAAU;AACf,QAAK,SAAS;AACd,QAAK,QAAQ,IAAI,aAAa;;;;;;;;;;;CAYlC,MAAM,SACJ,OACA,QACA,SACA,UACY;AACZ,MAAI,CAAC,KAAK,QACR,QAAO,UAAU;EAGnB,MAAM,MAAM,KAAK,SAAS,OAAO,QAAQ,QAAQ;EACjD,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,MAAI,WAAW,KAAA,GAAW;AACxB,QAAK,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK,OAAO;AACpD,UAAO;;EAGT,MAAM,SAAS,MAAM,UAAU;AAC/B,OAAK,MAAM,IAAI,KAAK,QAAQ,KAAK,QAAQ;AACzC,SAAO;;;;;;;;CAST,UAAU,OAAe,IAAqB,MAAqB;AACjE,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;AAC/B,OAAK,MAAM,IAAI,KAAK,MAAM,KAAK,QAAQ;;;;;;;;CASzC,UAAU,OAAe,IAA0C;AACjE,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;EAC/B,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,MAAI,WAAW,KAAA,EACb,MAAK,MAAM,UAAU,KAAK,KAAK,SAAS,KAAK,OAAO;AAEtD,SAAO;;;;;;CAOT,gBAAgB,OAAqB;AACnC,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;AAChD,OAAK,MAAM,mBAAmB,UAAU,MAAM,GAAG;;;;;;;CAQnD,iBAAiB,OAAe,IAA2B;AACzD,MAAI,CAAC,KAAK,QACR;AAEF,OAAK,MAAM,OAAO,UAAU,MAAM,GAAG,KAAK;AAC1C,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;;;;;;;;CASlD,aAAa,OAAe,IAAqB,MAAqC;AACpF,MAAI,CAAC,KAAK,QACR;EAEF,MAAM,MAAM,UAAU,MAAM,GAAG;EAC/B,MAAM,WAAW,KAAK,MAAM,IAAI,IAAI;AACpC,MAAI,YAAY,OAAO,aAAa,SAClC,MAAK,MAAM,IAAI,KAAK;GAAE,GAAG;GAAU,GAAG;GAAM,EAAE,KAAK,QAAQ;AAE7D,OAAK,MAAM,mBAAmB,SAAS,MAAM,GAAG;;;;;CAMlD,QAAc;AACZ,OAAK,MAAM,OAAO;;;;;;CAOpB,IAAI,OAAe;AACjB,SAAO,KAAK,MAAM;;;;;;CAOpB,IAAI,YAAqB;AACvB,SAAO,KAAK;;CAGd,SAAiB,OAAe,QAAgB,SAA0B;AACxE,SAAO,SAAS,MAAM,GAAG,OAAO,GAAG,gBAAgB,QAAQ"}
1
+ {"version":3,"file":"manager.mjs","names":[],"sources":["../../src/cache/manager.ts"],"sourcesContent":["import { DEFAULT_CACHE_MAX_ENTRIES, DEFAULT_CACHE_MAX_TTL, DEFAULT_CACHE_TTL } from \"../constants\";\nimport type { CacheConfig } from \"../types\";\nimport { stableStringify } from \"../utils\";\nimport { MemoryStore } from \"./memory-store\";\n\n/**\n * Cache manager that wraps query execution with caching behavior\n */\nexport class CacheManager {\n private store: MemoryStore;\n private baseTtl: number;\n private maxTtl: number;\n private enabled: boolean;\n\n constructor(config?: boolean | CacheConfig) {\n if (typeof config === \"boolean\") {\n this.enabled = config;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(DEFAULT_CACHE_MAX_ENTRIES);\n } else if (config) {\n this.enabled = config.enabled;\n this.baseTtl = config.ttl ?? DEFAULT_CACHE_TTL;\n this.maxTtl = config.maxTtl ?? DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore(config.maxEntries ?? DEFAULT_CACHE_MAX_ENTRIES);\n } else {\n this.enabled = false;\n this.baseTtl = DEFAULT_CACHE_TTL;\n this.maxTtl = DEFAULT_CACHE_MAX_TTL;\n this.store = new MemoryStore();\n }\n }\n\n /**\n * Get a cached query result or execute the query and cache the result\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @returns {Promise<T>} The query result\n */\n async getOrSet<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n ): Promise<T> {\n if (!this.enabled) {\n return executor();\n }\n\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, this.baseTtl);\n return result;\n }\n\n /**\n * Set an entity in the cache by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {unknown} data - Entity data\n */\n setEntity(table: string, id: string | number, data: unknown): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n this.store.set(key, data, this.baseTtl);\n }\n\n /**\n * Get a cached entity by primary key\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @returns {unknown | undefined} Cached entity or undefined\n */\n getEntity(table: string, id: string | number): unknown | undefined {\n if (!this.enabled) {\n return undefined;\n }\n const key = `entity:${table}:${id}`;\n const result = this.store.get(key);\n if (result !== undefined) {\n this.store.extendTtl(key, this.baseTtl, this.maxTtl);\n }\n return result;\n }\n\n /**\n * Invalidate all cache entries for a table\n * @param {string} table - Table name\n */\n invalidateTable(table: string): void {\n if (!this.enabled) {\n return;\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n this.store.invalidateByPrefix(`entity:${table}:`);\n }\n\n /**\n * Invalidate a specific entity cache entry\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n */\n invalidateEntity(table: string, id: string | number): void {\n if (!this.enabled) {\n return;\n }\n this.store.delete(`entity:${table}:${id}`);\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Update an entity in cache if it exists\n * @param {string} table - Table name\n * @param {string | number} id - Primary key value\n * @param {Record<string, unknown>} data - Updated data\n */\n updateEntity(table: string, id: string | number, data: Record<string, unknown>): void {\n if (!this.enabled) {\n return;\n }\n const key = `entity:${table}:${id}`;\n const existing = this.store.get(key);\n if (existing && typeof existing === \"object\") {\n this.store.set(key, { ...existing, ...data }, this.baseTtl);\n }\n this.store.invalidateByPrefix(`query:${table}:`);\n }\n\n /**\n * Clear the entire cache\n */\n clear(): void {\n this.store.clear();\n }\n\n /**\n * Get the number of cached entries\n * @returns {number} Cache size\n */\n get size(): number {\n return this.store.size;\n }\n\n /**\n * Check if caching is enabled\n * @returns {boolean} Whether caching is enabled\n */\n get isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Get a cached query result or execute the query with per-table cache config override\n * @param {string} table - Table name\n * @param {string} method - Method name (find, findFirst, etc.)\n * @param {unknown} options - Query options\n * @param {() => Promise<T>} executor - Function that executes the query\n * @param {{ enabled: boolean; ttl?: number; maxTtl?: number }} [tableConfig] - Per-table cache config\n * @returns {Promise<T>} The query result\n */\n async getOrSetWithTableConfig<T>(\n table: string,\n method: string,\n options: unknown,\n executor: () => Promise<T>,\n tableConfig?: { enabled: boolean; ttl?: number; maxTtl?: number },\n ): Promise<T> {\n const effectiveEnabled = tableConfig ? tableConfig.enabled : this.enabled;\n if (!effectiveEnabled) {\n return executor();\n }\n\n const effectiveTtl = tableConfig?.ttl ?? this.baseTtl;\n const effectiveMaxTtl = tableConfig?.maxTtl ?? this.maxTtl;\n const key = this.buildKey(table, method, options);\n const cached = this.store.get(key);\n if (cached !== undefined) {\n this.store.extendTtl(key, effectiveTtl, effectiveMaxTtl);\n return cached as T;\n }\n\n const result = await executor();\n this.store.set(key, result, effectiveTtl);\n return result;\n }\n\n private buildKey(table: string, method: string, options: unknown): string {\n return `query:${table}:${method}:${stableStringify(options)}`;\n }\n}\n"],"mappings":"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"}
@@ -12,8 +12,9 @@ let path = require("path");
12
12
  function createMigration(name, path$1) {
13
13
  const dir = path$1 ?? "src/database/migrations";
14
14
  require_fs.ensureDir(dir);
15
- const filePath = (0, path.join)(dir, `${require_naming.generateTimestamp()}_${name}.ts`);
16
- require_fs.writeFileSafe(filePath, require_templates.generateMigrationTemplate(name));
15
+ const timestamp = require_naming.generateTimestamp();
16
+ const filePath = (0, path.join)(dir, `${timestamp}_${name}.ts`);
17
+ require_fs.writeFileSafe(filePath, require_templates.generateMigrationTemplate(`${timestamp}_${name}`));
17
18
  console.log(`Created migration: ${filePath}`);
18
19
  }
19
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"migration.cjs","names":["path","generateTimestamp","generateMigrationTemplate"],"sources":["../../../src/cli/commands/migration.ts"],"sourcesContent":["import { join } from \"path\";\nimport { DEFAULT_MIGRATIONS_PATH } from \"../../constants\";\nimport { generateMigrationTemplate } from \"../../migrations\";\nimport { ensureDir, writeFileSafe } from \"../../utils\";\nimport { generateTimestamp } from \"../../utils/naming\";\n\n/**\n * Create a new migration file\n * @param {string} name - Migration name\n * @param {string} [path] - Output directory\n */\nexport function createMigration(name: string, path?: string): void {\n const dir = path ?? DEFAULT_MIGRATIONS_PATH;\n ensureDir(dir);\n\n const timestamp = generateTimestamp();\n const fileName = `${timestamp}_${name}.ts`;\n const filePath = join(dir, fileName);\n const content = generateMigrationTemplate(name);\n\n writeFileSafe(filePath, content);\n console.log(`Created migration: ${filePath}`);\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,gBAAgB,MAAc,QAAqB;CACjE,MAAM,MAAMA,UAAAA;AACZ,YAAA,UAAU,IAAI;CAId,MAAM,YAAA,GAAA,KAAA,MAAgB,KADL,GADCC,eAAAA,mBAAmB,CACP,GAAG,KAAK,KACF;AAGpC,YAAA,cAAc,UAFEC,kBAAAA,0BAA0B,KAAK,CAEf;AAChC,SAAQ,IAAI,sBAAsB,WAAW"}
1
+ {"version":3,"file":"migration.cjs","names":["path","generateTimestamp","generateMigrationTemplate"],"sources":["../../../src/cli/commands/migration.ts"],"sourcesContent":["import { join } from \"path\";\nimport { DEFAULT_MIGRATIONS_PATH } from \"../../constants\";\nimport { generateMigrationTemplate } from \"../../migrations\";\nimport { ensureDir, writeFileSafe } from \"../../utils\";\nimport { generateTimestamp } from \"../../utils/naming\";\n\n/**\n * Create a new migration file\n * @param {string} name - Migration name\n * @param {string} [path] - Output directory\n */\nexport function createMigration(name: string, path?: string): void {\n const dir = path ?? DEFAULT_MIGRATIONS_PATH;\n ensureDir(dir);\n\n const timestamp = generateTimestamp();\n const fileName = `${timestamp}_${name}.ts`;\n const filePath = join(dir, fileName);\n const migrationId = `${timestamp}_${name}`;\n const content = generateMigrationTemplate(migrationId);\n\n writeFileSafe(filePath, content);\n console.log(`Created migration: ${filePath}`);\n}\n"],"mappings":";;;;;;;;;;;AAWA,SAAgB,gBAAgB,MAAc,QAAqB;CACjE,MAAM,MAAMA,UAAAA;AACZ,YAAA,UAAU,IAAI;CAEd,MAAM,YAAYC,eAAAA,mBAAmB;CAErC,MAAM,YAAA,GAAA,KAAA,MAAgB,KADL,GAAG,UAAU,GAAG,KAAK,KACF;AAIpC,YAAA,cAAc,UAFEC,kBAAAA,0BADI,GAAG,UAAU,GAAG,OACkB,CAEtB;AAChC,SAAQ,IAAI,sBAAsB,WAAW"}
@@ -15,8 +15,9 @@ import { join } from "path";
15
15
  function createMigration(name, path) {
16
16
  const dir = path ?? "src/database/migrations";
17
17
  ensureDir(dir);
18
- const filePath = join(dir, `${generateTimestamp()}_${name}.ts`);
19
- writeFileSafe(filePath, generateMigrationTemplate(name));
18
+ const timestamp = generateTimestamp();
19
+ const filePath = join(dir, `${timestamp}_${name}.ts`);
20
+ writeFileSafe(filePath, generateMigrationTemplate(`${timestamp}_${name}`));
20
21
  console.log(`Created migration: ${filePath}`);
21
22
  }
22
23
  var init_migration = __esmMin((() => {
@@ -1 +1 @@
1
- {"version":3,"file":"migration.mjs","names":[],"sources":["../../../src/cli/commands/migration.ts"],"sourcesContent":["import { join } from \"path\";\nimport { DEFAULT_MIGRATIONS_PATH } from \"../../constants\";\nimport { generateMigrationTemplate } from \"../../migrations\";\nimport { ensureDir, writeFileSafe } from \"../../utils\";\nimport { generateTimestamp } from \"../../utils/naming\";\n\n/**\n * Create a new migration file\n * @param {string} name - Migration name\n * @param {string} [path] - Output directory\n */\nexport function createMigration(name: string, path?: string): void {\n const dir = path ?? DEFAULT_MIGRATIONS_PATH;\n ensureDir(dir);\n\n const timestamp = generateTimestamp();\n const fileName = `${timestamp}_${name}.ts`;\n const filePath = join(dir, fileName);\n const content = generateMigrationTemplate(name);\n\n writeFileSafe(filePath, content);\n console.log(`Created migration: ${filePath}`);\n}\n"],"mappings":";;;;;;;;;;;;;;AAWA,SAAgB,gBAAgB,MAAc,MAAqB;CACjE,MAAM,MAAM,QAAA;AACZ,WAAU,IAAI;CAId,MAAM,WAAW,KAAK,KADL,GADC,mBAAmB,CACP,GAAG,KAAK,KACF;AAGpC,eAAc,UAFE,0BAA0B,KAAK,CAEf;AAChC,SAAQ,IAAI,sBAAsB,WAAW;;;iBApBW;kBACG;aACN;cACA"}
1
+ {"version":3,"file":"migration.mjs","names":[],"sources":["../../../src/cli/commands/migration.ts"],"sourcesContent":["import { join } from \"path\";\nimport { DEFAULT_MIGRATIONS_PATH } from \"../../constants\";\nimport { generateMigrationTemplate } from \"../../migrations\";\nimport { ensureDir, writeFileSafe } from \"../../utils\";\nimport { generateTimestamp } from \"../../utils/naming\";\n\n/**\n * Create a new migration file\n * @param {string} name - Migration name\n * @param {string} [path] - Output directory\n */\nexport function createMigration(name: string, path?: string): void {\n const dir = path ?? DEFAULT_MIGRATIONS_PATH;\n ensureDir(dir);\n\n const timestamp = generateTimestamp();\n const fileName = `${timestamp}_${name}.ts`;\n const filePath = join(dir, fileName);\n const migrationId = `${timestamp}_${name}`;\n const content = generateMigrationTemplate(migrationId);\n\n writeFileSafe(filePath, content);\n console.log(`Created migration: ${filePath}`);\n}\n"],"mappings":";;;;;;;;;;;;;;AAWA,SAAgB,gBAAgB,MAAc,MAAqB;CACjE,MAAM,MAAM,QAAA;AACZ,WAAU,IAAI;CAEd,MAAM,YAAY,mBAAmB;CAErC,MAAM,WAAW,KAAK,KADL,GAAG,UAAU,GAAG,KAAK,KACF;AAIpC,eAAc,UAFE,0BADI,GAAG,UAAU,GAAG,OACkB,CAEtB;AAChC,SAAQ,IAAI,sBAAsB,WAAW;;;iBArBW;kBACG;aACN;cACA"}
@@ -10,9 +10,14 @@ const require_repository = require("./repository.cjs");
10
10
  * @param {DatabaseConfig} config - Database configuration
11
11
  * @returns {DatabaseInstance<S>} Database instance with table repositories
12
12
  */
13
+ function normalizeSchemas(schemas) {
14
+ if (Array.isArray(schemas)) return schemas;
15
+ return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
16
+ }
13
17
  function database(config) {
18
+ const schemas = normalizeSchemas(config.schemas);
14
19
  const registry = new require_registry.SchemaRegistry();
15
- registry.register(config.schemas);
20
+ registry.register(schemas);
16
21
  const connectionConfig = Array.isArray(config.connection) ? config.connection[0] : config.connection;
17
22
  if (!connectionConfig) throw new require_errors.DatabaseError("Connection config is required");
18
23
  const driver = require_index.createDriver(config.database, connectionConfig);
@@ -45,8 +50,8 @@ function database(config) {
45
50
  if (config.runMigrations && config.migrations && config.migrations.length > 0) await runMigrations(driver, registry, config.migrations);
46
51
  };
47
52
  const repos = /* @__PURE__ */ new Map();
48
- for (const schema of config.schemas) {
49
- const repo = new require_repository.TableRepository(schema.__name, driver, cache, registry);
53
+ for (const schema of schemas) {
54
+ const repo = new require_repository.TableRepository(schema.__name, driver, cache, registry, schema.__cache);
50
55
  repos.set(schema.__name, repo);
51
56
  }
52
57
  const instance = {
@@ -71,7 +76,7 @@ function database(config) {
71
76
  return driver.transaction(fn);
72
77
  }
73
78
  };
74
- for (const schema of config.schemas) {
79
+ for (const schema of schemas) {
75
80
  const repo = repos.get(schema.__name);
76
81
  const proxy = new Proxy(repo, { get(target, prop, receiver) {
77
82
  const original = Reflect.get(target, prop, receiver);
@@ -1 +1 @@
1
- {"version":3,"file":"database.cjs","names":["SchemaRegistry","DatabaseError","createDriver","CacheManager","TableRepository","MIGRATIONS_TABLE"],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S extends readonly AnyTableDef[]> = {\n [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T>;\n};\n\ntype DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nexport function database<S extends readonly AnyTableDef[]>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const registry = new SchemaRegistry();\n registry.register(config.schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations && config.migrations.length > 0) {\n await runMigrations(driver, registry, config.migrations);\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of config.schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of config.schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.cjs","names":["SchemaRegistry","DatabaseError","createDriver","CacheManager","TableRepository","MIGRATIONS_TABLE"],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations && config.migrations.length > 0) {\n await runMigrations(driver, registry, config.migrations);\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { AnyTableDef, DatabaseConfig, DatabaseDriver, DeleteOptions, InferRow, QueryOptions, RelationQueryMap, ResolveResult, UpdateOptions, WhereClause } from "../types.cjs";
1
+ import { AnyTableDef, DatabaseConfig, DatabaseDriver, DeleteOptions, InferRow, InferSchemas, QueryOptions, RelationQueryMap, ResolveResult, UpdateOptions, WhereClause } from "../types.cjs";
2
2
  import { CacheManager } from "../cache/manager.cjs";
3
3
  import { SchemaRegistry } from "../schema/registry.cjs";
4
4
 
@@ -20,8 +20,8 @@ type TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDe
20
20
  }): Promise<InferRow<T>>;
21
21
  truncate(): Promise<void>;
22
22
  };
23
- type ExtractRepos<S extends readonly AnyTableDef[]> = { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> };
24
- type DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {
23
+ type ExtractRepos<S> = S extends readonly AnyTableDef[] ? { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> } : S extends Record<string, any> ? { [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<InferSchemas<S>, Extract<S[K], AnyTableDef>> } : never;
24
+ type DatabaseInstance<S> = ExtractRepos<S> & {
25
25
  /**
26
26
  * Initialize the database connection, create tables and run migrations
27
27
  * @returns {Promise<void>}
@@ -61,12 +61,7 @@ type DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {
61
61
  */
62
62
  transaction<T>(fn: () => Promise<T>): Promise<T>;
63
63
  };
64
- /**
65
- * Create a database instance with typed repositories for each schema
66
- * @param {DatabaseConfig} config - Database configuration
67
- * @returns {DatabaseInstance<S>} Database instance with table repositories
68
- */
69
- declare function database<S extends readonly AnyTableDef[]>(config: DatabaseConfig & {
64
+ declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
70
65
  schemas: S;
71
66
  }): DatabaseInstance<S>;
72
67
  //#endregion
@@ -1,4 +1,4 @@
1
- import { AnyTableDef, DatabaseConfig, DatabaseDriver, DeleteOptions, InferRow, QueryOptions, RelationQueryMap, ResolveResult, UpdateOptions, WhereClause } from "../types.mjs";
1
+ import { AnyTableDef, DatabaseConfig, DatabaseDriver, DeleteOptions, InferRow, InferSchemas, QueryOptions, RelationQueryMap, ResolveResult, UpdateOptions, WhereClause } from "../types.mjs";
2
2
  import { CacheManager } from "../cache/manager.mjs";
3
3
  import { SchemaRegistry } from "../schema/registry.mjs";
4
4
 
@@ -20,8 +20,8 @@ type TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDe
20
20
  }): Promise<InferRow<T>>;
21
21
  truncate(): Promise<void>;
22
22
  };
23
- type ExtractRepos<S extends readonly AnyTableDef[]> = { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> };
24
- type DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {
23
+ type ExtractRepos<S> = S extends readonly AnyTableDef[] ? { [T in S[number] as T["__name"]]: TypedTableRepository<S, T> } : S extends Record<string, any> ? { [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<InferSchemas<S>, Extract<S[K], AnyTableDef>> } : never;
24
+ type DatabaseInstance<S> = ExtractRepos<S> & {
25
25
  /**
26
26
  * Initialize the database connection, create tables and run migrations
27
27
  * @returns {Promise<void>}
@@ -61,12 +61,7 @@ type DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {
61
61
  */
62
62
  transaction<T>(fn: () => Promise<T>): Promise<T>;
63
63
  };
64
- /**
65
- * Create a database instance with typed repositories for each schema
66
- * @param {DatabaseConfig} config - Database configuration
67
- * @returns {DatabaseInstance<S>} Database instance with table repositories
68
- */
69
- declare function database<S extends readonly AnyTableDef[]>(config: DatabaseConfig & {
64
+ declare function database<const S extends readonly AnyTableDef[] | Record<string, any>>(config: DatabaseConfig & {
70
65
  schemas: S;
71
66
  }): DatabaseInstance<S>;
72
67
  //#endregion
@@ -11,9 +11,14 @@ init_constants();
11
11
  * @param {DatabaseConfig} config - Database configuration
12
12
  * @returns {DatabaseInstance<S>} Database instance with table repositories
13
13
  */
14
+ function normalizeSchemas(schemas) {
15
+ if (Array.isArray(schemas)) return schemas;
16
+ return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
17
+ }
14
18
  function database(config) {
19
+ const schemas = normalizeSchemas(config.schemas);
15
20
  const registry = new SchemaRegistry();
16
- registry.register(config.schemas);
21
+ registry.register(schemas);
17
22
  const connectionConfig = Array.isArray(config.connection) ? config.connection[0] : config.connection;
18
23
  if (!connectionConfig) throw new DatabaseError("Connection config is required");
19
24
  const driver = createDriver(config.database, connectionConfig);
@@ -46,8 +51,8 @@ function database(config) {
46
51
  if (config.runMigrations && config.migrations && config.migrations.length > 0) await runMigrations(driver, registry, config.migrations);
47
52
  };
48
53
  const repos = /* @__PURE__ */ new Map();
49
- for (const schema of config.schemas) {
50
- const repo = new TableRepository(schema.__name, driver, cache, registry);
54
+ for (const schema of schemas) {
55
+ const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);
51
56
  repos.set(schema.__name, repo);
52
57
  }
53
58
  const instance = {
@@ -72,7 +77,7 @@ function database(config) {
72
77
  return driver.transaction(fn);
73
78
  }
74
79
  };
75
- for (const schema of config.schemas) {
80
+ for (const schema of schemas) {
76
81
  const repo = repos.get(schema.__name);
77
82
  const proxy = new Proxy(repo, { get(target, prop, receiver) {
78
83
  const original = Reflect.get(target, prop, receiver);
@@ -1 +1 @@
1
- {"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S extends readonly AnyTableDef[]> = {\n [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T>;\n};\n\ntype DatabaseInstance<S extends readonly AnyTableDef[]> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nexport function database<S extends readonly AnyTableDef[]>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const registry = new SchemaRegistry();\n registry.register(config.schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations && config.migrations.length > 0) {\n await runMigrations(driver, registry, config.migrations);\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of config.schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of config.schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.mjs","names":[],"sources":["../../src/core/database.ts"],"sourcesContent":["import { CacheManager } from \"../cache\";\nimport { MIGRATIONS_TABLE } from \"../constants\";\nimport { createDriver } from \"../drivers\";\nimport { DatabaseError } from \"../errors\";\nimport { SchemaRegistry } from \"../schema\";\nimport type {\n AnyTableDef,\n ConnectionConfig,\n DatabaseConfig,\n DatabaseDriver,\n DeleteOptions,\n InferRow,\n InferSchemas,\n MigrationDefinition,\n QueryOptions,\n RelationQueryMap,\n ResolveResult,\n TableMetadata,\n UpdateOptions,\n WhereClause,\n} from \"../types\";\nimport { TableRepository } from \"./repository\";\n\ntype TypedTableRepository<S extends readonly AnyTableDef[], T extends AnyTableDef> = {\n find<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findMany<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O>[]>;\n\n findFirst<O extends QueryOptions<InferRow<T>, RelationQueryMap<S, T>> = {}>(\n options?: O,\n ): Promise<ResolveResult<S, T, O> | null>;\n\n insert(data: Partial<InferRow<T>> | Partial<InferRow<T>>[]): Promise<InferRow<T>>;\n insertMany(data: Partial<InferRow<T>>[]): Promise<InferRow<T>[]>;\n update(options: UpdateOptions<InferRow<T>>): Promise<InferRow<T>[]>;\n delete(options: DeleteOptions<InferRow<T>>): Promise<number>;\n count(options?: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<number>;\n exists(options: Pick<QueryOptions<InferRow<T>>, \"where\">): Promise<boolean>;\n upsert(options: {\n where: WhereClause<InferRow<T>>;\n create: Partial<InferRow<T>>;\n update: Partial<InferRow<T>>;\n }): Promise<InferRow<T>>;\n truncate(): Promise<void>;\n};\n\ntype ExtractRepos<S> = S extends readonly AnyTableDef[]\n ? { [T in S[number] as T[\"__name\"]]: TypedTableRepository<S, T> }\n : S extends Record<string, any>\n ? {\n [K in keyof S as S[K] extends AnyTableDef ? K : never]: TypedTableRepository<\n InferSchemas<S>,\n Extract<S[K], AnyTableDef>\n >;\n }\n : never;\n\ntype DatabaseInstance<S> = ExtractRepos<S> & {\n /**\n * Initialize the database connection, create tables and run migrations\n * @returns {Promise<void>}\n */\n initialize(): Promise<void>;\n /**\n * Close the database connection\n * @returns {Promise<void>}\n */\n close(): Promise<void>;\n /**\n * Get the underlying database driver\n * @returns {DatabaseDriver} The database driver\n */\n getDriver(): DatabaseDriver;\n /**\n * Get the schema registry\n * @returns {SchemaRegistry} The schema registry\n */\n getRegistry(): SchemaRegistry;\n /**\n * Get the cache manager\n * @returns {CacheManager} The cache manager\n */\n getCache(): CacheManager;\n /**\n * Execute a raw SQL query\n * @param {string} sql - SQL query\n * @param {unknown[]} [params] - Query parameters\n * @returns {Promise<any[]>} Query results\n */\n raw(sql: string, params?: unknown[]): Promise<any[]>;\n /**\n * Execute within a transaction\n * @param {() => Promise<T>} fn - Function to execute\n * @returns {Promise<T>} Result\n */\n transaction<T>(fn: () => Promise<T>): Promise<T>;\n};\n\n/**\n * Create a database instance with typed repositories for each schema\n * @param {DatabaseConfig} config - Database configuration\n * @returns {DatabaseInstance<S>} Database instance with table repositories\n */\nfunction normalizeSchemas<S extends readonly AnyTableDef[]>(schemas: any): S {\n if (Array.isArray(schemas)) {\n return schemas as any as S;\n }\n return Object.values(schemas).filter(\n (v): v is AnyTableDef => v != null && typeof v === \"object\" && (v as any).__table === true,\n ) as any;\n}\n\nexport function database<const S extends readonly AnyTableDef[] | Record<string, any>>(\n config: DatabaseConfig & { schemas: S },\n): DatabaseInstance<S> {\n const schemas = normalizeSchemas(config.schemas) as any;\n const registry = new SchemaRegistry();\n registry.register(schemas);\n\n const connectionConfig = Array.isArray(config.connection)\n ? config.connection[0]\n : config.connection;\n\n if (!connectionConfig) {\n throw new DatabaseError(\"Connection config is required\");\n }\n\n const driver = createDriver(config.database, connectionConfig as ConnectionConfig);\n const cache = new CacheManager(config.cache);\n\n let initialized = false;\n let initPromise: Promise<void> | null = null;\n\n const ensureInitialized = async () => {\n if (initialized) {\n return;\n }\n if (initPromise) {\n return initPromise;\n }\n initPromise = doInit();\n await initPromise;\n initialized = true;\n };\n\n const doInit = async () => {\n await driver.connect();\n\n if (config.syncSchemas) {\n const allMetadata = driver.getAllTableColumns ? await driver.getAllTableColumns() : null;\n\n const syncPromises = Array.from(registry.getAllTables()).map(async ([, tableMeta]) => {\n const existingCols = allMetadata ? allMetadata[tableMeta.name] : null;\n const exists = allMetadata ? !!existingCols : await driver.tableExists(tableMeta.name);\n\n if (!exists) {\n await driver.createTable(tableMeta);\n } else {\n const cols = existingCols || (await driver.getTableColumns(tableMeta.name));\n const existingNames = new Set(cols.map((c) => c.name));\n const addColumnPromises = tableMeta.columns\n .filter((colMeta) => !existingNames.has(colMeta.name))\n .map((colMeta) => driver.addColumn(tableMeta.name, colMeta));\n await Promise.all(addColumnPromises);\n }\n });\n await Promise.all(syncPromises);\n }\n\n if (config.runMigrations && config.migrations && config.migrations.length > 0) {\n await runMigrations(driver, registry, config.migrations);\n }\n };\n\n const repos = new Map<string, TableRepository<any>>();\n for (const schema of schemas) {\n const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);\n repos.set(schema.__name, repo);\n }\n\n const instance: any = {\n initialize: async () => {\n await ensureInitialized();\n },\n close: async () => {\n await driver.disconnect();\n cache.clear();\n initialized = false;\n initPromise = null;\n },\n getDriver: () => driver,\n getRegistry: () => registry,\n getCache: () => cache,\n raw: async (sql: string, params?: unknown[]) => {\n await ensureInitialized();\n return driver.query(sql, params);\n },\n transaction: async <T>(fn: () => Promise<T>) => {\n await ensureInitialized();\n return driver.transaction(fn);\n },\n };\n\n for (const schema of schemas) {\n const repo = repos.get(schema.__name)!;\n const proxy = new Proxy(repo, {\n get(target, prop, receiver) {\n const original = Reflect.get(target, prop, receiver);\n if (typeof original === \"function\") {\n return async (...args: any[]) => {\n await ensureInitialized();\n return original.apply(target, args);\n };\n }\n return original;\n },\n });\n instance[schema.__name] = proxy;\n }\n\n return instance as any as DatabaseInstance<S>;\n}\n\nasync function runMigrations(\n driver: DatabaseDriver,\n registry: SchemaRegistry,\n migrations: MigrationDefinition[],\n): Promise<void> {\n const migrationsTableMeta: TableMetadata = {\n name: MIGRATIONS_TABLE,\n columns: [\n {\n name: \"id\",\n type: \"integer\",\n primaryKey: true,\n autoIncrement: true,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n },\n {\n name: \"name\",\n type: \"varchar\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: true,\n defaultValue: undefined,\n length: 255,\n },\n {\n name: \"executed_at\",\n type: \"datetime\",\n primaryKey: false,\n autoIncrement: false,\n notNull: true,\n unique: false,\n defaultValue: undefined,\n },\n ],\n };\n\n const exists = await driver.tableExists(MIGRATIONS_TABLE);\n if (!exists) {\n await driver.createTable(migrationsTableMeta);\n }\n\n const executed = await driver.query(`SELECT name FROM \\`${MIGRATIONS_TABLE}\\``);\n const executedNames = new Set(executed.map((r: any) => r.name));\n\n for (const migration of migrations) {\n if (executedNames.has(migration.name)) {\n continue;\n }\n\n const ctx = {\n schema: {\n createTable: async (tableDef: AnyTableDef) => {\n const meta = registry.getTable(tableDef.__name);\n if (meta) {\n await driver.createTable(meta);\n }\n },\n dropTable: async (name: string) => {\n await driver.dropTable(name);\n },\n addColumn: async (table: string, _name: string, column: any) => {\n await driver.addColumn(table, column);\n },\n dropColumn: async (table: string, name: string) => {\n await driver.dropColumn(table, name);\n },\n renameColumn: async (table: string, oldName: string, newName: string) => {\n await driver.renameColumn(table, oldName, newName);\n },\n addIndex: async () => {},\n dropIndex: async () => {},\n },\n sql: async (query: string, params?: unknown[]) => {\n return driver.execute(query, params);\n },\n };\n\n await migration.up(ctx);\n\n await driver.execute(\n `INSERT INTO \\`${MIGRATIONS_TABLE}\\` (\\`name\\`, \\`executed_at\\`) VALUES (?, ?)`,\n [migration.name, new Date()],\n );\n }\n}\n"],"mappings":"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"}
@@ -15,17 +15,27 @@ var TableRepository = class {
15
15
  columnMap;
16
16
  reverseColumnMap;
17
17
  hasAliases;
18
- constructor(tableName, driver, cache, registry) {
18
+ tableCacheConfig;
19
+ jsonColumns;
20
+ jsonCodeKeys;
21
+ constructor(tableName, driver, cache, registry, tableCacheConfig) {
19
22
  this.tableName = tableName;
20
23
  this.driver = driver;
21
24
  this.cache = cache;
22
25
  this.registry = registry;
26
+ this.tableCacheConfig = tableCacheConfig;
23
27
  const meta = registry.getTable(tableName);
24
28
  if (!meta) throw new require_errors.QueryError(`Table "${tableName}" is not registered`);
25
29
  this.meta = meta;
26
30
  this.columnMap = registry.getColumnMap(tableName);
27
31
  this.reverseColumnMap = registry.getReverseColumnMap(tableName);
28
32
  this.hasAliases = Object.entries(this.columnMap).some(([codeKey, dbName]) => codeKey !== dbName);
33
+ this.jsonColumns = new Set(meta.columns.filter((c) => c.type === "json" || c.type === "array").map((c) => c.name));
34
+ this.jsonCodeKeys = /* @__PURE__ */ new Set();
35
+ for (const col of meta.columns) if (col.type === "json" || col.type === "array") {
36
+ const codeKey = this.reverseColumnMap[col.name] ?? col.name;
37
+ this.jsonCodeKeys.add(codeKey);
38
+ }
29
39
  }
30
40
  /**
31
41
  * Find all rows matching the query options
@@ -33,7 +43,7 @@ var TableRepository = class {
33
43
  * @returns {Promise<T[]>} Array of matching rows
34
44
  */
35
45
  async find(options) {
36
- return this.cache.getOrSet(this.tableName, "find", options, async () => {
46
+ return this.cache.getOrSetWithTableConfig(this.tableName, "find", options, async () => {
37
47
  const dbOptions = this.mapOptionsToDb(options);
38
48
  let rows;
39
49
  if (this.driver instanceof require_file.FileDriver) rows = this.mapRows(this.findFile(dbOptions));
@@ -41,7 +51,7 @@ var TableRepository = class {
41
51
  if (options?.with) rows = await this.loadRelations(rows, options.with);
42
52
  this.cacheEntities(rows);
43
53
  return rows;
44
- });
54
+ }, this.tableCacheConfig);
45
55
  }
46
56
  /**
47
57
  * Find all rows matching the query options (alias for find)
@@ -57,7 +67,7 @@ var TableRepository = class {
57
67
  * @returns {Promise<T | null>} The first matching row or null
58
68
  */
59
69
  async findFirst(options) {
60
- return this.cache.getOrSet(this.tableName, "findFirst", options, async () => {
70
+ return this.cache.getOrSetWithTableConfig(this.tableName, "findFirst", options, async () => {
61
71
  const opts = {
62
72
  ...this.mapOptionsToDb(options),
63
73
  take: 1
@@ -70,7 +80,7 @@ var TableRepository = class {
70
80
  const row = rows[0] ?? null;
71
81
  if (row) this.cacheEntity(row);
72
82
  return row;
73
- });
83
+ }, this.tableCacheConfig);
74
84
  }
75
85
  /**
76
86
  * Insert one or more rows
@@ -168,7 +178,7 @@ var TableRepository = class {
168
178
  * @returns {Promise<number>} Row count
169
179
  */
170
180
  async count(options) {
171
- return this.cache.getOrSet(this.tableName, "count", options, async () => {
181
+ return this.cache.getOrSetWithTableConfig(this.tableName, "count", options, async () => {
172
182
  const dbWhere = options?.where ? this.mapWhereToDb(options.where) : void 0;
173
183
  if (this.driver instanceof require_file.FileDriver) {
174
184
  const filter = dbWhere ? this.buildFileFilter(dbWhere) : void 0;
@@ -178,7 +188,7 @@ var TableRepository = class {
178
188
  let sql = `SELECT COUNT(*) as count FROM \`${this.tableName}\``;
179
189
  if (dbWhere && Object.keys(dbWhere).length > 0) sql += ` WHERE ${require_sql_compiler.compileWhere(dbWhere, params)}`;
180
190
  return (await this.driver.query(sql, params))[0]?.count ?? 0;
181
- });
191
+ }, this.tableCacheConfig);
182
192
  }
183
193
  /**
184
194
  * Check if any row exists matching the where clause
@@ -355,7 +365,9 @@ var TableRepository = class {
355
365
  const cleaned = {};
356
366
  const dbColumnNames = new Set(this.meta.columns.map((c) => c.name));
357
367
  const codeKeys = new Set(Object.keys(this.columnMap));
358
- for (const [key, value] of Object.entries(data)) if (codeKeys.has(key) || dbColumnNames.has(key)) cleaned[key] = value;
368
+ const shouldSerialize = !(this.driver instanceof require_file.FileDriver);
369
+ for (const [key, value] of Object.entries(data)) if (codeKeys.has(key) || dbColumnNames.has(key)) if (shouldSerialize && (this.jsonCodeKeys.has(key) || this.jsonColumns.has(key)) && value != null && typeof value === "object") cleaned[key] = JSON.stringify(value);
370
+ else cleaned[key] = value;
359
371
  return cleaned;
360
372
  }
361
373
  cacheEntities(rows) {
@@ -406,8 +418,18 @@ var TableRepository = class {
406
418
  return mapped;
407
419
  }
408
420
  mapRows(rows) {
409
- if (!this.hasAliases) return rows;
410
- return rows.map((row) => this.toCodeKeys(row));
421
+ const shouldDeserialize = this.jsonCodeKeys.size > 0 && !(this.driver instanceof require_file.FileDriver);
422
+ if (!this.hasAliases && !shouldDeserialize) return rows;
423
+ return rows.map((row) => {
424
+ const mapped = this.hasAliases ? this.toCodeKeys(row) : { ...row };
425
+ if (shouldDeserialize) for (const key of this.jsonCodeKeys) {
426
+ const val = mapped[key];
427
+ if (typeof val === "string") try {
428
+ mapped[key] = JSON.parse(val);
429
+ } catch {}
430
+ }
431
+ return mapped;
432
+ });
411
433
  }
412
434
  };
413
435
  //#endregion