@lde/search-typesense 0.29.3 → 0.30.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.
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
174
|
+
type: typesenseValueType(field),
|
|
172
175
|
index: false,
|
|
173
176
|
optional: true,
|
|
174
177
|
},
|
|
@@ -314,7 +317,7 @@ function nestedFields(prefix, reference, nestedType, schema, defaultLocale, with
|
|
|
314
317
|
type: boundaryArray ? 'string[]' : 'string',
|
|
315
318
|
index: false,
|
|
316
319
|
optional: true,
|
|
317
|
-
}, ...nestedIdentityFields(prefix, field, schema));
|
|
320
|
+
}, ...nestedIdentityFields(prefix, field, schema, flattensToArray));
|
|
318
321
|
continue;
|
|
319
322
|
}
|
|
320
323
|
if (deeper !== undefined) {
|
|
@@ -324,7 +327,7 @@ function nestedFields(prefix, reference, nestedType, schema, defaultLocale, with
|
|
|
324
327
|
// an engine welds conditions on an entry's LEAF fields only. Its
|
|
325
328
|
// identity companion is that leaf, so it sits beside the object rather
|
|
326
329
|
// than inside it.
|
|
327
|
-
...nestedIdentityFields(prefix, field, schema));
|
|
330
|
+
...nestedIdentityFields(prefix, field, schema, flattensToArray));
|
|
328
331
|
continue;
|
|
329
332
|
}
|
|
330
333
|
children.push(...nestedLeafFields(prefix, field, defaultLocale, flattensToArray));
|
|
@@ -381,7 +384,7 @@ function identityCompanionFields(field, schema) {
|
|
|
381
384
|
/** The identity companion of a nested field that stores an object: a flat leaf
|
|
382
385
|
* beside it, holding the ids a filter welds on. Empty for a nested field that
|
|
383
386
|
* declares no query Role, which needs none. */
|
|
384
|
-
function nestedIdentityFields(prefix, field, schema) {
|
|
387
|
+
function nestedIdentityFields(prefix, field, schema, flattensToArray) {
|
|
385
388
|
const names = physicalFields(field, schema);
|
|
386
389
|
if (names.identity === undefined) {
|
|
387
390
|
return [];
|
|
@@ -389,11 +392,23 @@ function nestedIdentityFields(prefix, field, schema) {
|
|
|
389
392
|
return [
|
|
390
393
|
{
|
|
391
394
|
name: nestedFieldName(prefix, names.identity),
|
|
392
|
-
//
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
|
|
395
|
+
// Typed by what the PATH yields across the document, exactly as the `id`
|
|
396
|
+
// beside it is, and by the same two routes every other declaration here
|
|
397
|
+
// uses: an `object[]` ancestor multiplying the entries, or the field's
|
|
398
|
+
// own `array` making each entry hold a list. A weldable leaf is
|
|
399
|
+
// single-valued (ADR 26), so a companion that a weld names contributes
|
|
400
|
+
// one id per entry – but a multi-valued reference reached through a
|
|
401
|
+
// locally-nested Root Type is not weldable and still harvests a list.
|
|
402
|
+
// Getting either route wrong rejects the document at import: Typesense
|
|
403
|
+
// enforces the declared arity wherever nothing widens the path.
|
|
404
|
+
// `filterable` is the condition because it is what the projection writes
|
|
405
|
+
// a single id under, not because it decides the split: `tuplesOf` splits
|
|
406
|
+
// the identity field whatever Role earned it. A `facetable`-only
|
|
407
|
+
// companion is declared a list, which is what a facet reads and what the
|
|
408
|
+
// projection writes for it.
|
|
409
|
+
type: flattensToArray || field.array === true || field.filterable !== true
|
|
410
|
+
? 'string[]'
|
|
411
|
+
: 'string',
|
|
397
412
|
index: true,
|
|
398
413
|
optional: true,
|
|
399
414
|
},
|
|
@@ -426,10 +441,11 @@ function nestedLeafFields(prefix, field, defaultLocale, flattensToArray) {
|
|
|
426
441
|
if (pattern !== undefined) {
|
|
427
442
|
// Display values are never indexed, whatever Roles the field declares:
|
|
428
443
|
// search hits the folded companions below, so the display copies stay on
|
|
429
|
-
// disk with every language they carry
|
|
444
|
+
// disk with every language they carry – every value of it for an
|
|
445
|
+
// `array` field.
|
|
430
446
|
fields.push({
|
|
431
447
|
name: nestedFieldName(prefix, pattern),
|
|
432
|
-
type:
|
|
448
|
+
type: typesenseValueType(field),
|
|
433
449
|
index: false,
|
|
434
450
|
optional: true,
|
|
435
451
|
});
|
|
@@ -454,6 +470,10 @@ function nestedLeafFields(prefix, field, defaultLocale, flattensToArray) {
|
|
|
454
470
|
// `object[]` flattens it into one. `typesenseValueType` honours `array` only
|
|
455
471
|
// for the string-shaped kinds, so a multi-valued nested `integer` would
|
|
456
472
|
// otherwise be declared scalar and rejected at import.
|
|
473
|
+
//
|
|
474
|
+
// A weldable leaf of a Reference Type is single-valued (ADR 26), but that
|
|
475
|
+
// narrows nothing here: this same path declares the fields of the Root Type a
|
|
476
|
+
// `local` lookup nests, where `array` and `filterable` may legitimately meet.
|
|
457
477
|
const storesAList = flattensToArray || field.array === true;
|
|
458
478
|
fields.push({
|
|
459
479
|
name: nestedFieldName(prefix, field.name),
|
|
@@ -494,8 +514,11 @@ function arrayValueType(type) {
|
|
|
494
514
|
return 'float[]';
|
|
495
515
|
case 'bool':
|
|
496
516
|
return 'bool[]';
|
|
497
|
-
// Already a list
|
|
498
|
-
//
|
|
517
|
+
// Already a list, and reachable even though a weldable leaf of a Reference
|
|
518
|
+
// Type is single-valued (ADR 26): this path also declares the fields of the
|
|
519
|
+
// Root Type a `local` lookup nests, and `searchSchema` constrains only
|
|
520
|
+
// Reference Types. A root keyword may be `array` and `filterable` at once –
|
|
521
|
+
// an ordinary facet – so flattening it must widen no further.
|
|
499
522
|
case 'string[]':
|
|
500
523
|
return 'string[]';
|
|
501
524
|
}
|
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
|
-
|
|
666
|
+
const lang = displayLangOf(field, key);
|
|
667
|
+
if (lang === undefined) {
|
|
664
668
|
continue;
|
|
665
669
|
}
|
|
666
|
-
const
|
|
667
|
-
if (
|
|
668
|
-
map[lang] =
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lde/search-typesense",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.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.
|
|
28
|
+
"@lde/search": "^0.25.0",
|
|
29
29
|
"@lde/text-normalization": "^0.1.2",
|
|
30
30
|
"tslib": "^2.3.0",
|
|
31
31
|
"typesense": "^3.0.6"
|