@open-mercato/shared 0.6.8-develop.7091.1.15ffbe30ce → 0.6.8-develop.7093.1.700c5c8d96
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/lib/crud/factory.js +23 -8
- package/dist/lib/crud/factory.js.map +2 -2
- package/dist/lib/query/engine.js +33 -8
- package/dist/lib/query/engine.js.map +2 -2
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/package.json +2 -2
- package/src/lib/crud/__tests__/crud-factory.test.ts +143 -0
- package/src/lib/crud/factory.ts +32 -7
- package/src/lib/query/__tests__/engine.count-distinct.test.ts +8 -1
- package/src/lib/query/__tests__/engine.scope-and-or.test.ts +11 -1
- package/src/lib/query/__tests__/engine.test.ts +158 -1
- package/src/lib/query/engine.ts +59 -9
package/dist/lib/query/engine.js
CHANGED
|
@@ -22,6 +22,7 @@ import { warnOnCiphertextLikeFallback } from "./ciphertext-search-warning.js";
|
|
|
22
22
|
import { resolveEncryptedSortFields, resolveEncryptedSortMaxRows, sortRowsInMemory } from "./encrypted-sort.js";
|
|
23
23
|
import { resolveListCountCap } from "./count-cap.js";
|
|
24
24
|
import { mapWithConcurrency } from "./bounded-decrypt.js";
|
|
25
|
+
import { parseNumberWithDefault } from "../number.js";
|
|
25
26
|
import { createLogger } from "../logger/index.js";
|
|
26
27
|
const logger = createLogger("shared").child({ component: "query" });
|
|
27
28
|
const DECRYPT_CONCURRENCY = 8;
|
|
@@ -48,6 +49,32 @@ async function resolveEncryptedLikeFieldSet(read, entity, tenantId) {
|
|
|
48
49
|
function clearEncryptedLikeFieldsCache() {
|
|
49
50
|
encryptedLikeFieldsCache.clear();
|
|
50
51
|
}
|
|
52
|
+
const COLUMN_EXISTS_CACHE_DEFAULT_TTL_MS = 3e5;
|
|
53
|
+
const COLUMN_EXISTS_CACHE_DEFAULT_MAX_ENTRIES = 1e4;
|
|
54
|
+
const columnExistsCache = /* @__PURE__ */ new Map();
|
|
55
|
+
function resolveColumnExistsCacheTtlMs() {
|
|
56
|
+
return parseNumberWithDefault(process.env.OM_QUERY_COLUMN_EXISTS_CACHE_MS, COLUMN_EXISTS_CACHE_DEFAULT_TTL_MS, { integer: true, min: 0 });
|
|
57
|
+
}
|
|
58
|
+
function resolveColumnExistsCacheMaxEntries() {
|
|
59
|
+
return parseNumberWithDefault(process.env.OM_QUERY_COLUMN_EXISTS_CACHE_MAX_ENTRIES, COLUMN_EXISTS_CACHE_DEFAULT_MAX_ENTRIES, { integer: true, min: 1 });
|
|
60
|
+
}
|
|
61
|
+
function storeColumnExists(key, value, ttlMs) {
|
|
62
|
+
const maxEntries = resolveColumnExistsCacheMaxEntries();
|
|
63
|
+
if (columnExistsCache.size >= maxEntries) {
|
|
64
|
+
const now = Date.now();
|
|
65
|
+
for (const [entryKey, entry] of columnExistsCache) {
|
|
66
|
+
if (entry.expiresAt <= now) columnExistsCache.delete(entryKey);
|
|
67
|
+
}
|
|
68
|
+
if (columnExistsCache.size >= maxEntries) columnExistsCache.clear();
|
|
69
|
+
}
|
|
70
|
+
columnExistsCache.set(key, { value, expiresAt: Date.now() + ttlMs });
|
|
71
|
+
}
|
|
72
|
+
function clearColumnExistsCache() {
|
|
73
|
+
columnExistsCache.clear();
|
|
74
|
+
}
|
|
75
|
+
function columnExistsCacheSize() {
|
|
76
|
+
return columnExistsCache.size;
|
|
77
|
+
}
|
|
51
78
|
const ENTITY_ID_PATTERN = /^[a-z][a-z0-9_]*:[a-z][a-z0-9_]*$/;
|
|
52
79
|
const isValidEntityIdShape = (value) => ENTITY_ID_PATTERN.test(value);
|
|
53
80
|
const pluralizeBaseName = (name) => {
|
|
@@ -164,7 +191,6 @@ class BasicQueryEngine {
|
|
|
164
191
|
this.em = em;
|
|
165
192
|
this.getDbFn = getDbFn;
|
|
166
193
|
this.resolveEncryptionService = resolveEncryptionService;
|
|
167
|
-
this.columnCache = /* @__PURE__ */ new Map();
|
|
168
194
|
this.searchAliasSeq = 0;
|
|
169
195
|
this.searchAvailabilityInstance = null;
|
|
170
196
|
}
|
|
@@ -1115,16 +1141,13 @@ class BasicQueryEngine {
|
|
|
1115
1141
|
}
|
|
1116
1142
|
async columnExists(table, column) {
|
|
1117
1143
|
const key = `${table}.${column}`;
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
this.columnCache.delete(key);
|
|
1122
|
-
}
|
|
1144
|
+
const ttlMs = resolveColumnExistsCacheTtlMs();
|
|
1145
|
+
const cached = columnExistsCache.get(key);
|
|
1146
|
+
if (cached && cached.expiresAt > Date.now()) return cached.value;
|
|
1123
1147
|
const db = this.getDb();
|
|
1124
1148
|
const exists = await db.selectFrom("information_schema.columns").select(sql`1`.as("one")).where("table_name", "=", table).where("column_name", "=", column).limit(1).executeTakeFirst();
|
|
1125
1149
|
const present = !!exists;
|
|
1126
|
-
if (
|
|
1127
|
-
else this.columnCache.delete(key);
|
|
1150
|
+
if (ttlMs > 0) storeColumnExists(key, present, ttlMs);
|
|
1128
1151
|
return present;
|
|
1129
1152
|
}
|
|
1130
1153
|
applySearchTokens(q, opts) {
|
|
@@ -1334,7 +1357,9 @@ class BasicQueryEngine {
|
|
|
1334
1357
|
export {
|
|
1335
1358
|
BasicQueryEngine,
|
|
1336
1359
|
ENTITY_ID_PATTERN,
|
|
1360
|
+
clearColumnExistsCache,
|
|
1337
1361
|
clearEncryptedLikeFieldsCache,
|
|
1362
|
+
columnExistsCacheSize,
|
|
1338
1363
|
isEncryptedLikeField,
|
|
1339
1364
|
isValidEntityIdShape,
|
|
1340
1365
|
resolveEncryptedLikeFieldSet,
|