@lde/search-typesense 0.29.2 → 0.29.4

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.
@@ -73,7 +73,8 @@ export interface CollectionDefinitionOptions {
73
73
  * size of the fields you search, facet or sort on – not the whole document.
74
74
  * This builder keeps that surface minimal: the `output` display labels land in
75
75
  * a single `index: false` regex field (`${name}_<lang>`, one value per present
76
- * language), kept on disk and read back only for a hit, so they cost no RAM;
76
+ * language, or every value of it as a `string[]` for an `array` field), kept
77
+ * on disk and read back only for a hit, so they cost no RAM;
77
78
  * only the folded `*_search_${locale}`, facet/reference and `*_sort_${locale}`
78
79
  * companions are indexed. Keeping retrieval-only fields un-indexed is the lever
79
80
  * for holding a large index’s RAM down.
@@ -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;AAcrB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,UAAU,EACtB,OAAO,GAAE,2BAAgC,GACxC,sBAAsB,CA2BxB"}
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;AAcrB,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,CA2BxB"}
@@ -27,7 +27,8 @@ import { deriveCollectionName } from './collection-name.js';
27
27
  * size of the fields you search, facet or sort on – not the whole document.
28
28
  * This builder keeps that surface minimal: the `output` display labels land in
29
29
  * a single `index: false` regex field (`${name}_<lang>`, one value per present
30
- * language), kept on disk and read back only for a hit, so they cost no RAM;
30
+ * language, or every value of it as a `string[]` for an `array` field), kept
31
+ * on disk and read back only for a hit, so they cost no RAM;
31
32
  * only the folded `*_search_${locale}`, facet/reference and `*_sort_${locale}`
32
33
  * companions are indexed. Keeping retrieval-only fields un-indexed is the lever
33
34
  * for holding a large index’s RAM down.
@@ -163,12 +164,14 @@ function typesenseFields(searchType, field, defaultLocale, defaultSortingField,
163
164
  // the folded `*_search` companions, so the display copies stay on disk and
164
165
  // off RAM (fetched only for a hit), accents preserved, and a language
165
166
  // outside `locales` still renders. This is the memory lever: RAM tracks
166
- // the search surface, not the display text. Absent for a non-output field.
167
+ // the search surface, not the display text. Absent for a non-output
168
+ // field. An `array` field stores every value of a language, so its
169
+ // pattern is typed a list – `array` decides the shape for every kind.
167
170
  ...(displayPattern !== undefined
168
171
  ? [
169
172
  {
170
173
  name: displayPattern,
171
- type: 'string',
174
+ type: typesenseValueType(field),
172
175
  index: false,
173
176
  optional: true,
174
177
  },
@@ -426,10 +429,11 @@ function nestedLeafFields(prefix, field, defaultLocale, flattensToArray) {
426
429
  if (pattern !== undefined) {
427
430
  // Display values are never indexed, whatever Roles the field declares:
428
431
  // search hits the folded companions below, so the display copies stay on
429
- // disk with every language they carry.
432
+ // disk with every language they carry – every value of it for an
433
+ // `array` field.
430
434
  fields.push({
431
435
  name: nestedFieldName(prefix, pattern),
432
- type: 'string',
436
+ type: typesenseValueType(field),
433
437
  index: false,
434
438
  optional: true,
435
439
  });
package/dist/search.js CHANGED
@@ -656,16 +656,20 @@ function logicalValue(flat, field, labels, schema, referents) {
656
656
  * recovers languages outside the declared `locales` too – a value tagged in an
657
657
  * undeclared language, or untagged (`und`), still reconstructs rather than being
658
658
  * dropped.
659
+ *
660
+ * A display field holds one string for a plain field, or a list of them for an
661
+ * `array` field.
659
662
  */
660
663
  function localizedValue(flat, field) {
661
664
  const map = {};
662
665
  for (const [key, value] of Object.entries(flat)) {
663
- if (typeof value !== 'string') {
666
+ const lang = displayLangOf(field, key);
667
+ if (lang === undefined) {
664
668
  continue;
665
669
  }
666
- const lang = displayLangOf(field, key);
667
- if (lang !== undefined) {
668
- map[lang] = [value];
670
+ const values = (Array.isArray(value) ? value : [value]).filter((entry) => typeof entry === 'string');
671
+ if (values.length > 0) {
672
+ map[lang] = values;
669
673
  }
670
674
  }
671
675
  return Object.keys(map).length > 0 ? map : undefined;
@@ -694,31 +698,33 @@ function nestedValue(raw, field, referenceType, labels, schema, children) {
694
698
  }
695
699
  /**
696
700
  * Rebuild a {@link ReferenceStrategy.local local} lookup: the endpoint’s own
697
- * document as this document stated it, with the **resolved** document overlaid
701
+ * document as this document stated it, **replaced** by the resolved document
698
702
  * where the lookup found one.
699
703
  *
700
- * Both sides are the target type’s flat physical shape, so the merge is a plain
701
- * override and the authoritative value wins field by field. Three cases fall
702
- * out of one expression, which is the point of storing local fields
703
- * unconditionally:
704
+ * Replaced rather than merged, because both sides are the target type’s flat
705
+ * physical shape and a logical field fans out into several physical ones: a
706
+ * name this document stated in one language would survive beside the target’s
707
+ * name in another, and a field the target’s record does not carry would
708
+ * survive after the target dropped it. The resolved document carries what the
709
+ * projection asked for, and a resolved entry says exactly that – what a plain
710
+ * lookup says too. Three cases fall out of one expression, which is the point
711
+ * of storing local fields unconditionally:
704
712
  *
705
- * - identified and indexed → the target’s own record, over what was stated here;
713
+ * - identified and indexed → the target’s own record;
706
714
  * - identified but not indexed → what was stated here, plus the `id`, rather
707
715
  * than a bare IRI;
708
716
  * - not identified → what was stated here, with no `id` at all.
709
717
  */
710
718
  function localLookupValue(raw, field, target, resolved, labels, schema) {
711
719
  const fetched = resolved?.via === 'lookup' ? resolved.documents : new Map();
712
- const merged = (Array.isArray(raw) ? raw : [raw])
720
+ const entries = (Array.isArray(raw) ? raw : [raw])
713
721
  .filter((entry) => typeof entry === 'object' && entry !== null)
714
722
  .map((entry) => {
715
723
  const id = typeof entry.id === 'string' ? entry.id : undefined;
716
724
  const authoritative = id === undefined ? undefined : fetched.get(id);
717
- return authoritative === undefined
718
- ? entry
719
- : { ...entry, ...authoritative };
725
+ return authoritative ?? entry;
720
726
  });
721
- return nestedValue(merged, field, target, labels, schema, resolved?.children);
727
+ return nestedValue(entries, field, target, labels, schema, resolved?.children);
722
728
  }
723
729
  /**
724
730
  * Rebuild a resolved `lookup` reference: each stored IRI becomes the referent’s
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lde/search-typesense",
3
- "version": "0.29.2",
3
+ "version": "0.29.4",
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.24.2",
28
+ "@lde/search": "^0.24.4",
29
29
  "@lde/text-normalization": "^0.1.2",
30
30
  "tslib": "^2.3.0",
31
31
  "typesense": "^3.0.6"