@lde/search-typesense 0.52.1 → 0.53.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"collection-definition.d.ts","sourceRoot":"","sources":["../src/collection-definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAgBrB,0EAA0E;AAC1E,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC;IAChE;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B;;;4BAGwB;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,2BAAgC,GACxC,sBAAsB,CA4BxB"}
1
+ {"version":3,"file":"collection-definition.d.ts","sourceRoot":"","sources":["../src/collection-definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAExD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,aAAa,CAAC;AAiBrB,0EAA0E;AAC1E,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC;IAChE;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B;;;4BAGwB;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,kEAAkE;IAClE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,kEAAkE;IAClE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,2BAAgC,GACxC,sBAAsB,CAwCxB"}
@@ -1,4 +1,4 @@
1
- import { displayFieldPattern, ID_FIELD, isInlineReference, isInternalField, isBinnedRangeFacet, joinGraph, localLookupTargetsOf, TARGET_FIELD, nestedFieldName, nestedReferenceType, physicalFields, } from '@lde/search/adapter';
1
+ import { displayFieldPattern, facetsOf, ID_FIELD, isInlineReference, isInternalField, isBinnedRangeFacet, joinGraph, localLookupTargetsOf, TARGET_FIELD, nestedFieldName, nestedReferenceType, physicalFields, } from '@lde/search/adapter';
2
2
  import { deriveCollectionName } from './collection-name.js';
3
3
  /**
4
4
  * Build a Typesense collection definition from the unified {@link SearchType}, so
@@ -56,6 +56,16 @@ export function buildCollectionDefinition(searchType, options = {}) {
56
56
  name: collectionNameFor(searchType),
57
57
  fields: searchType.fields.flatMap((field) => typesenseFields(searchType, field, defaultLocale, options.defaultSortingField, options.schema, collectionNameFor)),
58
58
  };
59
+ // A faceted leaf is faceted on its nested path, which Typesense flattens
60
+ // into one list per document – so a bucket counts documents, not entries.
61
+ const facetedPaths = new Set(facetsOf(searchType, options.schema)
62
+ .filter((facet) => facet.reference !== undefined)
63
+ .map((facet) => facet.engineField));
64
+ for (const field of collection.fields) {
65
+ if (facetedPaths.has(field.name)) {
66
+ field.facet = true;
67
+ }
68
+ }
59
69
  // Typesense rejects an `object`/`object[]` field unless nesting is enabled,
60
70
  // so the flag is a consequence of the declaration – never a knob.
61
71
  if (collection.fields?.some((field) => field.type.startsWith('object'))) {
@@ -589,7 +599,9 @@ function nestedLeafFields(prefix, field, defaultLocale, flattensToArray) {
589
599
  }
590
600
  // A nested field can be `filterable` or `searchable`, never `facetable` or
591
601
  // `sortable` (`searchSchema`), so `filterable` is what indexes the value
592
- // itself – its search companion below indexes on its own account.
602
+ // itself – its search companion below indexes on its own account. A leaf the
603
+ // root is faceted on is marked a facet field once the collection is built
604
+ // ({@link buildCollectionDefinition}), since only the root knows.
593
605
  const indexed = field.filterable === true;
594
606
  const valueType = typesenseValueType(field);
595
607
  // Two ways a list arrives: the field declares one, or an ancestor's
@@ -1,4 +1,4 @@
1
- import { facetableFields, physicalFields } from '@lde/search/adapter';
1
+ import { facetsOf } from '@lde/search/adapter';
2
2
  import { buildCollectionDefinition } from './collection-definition.js';
3
3
  import { ensureCollectionExists, openLockedRun, releaseLock } from './lock.js';
4
4
  import { assertBookkeepingPresent, assertWritableType, openDocuments, withBookkeeping, } from './documents.js';
@@ -176,16 +176,14 @@ function assertReferencesAndFacetCompanionsPresent(name, fields, facetCompanions
176
176
  if (missingCompanions.length > 0) {
177
177
  throw new Error(`Typesense collection “${name}” exists without the facet field(s) ${missingCompanions
178
178
  .map((companion) => `“${companion}”`)
179
- .join(', ')} its search type facets on in place of the field itself – an identity companion, or one narrowed by a facet policy (“facetKeys”). A facet field cannot be added to a live collection here: drop “${name}” (and the collections that join to it) and let the next run rebuild them.`);
179
+ .join(', ')} its search type facets on in place of the field itself – an identity companion, one narrowed by a facet policy (“facetKeys”), or the nested path of a faceted leaf. A facet field cannot be added to a live collection here: drop “${name}” (and the collections that join to it) and let the next run rebuild them.`);
180
180
  }
181
181
  }
182
- /** The companions a type’s facets read instead of the fields themselves – one
183
- * per facetable reference that stores a nested object or inherits a facet
184
- * policy ({@link physicalFields}). */
182
+ /** The fields a type’s facets read instead of the fields themselves – one per
183
+ * facetable reference that stores a nested object or inherits a facet policy
184
+ * ({@link facetsOf}), and the nested path of each faceted leaf. */
185
185
  function facetCompanionsOf(searchType, schema) {
186
- return facetableFields(searchType).flatMap((field) => {
187
- // A facetable field always has a facet field.
188
- const facet = physicalFields(field, schema).facet;
189
- return facet === field.name ? [] : [facet];
190
- });
186
+ return facetsOf(searchType, schema)
187
+ .filter((facet) => facet.engineField !== facet.field.name)
188
+ .map((facet) => facet.engineField);
191
189
  }
@@ -1 +1 @@
1
- {"version":3,"file":"query-compiler.d.ts","sourceRoot":"","sources":["../src/query-compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,QAAQ,EAEb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EAIhB,MAAM,aAAa,CAAC;AAsBrB;mDACmD;AACnD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,UAAU,GAAG,SAAS,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,wBAA6B,GACrC,YAAY,CAAC,MAAM,CAAC,CAkCtB;AAikBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD"}
1
+ {"version":3,"file":"query-compiler.d.ts","sourceRoot":"","sources":["../src/query-compiler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE,OAAO,EAGL,KAAK,MAAM,EACX,KAAK,QAAQ,EAEb,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,UAAU,EAIhB,MAAM,aAAa,CAAC;AAuBrB;mDACmD;AACnD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,CACvB,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,SAAS,MAAM,EAAE,KACpB,UAAU,GAAG,SAAS,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,wBAA6B,GACrC,YAAY,CAAC,MAAM,CAAC,CAkCtB;AAikBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD"}
@@ -1,5 +1,5 @@
1
1
  import { fold } from '@lde/text-normalization';
2
- import { fieldNamed, filterOperator, filterOperatorFor, ID_FIELD, storedFacetRanges, storedRangeBound, isInternalField, isBinnedRangeFacet, holdsNoIds, isWelded, joinGraph, localLookupTargetsOf, matchLanguage, pageForOffset, physicalFields, nestedReferenceType, resolvePath, searchableFields, } from '@lde/search/adapter';
2
+ import { fieldNamed, filterOperator, filterOperatorFor, ID_FIELD, storedFacetRanges, storedRangeBound, isInternalField, isBinnedRangeFacet, facetNamed, holdsNoIds, isWelded, joinGraph, localLookupTargetsOf, matchLanguage, pageForOffset, physicalFields, nestedReferenceType, resolvePath, searchableFields, } from '@lde/search/adapter';
3
3
  /**
4
4
  * Compile the engine-neutral {@link SearchQuery} into Typesense search
5
5
  * parameters – the query half of the engine adapter. Pure (no client, no env),
@@ -56,13 +56,13 @@ export function buildSearchParams(query, searchType, options = {}) {
56
56
  function compileFacetBy(facets, searchType, schema) {
57
57
  return facets
58
58
  .map((name) => {
59
- const field = fieldNamed(searchType, name);
60
- if (field === undefined) {
59
+ const facet = facetNamed(searchType, name, schema);
60
+ if (facet === undefined) {
61
61
  return name;
62
62
  }
63
- return isBinnedRangeFacet(field)
64
- ? compileRangeFacet(field.name, storedFacetRanges(field))
65
- : (physicalFields(field, schema).facet ?? name);
63
+ return isBinnedRangeFacet(facet.field)
64
+ ? compileRangeFacet(facet.engineField, storedFacetRanges(facet.field))
65
+ : facet.engineField;
66
66
  })
67
67
  .join(',');
68
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAIL,KAAK,cAAc,EAMnB,KAAK,UAAU,EAGf,KAAK,YAAY,EAEjB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,UAAU,EAEf,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AA+BrB,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAC;AAErB;;;;sDAIsD;AACtD,MAAM,WAAW,4BAA4B,CAC3C,QAAQ,SAAS,MAAM,GAAG,MAAM,CAIhC,SAAQ,IAAI,CAAC,wBAAwB,EAAE,eAAe,CAAC;IACvD;;;;;;;;OAQG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnE;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB,CACpC,KAAK,SAAS,SAAS,UAAU,EAAE,GAAG,SAAS,UAAU,EAAE,CAC3D,SAAQ,YAAY,CAAC,KAAK,CAAC;IAC3B;;;;;;;OAOG;IACH,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;CAC1D;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,CAAC,KAAK,SAAS,SAAS,UAAU,EAAE,EAEzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,EAC3B,OAAO,GAAE,4BAA4B,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAM,GAChE,qBAAqB,CAAC,KAAK,CAAC,CAyc9B;AAyCD,8EAA8E;AAC9E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC;AAqXD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,EACnC,MAAM,EAAE,SAAS,gBAAgB,EAAE,EACnC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAwDtC;AAgCD,oEAAoE;AACpE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS;QAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAC;IAC1E,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS;QAC/B;;2EAEmE;QACnE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS;YACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;YACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;SACxB,EAAE,CAAC;QACJ;;qFAE6E;QAC7E,QAAQ,CAAC,KAAK,CAAC,EACX;YAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;SAAE,GAC9C;YAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;YAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,KAAK,CAAA;SAAE,CAAC;KACpD,EAAE,CAAC;CACL;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,uBAAuB,EACjC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,EAC3C,MAAM,EAAE,YAAY,EACpB,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,GACjD,YAAY,CAuDd"}
package/dist/search.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { NESTED_DOCUMENT_TYPE, } from '@lde/search';
2
- import { assertTypeInSchema, assertValidQuery, displayLangOf, facetableFields, facetSearches, fieldNamed, filterOn, inheritedFacetPolicies, isDatePrecision, isInlineReference, isBinnedRangeFacet, isUnsatisfiable, joinGraph, labelFieldOf, labelSourceNamesOf, labelTargetNamesOf, literalKindOf, localLookupTargetsOf, nestedReferenceType, outputFields, physicalFields, referencedTargetsOf, referenceFields, storedFacetRanges, storedTargetOf, } from '@lde/search/adapter';
2
+ import { assertTypeInSchema, assertValidQuery, displayLangOf, facetNamed, facetSearches, facetsOf, selectionOf, fieldNamed, inheritedFacetPolicies, isDatePrecision, isInlineReference, isBinnedRangeFacet, isUnsatisfiable, joinGraph, labelFieldOf, labelSourceNamesOf, labelTargetNamesOf, literalKindOf, localLookupTargetsOf, nestedReferenceType, outputFields, physicalFields, referencedTargetsOf, referenceFields, storedFacetRanges, storedTargetOf, } from '@lde/search/adapter';
3
3
  import { buildSearchParams, escapeFilterValue, } from './query-compiler.js';
4
4
  import { deriveCollectionName } from './collection-name.js';
5
5
  import { resolveProjection, } from './lookup.js';
@@ -70,13 +70,20 @@ export function createTypesenseSearchEngine(client, schema, options = {}) {
70
70
  // reference naming several targets reads labels from every one of them.
71
71
  const labelSources = new Map([...schema.values()].map((searchType) => [
72
72
  searchType.class,
73
- new Map(referenceFields(searchType)
73
+ new Map([
74
+ ...referenceFields(searchType).map((field) => ({
75
+ name: field.name,
76
+ field,
77
+ })),
78
+ // A faceted leaf labels its buckets from the leaf’s own targets.
79
+ ...facetsOf(searchType, schema).filter((facet) => facet.reference !== undefined),
80
+ ]
74
81
  // An INLINE reference names its label target one level in, through
75
82
  // its identity companion: the companion holds that field's ids, so
76
83
  // that field's target is what can label them.
77
- .filter((field) => labelTargetNamesOf(field, schema).length > 0)
78
- .map((field) => [
79
- field.name,
84
+ .filter(({ field }) => labelTargetNamesOf(field, schema).length > 0)
85
+ .map(({ name, field }) => [
86
+ name,
80
87
  labelTargetNamesOf(field, schema).map((targetName) => {
81
88
  const source = typesByName.get(targetName);
82
89
  const labelField = labelFieldOf(source);
@@ -98,10 +105,9 @@ export function createTypesenseSearchEngine(client, schema, options = {}) {
98
105
  // facet’s labels, or its counts, or both.
99
106
  const declaredFacetNames = new Map([...schema.values()].map((searchType) => [
100
107
  searchType.class,
101
- new Map(facetableFields(searchType).map((field) => [
102
- // A facetable field always has a facet field.
103
- physicalFields(field, schema).facet,
104
- field.name,
108
+ new Map(facetsOf(searchType, schema).map((facet) => [
109
+ facet.engineField,
110
+ facet.name,
105
111
  ])),
106
112
  ]));
107
113
  // The distinct source collections per type, for the cached path – fixed at
@@ -577,7 +583,12 @@ async function withSelectedValues(client, collection, searchType, entries, optio
577
583
  collection,
578
584
  ...buildSearchParams({
579
585
  ...query,
580
- where: [...query.where, selecting(searchType, field, value)],
586
+ where: [
587
+ ...query.where,
588
+ // Only a facet the query asked for, and `assertValidQuery`
589
+ // admitted, is counted value by value.
590
+ selectionOf(facetNamed(searchType, field, options.schema), value),
591
+ ],
581
592
  facets: [],
582
593
  orderBy: [],
583
594
  limit: 0,
@@ -634,13 +645,6 @@ async function withSelectedValues(client, collection, searchType, entries, optio
634
645
  };
635
646
  });
636
647
  }
637
- /** The clause that selects one facet value: `is` on a boolean, `in` on
638
- * anything else. */
639
- function selecting(searchType, field, value) {
640
- return filterOn(fieldNamed(searchType, field)?.kind === 'boolean'
641
- ? { field, is: value === 'true' }
642
- : { field, in: [value] });
643
- }
644
648
  /** Orders buckets by descending count, as the engine orders its own. */
645
649
  function byCount(first, second) {
646
650
  return second.count - first.count;
@@ -757,16 +761,16 @@ export function parseSearchResponse(response, searchType, labels, schema, refere
757
761
  // Only reference facets with a label source get bucket labels; an id-only
758
762
  // reference facet stays id-only even when a cached full-collection map holds
759
763
  // its IRIs.
760
- const referenceFacets = new Set(referenceFields(searchType)
761
- .filter((field) => labelTargetNamesOf(field, schema).length > 0)
762
- .map((field) => field.name));
764
+ const referenceFacets = new Set(facetsOf(searchType, schema)
765
+ .filter((facet) => labelTargetNamesOf(facet.field, schema).length > 0)
766
+ .map((facet) => facet.name));
763
767
  const facets = {};
764
768
  for (const facet of response.facet_counts ?? []) {
765
769
  const labelled = referenceFacets.has(facet.field_name);
766
770
  // A binned facet echoes the declared range key as the bucket value; look
767
771
  // the bin’s half-open bounds back up by key, in stored terms, so the
768
772
  // bucket is self-describing.
769
- const field = fieldNamed(searchType, facet.field_name);
773
+ const field = facetNamed(searchType, facet.field_name, schema)?.field;
770
774
  const rangesByKey = field !== undefined && isBinnedRangeFacet(field)
771
775
  ? new Map(storedFacetRanges(field).map((range) => [range.key, range]))
772
776
  : undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search-typesense",
3
- "version": "0.52.1",
3
+ "version": "0.53.0",
4
4
  "description": "Typesense implementation of the @lde/search SearchEngine port: collection-schema builder, query compiler, label-resolving result reconstruction, and blue/green index lifecycle. Engine-specific (Typesense) but domain-agnostic.",
5
5
  "repository": {
6
6
  "url": "git+https://github.com/ldelements/lde.git",
@@ -25,7 +25,7 @@
25
25
  "!**/*.tsbuildinfo"
26
26
  ],
27
27
  "dependencies": {
28
- "@lde/search": "^0.41.2",
28
+ "@lde/search": "^0.41.3",
29
29
  "@lde/text-normalization": "^0.3.0",
30
30
  "tslib": "^2.3.0",
31
31
  "typesense": "^3.2.0"
@@ -36,6 +36,6 @@
36
36
  },
37
37
  "peerDependencies": {
38
38
  "@lde/dataset": "^0.10.1",
39
- "@lde/pipeline": "^0.46.0"
39
+ "@lde/pipeline": "^0.47.0"
40
40
  }
41
41
  }