@open-mercato/shared 0.6.5-develop.5337.1.534b781eac → 0.6.5-develop.5382.1.f542de69af
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +1 -1
- package/dist/lib/ai/llm-provider-registry.js.map +1 -1
- package/dist/lib/crud/custom-fields.js +23 -15
- package/dist/lib/crud/custom-fields.js.map +2 -2
- package/dist/lib/crud/factory.js.map +1 -1
- package/dist/lib/crud/optimistic-lock-command.js.map +1 -1
- package/dist/lib/crud/optimistic-lock-headers.js.map +1 -1
- package/dist/lib/crud/optimistic-lock-store.js.map +1 -1
- package/dist/lib/crud/optimistic-lock.js.map +1 -1
- package/dist/lib/db/buildIlikeTerm.js +17 -0
- package/dist/lib/db/buildIlikeTerm.js.map +7 -0
- package/dist/lib/di/container.js +1 -1
- package/dist/lib/di/container.js.map +1 -1
- package/dist/lib/query/advanced-filter-tree.js +5 -5
- package/dist/lib/query/advanced-filter-tree.js.map +2 -2
- package/dist/lib/query/advanced-filter.js +5 -5
- package/dist/lib/query/advanced-filter.js.map +2 -2
- package/dist/lib/query/engine.js +3 -1
- package/dist/lib/query/engine.js.map +2 -2
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/overrides.js +1 -1
- package/dist/modules/overrides.js.map +1 -1
- package/dist/modules/search.js.map +1 -1
- package/package.json +2 -2
- package/src/lib/ai/llm-provider-registry.ts +1 -1
- package/src/lib/ai/llm-provider.ts +1 -1
- package/src/lib/crud/__tests__/custom-fields.test.ts +91 -0
- package/src/lib/crud/custom-fields.ts +30 -17
- package/src/lib/crud/factory.ts +1 -1
- package/src/lib/crud/optimistic-lock-command.ts +1 -1
- package/src/lib/crud/optimistic-lock-headers.ts +1 -1
- package/src/lib/crud/optimistic-lock-store.ts +1 -1
- package/src/lib/crud/optimistic-lock.ts +1 -1
- package/src/lib/db/__tests__/buildIlikeTerm.test.ts +40 -0
- package/src/lib/db/__tests__/escapeLikePattern.test.ts +123 -0
- package/src/lib/db/buildIlikeTerm.ts +16 -0
- package/src/lib/di/container.ts +1 -1
- package/src/lib/query/__tests__/engine.count-distinct.test.ts +229 -0
- package/src/lib/query/advanced-filter-tree.ts +5 -5
- package/src/lib/query/advanced-filter.ts +5 -5
- package/src/lib/query/engine.ts +13 -2
- package/src/modules/__tests__/overrides.test.ts +1 -1
- package/src/modules/__tests__/route-overrides.test.ts +1 -1
- package/src/modules/overrides.ts +3 -3
- package/src/modules/search.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildIlikeTerm } from '../db/buildIlikeTerm'
|
|
2
2
|
|
|
3
3
|
export type FilterOperator =
|
|
4
4
|
| 'is' | 'is_not' | 'contains' | 'does_not_contain' | 'starts_with' | 'ends_with' | 'is_empty' | 'is_not_empty'
|
|
@@ -190,19 +190,19 @@ function buildConditionFilter(condition: FilterCondition): Record<string, unknow
|
|
|
190
190
|
break
|
|
191
191
|
case 'contains':
|
|
192
192
|
if (normalizeSingleValue(condition.value) === null) return null
|
|
193
|
-
filter[condition.field] = { $ilike:
|
|
193
|
+
filter[condition.field] = { $ilike: buildIlikeTerm(String(normalizeSingleValue(condition.value))) }
|
|
194
194
|
break
|
|
195
195
|
case 'does_not_contain':
|
|
196
196
|
if (normalizeSingleValue(condition.value) === null) return null
|
|
197
|
-
filter[condition.field] = { $not: { $ilike:
|
|
197
|
+
filter[condition.field] = { $not: { $ilike: buildIlikeTerm(String(normalizeSingleValue(condition.value))) } }
|
|
198
198
|
break
|
|
199
199
|
case 'starts_with':
|
|
200
200
|
if (normalizeSingleValue(condition.value) === null) return null
|
|
201
|
-
filter[condition.field] = { $ilike:
|
|
201
|
+
filter[condition.field] = { $ilike: buildIlikeTerm(String(normalizeSingleValue(condition.value)), 'startsWith') }
|
|
202
202
|
break
|
|
203
203
|
case 'ends_with':
|
|
204
204
|
if (normalizeSingleValue(condition.value) === null) return null
|
|
205
|
-
filter[condition.field] = { $ilike:
|
|
205
|
+
filter[condition.field] = { $ilike: buildIlikeTerm(String(normalizeSingleValue(condition.value)), 'endsWith') }
|
|
206
206
|
break
|
|
207
207
|
case 'is_empty':
|
|
208
208
|
filter[condition.field] = { $exists: false }
|
package/src/lib/query/engine.ts
CHANGED
|
@@ -844,9 +844,20 @@ export class BasicQueryEngine implements QueryEngine {
|
|
|
844
844
|
if (hasJoinedAggregates) {
|
|
845
845
|
q = q.groupBy(`${table}.id`)
|
|
846
846
|
}
|
|
847
|
+
// `count(distinct base.id)` is only required when a join can multiply base rows
|
|
848
|
+
// (CF/extension aggregates, explicit relation joins, or custom-field sources).
|
|
849
|
+
// Without such joins base.id is the unique PK, so `count(*)` is equivalent and
|
|
850
|
+
// lets Postgres skip the redundant DISTINCT sort/hash for an index-only count (#2227).
|
|
851
|
+
const mayMultiplyBaseRows =
|
|
852
|
+
hasJoinedAggregates ||
|
|
853
|
+
(Array.isArray(opts.joins) && opts.joins.length > 0) ||
|
|
854
|
+
(Array.isArray(opts.customFieldSources) && opts.customFieldSources.length > 0)
|
|
855
|
+
const countExpr = mayMultiplyBaseRows
|
|
856
|
+
? sql<string>`count(distinct ${sql.ref(`${table}.id`)})`
|
|
857
|
+
: sql<string>`count(*)`
|
|
847
858
|
const countBuilder = hasJoinedAggregates
|
|
848
|
-
? q.clearSelect().clearOrderBy().clearGroupBy().select(
|
|
849
|
-
: q.clearSelect().clearOrderBy().select(
|
|
859
|
+
? q.clearSelect().clearOrderBy().clearGroupBy().select(countExpr.as('count'))
|
|
860
|
+
: q.clearSelect().clearOrderBy().select(countExpr.as('count'))
|
|
850
861
|
const countRow = await countBuilder.executeTakeFirst() as { count: unknown } | undefined
|
|
851
862
|
const total = Number((countRow as any)?.count ?? 0)
|
|
852
863
|
const dataQuery = requiresPlaintextSort
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* by shared's default appliers; custom/future domains still warn if no
|
|
7
7
|
* applier is registered.
|
|
8
8
|
*
|
|
9
|
-
* Spec: `.ai/specs/2026-05-04-modules-ts-unified-overrides.md`.
|
|
9
|
+
* Spec: `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md`.
|
|
10
10
|
*/
|
|
11
11
|
import {
|
|
12
12
|
applyModuleOverridesFromEnabledModules,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - `registerApiRouteManifests` consults the override composer.
|
|
13
13
|
* - Stale override keys emit a warning so operators notice.
|
|
14
14
|
*
|
|
15
|
-
* Spec: `.ai/specs/2026-05-04-modules-ts-unified-overrides.md`.
|
|
15
|
+
* Spec: `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md`.
|
|
16
16
|
*/
|
|
17
17
|
import {
|
|
18
18
|
applyApiOverridesToManifests,
|
package/src/modules/overrides.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Unified `modules.ts` override surface — one place for downstream apps to
|
|
3
3
|
* replace or disable any contract a module presents.
|
|
4
4
|
*
|
|
5
|
-
* Spec: `.ai/specs/2026-05-04-modules-ts-unified-overrides.md`
|
|
5
|
+
* Spec: `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md`
|
|
6
6
|
*
|
|
7
7
|
* Each `ModuleEntry` in `apps/<app>/src/modules.ts` may carry an
|
|
8
8
|
* `overrides` field whose sub-keys address one domain at a time:
|
|
@@ -229,7 +229,7 @@ const DOMAIN_KEYS: ModuleOverrideDomain[] = [
|
|
|
229
229
|
]
|
|
230
230
|
|
|
231
231
|
const TRACKING_ISSUE_HINT =
|
|
232
|
-
'See `.ai/specs/2026-05-04-modules-ts-unified-overrides.md` and tracking issue https://github.com/open-mercato/open-mercato/issues/1787.'
|
|
232
|
+
'See `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md` and tracking issue https://github.com/open-mercato/open-mercato/issues/1787.'
|
|
233
233
|
|
|
234
234
|
/**
|
|
235
235
|
* Walk every `ModuleEntry` and dispatch its `overrides.<domain>` shape
|
|
@@ -312,7 +312,7 @@ export function applyModuleOverridesFromEnabledModules(
|
|
|
312
312
|
// runtime override scenarios call the dispatcher / programmatic API
|
|
313
313
|
// before `bootstrap.ts` triggers manifest registration.
|
|
314
314
|
//
|
|
315
|
-
// Spec: `.ai/specs/2026-05-04-modules-ts-unified-overrides.md` (Phases 2/3).
|
|
315
|
+
// Spec: `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md` (Phases 2/3).
|
|
316
316
|
|
|
317
317
|
// ApiRouteManifestEntry / ApiHandler / HttpMethod live in ./registry. The
|
|
318
318
|
// type-only import is erased at runtime, so there is no cycle even though
|
package/src/modules/search.ts
CHANGED
|
@@ -160,7 +160,7 @@ export interface SearchStrategy {
|
|
|
160
160
|
bulkIndex?(records: IndexableRecord[]): Promise<void>
|
|
161
161
|
|
|
162
162
|
/** Purge all records for an entity type (optional) */
|
|
163
|
-
purge?(entityId: EntityId, tenantId: string): Promise<void>
|
|
163
|
+
purge?(entityId: EntityId, tenantId: string, organizationId?: string | null): Promise<void>
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
// =============================================================================
|