@hedystia/db 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cache/manager.cjs +23 -0
- package/dist/cache/manager.cjs.map +1 -1
- package/dist/cache/manager.d.cts +14 -0
- package/dist/cache/manager.d.mts +14 -0
- package/dist/cache/manager.mjs +23 -0
- package/dist/cache/manager.mjs.map +1 -1
- package/dist/core/database.cjs +17 -5
- package/dist/core/database.cjs.map +1 -1
- package/dist/core/database.d.cts +4 -9
- package/dist/core/database.d.mts +4 -9
- package/dist/core/database.mjs +17 -5
- package/dist/core/database.mjs.map +1 -1
- package/dist/core/repository.cjs +32 -10
- package/dist/core/repository.cjs.map +1 -1
- package/dist/core/repository.d.cts +8 -1
- package/dist/core/repository.d.mts +8 -1
- package/dist/core/repository.mjs +32 -10
- package/dist/core/repository.mjs.map +1 -1
- package/dist/drivers/sql-compiler.cjs +6 -0
- package/dist/drivers/sql-compiler.cjs.map +1 -1
- package/dist/drivers/sql-compiler.mjs +6 -0
- package/dist/drivers/sql-compiler.mjs.map +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/schema/column.cjs +2 -2
- package/dist/schema/column.cjs.map +1 -1
- package/dist/schema/column.d.cts +2 -2
- package/dist/schema/column.d.mts +2 -2
- package/dist/schema/column.mjs +2 -2
- package/dist/schema/column.mjs.map +1 -1
- package/dist/schema/columns/index.cjs +12 -0
- package/dist/schema/columns/index.cjs.map +1 -1
- package/dist/schema/columns/index.d.cts +10 -2
- package/dist/schema/columns/index.d.mts +10 -2
- package/dist/schema/columns/index.mjs +12 -1
- package/dist/schema/columns/index.mjs.map +1 -1
- package/dist/schema/table.cjs +2 -1
- package/dist/schema/table.cjs.map +1 -1
- package/dist/schema/table.d.cts +4 -2
- package/dist/schema/table.d.mts +4 -2
- package/dist/schema/table.mjs +2 -1
- package/dist/schema/table.mjs.map +1 -1
- package/dist/types.d.cts +109 -4
- package/dist/types.d.mts +109 -4
- package/package.json +1 -1
package/dist/cache/manager.cjs
CHANGED
|
@@ -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;;
|
|
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":";;;;;;;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;;;;;;;;;;;CAYd,MAAM,wBACJ,OACA,QACA,SACA,UACA,aACY;AAEZ,MAAI,EADqB,cAAc,YAAY,UAAU,KAAK,SAEhE,QAAO,UAAU;EAGnB,MAAM,eAAe,aAAa,OAAO,KAAK;EAC9C,MAAM,kBAAkB,aAAa,UAAU,KAAK;EACpD,MAAM,MAAM,KAAK,SAAS,OAAO,QAAQ,QAAQ;EACjD,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI;AAClC,MAAI,WAAW,KAAA,GAAW;AACxB,QAAK,MAAM,UAAU,KAAK,cAAc,gBAAgB;AACxD,UAAO;;EAGT,MAAM,SAAS,MAAM,UAAU;AAC/B,OAAK,MAAM,IAAI,KAAK,QAAQ,aAAa;AACzC,SAAO;;CAGT,SAAiB,OAAe,QAAgB,SAA0B;AACxE,SAAO,SAAS,MAAM,GAAG,OAAO,GAAGE,yBAAAA,gBAAgB,QAAQ"}
|
package/dist/cache/manager.d.cts
CHANGED
|
@@ -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
|
package/dist/cache/manager.d.mts
CHANGED
|
@@ -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
|
package/dist/cache/manager.mjs
CHANGED
|
@@ -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;;
|
|
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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"}
|
package/dist/core/database.cjs
CHANGED
|
@@ -10,9 +10,18 @@ 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 normalizeMigrations(migrations) {
|
|
14
|
+
if (Array.isArray(migrations)) return migrations;
|
|
15
|
+
return Object.values(migrations).filter((v) => v != null && typeof v === "object" && "name" in v && "up" in v && "down" in v);
|
|
16
|
+
}
|
|
17
|
+
function normalizeSchemas(schemas) {
|
|
18
|
+
if (Array.isArray(schemas)) return schemas;
|
|
19
|
+
return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
|
|
20
|
+
}
|
|
13
21
|
function database(config) {
|
|
22
|
+
const schemas = normalizeSchemas(config.schemas);
|
|
14
23
|
const registry = new require_registry.SchemaRegistry();
|
|
15
|
-
registry.register(
|
|
24
|
+
registry.register(schemas);
|
|
16
25
|
const connectionConfig = Array.isArray(config.connection) ? config.connection[0] : config.connection;
|
|
17
26
|
if (!connectionConfig) throw new require_errors.DatabaseError("Connection config is required");
|
|
18
27
|
const driver = require_index.createDriver(config.database, connectionConfig);
|
|
@@ -42,11 +51,14 @@ function database(config) {
|
|
|
42
51
|
});
|
|
43
52
|
await Promise.all(syncPromises);
|
|
44
53
|
}
|
|
45
|
-
if (config.runMigrations && config.migrations
|
|
54
|
+
if (config.runMigrations && config.migrations) {
|
|
55
|
+
const migrations = normalizeMigrations(config.migrations);
|
|
56
|
+
if (migrations.length > 0) await runMigrations(driver, registry, migrations);
|
|
57
|
+
}
|
|
46
58
|
};
|
|
47
59
|
const repos = /* @__PURE__ */ new Map();
|
|
48
|
-
for (const schema of
|
|
49
|
-
const repo = new require_repository.TableRepository(schema.__name, driver, cache, registry);
|
|
60
|
+
for (const schema of schemas) {
|
|
61
|
+
const repo = new require_repository.TableRepository(schema.__name, driver, cache, registry, schema.__cache);
|
|
50
62
|
repos.set(schema.__name, repo);
|
|
51
63
|
}
|
|
52
64
|
const instance = {
|
|
@@ -71,7 +83,7 @@ function database(config) {
|
|
|
71
83
|
return driver.transaction(fn);
|
|
72
84
|
}
|
|
73
85
|
};
|
|
74
|
-
for (const schema of
|
|
86
|
+
for (const schema of schemas) {
|
|
75
87
|
const repo = repos.get(schema.__name);
|
|
76
88
|
const proxy = new Proxy(repo, { get(target, prop, receiver) {
|
|
77
89
|
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 normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\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) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\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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"}
|
package/dist/core/database.d.cts
CHANGED
|
@@ -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[]
|
|
24
|
-
type DatabaseInstance<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
|
package/dist/core/database.d.mts
CHANGED
|
@@ -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[]
|
|
24
|
-
type DatabaseInstance<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
|
package/dist/core/database.mjs
CHANGED
|
@@ -11,9 +11,18 @@ init_constants();
|
|
|
11
11
|
* @param {DatabaseConfig} config - Database configuration
|
|
12
12
|
* @returns {DatabaseInstance<S>} Database instance with table repositories
|
|
13
13
|
*/
|
|
14
|
+
function normalizeMigrations(migrations) {
|
|
15
|
+
if (Array.isArray(migrations)) return migrations;
|
|
16
|
+
return Object.values(migrations).filter((v) => v != null && typeof v === "object" && "name" in v && "up" in v && "down" in v);
|
|
17
|
+
}
|
|
18
|
+
function normalizeSchemas(schemas) {
|
|
19
|
+
if (Array.isArray(schemas)) return schemas;
|
|
20
|
+
return Object.values(schemas).filter((v) => v != null && typeof v === "object" && v.__table === true);
|
|
21
|
+
}
|
|
14
22
|
function database(config) {
|
|
23
|
+
const schemas = normalizeSchemas(config.schemas);
|
|
15
24
|
const registry = new SchemaRegistry();
|
|
16
|
-
registry.register(
|
|
25
|
+
registry.register(schemas);
|
|
17
26
|
const connectionConfig = Array.isArray(config.connection) ? config.connection[0] : config.connection;
|
|
18
27
|
if (!connectionConfig) throw new DatabaseError("Connection config is required");
|
|
19
28
|
const driver = createDriver(config.database, connectionConfig);
|
|
@@ -43,11 +52,14 @@ function database(config) {
|
|
|
43
52
|
});
|
|
44
53
|
await Promise.all(syncPromises);
|
|
45
54
|
}
|
|
46
|
-
if (config.runMigrations && config.migrations
|
|
55
|
+
if (config.runMigrations && config.migrations) {
|
|
56
|
+
const migrations = normalizeMigrations(config.migrations);
|
|
57
|
+
if (migrations.length > 0) await runMigrations(driver, registry, migrations);
|
|
58
|
+
}
|
|
47
59
|
};
|
|
48
60
|
const repos = /* @__PURE__ */ new Map();
|
|
49
|
-
for (const schema of
|
|
50
|
-
const repo = new TableRepository(schema.__name, driver, cache, registry);
|
|
61
|
+
for (const schema of schemas) {
|
|
62
|
+
const repo = new TableRepository(schema.__name, driver, cache, registry, schema.__cache);
|
|
51
63
|
repos.set(schema.__name, repo);
|
|
52
64
|
}
|
|
53
65
|
const instance = {
|
|
@@ -72,7 +84,7 @@ function database(config) {
|
|
|
72
84
|
return driver.transaction(fn);
|
|
73
85
|
}
|
|
74
86
|
};
|
|
75
|
-
for (const schema of
|
|
87
|
+
for (const schema of schemas) {
|
|
76
88
|
const repo = repos.get(schema.__name);
|
|
77
89
|
const proxy = new Proxy(repo, { get(target, prop, receiver) {
|
|
78
90
|
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 normalizeMigrations(\n migrations: MigrationDefinition[] | Record<string, unknown>,\n): MigrationDefinition[] {\n if (Array.isArray(migrations)) {\n return migrations;\n }\n return Object.values(migrations).filter(\n (v): v is MigrationDefinition =>\n v != null && typeof v === \"object\" && \"name\" in v && \"up\" in v && \"down\" in v,\n );\n}\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) {\n const migrations = normalizeMigrations(config.migrations);\n if (migrations.length > 0) {\n await runMigrations(driver, registry, migrations);\n }\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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"}
|
package/dist/core/repository.cjs
CHANGED
|
@@ -15,17 +15,27 @@ var TableRepository = class {
|
|
|
15
15
|
columnMap;
|
|
16
16
|
reverseColumnMap;
|
|
17
17
|
hasAliases;
|
|
18
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
410
|
-
|
|
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
|