@open-mercato/core 0.6.4-develop.4264.1.53368d85fe → 0.6.4-develop.4270.1.a614eb18e6
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/modules/query_index/lib/coverage.js +13 -10
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +23 -12
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/query_index/lib/coverage.ts +15 -12
- package/src/modules/query_index/lib/engine.ts +32 -9
|
@@ -146,24 +146,20 @@ async function refreshCoverageSnapshot(em, scope) {
|
|
|
146
146
|
if (organizationId !== null && hasOrg) baseQuery = baseQuery.where("b.organization_id", "=", organizationId);
|
|
147
147
|
if (tenantId !== null && hasTenant) baseQuery = baseQuery.where("b.tenant_id", "=", tenantId);
|
|
148
148
|
if (!withDeleted && hasDeleted) baseQuery = baseQuery.where("b.deleted_at", "is", null);
|
|
149
|
-
const baseRow = await baseQuery.executeTakeFirst();
|
|
150
|
-
const baseCount = toCount(baseRow?.count);
|
|
151
149
|
let indexQuery = db.selectFrom("entity_indexes as ei").select(sql`count(*)`.as("count")).where("ei.entity_type", "=", entityType);
|
|
152
150
|
if (organizationId !== null) indexQuery = indexQuery.where("ei.organization_id", "=", organizationId);
|
|
153
151
|
if (tenantId !== null) indexQuery = indexQuery.where("ei.tenant_id", "=", tenantId);
|
|
154
152
|
if (!withDeleted) indexQuery = indexQuery.where("ei.deleted_at", "is", null);
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const hasVectorTable = await tableHasColumn(db, "vector_search", "entity_id");
|
|
159
|
-
if (hasVectorTable && typeof tenantId === "string" && tenantId.length > 0) {
|
|
153
|
+
const vectorCountPromise = (async () => {
|
|
154
|
+
const hasVectorTable = await tableHasColumn(db, "vector_search", "entity_id");
|
|
155
|
+
if (!hasVectorTable || typeof tenantId !== "string" || tenantId.length === 0) return void 0;
|
|
160
156
|
try {
|
|
161
157
|
let vectorQuery = db.selectFrom("vector_search").select(sql`count(*)`.as("count")).where("entity_id", "=", entityType).where("tenant_id", "=", tenantId);
|
|
162
158
|
if (organizationId !== null) {
|
|
163
159
|
vectorQuery = vectorQuery.where("organization_id", "=", organizationId);
|
|
164
160
|
}
|
|
165
161
|
const vectorRow = await vectorQuery.executeTakeFirst();
|
|
166
|
-
|
|
162
|
+
return toCount(vectorRow?.count);
|
|
167
163
|
} catch (err) {
|
|
168
164
|
console.warn("[query_index] Failed to resolve vector count for coverage snapshot", {
|
|
169
165
|
entityType,
|
|
@@ -171,9 +167,16 @@ async function refreshCoverageSnapshot(em, scope) {
|
|
|
171
167
|
organizationId,
|
|
172
168
|
error: err instanceof Error ? err.message : err
|
|
173
169
|
});
|
|
174
|
-
|
|
170
|
+
return void 0;
|
|
175
171
|
}
|
|
176
|
-
}
|
|
172
|
+
})();
|
|
173
|
+
const [baseRow, indexRow, vectorCount] = await Promise.all([
|
|
174
|
+
baseQuery.executeTakeFirst(),
|
|
175
|
+
indexQuery.executeTakeFirst(),
|
|
176
|
+
vectorCountPromise
|
|
177
|
+
]);
|
|
178
|
+
const baseCount = toCount(baseRow?.count);
|
|
179
|
+
const indexCount = toCount(indexRow?.count);
|
|
177
180
|
await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {
|
|
178
181
|
baseCount,
|
|
179
182
|
indexedCount: indexCount,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/coverage.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { type Kysely, sql } from 'kysely'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\n\nexport type CoverageScope = {\n entityType: string\n tenantId?: string | null\n organizationId?: string | null\n withDeleted?: boolean\n}\n\ntype CoverageRow = {\n base_count: unknown\n indexed_count: unknown\n vector_indexed_count: unknown\n refreshed_at: Date | string | null\n}\n\nexport type CoverageAdjustment = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n deltaBase: number\n deltaIndex: number\n deltaVector?: number\n}\n\nexport type CoverageDeltaInput = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n baseDelta: number\n indexDelta: number\n vectorDelta?: number\n}\n\nconst COLUMN_CACHE = new Map<string, boolean>()\nconst GLOBAL_ORGANIZATION_PLACEHOLDER = '00000000-0000-0000-0000-000000000000'\nexport const COVERAGE_ORG_PLACEHOLDER = GLOBAL_ORGANIZATION_PLACEHOLDER\n\nfunction toCount(value: unknown): number {\n if (typeof value === 'number') return Number.isFinite(value) ? value : 0\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n }\n if (value != null && typeof (value as { valueOf: () => number }).valueOf === 'function') {\n const parsed = Number((value as { valueOf: () => number }).valueOf())\n return Number.isFinite(parsed) ? parsed : 0\n }\n return 0\n}\n\nfunction normalizeOrganizationForStore(orgId: string | null | undefined): string {\n return orgId ?? GLOBAL_ORGANIZATION_PLACEHOLDER\n}\n\nfunction applyOrganizationCondition<QB extends { where: (...args: any[]) => QB }>(\n qb: QB,\n column: string,\n organizationId: string | null | undefined,\n): QB {\n const stored = normalizeOrganizationForStore(organizationId ?? null)\n if (stored === GLOBAL_ORGANIZATION_PLACEHOLDER) {\n return qb.where((eb: any) => eb.or([\n eb(column as any, 'is', null),\n eb(column as any, '=', GLOBAL_ORGANIZATION_PLACEHOLDER),\n ]))\n }\n return qb.where(column as any, '=', stored)\n}\n\nasync function fetchCoverageRow(\n db: Kysely<any>,\n scope: CoverageScope\n): Promise<(CoverageRow & { organization_id: string | null }) | null> {\n const { entityType, tenantId, organizationId, withDeleted } = scope\n let query = db\n .selectFrom('entity_index_coverage' as any)\n .select([\n 'base_count' as any,\n 'indexed_count' as any,\n 'vector_indexed_count' as any,\n 'refreshed_at' as any,\n 'organization_id' as any,\n ])\n .where('entity_type' as any, '=', entityType)\n .where('with_deleted' as any, '=', withDeleted === true)\n .orderBy('refreshed_at' as any, 'desc')\n query = tenantId == null\n ? query.where('tenant_id' as any, 'is', null as any)\n : query.where('tenant_id' as any, '=', tenantId)\n query = applyOrganizationCondition(query as any, 'organization_id', organizationId ?? null)\n const row = await query.executeTakeFirst() as (CoverageRow & { organization_id: string | null }) | undefined\n return row ?? null\n}\n\nasync function pruneDuplicateCoverageRows(\n db: Kysely<any>,\n scope: CoverageScope,\n keepId: string | null\n): Promise<void> {\n let query = db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', scope.entityType)\n .where('with_deleted' as any, '=', scope.withDeleted === true)\n query = scope.tenantId == null\n ? query.where('tenant_id' as any, 'is', null as any)\n : query.where('tenant_id' as any, '=', scope.tenantId)\n query = applyOrganizationCondition(query as any, 'organization_id', scope.organizationId ?? null)\n if (keepId) {\n query = query.where('id' as any, '!=', keepId)\n }\n await query.execute()\n}\n\nasync function upsertCoverageRow(\n db: Kysely<any>,\n scope: CoverageScope,\n counts: { baseCount: number; indexedCount: number; vectorIndexedCount: number }\n): Promise<void> {\n const storedOrgId = normalizeOrganizationForStore(scope.organizationId ?? null)\n if (scope.organizationId == null) {\n let purge = db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', scope.entityType)\n .where('with_deleted' as any, '=', scope.withDeleted === true)\n .where('organization_id' as any, 'is', null as any)\n purge = scope.tenantId == null\n ? purge.where('tenant_id' as any, 'is', null as any)\n : purge.where('tenant_id' as any, '=', scope.tenantId)\n await purge.execute()\n }\n\n const rows = await db\n .insertInto('entity_index_coverage' as any)\n .values({\n entity_type: scope.entityType,\n tenant_id: scope.tenantId ?? null,\n organization_id: storedOrgId,\n with_deleted: scope.withDeleted === true,\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: sql`now()`,\n } as any)\n .onConflict((oc: any) => oc\n .columns(['entity_type', 'tenant_id', 'organization_id', 'with_deleted'])\n .doUpdateSet({\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: sql`now()`,\n } as any))\n .returning(['id' as any])\n .execute() as Array<{ id: string }>\n\n const keepId = rows?.[0]?.id ?? null\n await pruneDuplicateCoverageRows(db, scope, keepId)\n}\n\nexport async function readCoverageSnapshot(\n db: Kysely<any>,\n scope: CoverageScope\n): Promise<(CoverageRow & { baseCount: number; indexedCount: number; vectorIndexedCount: number }) | null> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return null\n const row = await fetchCoverageRow(db, {\n entityType,\n tenantId: scope.tenantId ?? null,\n organizationId: scope.organizationId ?? null,\n withDeleted: scope.withDeleted === true,\n })\n if (!row) return null\n const refreshedAt = row.refreshed_at instanceof Date ? row.refreshed_at : (row.refreshed_at ? new Date(row.refreshed_at) : null)\n return {\n base_count: row.base_count,\n indexed_count: row.indexed_count,\n vector_indexed_count: row.vector_indexed_count,\n refreshed_at: refreshedAt ?? null,\n baseCount: toCount(row.base_count),\n indexedCount: toCount(row.indexed_count),\n vectorIndexedCount: toCount(row.vector_indexed_count),\n }\n}\n\nexport async function applyCoverageAdjustments(\n em: EntityManager,\n adjustments: CoverageAdjustment[]\n): Promise<void> {\n if (!adjustments.length) return\n const db = (em as any).getKysely() as Kysely<any>\n const aggregated = aggregateAdjustments(adjustments)\n for (const entry of aggregated) {\n const scope = entry.scope\n const existing = await fetchCoverageRow(db, scope)\n const currentBase = existing ? toCount(existing.base_count) : 0\n const currentIndex = existing ? toCount(existing.indexed_count) : 0\n const currentVector = existing ? toCount(existing.vector_indexed_count) : 0\n const nextBase = Math.max(currentBase + entry.deltaBase, 0)\n const nextIndex = Math.max(currentIndex + entry.deltaIndex, 0)\n const nextVector = Math.max(currentVector + entry.deltaVector, 0)\n\n await upsertCoverageRow(db, scope, {\n baseCount: nextBase,\n indexedCount: nextIndex,\n vectorIndexedCount: nextVector,\n })\n }\n}\n\nexport async function deleteCoverageForEntity(db: Kysely<any>, entityType: string): Promise<void> {\n if (!entityType) return\n await db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', entityType)\n .execute()\n}\n\nasync function tableHasColumn(db: Kysely<any>, table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key)!\n const exists = await db\n .selectFrom('information_schema.columns' as any)\n .select(sql<number>`1`.as('present'))\n .where(sql<boolean>`table_schema = current_schema()`)\n .where('table_name' as any, '=', table)\n .where('column_name' as any, '=', column)\n .executeTakeFirst()\n const present = !!exists\n COLUMN_CACHE.set(key, present)\n return present\n}\n\nexport async function refreshCoverageSnapshot(\n em: EntityManager,\n scope: CoverageScope,\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n\n const db = (em as any).getKysely() as Kysely<any>\n const baseTable = resolveEntityTableName(em, entityType)\n\n const hasOrg = await tableHasColumn(db, baseTable, 'organization_id')\n const hasTenant = await tableHasColumn(db, baseTable, 'tenant_id')\n const hasDeleted = await tableHasColumn(db, baseTable, 'deleted_at')\n\n if (organizationId !== null && !hasOrg) return\n if (tenantId !== null && !hasTenant) return\n\n let baseQuery = db\n .selectFrom(`${baseTable} as b` as any)\n .select(sql`count(*)`.as('count'))\n if (organizationId !== null && hasOrg) baseQuery = baseQuery.where('b.organization_id' as any, '=', organizationId)\n if (tenantId !== null && hasTenant) baseQuery = baseQuery.where('b.tenant_id' as any, '=', tenantId)\n if (!withDeleted && hasDeleted) baseQuery = baseQuery.where('b.deleted_at' as any, 'is', null as any)\n\n const baseRow = await baseQuery.executeTakeFirst() as { count: unknown } | undefined\n const baseCount = toCount(baseRow?.count)\n\n let indexQuery = db\n .selectFrom('entity_indexes as ei' as any)\n .select(sql`count(*)`.as('count'))\n .where('ei.entity_type' as any, '=', entityType)\n if (organizationId !== null) indexQuery = indexQuery.where('ei.organization_id' as any, '=', organizationId)\n if (tenantId !== null) indexQuery = indexQuery.where('ei.tenant_id' as any, '=', tenantId)\n if (!withDeleted) indexQuery = indexQuery.where('ei.deleted_at' as any, 'is', null as any)\n\n const indexRow = await indexQuery.executeTakeFirst() as { count: unknown } | undefined\n const indexCount = toCount(indexRow?.count)\n\n // Count vector entries directly from database\n let vectorCount: number | undefined\n const hasVectorTable = await tableHasColumn(db, 'vector_search', 'entity_id')\n if (hasVectorTable && typeof tenantId === 'string' && tenantId.length > 0) {\n try {\n let vectorQuery = db\n .selectFrom('vector_search' as any)\n .select(sql`count(*)`.as('count'))\n .where('entity_id' as any, '=', entityType)\n .where('tenant_id' as any, '=', tenantId)\n if (organizationId !== null) {\n vectorQuery = vectorQuery.where('organization_id' as any, '=', organizationId)\n }\n const vectorRow = await vectorQuery.executeTakeFirst() as { count: unknown } | undefined\n vectorCount = toCount(vectorRow?.count)\n } catch (err) {\n console.warn('[query_index] Failed to resolve vector count for coverage snapshot', {\n entityType,\n tenantId,\n organizationId,\n error: err instanceof Error ? err.message : err,\n })\n vectorCount = undefined\n }\n }\n\n await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorCount,\n })\n}\n\nexport async function writeCoverageCounts(\n em: EntityManager,\n scope: CoverageScope,\n counts: { baseCount?: number; indexedCount?: number; vectorCount?: number }\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const db = (em as any).getKysely() as Kysely<any>\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n const existing = await fetchCoverageRow(db, {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n })\n const baseCount = counts.baseCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.baseCount)))\n : Math.max(0, Math.trunc(toCount(existing?.base_count)))\n const indexCount = counts.indexedCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))\n : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))\n const vectorCount = counts.vectorCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))\n : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))\n await upsertCoverageRow(db, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorIndexedCount: vectorCount,\n })\n}\n\ntype AggregatedAdjustment = {\n scope: CoverageScope\n deltaBase: number\n deltaIndex: number\n deltaVector: number\n}\n\nfunction aggregateAdjustments(adjustments: CoverageAdjustment[]): AggregatedAdjustment[] {\n const map = new Map<string, AggregatedAdjustment>()\n for (const adj of adjustments) {\n if (!adj?.entityType) continue\n const deltaBase = Number.isFinite(adj.deltaBase) ? adj.deltaBase : 0\n const deltaIndex = Number.isFinite(adj.deltaIndex) ? adj.deltaIndex : 0\n const deltaVector = Number.isFinite(adj.deltaVector) ? adj.deltaVector! : 0\n if (deltaBase === 0 && deltaIndex === 0 && deltaVector === 0) continue\n const scope: CoverageScope = {\n entityType: adj.entityType,\n tenantId: adj.tenantId ?? null,\n organizationId: adj.organizationId ?? null,\n withDeleted: adj.withDeleted === true,\n }\n const key = scopeKey(scope)\n const existing = map.get(key)\n if (existing) {\n existing.deltaBase += deltaBase\n existing.deltaIndex += deltaIndex\n existing.deltaVector += deltaVector\n } else {\n map.set(key, { scope, deltaBase, deltaIndex, deltaVector })\n }\n }\n return Array.from(map.values())\n}\n\nfunction scopeKey(scope: CoverageScope): string {\n const tenant = scope.tenantId ?? '__tenant_null__'\n const org = normalizeOrganizationForStore(scope.organizationId ?? null)\n const deleted = scope.withDeleted === true ? '1' : '0'\n return `${scope.entityType}|${tenant}|${org}|${deleted}`\n}\n\nexport function createCoverageAdjustments(input: CoverageDeltaInput): CoverageAdjustment[] {\n const entityType = String(input.entityType || '')\n if (!entityType) return []\n const baseDelta = Number.isFinite(input.baseDelta) ? input.baseDelta : 0\n const indexDelta = Number.isFinite(input.indexDelta) ? input.indexDelta : 0\n const vectorDelta = Number.isFinite(input.vectorDelta) ? input.vectorDelta! : 0\n if (baseDelta === 0 && indexDelta === 0 && vectorDelta === 0) return []\n const withDeleted = input.withDeleted === true\n const tenantId = input.tenantId ?? null\n const organizationId = input.organizationId ?? null\n return [\n {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n deltaBase: baseDelta,\n deltaIndex: indexDelta,\n deltaVector: vectorDelta,\n },\n ]\n}\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { type Kysely, sql } from 'kysely'\nimport { resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\n\nexport type CoverageScope = {\n entityType: string\n tenantId?: string | null\n organizationId?: string | null\n withDeleted?: boolean\n}\n\ntype CoverageRow = {\n base_count: unknown\n indexed_count: unknown\n vector_indexed_count: unknown\n refreshed_at: Date | string | null\n}\n\nexport type CoverageAdjustment = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n deltaBase: number\n deltaIndex: number\n deltaVector?: number\n}\n\nexport type CoverageDeltaInput = {\n entityType: string\n tenantId: string | null\n organizationId: string | null\n withDeleted?: boolean\n baseDelta: number\n indexDelta: number\n vectorDelta?: number\n}\n\nconst COLUMN_CACHE = new Map<string, boolean>()\nconst GLOBAL_ORGANIZATION_PLACEHOLDER = '00000000-0000-0000-0000-000000000000'\nexport const COVERAGE_ORG_PLACEHOLDER = GLOBAL_ORGANIZATION_PLACEHOLDER\n\nfunction toCount(value: unknown): number {\n if (typeof value === 'number') return Number.isFinite(value) ? value : 0\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : 0\n }\n if (value != null && typeof (value as { valueOf: () => number }).valueOf === 'function') {\n const parsed = Number((value as { valueOf: () => number }).valueOf())\n return Number.isFinite(parsed) ? parsed : 0\n }\n return 0\n}\n\nfunction normalizeOrganizationForStore(orgId: string | null | undefined): string {\n return orgId ?? GLOBAL_ORGANIZATION_PLACEHOLDER\n}\n\nfunction applyOrganizationCondition<QB extends { where: (...args: any[]) => QB }>(\n qb: QB,\n column: string,\n organizationId: string | null | undefined,\n): QB {\n const stored = normalizeOrganizationForStore(organizationId ?? null)\n if (stored === GLOBAL_ORGANIZATION_PLACEHOLDER) {\n return qb.where((eb: any) => eb.or([\n eb(column as any, 'is', null),\n eb(column as any, '=', GLOBAL_ORGANIZATION_PLACEHOLDER),\n ]))\n }\n return qb.where(column as any, '=', stored)\n}\n\nasync function fetchCoverageRow(\n db: Kysely<any>,\n scope: CoverageScope\n): Promise<(CoverageRow & { organization_id: string | null }) | null> {\n const { entityType, tenantId, organizationId, withDeleted } = scope\n let query = db\n .selectFrom('entity_index_coverage' as any)\n .select([\n 'base_count' as any,\n 'indexed_count' as any,\n 'vector_indexed_count' as any,\n 'refreshed_at' as any,\n 'organization_id' as any,\n ])\n .where('entity_type' as any, '=', entityType)\n .where('with_deleted' as any, '=', withDeleted === true)\n .orderBy('refreshed_at' as any, 'desc')\n query = tenantId == null\n ? query.where('tenant_id' as any, 'is', null as any)\n : query.where('tenant_id' as any, '=', tenantId)\n query = applyOrganizationCondition(query as any, 'organization_id', organizationId ?? null)\n const row = await query.executeTakeFirst() as (CoverageRow & { organization_id: string | null }) | undefined\n return row ?? null\n}\n\nasync function pruneDuplicateCoverageRows(\n db: Kysely<any>,\n scope: CoverageScope,\n keepId: string | null\n): Promise<void> {\n let query = db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', scope.entityType)\n .where('with_deleted' as any, '=', scope.withDeleted === true)\n query = scope.tenantId == null\n ? query.where('tenant_id' as any, 'is', null as any)\n : query.where('tenant_id' as any, '=', scope.tenantId)\n query = applyOrganizationCondition(query as any, 'organization_id', scope.organizationId ?? null)\n if (keepId) {\n query = query.where('id' as any, '!=', keepId)\n }\n await query.execute()\n}\n\nasync function upsertCoverageRow(\n db: Kysely<any>,\n scope: CoverageScope,\n counts: { baseCount: number; indexedCount: number; vectorIndexedCount: number }\n): Promise<void> {\n const storedOrgId = normalizeOrganizationForStore(scope.organizationId ?? null)\n if (scope.organizationId == null) {\n let purge = db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', scope.entityType)\n .where('with_deleted' as any, '=', scope.withDeleted === true)\n .where('organization_id' as any, 'is', null as any)\n purge = scope.tenantId == null\n ? purge.where('tenant_id' as any, 'is', null as any)\n : purge.where('tenant_id' as any, '=', scope.tenantId)\n await purge.execute()\n }\n\n const rows = await db\n .insertInto('entity_index_coverage' as any)\n .values({\n entity_type: scope.entityType,\n tenant_id: scope.tenantId ?? null,\n organization_id: storedOrgId,\n with_deleted: scope.withDeleted === true,\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: sql`now()`,\n } as any)\n .onConflict((oc: any) => oc\n .columns(['entity_type', 'tenant_id', 'organization_id', 'with_deleted'])\n .doUpdateSet({\n base_count: counts.baseCount,\n indexed_count: counts.indexedCount,\n vector_indexed_count: counts.vectorIndexedCount,\n refreshed_at: sql`now()`,\n } as any))\n .returning(['id' as any])\n .execute() as Array<{ id: string }>\n\n const keepId = rows?.[0]?.id ?? null\n await pruneDuplicateCoverageRows(db, scope, keepId)\n}\n\nexport async function readCoverageSnapshot(\n db: Kysely<any>,\n scope: CoverageScope\n): Promise<(CoverageRow & { baseCount: number; indexedCount: number; vectorIndexedCount: number }) | null> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return null\n const row = await fetchCoverageRow(db, {\n entityType,\n tenantId: scope.tenantId ?? null,\n organizationId: scope.organizationId ?? null,\n withDeleted: scope.withDeleted === true,\n })\n if (!row) return null\n const refreshedAt = row.refreshed_at instanceof Date ? row.refreshed_at : (row.refreshed_at ? new Date(row.refreshed_at) : null)\n return {\n base_count: row.base_count,\n indexed_count: row.indexed_count,\n vector_indexed_count: row.vector_indexed_count,\n refreshed_at: refreshedAt ?? null,\n baseCount: toCount(row.base_count),\n indexedCount: toCount(row.indexed_count),\n vectorIndexedCount: toCount(row.vector_indexed_count),\n }\n}\n\nexport async function applyCoverageAdjustments(\n em: EntityManager,\n adjustments: CoverageAdjustment[]\n): Promise<void> {\n if (!adjustments.length) return\n const db = (em as any).getKysely() as Kysely<any>\n const aggregated = aggregateAdjustments(adjustments)\n for (const entry of aggregated) {\n const scope = entry.scope\n const existing = await fetchCoverageRow(db, scope)\n const currentBase = existing ? toCount(existing.base_count) : 0\n const currentIndex = existing ? toCount(existing.indexed_count) : 0\n const currentVector = existing ? toCount(existing.vector_indexed_count) : 0\n const nextBase = Math.max(currentBase + entry.deltaBase, 0)\n const nextIndex = Math.max(currentIndex + entry.deltaIndex, 0)\n const nextVector = Math.max(currentVector + entry.deltaVector, 0)\n\n await upsertCoverageRow(db, scope, {\n baseCount: nextBase,\n indexedCount: nextIndex,\n vectorIndexedCount: nextVector,\n })\n }\n}\n\nexport async function deleteCoverageForEntity(db: Kysely<any>, entityType: string): Promise<void> {\n if (!entityType) return\n await db\n .deleteFrom('entity_index_coverage' as any)\n .where('entity_type' as any, '=', entityType)\n .execute()\n}\n\nasync function tableHasColumn(db: Kysely<any>, table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (COLUMN_CACHE.has(key)) return COLUMN_CACHE.get(key)!\n const exists = await db\n .selectFrom('information_schema.columns' as any)\n .select(sql<number>`1`.as('present'))\n .where(sql<boolean>`table_schema = current_schema()`)\n .where('table_name' as any, '=', table)\n .where('column_name' as any, '=', column)\n .executeTakeFirst()\n const present = !!exists\n COLUMN_CACHE.set(key, present)\n return present\n}\n\nexport async function refreshCoverageSnapshot(\n em: EntityManager,\n scope: CoverageScope,\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n\n const db = (em as any).getKysely() as Kysely<any>\n const baseTable = resolveEntityTableName(em, entityType)\n\n const hasOrg = await tableHasColumn(db, baseTable, 'organization_id')\n const hasTenant = await tableHasColumn(db, baseTable, 'tenant_id')\n const hasDeleted = await tableHasColumn(db, baseTable, 'deleted_at')\n\n if (organizationId !== null && !hasOrg) return\n if (tenantId !== null && !hasTenant) return\n\n let baseQuery = db\n .selectFrom(`${baseTable} as b` as any)\n .select(sql`count(*)`.as('count'))\n if (organizationId !== null && hasOrg) baseQuery = baseQuery.where('b.organization_id' as any, '=', organizationId)\n if (tenantId !== null && hasTenant) baseQuery = baseQuery.where('b.tenant_id' as any, '=', tenantId)\n if (!withDeleted && hasDeleted) baseQuery = baseQuery.where('b.deleted_at' as any, 'is', null as any)\n\n let indexQuery = db\n .selectFrom('entity_indexes as ei' as any)\n .select(sql`count(*)`.as('count'))\n .where('ei.entity_type' as any, '=', entityType)\n if (organizationId !== null) indexQuery = indexQuery.where('ei.organization_id' as any, '=', organizationId)\n if (tenantId !== null) indexQuery = indexQuery.where('ei.tenant_id' as any, '=', tenantId)\n if (!withDeleted) indexQuery = indexQuery.where('ei.deleted_at' as any, 'is', null as any)\n\n const vectorCountPromise = (async (): Promise<number | undefined> => {\n const hasVectorTable = await tableHasColumn(db, 'vector_search', 'entity_id')\n if (!hasVectorTable || typeof tenantId !== 'string' || tenantId.length === 0) return undefined\n\n try {\n let vectorQuery = db\n .selectFrom('vector_search' as any)\n .select(sql`count(*)`.as('count'))\n .where('entity_id' as any, '=', entityType)\n .where('tenant_id' as any, '=', tenantId)\n if (organizationId !== null) {\n vectorQuery = vectorQuery.where('organization_id' as any, '=', organizationId)\n }\n const vectorRow = await vectorQuery.executeTakeFirst() as { count: unknown } | undefined\n return toCount(vectorRow?.count)\n } catch (err) {\n console.warn('[query_index] Failed to resolve vector count for coverage snapshot', {\n entityType,\n tenantId,\n organizationId,\n error: err instanceof Error ? err.message : err,\n })\n return undefined\n }\n })()\n\n const [baseRow, indexRow, vectorCount] = await Promise.all([\n baseQuery.executeTakeFirst() as Promise<{ count: unknown } | undefined>,\n indexQuery.executeTakeFirst() as Promise<{ count: unknown } | undefined>,\n vectorCountPromise,\n ])\n\n const baseCount = toCount(baseRow?.count)\n const indexCount = toCount(indexRow?.count)\n\n await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorCount,\n })\n}\n\nexport async function writeCoverageCounts(\n em: EntityManager,\n scope: CoverageScope,\n counts: { baseCount?: number; indexedCount?: number; vectorCount?: number }\n): Promise<void> {\n const entityType = String(scope.entityType || '')\n if (!entityType) return\n const db = (em as any).getKysely() as Kysely<any>\n const tenantId = scope.tenantId ?? null\n const organizationId = scope.organizationId ?? null\n const withDeleted = scope.withDeleted === true\n const existing = await fetchCoverageRow(db, {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n })\n const baseCount = counts.baseCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.baseCount)))\n : Math.max(0, Math.trunc(toCount(existing?.base_count)))\n const indexCount = counts.indexedCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.indexedCount)))\n : Math.max(0, Math.trunc(toCount(existing?.indexed_count)))\n const vectorCount = counts.vectorCount !== undefined\n ? Math.max(0, Math.trunc(toCount(counts.vectorCount)))\n : Math.max(0, Math.trunc(toCount(existing?.vector_indexed_count)))\n await upsertCoverageRow(db, { entityType, tenantId, organizationId, withDeleted }, {\n baseCount,\n indexedCount: indexCount,\n vectorIndexedCount: vectorCount,\n })\n}\n\ntype AggregatedAdjustment = {\n scope: CoverageScope\n deltaBase: number\n deltaIndex: number\n deltaVector: number\n}\n\nfunction aggregateAdjustments(adjustments: CoverageAdjustment[]): AggregatedAdjustment[] {\n const map = new Map<string, AggregatedAdjustment>()\n for (const adj of adjustments) {\n if (!adj?.entityType) continue\n const deltaBase = Number.isFinite(adj.deltaBase) ? adj.deltaBase : 0\n const deltaIndex = Number.isFinite(adj.deltaIndex) ? adj.deltaIndex : 0\n const deltaVector = Number.isFinite(adj.deltaVector) ? adj.deltaVector! : 0\n if (deltaBase === 0 && deltaIndex === 0 && deltaVector === 0) continue\n const scope: CoverageScope = {\n entityType: adj.entityType,\n tenantId: adj.tenantId ?? null,\n organizationId: adj.organizationId ?? null,\n withDeleted: adj.withDeleted === true,\n }\n const key = scopeKey(scope)\n const existing = map.get(key)\n if (existing) {\n existing.deltaBase += deltaBase\n existing.deltaIndex += deltaIndex\n existing.deltaVector += deltaVector\n } else {\n map.set(key, { scope, deltaBase, deltaIndex, deltaVector })\n }\n }\n return Array.from(map.values())\n}\n\nfunction scopeKey(scope: CoverageScope): string {\n const tenant = scope.tenantId ?? '__tenant_null__'\n const org = normalizeOrganizationForStore(scope.organizationId ?? null)\n const deleted = scope.withDeleted === true ? '1' : '0'\n return `${scope.entityType}|${tenant}|${org}|${deleted}`\n}\n\nexport function createCoverageAdjustments(input: CoverageDeltaInput): CoverageAdjustment[] {\n const entityType = String(input.entityType || '')\n if (!entityType) return []\n const baseDelta = Number.isFinite(input.baseDelta) ? input.baseDelta : 0\n const indexDelta = Number.isFinite(input.indexDelta) ? input.indexDelta : 0\n const vectorDelta = Number.isFinite(input.vectorDelta) ? input.vectorDelta! : 0\n if (baseDelta === 0 && indexDelta === 0 && vectorDelta === 0) return []\n const withDeleted = input.withDeleted === true\n const tenantId = input.tenantId ?? null\n const organizationId = input.organizationId ?? null\n return [\n {\n entityType,\n tenantId,\n organizationId,\n withDeleted,\n deltaBase: baseDelta,\n deltaIndex: indexDelta,\n deltaVector: vectorDelta,\n },\n ]\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1479,23 +1479,26 @@ class HybridQueryEngine {
|
|
|
1479
1479
|
}
|
|
1480
1480
|
async getStoredCoverageSnapshot(entity, tenantId, organizationId, withDeleted) {
|
|
1481
1481
|
try {
|
|
1482
|
-
if (!this.isCoverageOptimizationEnabled()) {
|
|
1483
|
-
await refreshCoverageSnapshot(this.em, {
|
|
1484
|
-
entityType: entity,
|
|
1485
|
-
tenantId,
|
|
1486
|
-
organizationId,
|
|
1487
|
-
withDeleted
|
|
1488
|
-
});
|
|
1489
|
-
}
|
|
1490
1482
|
const db = this.getDb();
|
|
1491
|
-
const
|
|
1483
|
+
const scope = {
|
|
1492
1484
|
entityType: entity,
|
|
1493
1485
|
tenantId,
|
|
1494
1486
|
organizationId,
|
|
1495
1487
|
withDeleted
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1488
|
+
};
|
|
1489
|
+
const row = await readCoverageSnapshot(db, scope);
|
|
1490
|
+
if (row && this.isCoverageSnapshotFresh(row)) {
|
|
1491
|
+
return { baseCount: row.baseCount, indexedCount: row.indexedCount };
|
|
1492
|
+
}
|
|
1493
|
+
if (this.isCoverageOptimizationEnabled()) {
|
|
1494
|
+
this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted);
|
|
1495
|
+
if (!row) return null;
|
|
1496
|
+
return { baseCount: row.baseCount, indexedCount: row.indexedCount };
|
|
1497
|
+
}
|
|
1498
|
+
await refreshCoverageSnapshot(this.em, scope);
|
|
1499
|
+
const refreshed = await readCoverageSnapshot(db, scope);
|
|
1500
|
+
if (!refreshed) return null;
|
|
1501
|
+
return { baseCount: refreshed.baseCount, indexedCount: refreshed.indexedCount };
|
|
1499
1502
|
} catch (err) {
|
|
1500
1503
|
if (this.isDebugVerbosity()) {
|
|
1501
1504
|
this.debug("coverage:snapshot:read-error", {
|
|
@@ -1509,6 +1512,14 @@ class HybridQueryEngine {
|
|
|
1509
1512
|
return null;
|
|
1510
1513
|
}
|
|
1511
1514
|
}
|
|
1515
|
+
isCoverageSnapshotFresh(row) {
|
|
1516
|
+
if (this.coverageStatsTtlMs <= 0) return false;
|
|
1517
|
+
if (!row) return false;
|
|
1518
|
+
const refreshedAt = row.refreshed_at instanceof Date ? row.refreshed_at : row.refreshed_at ? new Date(row.refreshed_at) : null;
|
|
1519
|
+
const refreshedAtMs = refreshedAt?.getTime();
|
|
1520
|
+
if (!refreshedAtMs || !Number.isFinite(refreshedAtMs)) return false;
|
|
1521
|
+
return Date.now() - refreshedAtMs <= this.coverageStatsTtlMs;
|
|
1522
|
+
}
|
|
1512
1523
|
scheduleAutoReindex(entity, opts, stats, organizationIdOverride) {
|
|
1513
1524
|
if (!this.isAutoReindexEnabled()) return;
|
|
1514
1525
|
const bus = this.resolveEventBus();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/query_index/lib/engine.ts"],
|
|
4
|
-
"sourcesContent": ["import type { QueryEngine, QueryOptions, QueryResult, FilterOp, Filter, QueryCustomFieldSource, PartialIndexWarning, QueryExtensionsConfig, Sort } from '@open-mercato/shared/lib/query/types'\nimport { SortDir } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BasicQueryEngine, resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { type Kysely, sql, type RawBuilder } from 'kysely'\nimport type { EventBus } from '@open-mercato/events'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from './coverage'\nimport { createProfiler, shouldEnableProfiler, type Profiler } from '@open-mercato/shared/lib/profiler'\nimport type { VectorIndexService } from '@open-mercato/search/vector'\nimport { decryptIndexDocCustomFields } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport {\n applyJoinFilters,\n normalizeFilters,\n partitionFilters,\n resolveJoins,\n type BaseFilter,\n type ResolvedJoin,\n} from '@open-mercato/shared/lib/query/join-utils'\nimport { resolveSearchConfig, type SearchConfig } from '@open-mercato/shared/lib/search/config'\nimport { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'\nimport { runBeforeQueryPipeline, runAfterQueryPipeline, type QueryExtensionContext } from '@open-mercato/shared/lib/query/query-extension-runner'\nimport { resolveEncryptedSortFields, sortRowsInMemory } from '@open-mercato/shared/lib/query/encrypted-sort'\n\nfunction buildFilterableCustomFieldJoins(\n sources: QueryCustomFieldSource[] | undefined,\n): Array<{\n alias: string\n table?: string\n entityId: EntityId\n from: { field: string }\n to: { field: string }\n type: 'left' | 'inner'\n}> {\n if (!sources || sources.length === 0) return []\n return sources.flatMap((source, index) => {\n if (!source.join) return []\n const alias = typeof source.alias === 'string' && source.alias.trim().length > 0\n ? source.alias.trim()\n : `cfs_${index}`\n return [{\n alias,\n table: source.table,\n entityId: source.entityId,\n from: { field: source.join.fromField },\n to: { field: source.join.toField },\n type: source.join.type === 'inner' ? 'inner' : 'left',\n }]\n })\n}\n\nfunction resolveBooleanEnv(names: readonly string[], defaultValue: boolean): boolean {\n for (const name of names) {\n const raw = process.env[name]\n if (raw !== undefined) return parseBooleanWithDefault(raw, defaultValue)\n }\n return defaultValue\n}\n\nfunction resolveDebugVerbosity(): boolean {\n const queryIndexDebug = process.env.OM_QUERY_INDEX_DEBUG\n if (queryIndexDebug !== undefined) {\n return parseBooleanToken(queryIndexDebug) ?? false\n }\n const level = (process.env.LOG_VERBOSITY ?? process.env.LOG_LEVEL ?? '').toLowerCase()\n if (['debug', 'trace', 'silly'].includes(level)) return true\n return false\n}\n\ntype AnyDb = Kysely<any>\ntype AnyBuilder = any\ntype NormalizedFilter = { field: string; op: FilterOp; value?: unknown }\ntype IndexDocSource = { alias: string; entityId: EntityId; recordIdColumn: string }\ntype PreparedCustomFieldSource = {\n alias: string\n indexAlias: string\n entityId: EntityId\n recordIdColumn: string\n organizationField?: string\n tenantField?: string\n table: string\n}\ntype SearchRuntime = {\n enabled: boolean\n config: SearchConfig\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n tenantId?: string | null\n searchSources?: SearchTokenSource[]\n}\n\ntype EncryptionResolver = () => {\n decryptEntityPayload?: (entityId: EntityId, payload: Record<string, unknown>, tenantId?: string | null, organizationId?: string | null) => Promise<Record<string, unknown>>\n getEncryptedFieldNames?: (entityId: EntityId, tenantId?: string | null, organizationId?: string | null) => Promise<readonly string[]>\n isEnabled?: () => boolean\n} | null\n\ntype SearchTokenSource = { entity: string; recordIdColumn: string }\n\nfunction createQueryProfiler(entity: string): Profiler {\n const enabled = shouldEnableProfiler(entity)\n return createProfiler({\n scope: 'query_engine',\n target: entity,\n label: `query_engine:${entity}`,\n loggerLabel: '[qe:profile]',\n enabled,\n })\n}\n\nexport class HybridQueryEngine implements QueryEngine {\n private coverageStatsTtlMs: number\n private customFieldKeysCache = new Map<string, { expiresAt: number; value: string[] }>()\n private customFieldKeysTtlMs: number\n private columnCache = new Map<string, boolean>()\n private debugVerbosity: boolean | null = null\n private sqlDebugEnabled: boolean | null = null\n private forcePartialIndexEnabled: boolean | null = null\n private autoReindexEnabled: boolean | null = null\n private coverageOptimizationEnabled: boolean | null = null\n private pendingCoverageRefreshKeys = new Set<string>()\n private searchAliasSeq = 0\n\n constructor(\n private em: EntityManager,\n private fallback: BasicQueryEngine,\n private eventBusResolver?: () => Pick<EventBus, 'emitEvent'> | null | undefined,\n private vectorServiceResolver?: () => VectorIndexService | null | undefined,\n private encryptionResolver?: EncryptionResolver,\n ) {\n const coverageTtl = Number.parseInt(process.env.QUERY_INDEX_COVERAGE_CACHE_MS ?? '', 10)\n this.coverageStatsTtlMs = Number.isFinite(coverageTtl) && coverageTtl >= 0 ? coverageTtl : 5 * 60 * 1000\n const cfTtl = Number.parseInt(process.env.QUERY_INDEX_CF_KEYS_CACHE_MS ?? '', 10)\n this.customFieldKeysTtlMs = Number.isFinite(cfTtl) && cfTtl >= 0 ? cfTtl : 5 * 60 * 1000\n }\n\n private getEncryptionService() {\n try {\n return this.encryptionResolver?.() ?? null\n } catch {\n return null\n }\n }\n\n private getDb(): AnyDb {\n const emAny = this.em as any\n if (typeof emAny.getKysely === 'function') return emAny.getKysely() as AnyDb\n throw new Error('HybridQueryEngine requires an EntityManager exposing getKysely() (MikroORM v7)')\n }\n\n async query<T = unknown>(entity: EntityId, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const ext: QueryExtensionsConfig | undefined = opts.extensions\n let hybridExtCtx: QueryExtensionContext | null = null\n const noopDi = { resolve: <R = unknown>(_name: string): R => { throw new Error('No DI context') } }\n\n if (ext) {\n hybridExtCtx = {\n entity: String(entity),\n engine: 'hybrid',\n tenantId: opts.tenantId ?? '',\n organizationId: opts.organizationId,\n userId: ext.userId,\n em: this.em,\n container: ext.container,\n userFeatures: ext.userFeatures,\n }\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n const beforeResult = await runBeforeQueryPipeline(opts, hybridExtCtx, diCtx)\n if (beforeResult.blocked) {\n throw new Error(beforeResult.errorMessage ?? 'Query blocked by extension subscriber')\n }\n opts = beforeResult.query\n }\n const { extensions: _stripExt, ...coreOpts } = opts\n opts = coreOpts\n\n const providedProfiler = opts.profiler\n const profiler = providedProfiler && providedProfiler.enabled\n ? providedProfiler\n : createQueryProfiler(String(entity))\n profiler.mark('query:init')\n let profileClosed = false\n const finishProfile = (meta?: Record<string, unknown>) => {\n if (!profiler.enabled || profileClosed) return\n profileClosed = true\n profiler.end(meta)\n }\n\n const applyAfterExtensions = async <R>(queryResult: QueryResult<R>): Promise<QueryResult<R>> => {\n if (!ext || !hybridExtCtx) return queryResult\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n return await runAfterQueryPipeline(\n queryResult as QueryResult<Record<string, unknown>>,\n opts,\n hybridExtCtx,\n diCtx,\n ) as QueryResult<R>\n }\n\n try {\n const debugEnabled = this.isDebugVerbosity()\n if (debugEnabled) this.debug('query:start', { entity })\n this.searchAliasSeq = 0\n\n const isCustom = await this.isCustomEntity(entity)\n if (isCustom) {\n if (debugEnabled) this.debug('query:custom-entity', { entity })\n const section = profiler.section('custom_entity')\n try {\n const result = await this.queryCustomEntity<T>(entity, opts)\n section.end({ mode: 'custom_entity' })\n finishProfile({\n result: 'custom_entity',\n total: Array.isArray(result.items) ? result.items.length : undefined,\n })\n return await applyAfterExtensions(result)\n } catch (err) {\n section.end({ error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n const db = this.getDb()\n profiler.mark('query:db_ready')\n const baseTable = resolveEntityTableName(this.em, entity)\n profiler.mark('query:base_table_resolved')\n const searchConfig = resolveSearchConfig()\n const orgScope = this.resolveOrganizationScope(opts)\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n\n const baseExists = await profiler.measure('base_table_exists', () => this.tableExists(baseTable))\n if (!baseExists) {\n if (debugEnabled) this.debug('query:fallback:missing-base', { entity, baseTable })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'missing_base' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n if (opts.omitAutomaticTenantOrgScope === true) {\n if (debugEnabled) this.debug('query:fallback:omit-automatic-scope', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'omit_automatic_tenant_org_scope' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n const cfFilters = normalizedFilters.filter((filter) => filter.field.startsWith('cf:') || filter.field.startsWith('l10n:'))\n const coverageScope = this.resolveCoverageSnapshotScope(opts)\n const wantsCf = (\n (opts.fields || []).some((field) => typeof field === 'string' && (field.startsWith('cf:') || field.startsWith('l10n:'))) ||\n cfFilters.length > 0 ||\n (Array.isArray(opts.includeCustomFields) && opts.includeCustomFields.length > 0)\n )\n\n if (debugEnabled) {\n this.debug('query:config', {\n entity,\n wantsCustomFields: wantsCf,\n customFieldSources: Array.isArray(opts.customFieldSources) ? opts.customFieldSources.map((src) => src?.entityId) : undefined,\n fields: opts.fields,\n })\n }\n\n let partialIndexWarning: PartialIndexWarning | null = null\n let entityHasActiveCustomFields = true\n\n if (wantsCf) {\n entityHasActiveCustomFields = await this.entityHasActiveCustomFields(entity, opts.tenantId ?? null)\n const hasIndexRows = await profiler.measure(\n 'index_any_rows',\n () => this.indexAnyRows(entity),\n (value) => ({ hasIndexRows: value })\n )\n if (!hasIndexRows) {\n if (debugEnabled) this.debug('query:fallback:no-index', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'no_index_rows' })\n return await applyAfterExtensions(fallbackResult)\n }\n if (entityHasActiveCustomFields) {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(entity, opts, coverageScope),\n (value) => (value\n ? {\n scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { scope: null })\n )\n if (gap) {\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(entity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n const force = this.isForcePartialIndexEnabled()\n if (!force) {\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity })\n }\n const fallbackResult = await this.fallback.query(entity, opts)\n const resultWithWarning: QueryResult<T> = {\n ...fallbackResult,\n meta: {\n ...(fallbackResult.meta ?? {}),\n partialIndexWarning: {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n },\n },\n }\n finishProfile({\n result: 'fallback',\n reason: 'partial_index',\n scope: gap.scope,\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n })\n return await applyAfterExtensions(resultWithWarning)\n }\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity })\n }\n partialIndexWarning = {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n }\n } else if (debugEnabled) {\n this.debug('query:coverage:skip-no-custom-fields', { entity })\n }\n }\n\n const qualify = (col: string) => `b.${col}`\n const columns = await this.getBaseColumnsForEntity(entity)\n const hasOrganizationColumn = await this.columnExists(baseTable, 'organization_id')\n const hasTenantColumn = await this.columnExists(baseTable, 'tenant_id')\n const hasDeletedColumn = await this.columnExists(baseTable, 'deleted_at')\n\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const resolvedJoinsConfig = resolveJoins(\n baseTable,\n [...(opts.joins ?? []), ...buildFilterableCustomFieldJoins(opts.customFieldSources)],\n (entityId) => resolveEntityTableName(this.em, entityId as any),\n )\n const joinMap = new Map<string, ResolvedJoin>()\n const aliasTables = new Map<string, string>()\n aliasTables.set('b', baseTable)\n aliasTables.set('base', baseTable)\n aliasTables.set(baseTable, baseTable)\n for (const join of resolvedJoinsConfig) {\n joinMap.set(join.alias, join)\n aliasTables.set(join.alias, join.table)\n }\n const { baseFilters, joinFilters } = partitionFilters(baseTable, normalizedFilters, joinMap)\n\n const searchRuntimeBase = {\n enabled: false,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n }\n\n // Prepare index sources for JSONB custom-field access.\n const indexSources: IndexDocSource[] = [{ alias: 'ei', entityId: entity, recordIdColumn: 'b.id' }]\n let preparedCfSources: PreparedCustomFieldSource[] = []\n const shouldAttachCustomSources = Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && (wantsCf || searchEnabled)\n if (shouldAttachCustomSources) {\n preparedCfSources = this.prepareCustomFieldSources(opts.customFieldSources ?? [])\n for (const source of preparedCfSources) {\n indexSources.push({ alias: source.indexAlias, entityId: source.entityId, recordIdColumn: `${source.alias}.${source.recordIdColumn}` })\n }\n }\n\n const searchSources: SearchTokenSource[] = indexSources\n .map((src) => ({ entity: String(src.entityId), recordIdColumn: src.recordIdColumn }))\n .filter((src) => src.recordIdColumn && src.entity)\n const hasSearchTokens = searchEnabled && searchSources.length\n ? await this.searchSourcesHaveTokens(searchSources, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = { ...searchRuntimeBase, searchSources, enabled: searchEnabled && hasSearchTokens }\n const joinSearchAvailability = new Map<string, boolean>()\n const searchFilters = normalizeFilters(opts.filters).filter((filter) => filter.op === 'like' || filter.op === 'ilike')\n if (searchFilters.length) {\n this.logSearchDebug('search:init', {\n entity,\n baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n fields: searchFilters.map((filter) => String(filter.field)),\n searchEnabled,\n hasSearchTokens,\n searchSources,\n searchConfig: {\n enabled: searchConfig.enabled,\n minTokenLength: searchConfig.minTokenLength,\n enablePartials: searchConfig.enablePartials,\n hashAlgorithm: searchConfig.hashAlgorithm,\n blocklistedFields: searchConfig.blocklistedFields,\n },\n })\n if (!searchEnabled) this.logSearchDebug('search:disabled', { entity, baseTable })\n else if (!hasSearchTokens) this.logSearchDebug('search:no-search-tokens', {\n entity, baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n searchSources,\n })\n }\n const hasNonBaseSearchSource = searchSources.some(\n (src) => src.entity !== String(entity) || src.recordIdColumn !== 'b.id'\n )\n\n // Additional partial-coverage checks for customFieldSources\n if (!partialIndexWarning && Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && this.isForcePartialIndexEnabled()) {\n const seen = new Set<string>([entity])\n for (const source of opts.customFieldSources) {\n const targetEntity = source?.entityId ? String(source.entityId) : null\n if (!targetEntity || seen.has(targetEntity)) continue\n seen.add(targetEntity)\n const sourceHasCustomFields = await this.entityHasActiveCustomFields(targetEntity, opts.tenantId ?? null)\n if (!sourceHasCustomFields) {\n if (debugEnabled) this.debug('query:coverage:skip-no-custom-fields', { entity: targetEntity })\n continue\n }\n const sourceTable = source.table ?? resolveEntityTableName(this.em, targetEntity)\n try {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(targetEntity, opts, coverageScope, sourceTable),\n (value) => (value\n ? {\n entity: targetEntity, scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { entity: targetEntity, scope: null })\n )\n if (!gap) continue\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(targetEntity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n partialIndexWarning = {\n entity: targetEntity,\n entityLabel: this.resolveEntityLabel(targetEntity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n if (debugEnabled) {\n if (gap.stats) this.debug('query:partial-coverage:forced', { entity: targetEntity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n else this.debug('query:partial-coverage:forced', { entity: targetEntity })\n }\n break\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:check-failed', { entity: targetEntity, error: err instanceof Error ? err.message : err })\n }\n }\n }\n\n if (\n !partialIndexWarning &&\n wantsCf &&\n entityHasActiveCustomFields &&\n this.isForcePartialIndexEnabled() &&\n opts.tenantId\n ) {\n try {\n await this.indexCoverageStats(entity, opts, coverageScope)\n const globalStats = await this.indexCoverageStats(entity, opts, coverageScope)\n if (globalStats) {\n const globalBase = globalStats.baseCount\n const globalIndexed = globalStats.indexedCount\n const globalGap = (globalBase > 0 && globalIndexed < globalBase) || globalIndexed > globalBase\n if (globalGap) {\n console.warn('[HybridQueryEngine] Partial index coverage detected at global scope; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n partialIndexWarning = {\n entity, entityLabel: this.resolveEntityLabel(entity),\n baseCount: globalBase, indexedCount: globalIndexed, scope: 'global',\n }\n }\n }\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:global-check-failed', { entity, error: err instanceof Error ? err.message : err })\n }\n }\n\n const resolveBaseColumn = (field: string): string | null => {\n if (columns.has(field)) return field\n if (field === 'organization_id' && columns.has('id')) return 'id'\n return null\n }\n const fallbackOrgId =\n opts.organizationId\n ?? (Array.isArray(opts.organizationIds) && opts.organizationIds.length === 1 ? opts.organizationIds[0] : null)\n const encSvc = this.getEncryptionService()\n const resolvedSorts: Sort[] = []\n for (const sort of opts.sort || []) {\n const field = String(sort.field)\n if (field.startsWith('cf:')) {\n resolvedSorts.push({ ...sort, field })\n } else {\n const baseField = resolveBaseColumn(field)\n if (baseField) resolvedSorts.push({ ...sort, field: baseField })\n }\n }\n const encryptedSortFields = await resolveEncryptedSortFields(\n encSvc,\n entity,\n resolvedSorts.filter((sort) => !sort.field.startsWith('cf:')).map((sort) => sort.field),\n opts.tenantId ?? null,\n fallbackOrgId,\n )\n const requiresPlaintextSort = encryptedSortFields.size > 0\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Build a reusable \"applyQueryShape\" function that applies every\n // WHERE/JOIN/scope to a fresh SelectQueryBuilder. We use this in\n // place of knex's `.clone()` for producing count + data queries.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const applyBaseScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (orgScope && hasOrganizationColumn) {\n next = this.applyOrganizationScope(next, qualify('organization_id'), orgScope)\n }\n if (hasTenantColumn) {\n next = next.where(qualify('tenant_id'), '=', opts.tenantId)\n }\n if (!opts.withDeleted && hasDeletedColumn) {\n next = next.where(qualify('deleted_at'), 'is', null)\n }\n return next\n }\n\n const applyEntityIndexesJoin = (q: AnyBuilder): AnyBuilder => {\n return q.leftJoin('entity_indexes as ei', (jb: any) => {\n let jc = jb\n .on('ei.entity_type', '=', String(entity))\n .onRef('ei.entity_id', '=', sql<string>`(${sql.ref(qualify('id'))}::text)`)\n if (hasOrganizationColumn) {\n jc = jc\n .onRef('ei.organization_id', '=', qualify('organization_id'))\n .on('ei.organization_id', 'is not', null)\n }\n if (hasTenantColumn) {\n jc = jc\n .onRef('ei.tenant_id', '=', qualify('tenant_id'))\n .on('ei.tenant_id', 'is not', null)\n }\n if (!opts.withDeleted) {\n jc = jc.on('ei.deleted_at', 'is', null)\n }\n return jc\n })\n }\n\n const applyCustomFieldSourceJoins = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const source of preparedCfSources) {\n const join = (opts.customFieldSources ?? []).find((s) => s && (s.alias ?? undefined) === source.alias)?.join\n if (!join) continue\n const joinType = (join.type ?? 'left') === 'inner' ? 'innerJoin' : 'leftJoin'\n next = (next as any)[joinType](`${source.table} as ${source.alias}`, (jb: any) =>\n jb.onRef(`${source.alias}.${join.toField}`, '=', qualify(join.fromField)))\n // Index join for source\n next = next.leftJoin(`entity_indexes as ${source.indexAlias}`, (jb: any) => {\n let jc = jb\n .on(`${source.indexAlias}.entity_type`, '=', String(source.entityId))\n .onRef(`${source.indexAlias}.entity_id`, '=', sql<string>`(${sql.ref(`${source.alias}.${source.recordIdColumn}`)}::text)`)\n const orgRef = source.organizationField\n ? `${source.alias}.${source.organizationField}`\n : (columns.has('organization_id') ? qualify('organization_id') : null)\n if (orgRef) {\n jc = jc\n .onRef(`${source.indexAlias}.organization_id`, '=', orgRef)\n .on(`${source.indexAlias}.organization_id`, 'is not', null)\n }\n const tenantRef = source.tenantField\n ? `${source.alias}.${source.tenantField}`\n : (columns.has('tenant_id') ? qualify('tenant_id') : null)\n if (tenantRef) {\n jc = jc\n .onRef(`${source.indexAlias}.tenant_id`, '=', tenantRef)\n .on(`${source.indexAlias}.tenant_id`, 'is not', null)\n }\n if (!opts.withDeleted) jc = jc.on(`${source.indexAlias}.deleted_at`, 'is', null)\n return jc\n })\n }\n return next\n }\n\n const applyCfFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of cfFilters) {\n next = this.applyCfFilterAcrossSources(\n next, filter.field, filter.op, filter.value, indexSources, searchRuntime,\n )\n }\n return next\n }\n\n const regularBaseFilters = baseFilters.filter((filter) => !filter.orGroup)\n const orGroupFilters = baseFilters.filter((filter) => filter.orGroup)\n\n const applyRegularBaseFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of regularBaseFilters) {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n next = this.applyIndexDocFilterFromAlias(\n next, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime,\n )\n continue\n }\n const column = qualify(baseField)\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime,\n entity, field: fieldName, recordIdColumn: 'b.id',\n })\n }\n return next\n }\n\n const applyOrGroupedBaseFilters = (q: AnyBuilder): AnyBuilder => {\n if (orGroupFilters.length === 0) return q\n const groups = new Map<string, BaseFilter[]>()\n for (const filter of orGroupFilters) {\n if (!filter.orGroup) continue\n const existing = groups.get(filter.orGroup) ?? []\n existing.push(filter)\n groups.set(filter.orGroup, existing)\n }\n const groupList = Array.from(groups.values()).filter((g) => g.length > 0)\n if (groupList.length === 0) return q\n // Combine all groups in a single WHERE: disjuncts are OR'd together; within\n // each disjunct, fields are AND'd. Building this as separate `.where()` calls\n // would AND the disjuncts (wrong semantics).\n return q.where((eb: any) => eb.or(\n groupList.map((groupFilters) => {\n const parts = groupFilters.map((filter) =>\n this.buildBaseFilterExpression(eb, filter, resolveBaseColumn, qualify, entity, searchRuntime),\n )\n return parts.length === 1 ? parts[0] : eb.and(parts)\n }),\n ))\n }\n\n const applyAliasScopes = async (target: AnyBuilder, aliasName: string): Promise<AnyBuilder> => {\n let next = target\n const tableName = aliasTables.get(aliasName)\n if (!tableName) return next\n if (orgScope && await this.columnExists(tableName, 'organization_id')) {\n next = this.applyOrganizationScope(next, `${aliasName}.organization_id`, orgScope)\n }\n if (opts.tenantId && await this.columnExists(tableName, 'tenant_id')) {\n next = next.where(`${aliasName}.tenant_id`, '=', opts.tenantId)\n }\n if (!opts.withDeleted && await this.columnExists(tableName, 'deleted_at')) {\n next = next.where(`${aliasName}.deleted_at`, 'is', null)\n }\n return next\n }\n\n const applyJoinFilterOpFn = (target: AnyBuilder, column: string, op: FilterOp, value?: unknown): AnyBuilder => {\n switch (op) {\n case 'eq': return target.where(column, '=', value as any)\n case 'ne': return target.where(column, '!=', value as any)\n case 'gt': return target.where(column, '>', value as any)\n case 'gte': return target.where(column, '>=', value as any)\n case 'lt': return target.where(column, '<', value as any)\n case 'lte': return target.where(column, '<=', value as any)\n case 'in': return target.where(column, 'in', this.toArray(value))\n case 'nin': return target.where(column, 'not in', this.toArray(value))\n case 'like': return target.where(column, 'like', value as any)\n case 'ilike': return target.where(column, 'ilike', value as any)\n case 'exists': return value ? target.where(column, 'is not', null) : target.where(column, 'is', null)\n default: return target\n }\n }\n\n const applyJoinSearchFilterOp = async (\n target: AnyBuilder,\n filter: { column: string; op: FilterOp; value?: unknown },\n _qualified: string,\n join: ResolvedJoin,\n ): Promise<boolean> => {\n if (!searchEnabled || !join.entityId) return false\n if (!['like', 'ilike'].includes(filter.op)) return false\n if (typeof filter.value !== 'string' || filter.value.trim().length === 0) return false\n\n let searchAvailable = joinSearchAvailability.get(join.entityId)\n if (searchAvailable === undefined) {\n searchAvailable = await this.hasSearchTokens(String(join.entityId), opts.tenantId ?? null, orgScope)\n joinSearchAvailability.set(join.entityId, searchAvailable)\n }\n if (!searchAvailable) return false\n\n const tokens = tokenizeText(String(filter.value), searchConfig)\n if (!tokens.hashes.length) return false\n\n return this.applySearchTokens(target, {\n entity: String(join.entityId),\n field: filter.column,\n hashes: tokens.hashes,\n recordIdColumn: `${join.alias}.id`,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n })\n }\n\n const applyQueryShape = async (q: AnyBuilder): Promise<AnyBuilder> => {\n let next = applyBaseScope(q)\n next = applyEntityIndexesJoin(next)\n next = applyCustomFieldSourceJoins(next)\n next = applyCfFilters(next)\n next = applyRegularBaseFilters(next)\n next = applyOrGroupedBaseFilters(next)\n // applyJoinFilters is the shared helper that handles `joinFilters` (ALIAS:col -> value).\n next = await applyJoinFilters({\n db,\n baseTable,\n builder: next,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n return next\n }\n\n const hasCustomFieldFilters = cfFilters.length > 0\n const canOptimizeCount = !hasCustomFieldFilters && !hasNonBaseSearchSource\n\n // Selection (for data query)\n const selectFieldSet = new Set<string>((opts.fields && opts.fields.length) ? opts.fields.map(String) : Array.from(columns.keys()))\n if (requiresPlaintextSort) {\n for (const field of encryptedSortFields) selectFieldSet.add(field)\n }\n if (opts.includeCustomFields === true) {\n const entityIds = Array.from(new Set(indexSources.map((src) => String(src.entityId))))\n try {\n const resolvedKeys = await this.resolveAvailableCustomFieldKeys(entityIds, opts.tenantId ?? null)\n resolvedKeys.forEach((key) => selectFieldSet.add(`cf:${key}`))\n if (this.isDebugVerbosity()) this.debug('query:cf:resolved-keys', { entity, keys: resolvedKeys })\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to resolve custom field keys for', entity, err)\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n opts.includeCustomFields.map((key) => String(key)).forEach((key) => selectFieldSet.add(`cf:${key}`))\n }\n const selectFields = Array.from(selectFieldSet)\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const field of selectFields) {\n const fieldName = String(field)\n if (fieldName.startsWith('cf:')) {\n const alias = this.sanitize(fieldName)\n const jsonExpr = this.buildCfJsonExprSql(fieldName, indexSources)\n const exprRaw = jsonExpr ?? sql`NULL::jsonb`\n next = next.select(exprRaw.as(alias))\n } else if (columns.has(fieldName)) {\n next = next.select(`${qualify(fieldName)} as ${fieldName}`)\n }\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (requiresPlaintextSort) return next\n for (const s of resolvedSorts) {\n const fieldName = String(s.field)\n if (fieldName.startsWith('cf:')) {\n const textExpr = this.buildCfTextExprSql(fieldName, indexSources)\n if (textExpr) {\n const direction = sql.raw(String(s.dir ?? SortDir.Asc))\n next = next.orderBy(sql`${textExpr} ${direction}`)\n }\n } else {\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) continue\n next = next.orderBy(qualify(baseField), s.dir ?? SortDir.Asc)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n const sqlDebugEnabled = this.isSqlDebugEnabled()\n\n let total: number\n\n if (canOptimizeCount) {\n // Optimized count: apply only base-scope + regular filters + or-group filters (no index joins).\n const optimizedRoot = db.selectFrom(`${baseTable} as b` as any)\n let countCore = applyBaseScope(optimizedRoot)\n countCore = applyRegularBaseFilters(countCore)\n countCore = applyOrGroupedBaseFilters(countCore)\n // joinFilters still need to be re-applied in the optimized path\n countCore = await applyJoinFilters({\n db,\n baseTable,\n builder: countCore,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n const sub = countCore.select(sql.ref(qualify('id')).as('id')).groupBy(qualify('id')).as('sq')\n const countQuery = db.selectFrom(sub as any).select(sql<string>`count(*)`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countQuery.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countQuery.executeTakeFirst(),\n { optimized: true }, profiler,\n )\n total = this.parseCount(countRow)\n } else {\n const countRoot = db.selectFrom(`${baseTable} as b` as any)\n const countBuilder = (await applyQueryShape(countRoot))\n .select(sql<string>`count(distinct ${sql.ref(qualify('id'))})`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countBuilder.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countBuilder.executeTakeFirst(),\n { optimized: false }, profiler,\n )\n total = this.parseCount(countRow)\n }\n\n const dataRoot = db.selectFrom(`${baseTable} as b` as any)\n let dataBuilder = await applyQueryShape(dataRoot)\n dataBuilder = applySelection(dataBuilder)\n dataBuilder = applySort(dataBuilder)\n if (!requiresPlaintextSort) {\n dataBuilder = dataBuilder.limit(pageSize).offset((page - 1) * pageSize)\n }\n\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = dataBuilder.compile()\n this.debug('query:sql:data', { entity, sql: compiled.sql, bindings: compiled.parameters, page, pageSize })\n }\n const itemsRaw = await this.captureSqlTiming(\n 'query:sql:data', entity,\n () => dataBuilder.execute(),\n { page, pageSize }, profiler,\n )\n if (debugEnabled) this.debug('query:complete', { entity, total, items: Array.isArray(itemsRaw) ? itemsRaw.length : 0 })\n\n let items = itemsRaw as any[]\n const dekKeyCache = new Map<string | null, string | null>()\n if (encSvc?.decryptEntityPayload) {\n const decrypt = encSvc.decryptEntityPayload.bind(encSvc) as (\n entityId: EntityId, payload: Record<string, unknown>, tenantId: string | null, organizationId: string | null,\n ) => Promise<Record<string, unknown>>\n items = await Promise.all(\n items.map(async (item) => {\n try {\n const decrypted = await decrypt(\n entity, item,\n item?.tenant_id ?? item?.tenantId ?? opts.tenantId ?? null,\n item?.organization_id ?? item?.organizationId ?? fallbackOrgId ?? null,\n )\n return { ...item, ...decrypted }\n } catch (err) {\n console.error('Error decrypting entity payload', err)\n return item\n }\n })\n )\n }\n if (encSvc) {\n items = await Promise.all(\n items.map(async (item) => {\n try {\n return await decryptIndexDocCustomFields(\n item,\n {\n tenantId: item?.tenant_id ?? item?.tenantId ?? opts.tenantId ?? null,\n organizationId: item?.organization_id ?? item?.organizationId ?? null,\n },\n encSvc as any, dekKeyCache,\n )\n } catch { return item }\n }),\n )\n }\n if (requiresPlaintextSort) {\n items = sortRowsInMemory(items as Record<string, unknown>[], resolvedSorts)\n .slice((page - 1) * pageSize, page * pageSize)\n }\n\n const typedItems = items as unknown as T[]\n let result: QueryResult<T> = { items: typedItems, page, pageSize, total }\n if (partialIndexWarning) result.meta = { partialIndexWarning }\n\n result = await applyAfterExtensions(result)\n finishProfile({\n result: 'ok', total, page, pageSize,\n itemCount: Array.isArray(items) ? items.length : undefined,\n partialIndexWarning: partialIndexWarning ? true : false,\n })\n return result\n } catch (err) {\n finishProfile({ result: 'error', error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n private prepareCustomFieldSources(\n sources: QueryCustomFieldSource[],\n ): PreparedCustomFieldSource[] {\n const prepared: PreparedCustomFieldSource[] = []\n sources.forEach((source, index) => {\n if (!source) return\n const joinTable = source.table ?? resolveEntityTableName(this.em, source.entityId)\n const alias = source.alias ?? `cfs_${index}`\n if (!source.join) {\n throw new Error(`QueryEngine: customFieldSources entry for ${String(source.entityId)} requires a join configuration`)\n }\n prepared.push({\n alias,\n indexAlias: `ei_${alias}`,\n entityId: source.entityId,\n recordIdColumn: source.recordIdColumn ?? 'id',\n organizationField: source.organizationField,\n tenantField: source.tenantField,\n table: joinTable,\n })\n })\n return prepared\n }\n\n private async isCustomEntity(entity: string): Promise<boolean> {\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities')\n .select('id')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .executeTakeFirst()\n return !!row\n } catch {\n return false\n }\n }\n\n /**\n * Adds a WHERE EXISTS / OR WHERE EXISTS subquery that matches\n * `search_tokens` for the supplied (entity, field) against the\n * provided record id column.\n *\n * Returns true when the sub-query was applied (i.e. tokens were\n * non-empty). Caller is responsible for the calling context\n * (direct where vs. inside `eb.or([...])`).\n */\n private applySearchTokens(\n q: AnyBuilder,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n combineWith?: 'and' | 'or'\n }\n ): boolean {\n if (!opts.hashes.length) {\n this.logSearchDebug('search:skip-no-hashes', {\n entity: opts.entity, field: opts.field,\n tenantId: opts.tenantId ?? null, organizationScope: opts.organizationScope,\n })\n return false\n }\n const alias = `st_${this.searchAliasSeq++}`\n this.logSearchDebug('search:apply-search-tokens', {\n entity: opts.entity, field: opts.field, alias,\n tokenCount: opts.hashes.length,\n tenantId: opts.tenantId ?? null,\n organizationScope: opts.organizationScope,\n combineWith: opts.combineWith ?? 'and',\n })\n\n const engine = this\n const buildSub = (eb: any) => {\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = engine.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n if (opts.combineWith === 'or') {\n // When called inside an .or([...]) array the caller supplied `eb`.\n // `q` is the ExpressionBuilder callable (eb) itself in that case.\n // We return the expression node rather than mutating q.\n ;(q as any).__pendingOrExists = buildSub(q)\n return true\n }\n\n // Default: append WHERE EXISTS (...) to the outer builder.\n ;(q as any).__applied = true\n const built = buildSub(q)\n // If q is a Kysely builder (has .where), use eb => eb.exists(sub)\n if (typeof q.where === 'function') {\n ;(q as any) = q.where((eb: any) => eb.exists(built))\n }\n return true\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as JSON across a single alias. */\n private jsonbSqlAlias(alias: string, key: string): RawBuilder<unknown> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql`coalesce(${sql.ref(alias + '.doc')} -> ${key}, ${sql.ref(alias + '.doc')} -> ${bare})`\n }\n return sql`${sql.ref(alias + '.doc')} -> ${key}`\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as text across a single alias. */\n private cfTextExprAlias(alias: string, key: string): RawBuilder<string | null> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql<string | null>`coalesce((${sql.ref(alias + '.doc')} ->> ${key}), (${sql.ref(alias + '.doc')} ->> ${bare}))`\n }\n return sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n }\n\n /** Build JSON/text SQL expressions across multiple index alias sources (coalesce over them). */\n private buildCfJsonExprSql(key: string, sources: IndexDocSource[]): RawBuilder<unknown> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.jsonbSqlAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private buildCfTextExprSql(key: string, sources: IndexDocSource[]): RawBuilder<string | null> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.cfTextExprAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql<string | null>`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private applyCfFilterAcrossSources(\n builder: AnyBuilder,\n key: string,\n op: FilterOp,\n value: unknown,\n sources: IndexDocSource[],\n search?: SearchRuntime\n ): AnyBuilder {\n if (!sources.length) return builder\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = this.applyMultiSourceSearchExists(builder, sources, key, hashes, search)\n this.logSearchDebug('search:cf-filter-across', {\n entity: sources.map((src) => src.entityId),\n field: key, tokens: tokens.tokens, hashes, applied,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n if (applied.builder !== builder) return applied.builder\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', {\n entity: sources.map((src) => src.entityId), field: key, value,\n })\n }\n return builder\n }\n\n const textExpr = this.buildCfTextExprSql(key, sources)\n const jsonExpr = this.buildCfJsonExprSql(key, sources)\n if (!textExpr || !jsonExpr) return builder\n\n const arrContains = (val: unknown) => sql<boolean>`${jsonExpr} @> ${JSON.stringify([val])}::jsonb`\n\n switch (op) {\n case 'eq':\n return builder.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return builder.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const values = this.toArray(value)\n return builder.where((eb: any) => eb.or(\n values.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const values = this.toArray(value)\n return builder.where(sql<boolean>`${textExpr} not in (${sql.join(values.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return builder.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return builder.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? builder.where(sql<boolean>`${textExpr} is not null`)\n : builder.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return builder.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return builder\n }\n }\n\n /** Apply a search-token EXISTS subquery across multiple sources (OR-joined). */\n private applyMultiSourceSearchExists(\n builder: AnyBuilder,\n sources: IndexDocSource[],\n key: string,\n hashes: string[],\n search: SearchRuntime,\n ): { builder: AnyBuilder; applied: boolean } {\n if (!sources.length || !hashes.length) return { builder, applied: false }\n const next = builder.where((eb: any) => eb.or(\n sources.map((source) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: String(source.entityId),\n field: key, hashes,\n recordIdColumn: `${source.alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n }))\n )\n ))\n return { builder: next, applied: true }\n }\n\n /** Construct a search-token EXISTS subquery using the given ExpressionBuilder. */\n private buildSearchTokensSub(\n eb: any,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n }\n ): any {\n const alias = `st_${this.searchAliasSeq++}`\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = this.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n private applyCfFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n search?: SearchRuntime\n ): AnyBuilder {\n const textExpr = this.cfTextExprAlias(alias, key)\n const arrExpr = sql<unknown>`(${sql.ref(alias + '.doc')} -> ${key})`\n const arrContains = (val: unknown) => sql<boolean>`${arrExpr} @> ${JSON.stringify([val])}::jsonb`\n\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes,\n recordIdColumn: `${alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n this.logSearchDebug('search:cf-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where((eb: any) => eb.or(\n vals.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n private applyIndexDocFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n recordIdColumn: string,\n search?: SearchRuntime,\n ): AnyBuilder {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes, recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n this.logSearchDebug('search:index-doc-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:index-doc-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where(sql<boolean>`${textExpr} = ${value}`)\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n /**\n * Build a single OR-group base filter expression as a Kysely predicate\n * (no side effects on the outer builder).\n */\n private buildBaseFilterExpression(\n eb: any,\n filter: BaseFilter,\n resolveBaseColumn: (field: string) => string | null,\n qualify: (col: string) => string,\n entity: EntityId,\n searchRuntime: SearchRuntime,\n ): any {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n // Doc-based filter via `ei` alias \u2014 returned as EXISTS where possible\n return this.buildIndexDocFilterExpression(eb, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime)\n }\n // For like/ilike with active search-tokens, route through hashed-token EXISTS subquery\n // so encrypted-at-rest columns can still be searched.\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n searchRuntime?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), searchRuntime.config)\n if (tokens.hashes.length) {\n const sources: SearchTokenSource[] = (searchRuntime.searchSources && searchRuntime.searchSources.length\n ? searchRuntime.searchSources\n : [{ entity: String(entity), recordIdColumn: 'b.id' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n return eb.or(\n sources.map((src) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: src.entity,\n field: fieldName,\n hashes: tokens.hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: searchRuntime.tenantId ?? null,\n organizationScope: searchRuntime.organizationScope ?? null,\n })),\n ),\n )\n }\n }\n // Tokenizer produced no hashes (e.g. value too short). Match the regular-base-filter\n // path's behavior of skipping the predicate (no filter), which is preferable to\n // silently turning into a plain `ilike` against an encrypted column.\n return sql<boolean>`true`\n }\n return this.buildColumnFilterExpression(eb, qualify(baseField), filter.op, filter.value)\n }\n\n private buildColumnFilterExpression(\n eb: any,\n column: string,\n op: FilterOp,\n value: unknown,\n ): any {\n switch (op) {\n case 'eq': return eb(column, '=', value)\n case 'ne': return eb(column, '!=', value)\n case 'gt': return eb(column, '>', value)\n case 'gte': return eb(column, '>=', value)\n case 'lt': return eb(column, '<', value)\n case 'lte': return eb(column, '<=', value)\n case 'in': return eb(column, 'in', this.toArray(value))\n case 'nin': return eb(column, 'not in', this.toArray(value))\n case 'like': return eb(column, 'like', value)\n case 'ilike': return eb(column, 'ilike', value)\n case 'exists': return eb(column, value ? 'is not' : 'is', null)\n default: return sql<boolean>`true`\n }\n }\n\n private buildIndexDocFilterExpression(\n eb: any,\n alias: string,\n _entity: EntityId,\n key: string,\n op: FilterOp,\n value: unknown,\n _recordIdColumn: string,\n _search?: SearchRuntime,\n ): any {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n switch (op) {\n case 'eq': return sql<boolean>`${textExpr} = ${value}`\n case 'ne': return sql<boolean>`${textExpr} <> ${value}`\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return sql<boolean>`${textExpr} ${operator} ${value}`\n }\n case 'like': return sql<boolean>`${textExpr} like ${value}`\n case 'ilike': return sql<boolean>`${textExpr} ilike ${value}`\n case 'in': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'nin': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'exists':\n return value ? sql<boolean>`${textExpr} is not null` : sql<boolean>`${textExpr} is null`\n default:\n return sql<boolean>`true`\n }\n }\n\n private async queryCustomEntity<T = unknown>(entity: string, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const db = this.getDb() as any\n const alias = 'ce'\n\n const orgScope = this.resolveOrganizationScope(opts)\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const searchConfig = resolveSearchConfig()\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n const hasSearchTokens = searchEnabled\n ? await this.hasSearchTokens(entity, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = {\n enabled: searchEnabled && hasSearchTokens,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n\n const applyScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n .where(`${alias}.entity_type`, '=', entity)\n .where(`${alias}.tenant_id`, '=', opts.tenantId)\n if (orgScope) {\n next = this.applyOrganizationScope(next, `${alias}.organization_id`, orgScope)\n }\n if (!opts.withDeleted) next = next.where(`${alias}.deleted_at`, 'is', null)\n for (const filter of normalizedFilters) {\n if (filter.field.startsWith('cf:')) {\n next = this.applyCfFilterFromAlias(next, alias, entity, filter.field, filter.op, filter.value, searchRuntime)\n continue\n }\n const column = this.resolveCustomEntityColumn(alias, String(filter.field))\n if (column) {\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n continue\n }\n // Unknown field \u2192 filter on doc JSON text\n const docExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${String(filter.field)})`\n next = this.applyColumnFilter(next, docExpr, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n }\n return next\n }\n\n // Determine CFs and l10n keys to include\n const cfKeys = new Set<string>()\n for (const f of (opts.fields || [])) {\n if (typeof f === 'string' && f.startsWith('cf:')) cfKeys.add(f.slice(3))\n else if (typeof f === 'string' && f.startsWith('l10n:')) cfKeys.add(f)\n }\n for (const filter of normalizedFilters) {\n if (typeof filter.field === 'string' && filter.field.startsWith('cf:')) cfKeys.add(filter.field.slice(3))\n else if (typeof filter.field === 'string' && filter.field.startsWith('l10n:')) cfKeys.add(filter.field)\n }\n if (opts.includeCustomFields === true) {\n try {\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .where('tenant_id', '=', opts.tenantId)\n .execute() as Array<{ key: unknown }>\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string') cfKeys.add(key)\n else if (key != null) cfKeys.add(String(key))\n }\n } catch {\n // ignore\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n for (const k of opts.includeCustomFields) cfKeys.add(k)\n }\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n const requested = (opts.fields && opts.fields.length) ? opts.fields : ['id']\n for (const field of requested) {\n const f = String(field)\n if (f.startsWith('cf:')) {\n const aliasName = this.sanitize(f)\n next = next.select(this.jsonbSqlAlias(alias, f).as(aliasName))\n } else if (f === 'id') {\n next = next.select(`${alias}.entity_id as id`)\n } else if (f === 'created_at' || f === 'updated_at' || f === 'deleted_at') {\n next = next.select(`${alias}.${f} as ${f}`)\n } else {\n const expr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${f})`\n next = next.select(expr.as(f))\n }\n }\n // Ensure CF fields for sort / includeCustomFields are selected\n for (const key of cfKeys) {\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.select(this.jsonbSqlAlias(alias, `cf:${key}`).as(aliasName))\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const s of opts.sort || []) {\n if (s.field.startsWith('cf:')) {\n const key = s.field.slice(3)\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.orderBy(aliasName, s.dir ?? SortDir.Asc)\n } else if (s.field === 'id') {\n next = next.orderBy(`${alias}.entity_id`, s.dir ?? SortDir.Asc)\n } else if (s.field === 'created_at' || s.field === 'updated_at' || s.field === 'deleted_at') {\n next = next.orderBy(`${alias}.${s.field}`, s.dir ?? SortDir.Asc)\n } else {\n const direction = sql.raw(String(s.dir ?? SortDir.Asc))\n next = next.orderBy(sql`(${sql.ref(alias + '.doc')} ->> ${s.field}) ${direction}`)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n\n const root = db.selectFrom(`custom_entities_storage as ${alias}`)\n const countQuery = applyScope(root).select(sql<string>`count(distinct ${sql.ref(`${alias}.entity_id`)})`.as('count'))\n const countRow = await countQuery.executeTakeFirst()\n const total = this.parseCount(countRow)\n\n let dataQuery = applyScope(db.selectFrom(`custom_entities_storage as ${alias}`))\n dataQuery = applySelection(dataQuery)\n dataQuery = applySort(dataQuery)\n dataQuery = dataQuery.limit(pageSize).offset((page - 1) * pageSize)\n const items = await dataQuery.execute()\n return { items, page, pageSize, total }\n }\n\n private async tableExists(table: string): Promise<boolean> {\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.tables')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .executeTakeFirst()\n return !!exists\n }\n\n private async hasSearchTokens(\n entity: string,\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n try {\n const db = this.getDb() as any\n let query = db\n .selectFrom('search_tokens')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n if (tenantId !== undefined) {\n query = query.where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n }\n if (orgScope) {\n query = this.applyOrganizationScope(query, 'search_tokens.organization_id', orgScope)\n }\n const row = await query.limit(1).executeTakeFirst()\n return !!row\n } catch (err) {\n this.logSearchDebug('search:has-tokens-error', {\n entity, tenantId, organizationScope: orgScope,\n error: err instanceof Error ? err.message : String(err),\n })\n return false\n }\n }\n\n private async searchSourcesHaveTokens(\n sources: SearchTokenSource[],\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n for (const source of sources) {\n const ok = await this.hasSearchTokens(source.entity, tenantId, orgScope)\n this.logSearchDebug('search:source-has-tokens', {\n entity: source.entity, recordIdColumn: source.recordIdColumn,\n tenantId, organizationScope: orgScope, hasTokens: ok,\n })\n if (ok) return true\n }\n return false\n }\n\n private async resolveAvailableCustomFieldKeys(entityIds: string[], tenantId: string | null): Promise<string[]> {\n if (!entityIds.length) return []\n const cacheKey = this.customFieldKeysCacheKey(entityIds, tenantId)\n const now = Date.now()\n const cached = this.customFieldKeysCache.get(cacheKey)\n if (cached && cached.expiresAt > now) return cached.value.slice()\n\n const db = this.getDb() as any\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', 'in', entityIds)\n .where('is_active', '=', true)\n .where((eb: any) => eb.or([\n eb('tenant_id', '=', tenantId),\n eb('tenant_id', 'is', null),\n ]))\n .execute() as Array<{ key: unknown }>\n const keys = new Set<string>()\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string' && key.trim().length) keys.add(key.trim())\n else if (key != null) keys.add(String(key))\n }\n const result = Array.from(keys)\n if (this.customFieldKeysTtlMs > 0) {\n this.customFieldKeysCache.set(cacheKey, { expiresAt: now + this.customFieldKeysTtlMs, value: result })\n }\n return result.slice()\n }\n\n private async entityHasActiveCustomFields(entityId: string, tenantId: string | null): Promise<boolean> {\n try {\n const keys = await this.resolveAvailableCustomFieldKeys([entityId], tenantId)\n return keys.length > 0\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('query:cf:check-error', {\n entity: entityId, tenantId: tenantId ?? null,\n error: err instanceof Error ? err.message : err,\n })\n }\n return true\n }\n }\n\n private customFieldKeysCacheKey(entityIds: string[], tenantId: string | null): string {\n const sorted = entityIds.slice().sort((a, b) => a.localeCompare(b)).join(',')\n return `${tenantId ?? '__none__'}|${sorted}`\n }\n\n private resolveVectorService(): VectorIndexService | null {\n if (!this.vectorServiceResolver) return null\n try {\n return this.vectorServiceResolver() ?? null\n } catch {\n return null\n }\n }\n\n private resolveEntityLabel(entity: string): string {\n return entity\n }\n\n private async indexAnyRows(entity: string): Promise<boolean> {\n const db = this.getDb() as any\n const coverage = await db\n .selectFrom('entity_index_coverage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .where('indexed_count', '>', 0)\n .executeTakeFirst()\n if (coverage) return true\n const exists = await db\n .selectFrom('entity_indexes')\n .select('entity_id')\n .where('entity_type', '=', entity)\n .executeTakeFirst()\n return !!exists\n }\n\n private async getStoredCoverageSnapshot(\n entity: string,\n tenantId: string | null,\n organizationId: string | null,\n withDeleted: boolean\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n try {\n if (!this.isCoverageOptimizationEnabled()) {\n await refreshCoverageSnapshot(this.em, {\n entityType: entity, tenantId, organizationId, withDeleted,\n })\n }\n const db = this.getDb()\n const row = await readCoverageSnapshot(db as any, {\n entityType: entity, tenantId, organizationId, withDeleted,\n })\n if (!row) return null\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:snapshot:read-error', {\n entity, tenantId, organizationId, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n return null\n }\n }\n\n private scheduleAutoReindex(\n entity: string,\n opts: QueryOptions,\n stats?: { baseCount: number; indexedCount: number },\n organizationIdOverride?: string | null\n ) {\n if (!this.isAutoReindexEnabled()) return\n const bus = this.resolveEventBus()\n if (!bus) return\n const payload = {\n entityType: entity,\n tenantId: opts.tenantId ?? null,\n organizationId: organizationIdOverride ?? opts.organizationId ?? null,\n force: false,\n }\n const context = stats\n ? { entity, tenantId: payload.tenantId, organizationId: payload.organizationId, baseCount: stats.baseCount, indexedCount: stats.indexedCount }\n : { entity, tenantId: payload.tenantId, organizationId: payload.organizationId }\n\n void Promise.resolve().then(async () => {\n try {\n await bus.emitEvent('query_index.reindex', payload, { persistent: true })\n if (this.isDebugVerbosity()) this.debug('query:auto-reindex:scheduled', context)\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to schedule auto reindex:', {\n ...context, error: err instanceof Error ? err.message : err,\n })\n }\n })\n }\n\n private scheduleCoverageRefresh(\n entity: string,\n tenantId: string | null | undefined,\n organizationId: string | null | undefined,\n withDeleted: boolean\n ): void {\n const bus = this.resolveEventBus()\n if (!bus) return\n const key = [entity, tenantId ?? '__tenant__', organizationId ?? '__org__', withDeleted ? '1' : '0'].join('|')\n if (this.pendingCoverageRefreshKeys.has(key)) return\n this.pendingCoverageRefreshKeys.add(key)\n void Promise.resolve()\n .then(async () => {\n try {\n await bus.emitEvent('query_index.coverage.refresh', {\n entityType: entity,\n tenantId: tenantId ?? null, organizationId: organizationId ?? null,\n withDeleted, delayMs: 0,\n })\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:scheduled', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n })\n }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:failed', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n })\n .finally(() => { this.pendingCoverageRefreshKeys.delete(key) })\n }\n\n private resolveEventBus(): Pick<EventBus, 'emitEvent'> | null {\n if (!this.eventBusResolver) return null\n try {\n const bus = this.eventBusResolver()\n return bus ?? null\n } catch {\n return null\n }\n }\n\n private isAutoReindexEnabled(): boolean {\n if (this.autoReindexEnabled != null) return this.autoReindexEnabled\n const raw = (process.env.SCHEDULE_AUTO_REINDEX ?? process.env.QUERY_INDEX_AUTO_REINDEX ?? '').trim().toLowerCase()\n if (!raw) { this.autoReindexEnabled = true; return true }\n const parsed = parseBooleanToken(raw)\n this.autoReindexEnabled = parsed === null ? true : parsed\n return this.autoReindexEnabled\n }\n\n private isCoverageOptimizationEnabled(): boolean {\n if (this.coverageOptimizationEnabled != null) return this.coverageOptimizationEnabled\n const raw = (process.env.OPTIMIZE_INDEX_COVERAGE_STATS ?? '').trim().toLowerCase()\n if (!raw) { this.coverageOptimizationEnabled = false; return false }\n this.coverageOptimizationEnabled = parseBooleanToken(raw) === true\n return this.coverageOptimizationEnabled\n }\n\n private async columnExists(table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (this.columnCache.has(key)) {\n const cached = this.columnCache.get(key)\n if (cached === true) return true\n this.columnCache.delete(key)\n }\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.columns')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .where('column_name', '=', column)\n .executeTakeFirst()\n const present = !!exists\n if (present) this.columnCache.set(key, true)\n else this.columnCache.delete(key)\n return present\n }\n\n private async getBaseColumnsForEntity(entity: string): Promise<Map<string, string>> {\n const db = this.getDb() as any\n const table = resolveEntityTableName(this.em, entity)\n const rows = await db\n .selectFrom('information_schema.columns')\n .select(['column_name', 'data_type'])\n .where('table_name', '=', table)\n .execute() as Array<{ column_name: string; data_type: string }>\n const map = new Map<string, string>()\n for (const r of rows) map.set(r.column_name, r.data_type)\n return map\n }\n\n private resolveOrganizationScope(opts: QueryOptions): { ids: string[]; includeNull: boolean } | null {\n if (opts.organizationIds !== undefined) {\n const raw = (opts.organizationIds ?? []).map((id) => (typeof id === 'string' ? id.trim() : id))\n const includeNull = raw.some((id) => id == null || id === '')\n const ids = raw.filter((id): id is string => typeof id === 'string' && id.length > 0)\n const unique = Array.from(new Set(ids))\n return { ids: unique, includeNull }\n }\n if (typeof opts.organizationId === 'string' && opts.organizationId.trim().length > 0) {\n return { ids: [opts.organizationId], includeNull: false }\n }\n return null\n }\n\n private resolveCoverageSnapshotScope(\n opts: QueryOptions\n ): { tenantId: string | null; organizationId: string | null } | null {\n const tenantId = opts.tenantId ?? null\n const orgScope = this.resolveOrganizationScope(opts)\n if (!orgScope) return { tenantId, organizationId: null }\n if (orgScope.includeNull) {\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n if (orgScope.ids.length === 1) return { tenantId, organizationId: orgScope.ids[0] }\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n\n private applyOrganizationScope(\n q: AnyBuilder,\n column: string,\n scope: { ids: string[]; includeNull: boolean }\n ): AnyBuilder {\n if (scope.ids.length === 0 && !scope.includeNull) {\n return q.where(sql<boolean>`1 = 0`)\n }\n return q.where((eb: any) => {\n const parts: any[] = []\n if (scope.ids.length > 0) parts.push(eb(column, 'in', scope.ids))\n if (scope.includeNull) parts.push(eb(column, 'is', null))\n if (parts.length === 1) return parts[0]\n return eb.or(parts)\n })\n }\n\n private normalizeFilters(filters?: QueryOptions['filters']): NormalizedFilter[] {\n if (!filters) return []\n const normalizeField = (k: string) => k.startsWith('cf_') ? `cf:${k.slice(3)}` : k\n if (Array.isArray(filters)) {\n return (filters as Filter[]).map((filter) => ({\n field: normalizeField(String(filter.field)),\n op: filter.op, value: filter.value,\n }))\n }\n const out: NormalizedFilter[] = []\n const obj = filters as Record<string, unknown>\n const add = (field: string, op: FilterOp, value?: unknown) => out.push({ field, op, value })\n for (const [rawKey, rawVal] of Object.entries(obj)) {\n const field = normalizeField(rawKey)\n if (rawVal !== null && typeof rawVal === 'object' && !Array.isArray(rawVal)) {\n for (const [opKey, opVal] of Object.entries(rawVal as Record<string, unknown>)) {\n switch (opKey) {\n case '$eq': add(field, 'eq', opVal); break\n case '$ne': add(field, 'ne', opVal); break\n case '$gt': add(field, 'gt', opVal); break\n case '$gte': add(field, 'gte', opVal); break\n case '$lt': add(field, 'lt', opVal); break\n case '$lte': add(field, 'lte', opVal); break\n case '$in': add(field, 'in', opVal); break\n case '$nin': add(field, 'nin', opVal); break\n case '$like': add(field, 'like', opVal); break\n case '$ilike': add(field, 'ilike', opVal); break\n case '$exists': add(field, 'exists', opVal); break\n }\n }\n } else {\n add(field, 'eq', rawVal)\n }\n }\n return out\n }\n\n private sanitize(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n }\n\n private toArray(value: unknown): readonly unknown[] {\n if (Array.isArray(value)) return value\n if (value === undefined) return []\n return [value]\n }\n\n private parseCount(row: unknown): number {\n if (row && typeof row === 'object' && 'count' in row) {\n const value = (row as { count: unknown }).count\n if (typeof value === 'number') return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? 0 : parsed\n }\n if (typeof value === 'bigint') return Number(value)\n }\n return 0\n }\n\n private logSearchDebug(event: string, payload: Record<string, unknown>) {\n if (!this.isDebugVerbosity()) return\n try {\n console.info('[query-index:search]', event, JSON.stringify(payload))\n } catch {\n console.info('[query-index:search]', event, payload)\n }\n }\n\n private applyColumnFilter(\n q: AnyBuilder,\n column: string | RawBuilder<unknown>,\n filter: NormalizedFilter,\n search?: SearchRuntime & { entity: string; field: string; recordIdColumn?: string },\n ): AnyBuilder {\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n search?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const sources: SearchTokenSource[] = (search.searchSources && search.searchSources.length\n ? search.searchSources\n : [{ entity: search.entity, recordIdColumn: search.recordIdColumn ?? '' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n const engine = this\n q = q.where((eb: any) => eb.or(\n sources.map((src) =>\n eb.exists(engine.buildSearchTokensSub(eb, {\n entity: src.entity, field: search.field, hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n ))\n this.logSearchDebug('search:filter', {\n entity: search.entity, field: search.field, tokens: tokens.tokens, hashes,\n applied: true, tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope,\n sources: sources.map((src) => ({ entity: src.entity, recordIdColumn: src.recordIdColumn })),\n })\n return q\n }\n } else {\n this.logSearchDebug('search:skip-empty-hashes', {\n entity: search.entity, field: search.field, value: filter.value,\n })\n }\n return q\n }\n const col: any = column\n switch (filter.op) {\n case 'eq': return q.where(col, '=', filter.value as any)\n case 'ne': return q.where(col, '!=', filter.value as any)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = filter.op === 'gt' ? '>' : filter.op === 'gte' ? '>=' : filter.op === 'lt' ? '<' : '<='\n return q.where(col, operator, filter.value as any)\n }\n case 'in':\n return q.where(col, 'in', this.toArray(filter.value))\n case 'nin':\n return q.where(col, 'not in', this.toArray(filter.value))\n case 'like':\n return q.where(col, 'like', filter.value as any)\n case 'ilike':\n return q.where(col, 'ilike', filter.value as any)\n case 'exists':\n return filter.value ? q.where(col, 'is not', null) : q.where(col, 'is', null)\n default:\n return q\n }\n }\n\n private resolveCustomEntityColumn(alias: string, field: string): string | null {\n if (field === 'id') return `${alias}.entity_id`\n if (field === 'organization_id' || field === 'organizationId') return `${alias}.organization_id`\n if (field === 'tenant_id' || field === 'tenantId') return `${alias}.tenant_id`\n if (field === 'created_at' || field === 'updated_at' || field === 'deleted_at') return `${alias}.${field}`\n return null\n }\n\n private isDebugVerbosity(): boolean {\n if (this.debugVerbosity != null) return this.debugVerbosity\n this.debugVerbosity = resolveDebugVerbosity()\n return this.debugVerbosity\n }\n\n private isSqlDebugEnabled(): boolean {\n if (this.sqlDebugEnabled != null) return this.sqlDebugEnabled\n this.sqlDebugEnabled = resolveBooleanEnv(['QUERY_ENGINE_DEBUG_SQL'], false)\n return this.sqlDebugEnabled\n }\n\n private isForcePartialIndexEnabled(): boolean {\n if (this.forcePartialIndexEnabled != null) return this.forcePartialIndexEnabled\n this.forcePartialIndexEnabled = resolveBooleanEnv(['FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES'], false)\n return this.forcePartialIndexEnabled\n }\n\n private async resolveCoverageGap(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n _sourceTable?: string\n ): Promise<{ stats?: { baseCount: number; indexedCount: number }; scope: 'scoped' | 'global' } | null> {\n const scope = coverageScope ?? this.resolveCoverageSnapshotScope(opts)\n if (!scope) return null\n const tenantId = scope.tenantId\n const organizationId = scope.organizationId\n const withDeleted = !!opts.withDeleted\n\n const snapshot = await this.getStoredCoverageSnapshot(entity, tenantId, organizationId, withDeleted)\n if (!snapshot) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n return { stats: undefined, scope: 'scoped' }\n }\n\n const baseCount = snapshot.baseCount\n const indexCount = snapshot.indexedCount\n const hasGap = baseCount > 0 && indexCount < baseCount\n if (hasGap || indexCount > baseCount) return { stats: snapshot, scope: 'scoped' }\n return null\n }\n\n // Backward-compatible hook for tests that mock coverage stats\n private async indexCoverageStats(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n const gap = await this.resolveCoverageGap(entity, opts, coverageScope)\n return gap?.stats ?? null\n }\n\n private async captureSqlTiming<TResult>(\n label: string,\n entity: EntityId,\n execute: () => Promise<TResult> | TResult,\n extra?: Record<string, unknown>,\n profiler?: Profiler\n ): Promise<TResult> {\n const shouldDebug = this.isSqlDebugEnabled() && this.isDebugVerbosity()\n const shouldProfile = profiler?.enabled === true\n if (!shouldDebug && !shouldProfile) return Promise.resolve(execute())\n const startedAt = process.hrtime.bigint()\n try {\n return await Promise.resolve(execute())\n } finally {\n const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const context: Record<string, unknown> = { entity, durationMs: Math.round(elapsedMs * 1000) / 1000 }\n if (extra) Object.assign(context, extra)\n if (shouldProfile) profiler!.record(label, context.durationMs as number, extra)\n if (shouldDebug) this.debug(`${label}:timing`, context)\n }\n }\n\n private debug(message: string, context?: Record<string, unknown>): void {\n if (!this.isDebugVerbosity()) return\n if (!this.isSqlDebugEnabled()) return\n if (context) console.debug('[HybridQueryEngine]', message, context)\n else console.debug('[HybridQueryEngine]', message)\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { QueryEngine, QueryOptions, QueryResult, FilterOp, Filter, QueryCustomFieldSource, PartialIndexWarning, QueryExtensionsConfig, Sort } from '@open-mercato/shared/lib/query/types'\nimport { SortDir } from '@open-mercato/shared/lib/query/types'\nimport type { EntityId } from '@open-mercato/shared/modules/entities'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { BasicQueryEngine, resolveEntityTableName } from '@open-mercato/shared/lib/query/engine'\nimport { type Kysely, sql, type RawBuilder } from 'kysely'\nimport type { EventBus } from '@open-mercato/events'\nimport { readCoverageSnapshot, refreshCoverageSnapshot } from './coverage'\nimport { createProfiler, shouldEnableProfiler, type Profiler } from '@open-mercato/shared/lib/profiler'\nimport type { VectorIndexService } from '@open-mercato/search/vector'\nimport { decryptIndexDocCustomFields } from '@open-mercato/shared/lib/encryption/indexDoc'\nimport { parseBooleanToken, parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\nimport {\n applyJoinFilters,\n normalizeFilters,\n partitionFilters,\n resolveJoins,\n type BaseFilter,\n type ResolvedJoin,\n} from '@open-mercato/shared/lib/query/join-utils'\nimport { resolveSearchConfig, type SearchConfig } from '@open-mercato/shared/lib/search/config'\nimport { tokenizeText } from '@open-mercato/shared/lib/search/tokenize'\nimport { runBeforeQueryPipeline, runAfterQueryPipeline, type QueryExtensionContext } from '@open-mercato/shared/lib/query/query-extension-runner'\nimport { resolveEncryptedSortFields, sortRowsInMemory } from '@open-mercato/shared/lib/query/encrypted-sort'\n\nfunction buildFilterableCustomFieldJoins(\n sources: QueryCustomFieldSource[] | undefined,\n): Array<{\n alias: string\n table?: string\n entityId: EntityId\n from: { field: string }\n to: { field: string }\n type: 'left' | 'inner'\n}> {\n if (!sources || sources.length === 0) return []\n return sources.flatMap((source, index) => {\n if (!source.join) return []\n const alias = typeof source.alias === 'string' && source.alias.trim().length > 0\n ? source.alias.trim()\n : `cfs_${index}`\n return [{\n alias,\n table: source.table,\n entityId: source.entityId,\n from: { field: source.join.fromField },\n to: { field: source.join.toField },\n type: source.join.type === 'inner' ? 'inner' : 'left',\n }]\n })\n}\n\nfunction resolveBooleanEnv(names: readonly string[], defaultValue: boolean): boolean {\n for (const name of names) {\n const raw = process.env[name]\n if (raw !== undefined) return parseBooleanWithDefault(raw, defaultValue)\n }\n return defaultValue\n}\n\nfunction resolveDebugVerbosity(): boolean {\n const queryIndexDebug = process.env.OM_QUERY_INDEX_DEBUG\n if (queryIndexDebug !== undefined) {\n return parseBooleanToken(queryIndexDebug) ?? false\n }\n const level = (process.env.LOG_VERBOSITY ?? process.env.LOG_LEVEL ?? '').toLowerCase()\n if (['debug', 'trace', 'silly'].includes(level)) return true\n return false\n}\n\ntype AnyDb = Kysely<any>\ntype AnyBuilder = any\ntype NormalizedFilter = { field: string; op: FilterOp; value?: unknown }\ntype IndexDocSource = { alias: string; entityId: EntityId; recordIdColumn: string }\ntype PreparedCustomFieldSource = {\n alias: string\n indexAlias: string\n entityId: EntityId\n recordIdColumn: string\n organizationField?: string\n tenantField?: string\n table: string\n}\ntype SearchRuntime = {\n enabled: boolean\n config: SearchConfig\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n tenantId?: string | null\n searchSources?: SearchTokenSource[]\n}\n\ntype EncryptionResolver = () => {\n decryptEntityPayload?: (entityId: EntityId, payload: Record<string, unknown>, tenantId?: string | null, organizationId?: string | null) => Promise<Record<string, unknown>>\n getEncryptedFieldNames?: (entityId: EntityId, tenantId?: string | null, organizationId?: string | null) => Promise<readonly string[]>\n isEnabled?: () => boolean\n} | null\n\ntype SearchTokenSource = { entity: string; recordIdColumn: string }\n\nfunction createQueryProfiler(entity: string): Profiler {\n const enabled = shouldEnableProfiler(entity)\n return createProfiler({\n scope: 'query_engine',\n target: entity,\n label: `query_engine:${entity}`,\n loggerLabel: '[qe:profile]',\n enabled,\n })\n}\n\nexport class HybridQueryEngine implements QueryEngine {\n private coverageStatsTtlMs: number\n private customFieldKeysCache = new Map<string, { expiresAt: number; value: string[] }>()\n private customFieldKeysTtlMs: number\n private columnCache = new Map<string, boolean>()\n private debugVerbosity: boolean | null = null\n private sqlDebugEnabled: boolean | null = null\n private forcePartialIndexEnabled: boolean | null = null\n private autoReindexEnabled: boolean | null = null\n private coverageOptimizationEnabled: boolean | null = null\n private pendingCoverageRefreshKeys = new Set<string>()\n private searchAliasSeq = 0\n\n constructor(\n private em: EntityManager,\n private fallback: BasicQueryEngine,\n private eventBusResolver?: () => Pick<EventBus, 'emitEvent'> | null | undefined,\n private vectorServiceResolver?: () => VectorIndexService | null | undefined,\n private encryptionResolver?: EncryptionResolver,\n ) {\n const coverageTtl = Number.parseInt(process.env.QUERY_INDEX_COVERAGE_CACHE_MS ?? '', 10)\n this.coverageStatsTtlMs = Number.isFinite(coverageTtl) && coverageTtl >= 0 ? coverageTtl : 5 * 60 * 1000\n const cfTtl = Number.parseInt(process.env.QUERY_INDEX_CF_KEYS_CACHE_MS ?? '', 10)\n this.customFieldKeysTtlMs = Number.isFinite(cfTtl) && cfTtl >= 0 ? cfTtl : 5 * 60 * 1000\n }\n\n private getEncryptionService() {\n try {\n return this.encryptionResolver?.() ?? null\n } catch {\n return null\n }\n }\n\n private getDb(): AnyDb {\n const emAny = this.em as any\n if (typeof emAny.getKysely === 'function') return emAny.getKysely() as AnyDb\n throw new Error('HybridQueryEngine requires an EntityManager exposing getKysely() (MikroORM v7)')\n }\n\n async query<T = unknown>(entity: EntityId, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const ext: QueryExtensionsConfig | undefined = opts.extensions\n let hybridExtCtx: QueryExtensionContext | null = null\n const noopDi = { resolve: <R = unknown>(_name: string): R => { throw new Error('No DI context') } }\n\n if (ext) {\n hybridExtCtx = {\n entity: String(entity),\n engine: 'hybrid',\n tenantId: opts.tenantId ?? '',\n organizationId: opts.organizationId,\n userId: ext.userId,\n em: this.em,\n container: ext.container,\n userFeatures: ext.userFeatures,\n }\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n const beforeResult = await runBeforeQueryPipeline(opts, hybridExtCtx, diCtx)\n if (beforeResult.blocked) {\n throw new Error(beforeResult.errorMessage ?? 'Query blocked by extension subscriber')\n }\n opts = beforeResult.query\n }\n const { extensions: _stripExt, ...coreOpts } = opts\n opts = coreOpts\n\n const providedProfiler = opts.profiler\n const profiler = providedProfiler && providedProfiler.enabled\n ? providedProfiler\n : createQueryProfiler(String(entity))\n profiler.mark('query:init')\n let profileClosed = false\n const finishProfile = (meta?: Record<string, unknown>) => {\n if (!profiler.enabled || profileClosed) return\n profileClosed = true\n profiler.end(meta)\n }\n\n const applyAfterExtensions = async <R>(queryResult: QueryResult<R>): Promise<QueryResult<R>> => {\n if (!ext || !hybridExtCtx) return queryResult\n const diCtx = ext.resolve ? { resolve: ext.resolve } : noopDi\n return await runAfterQueryPipeline(\n queryResult as QueryResult<Record<string, unknown>>,\n opts,\n hybridExtCtx,\n diCtx,\n ) as QueryResult<R>\n }\n\n try {\n const debugEnabled = this.isDebugVerbosity()\n if (debugEnabled) this.debug('query:start', { entity })\n this.searchAliasSeq = 0\n\n const isCustom = await this.isCustomEntity(entity)\n if (isCustom) {\n if (debugEnabled) this.debug('query:custom-entity', { entity })\n const section = profiler.section('custom_entity')\n try {\n const result = await this.queryCustomEntity<T>(entity, opts)\n section.end({ mode: 'custom_entity' })\n finishProfile({\n result: 'custom_entity',\n total: Array.isArray(result.items) ? result.items.length : undefined,\n })\n return await applyAfterExtensions(result)\n } catch (err) {\n section.end({ error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n const db = this.getDb()\n profiler.mark('query:db_ready')\n const baseTable = resolveEntityTableName(this.em, entity)\n profiler.mark('query:base_table_resolved')\n const searchConfig = resolveSearchConfig()\n const orgScope = this.resolveOrganizationScope(opts)\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n\n const baseExists = await profiler.measure('base_table_exists', () => this.tableExists(baseTable))\n if (!baseExists) {\n if (debugEnabled) this.debug('query:fallback:missing-base', { entity, baseTable })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'missing_base' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n if (opts.omitAutomaticTenantOrgScope === true) {\n if (debugEnabled) this.debug('query:fallback:omit-automatic-scope', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'omit_automatic_tenant_org_scope' })\n return await applyAfterExtensions(fallbackResult)\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n const cfFilters = normalizedFilters.filter((filter) => filter.field.startsWith('cf:') || filter.field.startsWith('l10n:'))\n const coverageScope = this.resolveCoverageSnapshotScope(opts)\n const wantsCf = (\n (opts.fields || []).some((field) => typeof field === 'string' && (field.startsWith('cf:') || field.startsWith('l10n:'))) ||\n cfFilters.length > 0 ||\n (Array.isArray(opts.includeCustomFields) && opts.includeCustomFields.length > 0)\n )\n\n if (debugEnabled) {\n this.debug('query:config', {\n entity,\n wantsCustomFields: wantsCf,\n customFieldSources: Array.isArray(opts.customFieldSources) ? opts.customFieldSources.map((src) => src?.entityId) : undefined,\n fields: opts.fields,\n })\n }\n\n let partialIndexWarning: PartialIndexWarning | null = null\n let entityHasActiveCustomFields = true\n\n if (wantsCf) {\n entityHasActiveCustomFields = await this.entityHasActiveCustomFields(entity, opts.tenantId ?? null)\n const hasIndexRows = await profiler.measure(\n 'index_any_rows',\n () => this.indexAnyRows(entity),\n (value) => ({ hasIndexRows: value })\n )\n if (!hasIndexRows) {\n if (debugEnabled) this.debug('query:fallback:no-index', { entity })\n const fallbackResult = await this.fallback.query(entity, opts)\n finishProfile({ result: 'fallback', reason: 'no_index_rows' })\n return await applyAfterExtensions(fallbackResult)\n }\n if (entityHasActiveCustomFields) {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(entity, opts, coverageScope),\n (value) => (value\n ? {\n scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { scope: null })\n )\n if (gap) {\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(entity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n const force = this.isForcePartialIndexEnabled()\n if (!force) {\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; falling back to basic engine:', { entity })\n if (debugEnabled) this.debug('query:fallback:partial-coverage', { entity })\n }\n const fallbackResult = await this.fallback.query(entity, opts)\n const resultWithWarning: QueryResult<T> = {\n ...fallbackResult,\n meta: {\n ...(fallbackResult.meta ?? {}),\n partialIndexWarning: {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n },\n },\n }\n finishProfile({\n result: 'fallback',\n reason: 'partial_index',\n scope: gap.scope,\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n })\n return await applyAfterExtensions(resultWithWarning)\n }\n if (gap.stats) {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n } else {\n console.warn('[HybridQueryEngine] Partial index coverage detected; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity })\n }\n partialIndexWarning = {\n entity,\n entityLabel: this.resolveEntityLabel(entity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n }\n } else if (debugEnabled) {\n this.debug('query:coverage:skip-no-custom-fields', { entity })\n }\n }\n\n const qualify = (col: string) => `b.${col}`\n const columns = await this.getBaseColumnsForEntity(entity)\n const hasOrganizationColumn = await this.columnExists(baseTable, 'organization_id')\n const hasTenantColumn = await this.columnExists(baseTable, 'tenant_id')\n const hasDeletedColumn = await this.columnExists(baseTable, 'deleted_at')\n\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const resolvedJoinsConfig = resolveJoins(\n baseTable,\n [...(opts.joins ?? []), ...buildFilterableCustomFieldJoins(opts.customFieldSources)],\n (entityId) => resolveEntityTableName(this.em, entityId as any),\n )\n const joinMap = new Map<string, ResolvedJoin>()\n const aliasTables = new Map<string, string>()\n aliasTables.set('b', baseTable)\n aliasTables.set('base', baseTable)\n aliasTables.set(baseTable, baseTable)\n for (const join of resolvedJoinsConfig) {\n joinMap.set(join.alias, join)\n aliasTables.set(join.alias, join.table)\n }\n const { baseFilters, joinFilters } = partitionFilters(baseTable, normalizedFilters, joinMap)\n\n const searchRuntimeBase = {\n enabled: false,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n }\n\n // Prepare index sources for JSONB custom-field access.\n const indexSources: IndexDocSource[] = [{ alias: 'ei', entityId: entity, recordIdColumn: 'b.id' }]\n let preparedCfSources: PreparedCustomFieldSource[] = []\n const shouldAttachCustomSources = Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && (wantsCf || searchEnabled)\n if (shouldAttachCustomSources) {\n preparedCfSources = this.prepareCustomFieldSources(opts.customFieldSources ?? [])\n for (const source of preparedCfSources) {\n indexSources.push({ alias: source.indexAlias, entityId: source.entityId, recordIdColumn: `${source.alias}.${source.recordIdColumn}` })\n }\n }\n\n const searchSources: SearchTokenSource[] = indexSources\n .map((src) => ({ entity: String(src.entityId), recordIdColumn: src.recordIdColumn }))\n .filter((src) => src.recordIdColumn && src.entity)\n const hasSearchTokens = searchEnabled && searchSources.length\n ? await this.searchSourcesHaveTokens(searchSources, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = { ...searchRuntimeBase, searchSources, enabled: searchEnabled && hasSearchTokens }\n const joinSearchAvailability = new Map<string, boolean>()\n const searchFilters = normalizeFilters(opts.filters).filter((filter) => filter.op === 'like' || filter.op === 'ilike')\n if (searchFilters.length) {\n this.logSearchDebug('search:init', {\n entity,\n baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n fields: searchFilters.map((filter) => String(filter.field)),\n searchEnabled,\n hasSearchTokens,\n searchSources,\n searchConfig: {\n enabled: searchConfig.enabled,\n minTokenLength: searchConfig.minTokenLength,\n enablePartials: searchConfig.enablePartials,\n hashAlgorithm: searchConfig.hashAlgorithm,\n blocklistedFields: searchConfig.blocklistedFields,\n },\n })\n if (!searchEnabled) this.logSearchDebug('search:disabled', { entity, baseTable })\n else if (!hasSearchTokens) this.logSearchDebug('search:no-search-tokens', {\n entity, baseTable,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n searchSources,\n })\n }\n const hasNonBaseSearchSource = searchSources.some(\n (src) => src.entity !== String(entity) || src.recordIdColumn !== 'b.id'\n )\n\n // Additional partial-coverage checks for customFieldSources\n if (!partialIndexWarning && Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0 && this.isForcePartialIndexEnabled()) {\n const seen = new Set<string>([entity])\n for (const source of opts.customFieldSources) {\n const targetEntity = source?.entityId ? String(source.entityId) : null\n if (!targetEntity || seen.has(targetEntity)) continue\n seen.add(targetEntity)\n const sourceHasCustomFields = await this.entityHasActiveCustomFields(targetEntity, opts.tenantId ?? null)\n if (!sourceHasCustomFields) {\n if (debugEnabled) this.debug('query:coverage:skip-no-custom-fields', { entity: targetEntity })\n continue\n }\n const sourceTable = source.table ?? resolveEntityTableName(this.em, targetEntity)\n try {\n const gap = await profiler.measure(\n 'resolve_coverage_gap',\n () => this.resolveCoverageGap(targetEntity, opts, coverageScope, sourceTable),\n (value) => (value\n ? {\n entity: targetEntity, scope: value.scope,\n baseCount: value.stats?.baseCount ?? null,\n indexedCount: value.stats?.indexedCount ?? null,\n }\n : { entity: targetEntity, scope: null })\n )\n if (!gap) continue\n if (!opts.skipAutoReindex) {\n this.scheduleAutoReindex(targetEntity, opts, gap.stats, coverageScope?.organizationId ?? null)\n }\n partialIndexWarning = {\n entity: targetEntity,\n entityLabel: this.resolveEntityLabel(targetEntity),\n baseCount: gap.stats?.baseCount ?? null,\n indexedCount: gap.stats?.indexedCount ?? null,\n scope: gap.stats ? gap.scope : undefined,\n }\n if (debugEnabled) {\n if (gap.stats) this.debug('query:partial-coverage:forced', { entity: targetEntity, baseCount: gap.stats.baseCount, indexedCount: gap.stats.indexedCount, scope: gap.scope })\n else this.debug('query:partial-coverage:forced', { entity: targetEntity })\n }\n break\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:check-failed', { entity: targetEntity, error: err instanceof Error ? err.message : err })\n }\n }\n }\n\n if (\n !partialIndexWarning &&\n wantsCf &&\n entityHasActiveCustomFields &&\n this.isForcePartialIndexEnabled() &&\n opts.tenantId\n ) {\n try {\n await this.indexCoverageStats(entity, opts, coverageScope)\n const globalStats = await this.indexCoverageStats(entity, opts, coverageScope)\n if (globalStats) {\n const globalBase = globalStats.baseCount\n const globalIndexed = globalStats.indexedCount\n const globalGap = (globalBase > 0 && globalIndexed < globalBase) || globalIndexed > globalBase\n if (globalGap) {\n console.warn('[HybridQueryEngine] Partial index coverage detected at global scope; forcing query index usage due to FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES:', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n if (debugEnabled) this.debug('query:partial-coverage:forced', { entity, baseCount: globalBase, indexedCount: globalIndexed, scope: 'global' })\n partialIndexWarning = {\n entity, entityLabel: this.resolveEntityLabel(entity),\n baseCount: globalBase, indexedCount: globalIndexed, scope: 'global',\n }\n }\n }\n } catch (err) {\n if (debugEnabled) this.debug('query:partial-coverage:global-check-failed', { entity, error: err instanceof Error ? err.message : err })\n }\n }\n\n const resolveBaseColumn = (field: string): string | null => {\n if (columns.has(field)) return field\n if (field === 'organization_id' && columns.has('id')) return 'id'\n return null\n }\n const fallbackOrgId =\n opts.organizationId\n ?? (Array.isArray(opts.organizationIds) && opts.organizationIds.length === 1 ? opts.organizationIds[0] : null)\n const encSvc = this.getEncryptionService()\n const resolvedSorts: Sort[] = []\n for (const sort of opts.sort || []) {\n const field = String(sort.field)\n if (field.startsWith('cf:')) {\n resolvedSorts.push({ ...sort, field })\n } else {\n const baseField = resolveBaseColumn(field)\n if (baseField) resolvedSorts.push({ ...sort, field: baseField })\n }\n }\n const encryptedSortFields = await resolveEncryptedSortFields(\n encSvc,\n entity,\n resolvedSorts.filter((sort) => !sort.field.startsWith('cf:')).map((sort) => sort.field),\n opts.tenantId ?? null,\n fallbackOrgId,\n )\n const requiresPlaintextSort = encryptedSortFields.size > 0\n\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Build a reusable \"applyQueryShape\" function that applies every\n // WHERE/JOIN/scope to a fresh SelectQueryBuilder. We use this in\n // place of knex's `.clone()` for producing count + data queries.\n // \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const applyBaseScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (orgScope && hasOrganizationColumn) {\n next = this.applyOrganizationScope(next, qualify('organization_id'), orgScope)\n }\n if (hasTenantColumn) {\n next = next.where(qualify('tenant_id'), '=', opts.tenantId)\n }\n if (!opts.withDeleted && hasDeletedColumn) {\n next = next.where(qualify('deleted_at'), 'is', null)\n }\n return next\n }\n\n const applyEntityIndexesJoin = (q: AnyBuilder): AnyBuilder => {\n return q.leftJoin('entity_indexes as ei', (jb: any) => {\n let jc = jb\n .on('ei.entity_type', '=', String(entity))\n .onRef('ei.entity_id', '=', sql<string>`(${sql.ref(qualify('id'))}::text)`)\n if (hasOrganizationColumn) {\n jc = jc\n .onRef('ei.organization_id', '=', qualify('organization_id'))\n .on('ei.organization_id', 'is not', null)\n }\n if (hasTenantColumn) {\n jc = jc\n .onRef('ei.tenant_id', '=', qualify('tenant_id'))\n .on('ei.tenant_id', 'is not', null)\n }\n if (!opts.withDeleted) {\n jc = jc.on('ei.deleted_at', 'is', null)\n }\n return jc\n })\n }\n\n const applyCustomFieldSourceJoins = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const source of preparedCfSources) {\n const join = (opts.customFieldSources ?? []).find((s) => s && (s.alias ?? undefined) === source.alias)?.join\n if (!join) continue\n const joinType = (join.type ?? 'left') === 'inner' ? 'innerJoin' : 'leftJoin'\n next = (next as any)[joinType](`${source.table} as ${source.alias}`, (jb: any) =>\n jb.onRef(`${source.alias}.${join.toField}`, '=', qualify(join.fromField)))\n // Index join for source\n next = next.leftJoin(`entity_indexes as ${source.indexAlias}`, (jb: any) => {\n let jc = jb\n .on(`${source.indexAlias}.entity_type`, '=', String(source.entityId))\n .onRef(`${source.indexAlias}.entity_id`, '=', sql<string>`(${sql.ref(`${source.alias}.${source.recordIdColumn}`)}::text)`)\n const orgRef = source.organizationField\n ? `${source.alias}.${source.organizationField}`\n : (columns.has('organization_id') ? qualify('organization_id') : null)\n if (orgRef) {\n jc = jc\n .onRef(`${source.indexAlias}.organization_id`, '=', orgRef)\n .on(`${source.indexAlias}.organization_id`, 'is not', null)\n }\n const tenantRef = source.tenantField\n ? `${source.alias}.${source.tenantField}`\n : (columns.has('tenant_id') ? qualify('tenant_id') : null)\n if (tenantRef) {\n jc = jc\n .onRef(`${source.indexAlias}.tenant_id`, '=', tenantRef)\n .on(`${source.indexAlias}.tenant_id`, 'is not', null)\n }\n if (!opts.withDeleted) jc = jc.on(`${source.indexAlias}.deleted_at`, 'is', null)\n return jc\n })\n }\n return next\n }\n\n const applyCfFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of cfFilters) {\n next = this.applyCfFilterAcrossSources(\n next, filter.field, filter.op, filter.value, indexSources, searchRuntime,\n )\n }\n return next\n }\n\n const regularBaseFilters = baseFilters.filter((filter) => !filter.orGroup)\n const orGroupFilters = baseFilters.filter((filter) => filter.orGroup)\n\n const applyRegularBaseFilters = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const filter of regularBaseFilters) {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n next = this.applyIndexDocFilterFromAlias(\n next, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime,\n )\n continue\n }\n const column = qualify(baseField)\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime,\n entity, field: fieldName, recordIdColumn: 'b.id',\n })\n }\n return next\n }\n\n const applyOrGroupedBaseFilters = (q: AnyBuilder): AnyBuilder => {\n if (orGroupFilters.length === 0) return q\n const groups = new Map<string, BaseFilter[]>()\n for (const filter of orGroupFilters) {\n if (!filter.orGroup) continue\n const existing = groups.get(filter.orGroup) ?? []\n existing.push(filter)\n groups.set(filter.orGroup, existing)\n }\n const groupList = Array.from(groups.values()).filter((g) => g.length > 0)\n if (groupList.length === 0) return q\n // Combine all groups in a single WHERE: disjuncts are OR'd together; within\n // each disjunct, fields are AND'd. Building this as separate `.where()` calls\n // would AND the disjuncts (wrong semantics).\n return q.where((eb: any) => eb.or(\n groupList.map((groupFilters) => {\n const parts = groupFilters.map((filter) =>\n this.buildBaseFilterExpression(eb, filter, resolveBaseColumn, qualify, entity, searchRuntime),\n )\n return parts.length === 1 ? parts[0] : eb.and(parts)\n }),\n ))\n }\n\n const applyAliasScopes = async (target: AnyBuilder, aliasName: string): Promise<AnyBuilder> => {\n let next = target\n const tableName = aliasTables.get(aliasName)\n if (!tableName) return next\n if (orgScope && await this.columnExists(tableName, 'organization_id')) {\n next = this.applyOrganizationScope(next, `${aliasName}.organization_id`, orgScope)\n }\n if (opts.tenantId && await this.columnExists(tableName, 'tenant_id')) {\n next = next.where(`${aliasName}.tenant_id`, '=', opts.tenantId)\n }\n if (!opts.withDeleted && await this.columnExists(tableName, 'deleted_at')) {\n next = next.where(`${aliasName}.deleted_at`, 'is', null)\n }\n return next\n }\n\n const applyJoinFilterOpFn = (target: AnyBuilder, column: string, op: FilterOp, value?: unknown): AnyBuilder => {\n switch (op) {\n case 'eq': return target.where(column, '=', value as any)\n case 'ne': return target.where(column, '!=', value as any)\n case 'gt': return target.where(column, '>', value as any)\n case 'gte': return target.where(column, '>=', value as any)\n case 'lt': return target.where(column, '<', value as any)\n case 'lte': return target.where(column, '<=', value as any)\n case 'in': return target.where(column, 'in', this.toArray(value))\n case 'nin': return target.where(column, 'not in', this.toArray(value))\n case 'like': return target.where(column, 'like', value as any)\n case 'ilike': return target.where(column, 'ilike', value as any)\n case 'exists': return value ? target.where(column, 'is not', null) : target.where(column, 'is', null)\n default: return target\n }\n }\n\n const applyJoinSearchFilterOp = async (\n target: AnyBuilder,\n filter: { column: string; op: FilterOp; value?: unknown },\n _qualified: string,\n join: ResolvedJoin,\n ): Promise<boolean> => {\n if (!searchEnabled || !join.entityId) return false\n if (!['like', 'ilike'].includes(filter.op)) return false\n if (typeof filter.value !== 'string' || filter.value.trim().length === 0) return false\n\n let searchAvailable = joinSearchAvailability.get(join.entityId)\n if (searchAvailable === undefined) {\n searchAvailable = await this.hasSearchTokens(String(join.entityId), opts.tenantId ?? null, orgScope)\n joinSearchAvailability.set(join.entityId, searchAvailable)\n }\n if (!searchAvailable) return false\n\n const tokens = tokenizeText(String(filter.value), searchConfig)\n if (!tokens.hashes.length) return false\n\n return this.applySearchTokens(target, {\n entity: String(join.entityId),\n field: filter.column,\n hashes: tokens.hashes,\n recordIdColumn: `${join.alias}.id`,\n tenantId: opts.tenantId ?? null,\n organizationScope: orgScope,\n })\n }\n\n const applyQueryShape = async (q: AnyBuilder): Promise<AnyBuilder> => {\n let next = applyBaseScope(q)\n next = applyEntityIndexesJoin(next)\n next = applyCustomFieldSourceJoins(next)\n next = applyCfFilters(next)\n next = applyRegularBaseFilters(next)\n next = applyOrGroupedBaseFilters(next)\n // applyJoinFilters is the shared helper that handles `joinFilters` (ALIAS:col -> value).\n next = await applyJoinFilters({\n db,\n baseTable,\n builder: next,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n return next\n }\n\n const hasCustomFieldFilters = cfFilters.length > 0\n const canOptimizeCount = !hasCustomFieldFilters && !hasNonBaseSearchSource\n\n // Selection (for data query)\n const selectFieldSet = new Set<string>((opts.fields && opts.fields.length) ? opts.fields.map(String) : Array.from(columns.keys()))\n if (requiresPlaintextSort) {\n for (const field of encryptedSortFields) selectFieldSet.add(field)\n }\n if (opts.includeCustomFields === true) {\n const entityIds = Array.from(new Set(indexSources.map((src) => String(src.entityId))))\n try {\n const resolvedKeys = await this.resolveAvailableCustomFieldKeys(entityIds, opts.tenantId ?? null)\n resolvedKeys.forEach((key) => selectFieldSet.add(`cf:${key}`))\n if (this.isDebugVerbosity()) this.debug('query:cf:resolved-keys', { entity, keys: resolvedKeys })\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to resolve custom field keys for', entity, err)\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n opts.includeCustomFields.map((key) => String(key)).forEach((key) => selectFieldSet.add(`cf:${key}`))\n }\n const selectFields = Array.from(selectFieldSet)\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const field of selectFields) {\n const fieldName = String(field)\n if (fieldName.startsWith('cf:')) {\n const alias = this.sanitize(fieldName)\n const jsonExpr = this.buildCfJsonExprSql(fieldName, indexSources)\n const exprRaw = jsonExpr ?? sql`NULL::jsonb`\n next = next.select(exprRaw.as(alias))\n } else if (columns.has(fieldName)) {\n next = next.select(`${qualify(fieldName)} as ${fieldName}`)\n }\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n if (requiresPlaintextSort) return next\n for (const s of resolvedSorts) {\n const fieldName = String(s.field)\n if (fieldName.startsWith('cf:')) {\n const textExpr = this.buildCfTextExprSql(fieldName, indexSources)\n if (textExpr) {\n const direction = sql.raw(String(s.dir ?? SortDir.Asc))\n next = next.orderBy(sql`${textExpr} ${direction}`)\n }\n } else {\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) continue\n next = next.orderBy(qualify(baseField), s.dir ?? SortDir.Asc)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n const sqlDebugEnabled = this.isSqlDebugEnabled()\n\n let total: number\n\n if (canOptimizeCount) {\n // Optimized count: apply only base-scope + regular filters + or-group filters (no index joins).\n const optimizedRoot = db.selectFrom(`${baseTable} as b` as any)\n let countCore = applyBaseScope(optimizedRoot)\n countCore = applyRegularBaseFilters(countCore)\n countCore = applyOrGroupedBaseFilters(countCore)\n // joinFilters still need to be re-applied in the optimized path\n countCore = await applyJoinFilters({\n db,\n baseTable,\n builder: countCore,\n joinMap,\n joinFilters,\n aliasTables,\n qualifyBase: (column) => qualify(column),\n applyAliasScope: async (target: any, alias: string) => applyAliasScopes(target as AnyBuilder, alias),\n applyFilterOp: (target, column, op, value) => applyJoinFilterOpFn(target as AnyBuilder, column, op, value),\n applyJoinFilterOp: async (target, filter, qualified, join) => {\n const applied = await applyJoinSearchFilterOp(target as AnyBuilder, filter, qualified, join)\n return { applied, builder: target }\n },\n columnExists: (tbl, column) => this.columnExists(tbl, column),\n })\n const sub = countCore.select(sql.ref(qualify('id')).as('id')).groupBy(qualify('id')).as('sq')\n const countQuery = db.selectFrom(sub as any).select(sql<string>`count(*)`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countQuery.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countQuery.executeTakeFirst(),\n { optimized: true }, profiler,\n )\n total = this.parseCount(countRow)\n } else {\n const countRoot = db.selectFrom(`${baseTable} as b` as any)\n const countBuilder = (await applyQueryShape(countRoot))\n .select(sql<string>`count(distinct ${sql.ref(qualify('id'))})`.as('count'))\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = countBuilder.compile()\n this.debug('query:sql:count', { entity, sql: compiled.sql, bindings: compiled.parameters })\n }\n const countRow = await this.captureSqlTiming(\n 'query:sql:count', entity,\n () => countBuilder.executeTakeFirst(),\n { optimized: false }, profiler,\n )\n total = this.parseCount(countRow)\n }\n\n const dataRoot = db.selectFrom(`${baseTable} as b` as any)\n let dataBuilder = await applyQueryShape(dataRoot)\n dataBuilder = applySelection(dataBuilder)\n dataBuilder = applySort(dataBuilder)\n if (!requiresPlaintextSort) {\n dataBuilder = dataBuilder.limit(pageSize).offset((page - 1) * pageSize)\n }\n\n if (debugEnabled && sqlDebugEnabled) {\n const compiled = dataBuilder.compile()\n this.debug('query:sql:data', { entity, sql: compiled.sql, bindings: compiled.parameters, page, pageSize })\n }\n const itemsRaw = await this.captureSqlTiming(\n 'query:sql:data', entity,\n () => dataBuilder.execute(),\n { page, pageSize }, profiler,\n )\n if (debugEnabled) this.debug('query:complete', { entity, total, items: Array.isArray(itemsRaw) ? itemsRaw.length : 0 })\n\n let items = itemsRaw as any[]\n const dekKeyCache = new Map<string | null, string | null>()\n if (encSvc?.decryptEntityPayload) {\n const decrypt = encSvc.decryptEntityPayload.bind(encSvc) as (\n entityId: EntityId, payload: Record<string, unknown>, tenantId: string | null, organizationId: string | null,\n ) => Promise<Record<string, unknown>>\n items = await Promise.all(\n items.map(async (item) => {\n try {\n const decrypted = await decrypt(\n entity, item,\n item?.tenant_id ?? item?.tenantId ?? opts.tenantId ?? null,\n item?.organization_id ?? item?.organizationId ?? fallbackOrgId ?? null,\n )\n return { ...item, ...decrypted }\n } catch (err) {\n console.error('Error decrypting entity payload', err)\n return item\n }\n })\n )\n }\n if (encSvc) {\n items = await Promise.all(\n items.map(async (item) => {\n try {\n return await decryptIndexDocCustomFields(\n item,\n {\n tenantId: item?.tenant_id ?? item?.tenantId ?? opts.tenantId ?? null,\n organizationId: item?.organization_id ?? item?.organizationId ?? null,\n },\n encSvc as any, dekKeyCache,\n )\n } catch { return item }\n }),\n )\n }\n if (requiresPlaintextSort) {\n items = sortRowsInMemory(items as Record<string, unknown>[], resolvedSorts)\n .slice((page - 1) * pageSize, page * pageSize)\n }\n\n const typedItems = items as unknown as T[]\n let result: QueryResult<T> = { items: typedItems, page, pageSize, total }\n if (partialIndexWarning) result.meta = { partialIndexWarning }\n\n result = await applyAfterExtensions(result)\n finishProfile({\n result: 'ok', total, page, pageSize,\n itemCount: Array.isArray(items) ? items.length : undefined,\n partialIndexWarning: partialIndexWarning ? true : false,\n })\n return result\n } catch (err) {\n finishProfile({ result: 'error', error: err instanceof Error ? err.message : String(err) })\n throw err\n }\n }\n\n private prepareCustomFieldSources(\n sources: QueryCustomFieldSource[],\n ): PreparedCustomFieldSource[] {\n const prepared: PreparedCustomFieldSource[] = []\n sources.forEach((source, index) => {\n if (!source) return\n const joinTable = source.table ?? resolveEntityTableName(this.em, source.entityId)\n const alias = source.alias ?? `cfs_${index}`\n if (!source.join) {\n throw new Error(`QueryEngine: customFieldSources entry for ${String(source.entityId)} requires a join configuration`)\n }\n prepared.push({\n alias,\n indexAlias: `ei_${alias}`,\n entityId: source.entityId,\n recordIdColumn: source.recordIdColumn ?? 'id',\n organizationField: source.organizationField,\n tenantField: source.tenantField,\n table: joinTable,\n })\n })\n return prepared\n }\n\n private async isCustomEntity(entity: string): Promise<boolean> {\n try {\n const db = this.getDb() as any\n const row = await db\n .selectFrom('custom_entities')\n .select('id')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .executeTakeFirst()\n return !!row\n } catch {\n return false\n }\n }\n\n /**\n * Adds a WHERE EXISTS / OR WHERE EXISTS subquery that matches\n * `search_tokens` for the supplied (entity, field) against the\n * provided record id column.\n *\n * Returns true when the sub-query was applied (i.e. tokens were\n * non-empty). Caller is responsible for the calling context\n * (direct where vs. inside `eb.or([...])`).\n */\n private applySearchTokens(\n q: AnyBuilder,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n combineWith?: 'and' | 'or'\n }\n ): boolean {\n if (!opts.hashes.length) {\n this.logSearchDebug('search:skip-no-hashes', {\n entity: opts.entity, field: opts.field,\n tenantId: opts.tenantId ?? null, organizationScope: opts.organizationScope,\n })\n return false\n }\n const alias = `st_${this.searchAliasSeq++}`\n this.logSearchDebug('search:apply-search-tokens', {\n entity: opts.entity, field: opts.field, alias,\n tokenCount: opts.hashes.length,\n tenantId: opts.tenantId ?? null,\n organizationScope: opts.organizationScope,\n combineWith: opts.combineWith ?? 'and',\n })\n\n const engine = this\n const buildSub = (eb: any) => {\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = engine.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n if (opts.combineWith === 'or') {\n // When called inside an .or([...]) array the caller supplied `eb`.\n // `q` is the ExpressionBuilder callable (eb) itself in that case.\n // We return the expression node rather than mutating q.\n ;(q as any).__pendingOrExists = buildSub(q)\n return true\n }\n\n // Default: append WHERE EXISTS (...) to the outer builder.\n ;(q as any).__applied = true\n const built = buildSub(q)\n // If q is a Kysely builder (has .where), use eb => eb.exists(sub)\n if (typeof q.where === 'function') {\n ;(q as any) = q.where((eb: any) => eb.exists(built))\n }\n return true\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as JSON across a single alias. */\n private jsonbSqlAlias(alias: string, key: string): RawBuilder<unknown> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql`coalesce(${sql.ref(alias + '.doc')} -> ${key}, ${sql.ref(alias + '.doc')} -> ${bare})`\n }\n return sql`${sql.ref(alias + '.doc')} -> ${key}`\n }\n\n /** SQL fragment for `cf:<key>` (or legacy bare key) as text across a single alias. */\n private cfTextExprAlias(alias: string, key: string): RawBuilder<string | null> {\n if (key.startsWith('cf:')) {\n const bare = key.slice(3)\n return sql<string | null>`coalesce((${sql.ref(alias + '.doc')} ->> ${key}), (${sql.ref(alias + '.doc')} ->> ${bare}))`\n }\n return sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n }\n\n /** Build JSON/text SQL expressions across multiple index alias sources (coalesce over them). */\n private buildCfJsonExprSql(key: string, sources: IndexDocSource[]): RawBuilder<unknown> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.jsonbSqlAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private buildCfTextExprSql(key: string, sources: IndexDocSource[]): RawBuilder<string | null> | null {\n if (!sources.length) return null\n const parts = sources.map((src) => this.cfTextExprAlias(src.alias, key))\n if (parts.length === 1) return parts[0]\n return sql<string | null>`coalesce(${sql.join(parts, sql`, `)})`\n }\n\n private applyCfFilterAcrossSources(\n builder: AnyBuilder,\n key: string,\n op: FilterOp,\n value: unknown,\n sources: IndexDocSource[],\n search?: SearchRuntime\n ): AnyBuilder {\n if (!sources.length) return builder\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = this.applyMultiSourceSearchExists(builder, sources, key, hashes, search)\n this.logSearchDebug('search:cf-filter-across', {\n entity: sources.map((src) => src.entityId),\n field: key, tokens: tokens.tokens, hashes, applied,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n if (applied.builder !== builder) return applied.builder\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', {\n entity: sources.map((src) => src.entityId), field: key, value,\n })\n }\n return builder\n }\n\n const textExpr = this.buildCfTextExprSql(key, sources)\n const jsonExpr = this.buildCfJsonExprSql(key, sources)\n if (!textExpr || !jsonExpr) return builder\n\n const arrContains = (val: unknown) => sql<boolean>`${jsonExpr} @> ${JSON.stringify([val])}::jsonb`\n\n switch (op) {\n case 'eq':\n return builder.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return builder.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const values = this.toArray(value)\n return builder.where((eb: any) => eb.or(\n values.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const values = this.toArray(value)\n return builder.where(sql<boolean>`${textExpr} not in (${sql.join(values.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return builder.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return builder.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? builder.where(sql<boolean>`${textExpr} is not null`)\n : builder.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return builder.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return builder\n }\n }\n\n /** Apply a search-token EXISTS subquery across multiple sources (OR-joined). */\n private applyMultiSourceSearchExists(\n builder: AnyBuilder,\n sources: IndexDocSource[],\n key: string,\n hashes: string[],\n search: SearchRuntime,\n ): { builder: AnyBuilder; applied: boolean } {\n if (!sources.length || !hashes.length) return { builder, applied: false }\n const next = builder.where((eb: any) => eb.or(\n sources.map((source) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: String(source.entityId),\n field: key, hashes,\n recordIdColumn: `${source.alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n }))\n )\n ))\n return { builder: next, applied: true }\n }\n\n /** Construct a search-token EXISTS subquery using the given ExpressionBuilder. */\n private buildSearchTokensSub(\n eb: any,\n opts: {\n entity: string\n field: string\n hashes: string[]\n recordIdColumn: string\n tenantId?: string | null\n organizationScope?: { ids: string[]; includeNull: boolean } | null\n }\n ): any {\n const alias = `st_${this.searchAliasSeq++}`\n let sub = eb\n .selectFrom(`search_tokens as ${alias}`)\n .select(sql<number>`1`.as('one'))\n .where(`${alias}.entity_type`, '=', opts.entity)\n .where(`${alias}.field`, '=', opts.field)\n .where(sql<boolean>`${sql.ref(`${alias}.entity_id`)} = ${sql.ref(opts.recordIdColumn)}::text`)\n .where(`${alias}.token_hash`, 'in', opts.hashes)\n .groupBy([`${alias}.entity_id`, `${alias}.field`])\n .having(sql<boolean>`count(distinct ${sql.ref(`${alias}.token_hash`)}) >= ${opts.hashes.length}`)\n if (opts.tenantId !== undefined) {\n sub = sub.where(sql<boolean>`${sql.ref(`${alias}.tenant_id`)} is not distinct from ${opts.tenantId ?? null}`)\n }\n if (opts.organizationScope) {\n sub = this.applyOrganizationScope(sub, `${alias}.organization_id`, opts.organizationScope)\n }\n return sub\n }\n\n private applyCfFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n search?: SearchRuntime\n ): AnyBuilder {\n const textExpr = this.cfTextExprAlias(alias, key)\n const arrExpr = sql<unknown>`(${sql.ref(alias + '.doc')} -> ${key})`\n const arrContains = (val: unknown) => sql<boolean>`${arrExpr} @> ${JSON.stringify([val])}::jsonb`\n\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes,\n recordIdColumn: `${alias}.entity_id`,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n this.logSearchDebug('search:cf-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:cf-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where((eb: any) => eb.or([\n sql<boolean>`${textExpr} = ${value}`,\n arrContains(value),\n ]))\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where((eb: any) => eb.or(\n vals.flatMap((val) => [\n sql<boolean>`${textExpr} = ${val}`,\n arrContains(val),\n ])\n ))\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n private applyIndexDocFilterFromAlias(\n q: AnyBuilder,\n alias: string,\n entityType: string,\n key: string,\n op: FilterOp,\n value: unknown,\n recordIdColumn: string,\n search?: SearchRuntime,\n ): AnyBuilder {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n if ((op === 'like' || op === 'ilike') && search?.enabled && typeof value === 'string') {\n const tokens = tokenizeText(String(value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const applied = q.where((eb: any) => eb.exists(this.buildSearchTokensSub(eb, {\n entity: entityType, field: key, hashes, recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n this.logSearchDebug('search:index-doc-filter', {\n entity: entityType, field: key, tokens: tokens.tokens, hashes, applied: true,\n tenantId: search.tenantId ?? null, organizationScope: search.organizationScope,\n })\n return applied\n } else {\n this.logSearchDebug('search:index-doc-skip-empty-hashes', { entity: entityType, field: key, value })\n }\n return q\n }\n switch (op) {\n case 'eq':\n return q.where(sql<boolean>`${textExpr} = ${value}`)\n case 'ne':\n return q.where(sql<boolean>`${textExpr} <> ${value}`)\n case 'in': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'nin': {\n const vals = this.toArray(value)\n return q.where(sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`)\n }\n case 'like':\n return q.where(sql<boolean>`${textExpr} like ${value}`)\n case 'ilike':\n return q.where(sql<boolean>`${textExpr} ilike ${value}`)\n case 'exists':\n return value\n ? q.where(sql<boolean>`${textExpr} is not null`)\n : q.where(sql<boolean>`${textExpr} is null`)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return q.where(sql<boolean>`${textExpr} ${operator} ${value}`)\n }\n default:\n return q\n }\n }\n\n /**\n * Build a single OR-group base filter expression as a Kysely predicate\n * (no side effects on the outer builder).\n */\n private buildBaseFilterExpression(\n eb: any,\n filter: BaseFilter,\n resolveBaseColumn: (field: string) => string | null,\n qualify: (col: string) => string,\n entity: EntityId,\n searchRuntime: SearchRuntime,\n ): any {\n const fieldName = String(filter.field)\n const baseField = resolveBaseColumn(fieldName)\n if (!baseField) {\n // Doc-based filter via `ei` alias \u2014 returned as EXISTS where possible\n return this.buildIndexDocFilterExpression(eb, 'ei', entity, fieldName, filter.op, filter.value, 'b.id', searchRuntime)\n }\n // For like/ilike with active search-tokens, route through hashed-token EXISTS subquery\n // so encrypted-at-rest columns can still be searched.\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n searchRuntime?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), searchRuntime.config)\n if (tokens.hashes.length) {\n const sources: SearchTokenSource[] = (searchRuntime.searchSources && searchRuntime.searchSources.length\n ? searchRuntime.searchSources\n : [{ entity: String(entity), recordIdColumn: 'b.id' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n return eb.or(\n sources.map((src) =>\n eb.exists(this.buildSearchTokensSub(eb, {\n entity: src.entity,\n field: fieldName,\n hashes: tokens.hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: searchRuntime.tenantId ?? null,\n organizationScope: searchRuntime.organizationScope ?? null,\n })),\n ),\n )\n }\n }\n // Tokenizer produced no hashes (e.g. value too short). Match the regular-base-filter\n // path's behavior of skipping the predicate (no filter), which is preferable to\n // silently turning into a plain `ilike` against an encrypted column.\n return sql<boolean>`true`\n }\n return this.buildColumnFilterExpression(eb, qualify(baseField), filter.op, filter.value)\n }\n\n private buildColumnFilterExpression(\n eb: any,\n column: string,\n op: FilterOp,\n value: unknown,\n ): any {\n switch (op) {\n case 'eq': return eb(column, '=', value)\n case 'ne': return eb(column, '!=', value)\n case 'gt': return eb(column, '>', value)\n case 'gte': return eb(column, '>=', value)\n case 'lt': return eb(column, '<', value)\n case 'lte': return eb(column, '<=', value)\n case 'in': return eb(column, 'in', this.toArray(value))\n case 'nin': return eb(column, 'not in', this.toArray(value))\n case 'like': return eb(column, 'like', value)\n case 'ilike': return eb(column, 'ilike', value)\n case 'exists': return eb(column, value ? 'is not' : 'is', null)\n default: return sql<boolean>`true`\n }\n }\n\n private buildIndexDocFilterExpression(\n eb: any,\n alias: string,\n _entity: EntityId,\n key: string,\n op: FilterOp,\n value: unknown,\n _recordIdColumn: string,\n _search?: SearchRuntime,\n ): any {\n const textExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${key})`\n switch (op) {\n case 'eq': return sql<boolean>`${textExpr} = ${value}`\n case 'ne': return sql<boolean>`${textExpr} <> ${value}`\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = sql.raw(op === 'gt' ? '>' : op === 'gte' ? '>=' : op === 'lt' ? '<' : '<=')\n return sql<boolean>`${textExpr} ${operator} ${value}`\n }\n case 'like': return sql<boolean>`${textExpr} like ${value}`\n case 'ilike': return sql<boolean>`${textExpr} ilike ${value}`\n case 'in': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'nin': {\n const vals = this.toArray(value)\n return sql<boolean>`${textExpr} not in (${sql.join(vals.map((v) => sql`${v}`), sql`, `)})`\n }\n case 'exists':\n return value ? sql<boolean>`${textExpr} is not null` : sql<boolean>`${textExpr} is null`\n default:\n return sql<boolean>`true`\n }\n }\n\n private async queryCustomEntity<T = unknown>(entity: string, opts: QueryOptions = {}): Promise<QueryResult<T>> {\n const db = this.getDb() as any\n const alias = 'ce'\n\n const orgScope = this.resolveOrganizationScope(opts)\n if (!opts.tenantId) throw new Error('QueryEngine: tenantId is required')\n\n const searchConfig = resolveSearchConfig()\n const searchEnabled = searchConfig.enabled && await this.tableExists('search_tokens')\n const hasSearchTokens = searchEnabled\n ? await this.hasSearchTokens(entity, opts.tenantId ?? null, orgScope)\n : false\n const searchRuntime: SearchRuntime = {\n enabled: searchEnabled && hasSearchTokens,\n config: searchConfig,\n organizationScope: orgScope,\n tenantId: opts.tenantId ?? null,\n }\n\n const normalizedFilters = normalizeFilters(opts.filters)\n\n const applyScope = (q: AnyBuilder): AnyBuilder => {\n let next = q\n .where(`${alias}.entity_type`, '=', entity)\n .where(`${alias}.tenant_id`, '=', opts.tenantId)\n if (orgScope) {\n next = this.applyOrganizationScope(next, `${alias}.organization_id`, orgScope)\n }\n if (!opts.withDeleted) next = next.where(`${alias}.deleted_at`, 'is', null)\n for (const filter of normalizedFilters) {\n if (filter.field.startsWith('cf:')) {\n next = this.applyCfFilterFromAlias(next, alias, entity, filter.field, filter.op, filter.value, searchRuntime)\n continue\n }\n const column = this.resolveCustomEntityColumn(alias, String(filter.field))\n if (column) {\n next = this.applyColumnFilter(next, column, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n continue\n }\n // Unknown field \u2192 filter on doc JSON text\n const docExpr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${String(filter.field)})`\n next = this.applyColumnFilter(next, docExpr, filter, {\n ...searchRuntime, entity, field: String(filter.field), recordIdColumn: `${alias}.entity_id`,\n })\n }\n return next\n }\n\n // Determine CFs and l10n keys to include\n const cfKeys = new Set<string>()\n for (const f of (opts.fields || [])) {\n if (typeof f === 'string' && f.startsWith('cf:')) cfKeys.add(f.slice(3))\n else if (typeof f === 'string' && f.startsWith('l10n:')) cfKeys.add(f)\n }\n for (const filter of normalizedFilters) {\n if (typeof filter.field === 'string' && filter.field.startsWith('cf:')) cfKeys.add(filter.field.slice(3))\n else if (typeof filter.field === 'string' && filter.field.startsWith('l10n:')) cfKeys.add(filter.field)\n }\n if (opts.includeCustomFields === true) {\n try {\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', '=', entity)\n .where('is_active', '=', true)\n .where('tenant_id', '=', opts.tenantId)\n .execute() as Array<{ key: unknown }>\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string') cfKeys.add(key)\n else if (key != null) cfKeys.add(String(key))\n }\n } catch {\n // ignore\n }\n } else if (Array.isArray(opts.includeCustomFields)) {\n for (const k of opts.includeCustomFields) cfKeys.add(k)\n }\n\n const applySelection = (q: AnyBuilder): AnyBuilder => {\n let next = q\n const requested = (opts.fields && opts.fields.length) ? opts.fields : ['id']\n for (const field of requested) {\n const f = String(field)\n if (f.startsWith('cf:')) {\n const aliasName = this.sanitize(f)\n next = next.select(this.jsonbSqlAlias(alias, f).as(aliasName))\n } else if (f === 'id') {\n next = next.select(`${alias}.entity_id as id`)\n } else if (f === 'created_at' || f === 'updated_at' || f === 'deleted_at') {\n next = next.select(`${alias}.${f} as ${f}`)\n } else {\n const expr = sql<string | null>`(${sql.ref(alias + '.doc')} ->> ${f})`\n next = next.select(expr.as(f))\n }\n }\n // Ensure CF fields for sort / includeCustomFields are selected\n for (const key of cfKeys) {\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.select(this.jsonbSqlAlias(alias, `cf:${key}`).as(aliasName))\n }\n return next\n }\n\n const applySort = (q: AnyBuilder): AnyBuilder => {\n let next = q\n for (const s of opts.sort || []) {\n if (s.field.startsWith('cf:')) {\n const key = s.field.slice(3)\n const aliasName = this.sanitize(`cf:${key}`)\n next = next.orderBy(aliasName, s.dir ?? SortDir.Asc)\n } else if (s.field === 'id') {\n next = next.orderBy(`${alias}.entity_id`, s.dir ?? SortDir.Asc)\n } else if (s.field === 'created_at' || s.field === 'updated_at' || s.field === 'deleted_at') {\n next = next.orderBy(`${alias}.${s.field}`, s.dir ?? SortDir.Asc)\n } else {\n const direction = sql.raw(String(s.dir ?? SortDir.Asc))\n next = next.orderBy(sql`(${sql.ref(alias + '.doc')} ->> ${s.field}) ${direction}`)\n }\n }\n return next\n }\n\n const page = opts.page?.page ?? 1\n const pageSize = opts.page?.pageSize ?? 20\n\n const root = db.selectFrom(`custom_entities_storage as ${alias}`)\n const countQuery = applyScope(root).select(sql<string>`count(distinct ${sql.ref(`${alias}.entity_id`)})`.as('count'))\n const countRow = await countQuery.executeTakeFirst()\n const total = this.parseCount(countRow)\n\n let dataQuery = applyScope(db.selectFrom(`custom_entities_storage as ${alias}`))\n dataQuery = applySelection(dataQuery)\n dataQuery = applySort(dataQuery)\n dataQuery = dataQuery.limit(pageSize).offset((page - 1) * pageSize)\n const items = await dataQuery.execute()\n return { items, page, pageSize, total }\n }\n\n private async tableExists(table: string): Promise<boolean> {\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.tables')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .executeTakeFirst()\n return !!exists\n }\n\n private async hasSearchTokens(\n entity: string,\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n try {\n const db = this.getDb() as any\n let query = db\n .selectFrom('search_tokens')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n if (tenantId !== undefined) {\n query = query.where(sql<boolean>`tenant_id is not distinct from ${tenantId}`)\n }\n if (orgScope) {\n query = this.applyOrganizationScope(query, 'search_tokens.organization_id', orgScope)\n }\n const row = await query.limit(1).executeTakeFirst()\n return !!row\n } catch (err) {\n this.logSearchDebug('search:has-tokens-error', {\n entity, tenantId, organizationScope: orgScope,\n error: err instanceof Error ? err.message : String(err),\n })\n return false\n }\n }\n\n private async searchSourcesHaveTokens(\n sources: SearchTokenSource[],\n tenantId: string | null,\n orgScope?: { ids: string[]; includeNull: boolean } | null\n ): Promise<boolean> {\n for (const source of sources) {\n const ok = await this.hasSearchTokens(source.entity, tenantId, orgScope)\n this.logSearchDebug('search:source-has-tokens', {\n entity: source.entity, recordIdColumn: source.recordIdColumn,\n tenantId, organizationScope: orgScope, hasTokens: ok,\n })\n if (ok) return true\n }\n return false\n }\n\n private async resolveAvailableCustomFieldKeys(entityIds: string[], tenantId: string | null): Promise<string[]> {\n if (!entityIds.length) return []\n const cacheKey = this.customFieldKeysCacheKey(entityIds, tenantId)\n const now = Date.now()\n const cached = this.customFieldKeysCache.get(cacheKey)\n if (cached && cached.expiresAt > now) return cached.value.slice()\n\n const db = this.getDb() as any\n const rows = await db\n .selectFrom('custom_field_defs')\n .select('key')\n .where('entity_id', 'in', entityIds)\n .where('is_active', '=', true)\n .where((eb: any) => eb.or([\n eb('tenant_id', '=', tenantId),\n eb('tenant_id', 'is', null),\n ]))\n .execute() as Array<{ key: unknown }>\n const keys = new Set<string>()\n for (const row of rows) {\n const key = row.key\n if (typeof key === 'string' && key.trim().length) keys.add(key.trim())\n else if (key != null) keys.add(String(key))\n }\n const result = Array.from(keys)\n if (this.customFieldKeysTtlMs > 0) {\n this.customFieldKeysCache.set(cacheKey, { expiresAt: now + this.customFieldKeysTtlMs, value: result })\n }\n return result.slice()\n }\n\n private async entityHasActiveCustomFields(entityId: string, tenantId: string | null): Promise<boolean> {\n try {\n const keys = await this.resolveAvailableCustomFieldKeys([entityId], tenantId)\n return keys.length > 0\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('query:cf:check-error', {\n entity: entityId, tenantId: tenantId ?? null,\n error: err instanceof Error ? err.message : err,\n })\n }\n return true\n }\n }\n\n private customFieldKeysCacheKey(entityIds: string[], tenantId: string | null): string {\n const sorted = entityIds.slice().sort((a, b) => a.localeCompare(b)).join(',')\n return `${tenantId ?? '__none__'}|${sorted}`\n }\n\n private resolveVectorService(): VectorIndexService | null {\n if (!this.vectorServiceResolver) return null\n try {\n return this.vectorServiceResolver() ?? null\n } catch {\n return null\n }\n }\n\n private resolveEntityLabel(entity: string): string {\n return entity\n }\n\n private async indexAnyRows(entity: string): Promise<boolean> {\n const db = this.getDb() as any\n const coverage = await db\n .selectFrom('entity_index_coverage')\n .select(sql<number>`1`.as('one'))\n .where('entity_type', '=', entity)\n .where('indexed_count', '>', 0)\n .executeTakeFirst()\n if (coverage) return true\n const exists = await db\n .selectFrom('entity_indexes')\n .select('entity_id')\n .where('entity_type', '=', entity)\n .executeTakeFirst()\n return !!exists\n }\n\n private async getStoredCoverageSnapshot(\n entity: string,\n tenantId: string | null,\n organizationId: string | null,\n withDeleted: boolean\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n try {\n const db = this.getDb()\n const scope = {\n entityType: entity, tenantId, organizationId, withDeleted,\n }\n const row = await readCoverageSnapshot(db as any, scope)\n if (row && this.isCoverageSnapshotFresh(row)) {\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n if (this.isCoverageOptimizationEnabled()) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n if (!row) return null\n return { baseCount: row.baseCount, indexedCount: row.indexedCount }\n }\n\n await refreshCoverageSnapshot(this.em, scope)\n const refreshed = await readCoverageSnapshot(db as any, scope)\n if (!refreshed) return null\n return { baseCount: refreshed.baseCount, indexedCount: refreshed.indexedCount }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:snapshot:read-error', {\n entity, tenantId, organizationId, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n return null\n }\n }\n\n private isCoverageSnapshotFresh(\n row: Awaited<ReturnType<typeof readCoverageSnapshot>>\n ): boolean {\n if (this.coverageStatsTtlMs <= 0) return false\n if (!row) return false\n const refreshedAt = row.refreshed_at instanceof Date\n ? row.refreshed_at\n : row.refreshed_at\n ? new Date(row.refreshed_at)\n : null\n const refreshedAtMs = refreshedAt?.getTime()\n if (!refreshedAtMs || !Number.isFinite(refreshedAtMs)) return false\n return Date.now() - refreshedAtMs <= this.coverageStatsTtlMs\n }\n\n private scheduleAutoReindex(\n entity: string,\n opts: QueryOptions,\n stats?: { baseCount: number; indexedCount: number },\n organizationIdOverride?: string | null\n ) {\n if (!this.isAutoReindexEnabled()) return\n const bus = this.resolveEventBus()\n if (!bus) return\n const payload = {\n entityType: entity,\n tenantId: opts.tenantId ?? null,\n organizationId: organizationIdOverride ?? opts.organizationId ?? null,\n force: false,\n }\n const context = stats\n ? { entity, tenantId: payload.tenantId, organizationId: payload.organizationId, baseCount: stats.baseCount, indexedCount: stats.indexedCount }\n : { entity, tenantId: payload.tenantId, organizationId: payload.organizationId }\n\n void Promise.resolve().then(async () => {\n try {\n await bus.emitEvent('query_index.reindex', payload, { persistent: true })\n if (this.isDebugVerbosity()) this.debug('query:auto-reindex:scheduled', context)\n } catch (err) {\n console.warn('[HybridQueryEngine] Failed to schedule auto reindex:', {\n ...context, error: err instanceof Error ? err.message : err,\n })\n }\n })\n }\n\n private scheduleCoverageRefresh(\n entity: string,\n tenantId: string | null | undefined,\n organizationId: string | null | undefined,\n withDeleted: boolean\n ): void {\n const bus = this.resolveEventBus()\n if (!bus) return\n const key = [entity, tenantId ?? '__tenant__', organizationId ?? '__org__', withDeleted ? '1' : '0'].join('|')\n if (this.pendingCoverageRefreshKeys.has(key)) return\n this.pendingCoverageRefreshKeys.add(key)\n void Promise.resolve()\n .then(async () => {\n try {\n await bus.emitEvent('query_index.coverage.refresh', {\n entityType: entity,\n tenantId: tenantId ?? null, organizationId: organizationId ?? null,\n withDeleted, delayMs: 0,\n })\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:scheduled', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n })\n }\n } catch (err) {\n if (this.isDebugVerbosity()) {\n this.debug('coverage:refresh:failed', {\n entity, tenantId: tenantId ?? null, organizationId: organizationId ?? null, withDeleted,\n error: err instanceof Error ? err.message : err,\n })\n }\n }\n })\n .finally(() => { this.pendingCoverageRefreshKeys.delete(key) })\n }\n\n private resolveEventBus(): Pick<EventBus, 'emitEvent'> | null {\n if (!this.eventBusResolver) return null\n try {\n const bus = this.eventBusResolver()\n return bus ?? null\n } catch {\n return null\n }\n }\n\n private isAutoReindexEnabled(): boolean {\n if (this.autoReindexEnabled != null) return this.autoReindexEnabled\n const raw = (process.env.SCHEDULE_AUTO_REINDEX ?? process.env.QUERY_INDEX_AUTO_REINDEX ?? '').trim().toLowerCase()\n if (!raw) { this.autoReindexEnabled = true; return true }\n const parsed = parseBooleanToken(raw)\n this.autoReindexEnabled = parsed === null ? true : parsed\n return this.autoReindexEnabled\n }\n\n private isCoverageOptimizationEnabled(): boolean {\n if (this.coverageOptimizationEnabled != null) return this.coverageOptimizationEnabled\n const raw = (process.env.OPTIMIZE_INDEX_COVERAGE_STATS ?? '').trim().toLowerCase()\n if (!raw) { this.coverageOptimizationEnabled = false; return false }\n this.coverageOptimizationEnabled = parseBooleanToken(raw) === true\n return this.coverageOptimizationEnabled\n }\n\n private async columnExists(table: string, column: string): Promise<boolean> {\n const key = `${table}.${column}`\n if (this.columnCache.has(key)) {\n const cached = this.columnCache.get(key)\n if (cached === true) return true\n this.columnCache.delete(key)\n }\n const db = this.getDb() as any\n const exists = await db\n .selectFrom('information_schema.columns')\n .select(sql<number>`1`.as('one'))\n .where('table_name', '=', table)\n .where('column_name', '=', column)\n .executeTakeFirst()\n const present = !!exists\n if (present) this.columnCache.set(key, true)\n else this.columnCache.delete(key)\n return present\n }\n\n private async getBaseColumnsForEntity(entity: string): Promise<Map<string, string>> {\n const db = this.getDb() as any\n const table = resolveEntityTableName(this.em, entity)\n const rows = await db\n .selectFrom('information_schema.columns')\n .select(['column_name', 'data_type'])\n .where('table_name', '=', table)\n .execute() as Array<{ column_name: string; data_type: string }>\n const map = new Map<string, string>()\n for (const r of rows) map.set(r.column_name, r.data_type)\n return map\n }\n\n private resolveOrganizationScope(opts: QueryOptions): { ids: string[]; includeNull: boolean } | null {\n if (opts.organizationIds !== undefined) {\n const raw = (opts.organizationIds ?? []).map((id) => (typeof id === 'string' ? id.trim() : id))\n const includeNull = raw.some((id) => id == null || id === '')\n const ids = raw.filter((id): id is string => typeof id === 'string' && id.length > 0)\n const unique = Array.from(new Set(ids))\n return { ids: unique, includeNull }\n }\n if (typeof opts.organizationId === 'string' && opts.organizationId.trim().length > 0) {\n return { ids: [opts.organizationId], includeNull: false }\n }\n return null\n }\n\n private resolveCoverageSnapshotScope(\n opts: QueryOptions\n ): { tenantId: string | null; organizationId: string | null } | null {\n const tenantId = opts.tenantId ?? null\n const orgScope = this.resolveOrganizationScope(opts)\n if (!orgScope) return { tenantId, organizationId: null }\n if (orgScope.includeNull) {\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n if (orgScope.ids.length === 1) return { tenantId, organizationId: orgScope.ids[0] }\n if (orgScope.ids.length === 0) return { tenantId, organizationId: null }\n return null\n }\n\n private applyOrganizationScope(\n q: AnyBuilder,\n column: string,\n scope: { ids: string[]; includeNull: boolean }\n ): AnyBuilder {\n if (scope.ids.length === 0 && !scope.includeNull) {\n return q.where(sql<boolean>`1 = 0`)\n }\n return q.where((eb: any) => {\n const parts: any[] = []\n if (scope.ids.length > 0) parts.push(eb(column, 'in', scope.ids))\n if (scope.includeNull) parts.push(eb(column, 'is', null))\n if (parts.length === 1) return parts[0]\n return eb.or(parts)\n })\n }\n\n private normalizeFilters(filters?: QueryOptions['filters']): NormalizedFilter[] {\n if (!filters) return []\n const normalizeField = (k: string) => k.startsWith('cf_') ? `cf:${k.slice(3)}` : k\n if (Array.isArray(filters)) {\n return (filters as Filter[]).map((filter) => ({\n field: normalizeField(String(filter.field)),\n op: filter.op, value: filter.value,\n }))\n }\n const out: NormalizedFilter[] = []\n const obj = filters as Record<string, unknown>\n const add = (field: string, op: FilterOp, value?: unknown) => out.push({ field, op, value })\n for (const [rawKey, rawVal] of Object.entries(obj)) {\n const field = normalizeField(rawKey)\n if (rawVal !== null && typeof rawVal === 'object' && !Array.isArray(rawVal)) {\n for (const [opKey, opVal] of Object.entries(rawVal as Record<string, unknown>)) {\n switch (opKey) {\n case '$eq': add(field, 'eq', opVal); break\n case '$ne': add(field, 'ne', opVal); break\n case '$gt': add(field, 'gt', opVal); break\n case '$gte': add(field, 'gte', opVal); break\n case '$lt': add(field, 'lt', opVal); break\n case '$lte': add(field, 'lte', opVal); break\n case '$in': add(field, 'in', opVal); break\n case '$nin': add(field, 'nin', opVal); break\n case '$like': add(field, 'like', opVal); break\n case '$ilike': add(field, 'ilike', opVal); break\n case '$exists': add(field, 'exists', opVal); break\n }\n }\n } else {\n add(field, 'eq', rawVal)\n }\n }\n return out\n }\n\n private sanitize(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n }\n\n private toArray(value: unknown): readonly unknown[] {\n if (Array.isArray(value)) return value\n if (value === undefined) return []\n return [value]\n }\n\n private parseCount(row: unknown): number {\n if (row && typeof row === 'object' && 'count' in row) {\n const value = (row as { count: unknown }).count\n if (typeof value === 'number') return value\n if (typeof value === 'string') {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? 0 : parsed\n }\n if (typeof value === 'bigint') return Number(value)\n }\n return 0\n }\n\n private logSearchDebug(event: string, payload: Record<string, unknown>) {\n if (!this.isDebugVerbosity()) return\n try {\n console.info('[query-index:search]', event, JSON.stringify(payload))\n } catch {\n console.info('[query-index:search]', event, payload)\n }\n }\n\n private applyColumnFilter(\n q: AnyBuilder,\n column: string | RawBuilder<unknown>,\n filter: NormalizedFilter,\n search?: SearchRuntime & { entity: string; field: string; recordIdColumn?: string },\n ): AnyBuilder {\n if (\n (filter.op === 'like' || filter.op === 'ilike') &&\n search?.enabled &&\n typeof filter.value === 'string'\n ) {\n const tokens = tokenizeText(String(filter.value), search.config)\n const hashes = tokens.hashes\n if (hashes.length) {\n const sources: SearchTokenSource[] = (search.searchSources && search.searchSources.length\n ? search.searchSources\n : [{ entity: search.entity, recordIdColumn: search.recordIdColumn ?? '' }]\n ).filter((src) => src.recordIdColumn && src.entity)\n if (sources.length) {\n const engine = this\n q = q.where((eb: any) => eb.or(\n sources.map((src) =>\n eb.exists(engine.buildSearchTokensSub(eb, {\n entity: src.entity, field: search.field, hashes,\n recordIdColumn: src.recordIdColumn,\n tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope ?? null,\n })))\n ))\n this.logSearchDebug('search:filter', {\n entity: search.entity, field: search.field, tokens: tokens.tokens, hashes,\n applied: true, tenantId: search.tenantId ?? null,\n organizationScope: search.organizationScope,\n sources: sources.map((src) => ({ entity: src.entity, recordIdColumn: src.recordIdColumn })),\n })\n return q\n }\n } else {\n this.logSearchDebug('search:skip-empty-hashes', {\n entity: search.entity, field: search.field, value: filter.value,\n })\n }\n return q\n }\n const col: any = column\n switch (filter.op) {\n case 'eq': return q.where(col, '=', filter.value as any)\n case 'ne': return q.where(col, '!=', filter.value as any)\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const operator = filter.op === 'gt' ? '>' : filter.op === 'gte' ? '>=' : filter.op === 'lt' ? '<' : '<='\n return q.where(col, operator, filter.value as any)\n }\n case 'in':\n return q.where(col, 'in', this.toArray(filter.value))\n case 'nin':\n return q.where(col, 'not in', this.toArray(filter.value))\n case 'like':\n return q.where(col, 'like', filter.value as any)\n case 'ilike':\n return q.where(col, 'ilike', filter.value as any)\n case 'exists':\n return filter.value ? q.where(col, 'is not', null) : q.where(col, 'is', null)\n default:\n return q\n }\n }\n\n private resolveCustomEntityColumn(alias: string, field: string): string | null {\n if (field === 'id') return `${alias}.entity_id`\n if (field === 'organization_id' || field === 'organizationId') return `${alias}.organization_id`\n if (field === 'tenant_id' || field === 'tenantId') return `${alias}.tenant_id`\n if (field === 'created_at' || field === 'updated_at' || field === 'deleted_at') return `${alias}.${field}`\n return null\n }\n\n private isDebugVerbosity(): boolean {\n if (this.debugVerbosity != null) return this.debugVerbosity\n this.debugVerbosity = resolveDebugVerbosity()\n return this.debugVerbosity\n }\n\n private isSqlDebugEnabled(): boolean {\n if (this.sqlDebugEnabled != null) return this.sqlDebugEnabled\n this.sqlDebugEnabled = resolveBooleanEnv(['QUERY_ENGINE_DEBUG_SQL'], false)\n return this.sqlDebugEnabled\n }\n\n private isForcePartialIndexEnabled(): boolean {\n if (this.forcePartialIndexEnabled != null) return this.forcePartialIndexEnabled\n this.forcePartialIndexEnabled = resolveBooleanEnv(['FORCE_QUERY_INDEX_ON_PARTIAL_INDEXES'], false)\n return this.forcePartialIndexEnabled\n }\n\n private async resolveCoverageGap(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n _sourceTable?: string\n ): Promise<{ stats?: { baseCount: number; indexedCount: number }; scope: 'scoped' | 'global' } | null> {\n const scope = coverageScope ?? this.resolveCoverageSnapshotScope(opts)\n if (!scope) return null\n const tenantId = scope.tenantId\n const organizationId = scope.organizationId\n const withDeleted = !!opts.withDeleted\n\n const snapshot = await this.getStoredCoverageSnapshot(entity, tenantId, organizationId, withDeleted)\n if (!snapshot) {\n this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)\n return { stats: undefined, scope: 'scoped' }\n }\n\n const baseCount = snapshot.baseCount\n const indexCount = snapshot.indexedCount\n const hasGap = baseCount > 0 && indexCount < baseCount\n if (hasGap || indexCount > baseCount) return { stats: snapshot, scope: 'scoped' }\n return null\n }\n\n // Backward-compatible hook for tests that mock coverage stats\n private async indexCoverageStats(\n entity: string,\n opts: QueryOptions,\n coverageScope?: { tenantId: string | null; organizationId: string | null } | null,\n ): Promise<{ baseCount: number; indexedCount: number } | null> {\n const gap = await this.resolveCoverageGap(entity, opts, coverageScope)\n return gap?.stats ?? null\n }\n\n private async captureSqlTiming<TResult>(\n label: string,\n entity: EntityId,\n execute: () => Promise<TResult> | TResult,\n extra?: Record<string, unknown>,\n profiler?: Profiler\n ): Promise<TResult> {\n const shouldDebug = this.isSqlDebugEnabled() && this.isDebugVerbosity()\n const shouldProfile = profiler?.enabled === true\n if (!shouldDebug && !shouldProfile) return Promise.resolve(execute())\n const startedAt = process.hrtime.bigint()\n try {\n return await Promise.resolve(execute())\n } finally {\n const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000\n const context: Record<string, unknown> = { entity, durationMs: Math.round(elapsedMs * 1000) / 1000 }\n if (extra) Object.assign(context, extra)\n if (shouldProfile) profiler!.record(label, context.durationMs as number, extra)\n if (shouldDebug) this.debug(`${label}:timing`, context)\n }\n }\n\n private debug(message: string, context?: Record<string, unknown>): void {\n if (!this.isDebugVerbosity()) return\n if (!this.isSqlDebugEnabled()) return\n if (context) console.debug('[HybridQueryEngine]', message, context)\n else console.debug('[HybridQueryEngine]', message)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["result"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.6.4-develop.
|
|
3
|
+
"version": "0.6.4-develop.4270.1.a614eb18e6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -243,16 +243,16 @@
|
|
|
243
243
|
"zod": "^4.4.3"
|
|
244
244
|
},
|
|
245
245
|
"peerDependencies": {
|
|
246
|
-
"@open-mercato/ai-assistant": "0.6.4-develop.
|
|
247
|
-
"@open-mercato/shared": "0.6.4-develop.
|
|
248
|
-
"@open-mercato/ui": "0.6.4-develop.
|
|
246
|
+
"@open-mercato/ai-assistant": "0.6.4-develop.4270.1.a614eb18e6",
|
|
247
|
+
"@open-mercato/shared": "0.6.4-develop.4270.1.a614eb18e6",
|
|
248
|
+
"@open-mercato/ui": "0.6.4-develop.4270.1.a614eb18e6",
|
|
249
249
|
"react": "^19.0.0",
|
|
250
250
|
"react-dom": "^19.0.0"
|
|
251
251
|
},
|
|
252
252
|
"devDependencies": {
|
|
253
|
-
"@open-mercato/ai-assistant": "0.6.4-develop.
|
|
254
|
-
"@open-mercato/shared": "0.6.4-develop.
|
|
255
|
-
"@open-mercato/ui": "0.6.4-develop.
|
|
253
|
+
"@open-mercato/ai-assistant": "0.6.4-develop.4270.1.a614eb18e6",
|
|
254
|
+
"@open-mercato/shared": "0.6.4-develop.4270.1.a614eb18e6",
|
|
255
|
+
"@open-mercato/ui": "0.6.4-develop.4270.1.a614eb18e6",
|
|
256
256
|
"@testing-library/dom": "^10.4.1",
|
|
257
257
|
"@testing-library/jest-dom": "^6.9.1",
|
|
258
258
|
"@testing-library/react": "^16.3.1",
|
|
@@ -261,9 +261,6 @@ export async function refreshCoverageSnapshot(
|
|
|
261
261
|
if (tenantId !== null && hasTenant) baseQuery = baseQuery.where('b.tenant_id' as any, '=', tenantId)
|
|
262
262
|
if (!withDeleted && hasDeleted) baseQuery = baseQuery.where('b.deleted_at' as any, 'is', null as any)
|
|
263
263
|
|
|
264
|
-
const baseRow = await baseQuery.executeTakeFirst() as { count: unknown } | undefined
|
|
265
|
-
const baseCount = toCount(baseRow?.count)
|
|
266
|
-
|
|
267
264
|
let indexQuery = db
|
|
268
265
|
.selectFrom('entity_indexes as ei' as any)
|
|
269
266
|
.select(sql`count(*)`.as('count'))
|
|
@@ -272,13 +269,10 @@ export async function refreshCoverageSnapshot(
|
|
|
272
269
|
if (tenantId !== null) indexQuery = indexQuery.where('ei.tenant_id' as any, '=', tenantId)
|
|
273
270
|
if (!withDeleted) indexQuery = indexQuery.where('ei.deleted_at' as any, 'is', null as any)
|
|
274
271
|
|
|
275
|
-
const
|
|
276
|
-
|
|
272
|
+
const vectorCountPromise = (async (): Promise<number | undefined> => {
|
|
273
|
+
const hasVectorTable = await tableHasColumn(db, 'vector_search', 'entity_id')
|
|
274
|
+
if (!hasVectorTable || typeof tenantId !== 'string' || tenantId.length === 0) return undefined
|
|
277
275
|
|
|
278
|
-
// Count vector entries directly from database
|
|
279
|
-
let vectorCount: number | undefined
|
|
280
|
-
const hasVectorTable = await tableHasColumn(db, 'vector_search', 'entity_id')
|
|
281
|
-
if (hasVectorTable && typeof tenantId === 'string' && tenantId.length > 0) {
|
|
282
276
|
try {
|
|
283
277
|
let vectorQuery = db
|
|
284
278
|
.selectFrom('vector_search' as any)
|
|
@@ -289,7 +283,7 @@ export async function refreshCoverageSnapshot(
|
|
|
289
283
|
vectorQuery = vectorQuery.where('organization_id' as any, '=', organizationId)
|
|
290
284
|
}
|
|
291
285
|
const vectorRow = await vectorQuery.executeTakeFirst() as { count: unknown } | undefined
|
|
292
|
-
|
|
286
|
+
return toCount(vectorRow?.count)
|
|
293
287
|
} catch (err) {
|
|
294
288
|
console.warn('[query_index] Failed to resolve vector count for coverage snapshot', {
|
|
295
289
|
entityType,
|
|
@@ -297,9 +291,18 @@ export async function refreshCoverageSnapshot(
|
|
|
297
291
|
organizationId,
|
|
298
292
|
error: err instanceof Error ? err.message : err,
|
|
299
293
|
})
|
|
300
|
-
|
|
294
|
+
return undefined
|
|
301
295
|
}
|
|
302
|
-
}
|
|
296
|
+
})()
|
|
297
|
+
|
|
298
|
+
const [baseRow, indexRow, vectorCount] = await Promise.all([
|
|
299
|
+
baseQuery.executeTakeFirst() as Promise<{ count: unknown } | undefined>,
|
|
300
|
+
indexQuery.executeTakeFirst() as Promise<{ count: unknown } | undefined>,
|
|
301
|
+
vectorCountPromise,
|
|
302
|
+
])
|
|
303
|
+
|
|
304
|
+
const baseCount = toCount(baseRow?.count)
|
|
305
|
+
const indexCount = toCount(indexRow?.count)
|
|
303
306
|
|
|
304
307
|
await writeCoverageCounts(em, { entityType, tenantId, organizationId, withDeleted }, {
|
|
305
308
|
baseCount,
|
|
@@ -1758,17 +1758,25 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
1758
1758
|
withDeleted: boolean
|
|
1759
1759
|
): Promise<{ baseCount: number; indexedCount: number } | null> {
|
|
1760
1760
|
try {
|
|
1761
|
-
if (!this.isCoverageOptimizationEnabled()) {
|
|
1762
|
-
await refreshCoverageSnapshot(this.em, {
|
|
1763
|
-
entityType: entity, tenantId, organizationId, withDeleted,
|
|
1764
|
-
})
|
|
1765
|
-
}
|
|
1766
1761
|
const db = this.getDb()
|
|
1767
|
-
const
|
|
1762
|
+
const scope = {
|
|
1768
1763
|
entityType: entity, tenantId, organizationId, withDeleted,
|
|
1769
|
-
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1764
|
+
}
|
|
1765
|
+
const row = await readCoverageSnapshot(db as any, scope)
|
|
1766
|
+
if (row && this.isCoverageSnapshotFresh(row)) {
|
|
1767
|
+
return { baseCount: row.baseCount, indexedCount: row.indexedCount }
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
if (this.isCoverageOptimizationEnabled()) {
|
|
1771
|
+
this.scheduleCoverageRefresh(entity, tenantId, organizationId, withDeleted)
|
|
1772
|
+
if (!row) return null
|
|
1773
|
+
return { baseCount: row.baseCount, indexedCount: row.indexedCount }
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
await refreshCoverageSnapshot(this.em, scope)
|
|
1777
|
+
const refreshed = await readCoverageSnapshot(db as any, scope)
|
|
1778
|
+
if (!refreshed) return null
|
|
1779
|
+
return { baseCount: refreshed.baseCount, indexedCount: refreshed.indexedCount }
|
|
1772
1780
|
} catch (err) {
|
|
1773
1781
|
if (this.isDebugVerbosity()) {
|
|
1774
1782
|
this.debug('coverage:snapshot:read-error', {
|
|
@@ -1780,6 +1788,21 @@ export class HybridQueryEngine implements QueryEngine {
|
|
|
1780
1788
|
}
|
|
1781
1789
|
}
|
|
1782
1790
|
|
|
1791
|
+
private isCoverageSnapshotFresh(
|
|
1792
|
+
row: Awaited<ReturnType<typeof readCoverageSnapshot>>
|
|
1793
|
+
): boolean {
|
|
1794
|
+
if (this.coverageStatsTtlMs <= 0) return false
|
|
1795
|
+
if (!row) return false
|
|
1796
|
+
const refreshedAt = row.refreshed_at instanceof Date
|
|
1797
|
+
? row.refreshed_at
|
|
1798
|
+
: row.refreshed_at
|
|
1799
|
+
? new Date(row.refreshed_at)
|
|
1800
|
+
: null
|
|
1801
|
+
const refreshedAtMs = refreshedAt?.getTime()
|
|
1802
|
+
if (!refreshedAtMs || !Number.isFinite(refreshedAtMs)) return false
|
|
1803
|
+
return Date.now() - refreshedAtMs <= this.coverageStatsTtlMs
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1783
1806
|
private scheduleAutoReindex(
|
|
1784
1807
|
entity: string,
|
|
1785
1808
|
opts: QueryOptions,
|