@delali/narsil 0.3.1-next.69 → 0.3.1-next.70
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/{capabilities-B1wz2Zl0.d.ts → capabilities-Dt-7B4Wz.d.ts} +2 -2
- package/dist/{chunk-DD5X23E6.mjs → chunk-2STVUTNA.mjs} +1 -1
- package/dist/chunk-3JGWULDF.mjs +256 -0
- package/dist/{chunk-6TGZG2TV.mjs → chunk-653BNMAF.mjs} +190 -58
- package/dist/{chunk-YA52AC2V.mjs → chunk-FVLQ63B7.mjs} +203 -9
- package/dist/{chunk-5JLSTECC.mjs → chunk-GIVAGD3Q.mjs} +1 -1
- package/dist/{chunk-AV4IJKD2.mjs → chunk-HWQLTLNG.mjs} +18 -1
- package/dist/{chunk-4VU5TWCR.mjs → chunk-LMO5TJUS.mjs} +40 -35
- package/dist/{chunk-BEWOA4VV.mjs → chunk-M76V3OGJ.mjs} +508 -401
- package/dist/{chunk-YMZCMH5M.mjs → chunk-OI42GWLR.mjs} +17 -1
- package/dist/{chunk-2BDG2IWP.mjs → chunk-P4DSQ6M4.mjs} +16 -6
- package/dist/{chunk-6IT3MH5M.mjs → chunk-VNMTB3KC.mjs} +130 -216
- package/dist/{chunk-THYRHHO2.mjs → chunk-YJDQ7NLA.mjs} +1 -1
- package/dist/{client-xVrOCYTW.d.ts → client-COek5GXK.d.ts} +3 -3
- package/dist/client.d.ts +8 -8
- package/dist/{config-CEeSV_Xo.d.ts → config-Dfanyqqt.d.ts} +2 -2
- package/dist/{config-CSvCVtB7.d.ts → config-rBpbgTw8.d.ts} +2 -2
- package/dist/direct-executor-GYJEKNV5.mjs +12 -0
- package/dist/distribution/coordinator/etcd.d.ts +2 -2
- package/dist/distribution/coordinator/etcd.mjs +1 -1
- package/dist/distribution/coordinator/in-memory.d.ts +2 -2
- package/dist/distribution/coordinator/in-memory.mjs +1 -1
- package/dist/distribution.d.ts +8 -8
- package/dist/distribution.mjs +109 -69
- package/dist/{engine-77ErLy8P.d.ts → engine-CXKfmK7I.d.ts} +12 -5
- package/dist/index.browser.mjs +1132 -740
- package/dist/index.d.ts +7 -7
- package/dist/index.mjs +10 -10
- package/dist/invalidation/filesystem.mjs +1 -1
- package/dist/{memory-CKF-9WLP.d.ts → memory-C7UMCMH3.d.ts} +35 -17
- package/dist/persistence/durability/checkpoint-worker.d.ts +2 -1
- package/dist/persistence/durability/checkpoint-worker.mjs +10 -10
- package/dist/react.d.ts +6 -6
- package/dist/{schema-d5Afu03A.d.ts → schema-Bgzr4g7b.d.ts} +62 -10
- package/dist/server.d.ts +10 -10
- package/dist/server.mjs +11 -7
- package/dist/{tasks-BEiNxDRs.d.ts → tasks-BZt_zes6.d.ts} +3 -1
- package/dist/{thread-FLP45EUD.mjs → thread-JEVAYETR.mjs} +6 -6
- package/dist/{types-DAK7mnUZ.d.ts → types-gOUqhs2F.d.ts} +1 -1
- package/dist/vector/search-worker.d.ts +1 -1
- package/dist/vector/search-worker.mjs +2 -2
- package/dist/workers/entry.mjs +3 -3
- package/package.json +7 -7
- package/dist/chunk-VTPLKNWI.mjs +0 -135
- package/dist/direct-executor-3ZYXSGFX.mjs +0 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { validateRequiredFields } from './chunk-
|
|
1
|
+
import { validateRequiredFields } from './chunk-653BNMAF.mjs';
|
|
2
2
|
import { ErrorCodes, NarsilError } from './chunk-USKFU7J5.mjs';
|
|
3
3
|
|
|
4
4
|
// src/narsil/internals.ts
|
|
@@ -245,15 +245,43 @@ function providedDocId(document) {
|
|
|
245
245
|
function asBatchInsertError(err) {
|
|
246
246
|
return err instanceof NarsilError ? err : new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, String(err));
|
|
247
247
|
}
|
|
248
|
-
function
|
|
249
|
-
|
|
250
|
-
|
|
248
|
+
function createPendingAdmissions() {
|
|
249
|
+
return { total: 0, byPartition: /* @__PURE__ */ new Map() };
|
|
250
|
+
}
|
|
251
|
+
function capsEachPartition(ctx, manager) {
|
|
252
|
+
return ctx.capacityScope === "partition" && manager.config.partitions?.maxDocsPerPartition !== void 0;
|
|
253
|
+
}
|
|
254
|
+
function recordPendingAdmission(ctx, pending, manager, docId) {
|
|
255
|
+
pending.total += 1;
|
|
256
|
+
if (!capsEachPartition(ctx, manager)) return;
|
|
257
|
+
const partitionId = manager.routePartition(docId);
|
|
258
|
+
pending.byPartition.set(partitionId, (pending.byPartition.get(partitionId) ?? 0) + 1);
|
|
259
|
+
}
|
|
260
|
+
function admitInsert(ctx, indexName, manager, docId, pending) {
|
|
261
|
+
const rebalancing = ctx.isRebalancing(indexName);
|
|
262
|
+
if (rebalancing) {
|
|
263
|
+
const bufferedState = ctx.bufferedDocState(indexName, docId);
|
|
264
|
+
const exists = bufferedState !== void 0 ? bufferedState === "present" : manager.has(docId);
|
|
265
|
+
if (exists) {
|
|
266
|
+
throw new NarsilError(ErrorCodes.DOC_ALREADY_EXISTS, `Document "${docId}" already exists`, { docId });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
assertRoomFor(ctx, indexName, manager, docId, pending, rebalancing);
|
|
270
|
+
}
|
|
271
|
+
function admitBufferedUpsert(ctx, indexName, manager, docId) {
|
|
272
|
+
assertRoomFor(ctx, indexName, manager, docId, void 0, true);
|
|
273
|
+
}
|
|
274
|
+
function assertRoomFor(ctx, indexName, manager, docId, pending, rebalancing) {
|
|
275
|
+
if (ctx.capacityScope === "partition") {
|
|
276
|
+
if (!capsEachPartition(ctx, manager)) return;
|
|
277
|
+
const partitionId = manager.routePartition(docId);
|
|
278
|
+
manager.assertPartitionCapacity(partitionId, pending?.byPartition.get(partitionId) ?? 0);
|
|
251
279
|
return;
|
|
252
280
|
}
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
281
|
+
const pendingAdmitted = pending?.total ?? 0;
|
|
282
|
+
if (!rebalancing) {
|
|
283
|
+
manager.assertCapacity(pendingAdmitted);
|
|
284
|
+
return;
|
|
257
285
|
}
|
|
258
286
|
manager.assertCapacity(
|
|
259
287
|
ctx.pendingRebalanceWrites(indexName) + pendingAdmitted,
|
|
@@ -372,4 +400,170 @@ async function resolveVectorText(params, embeddingAdapter, signal, embeddingAdap
|
|
|
372
400
|
return { ...params, vector: resolved };
|
|
373
401
|
}
|
|
374
402
|
|
|
375
|
-
|
|
403
|
+
// src/engine/snapshot/restore-config.ts
|
|
404
|
+
function rejectSnapshot(message) {
|
|
405
|
+
throw new NarsilError(ErrorCodes.DOC_VALIDATION_FAILED, `Invalid snapshot: ${message}`);
|
|
406
|
+
}
|
|
407
|
+
function isPlainObject(value) {
|
|
408
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
409
|
+
}
|
|
410
|
+
function restoredBm25(raw, reject) {
|
|
411
|
+
if (raw === void 0) {
|
|
412
|
+
return void 0;
|
|
413
|
+
}
|
|
414
|
+
if (!isPlainObject(raw)) {
|
|
415
|
+
reject("bm25 must be an object");
|
|
416
|
+
}
|
|
417
|
+
const { k1, b } = raw;
|
|
418
|
+
if (k1 !== void 0 && (typeof k1 !== "number" || !Number.isFinite(k1))) {
|
|
419
|
+
reject("bm25 k1 must be a finite number");
|
|
420
|
+
}
|
|
421
|
+
if (b !== void 0 && (typeof b !== "number" || !Number.isFinite(b))) {
|
|
422
|
+
reject("bm25 b must be a finite number");
|
|
423
|
+
}
|
|
424
|
+
return {
|
|
425
|
+
...k1 !== void 0 ? { k1 } : {},
|
|
426
|
+
...b !== void 0 ? { b } : {}
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
function restoredStopWords(name, list, reject) {
|
|
430
|
+
if (name !== void 0 && typeof name !== "string") {
|
|
431
|
+
reject("stopWords must be a name");
|
|
432
|
+
}
|
|
433
|
+
if (list !== void 0 && (!Array.isArray(list) || !list.every((word) => typeof word === "string"))) {
|
|
434
|
+
reject("stopWordList must be a list of words");
|
|
435
|
+
}
|
|
436
|
+
if (typeof name === "string" && Array.isArray(list)) {
|
|
437
|
+
reject("stopWords and stopWordList cannot both be present");
|
|
438
|
+
}
|
|
439
|
+
if (typeof name === "string") {
|
|
440
|
+
return name;
|
|
441
|
+
}
|
|
442
|
+
if (Array.isArray(list)) {
|
|
443
|
+
return new Set(list);
|
|
444
|
+
}
|
|
445
|
+
return void 0;
|
|
446
|
+
}
|
|
447
|
+
function restoredPartitionConfig(raw, reject = rejectSnapshot) {
|
|
448
|
+
if (raw === void 0) {
|
|
449
|
+
return void 0;
|
|
450
|
+
}
|
|
451
|
+
if (!isPlainObject(raw)) {
|
|
452
|
+
reject("partitionConfig must be an object");
|
|
453
|
+
}
|
|
454
|
+
const { maxDocsPerPartition, maxPartitions, watermark } = raw;
|
|
455
|
+
if (maxDocsPerPartition !== void 0 && (typeof maxDocsPerPartition !== "number" || !Number.isInteger(maxDocsPerPartition) || maxDocsPerPartition < 1)) {
|
|
456
|
+
reject("partitionConfig maxDocsPerPartition must be a positive integer");
|
|
457
|
+
}
|
|
458
|
+
if (maxPartitions !== void 0 && (typeof maxPartitions !== "number" || !Number.isInteger(maxPartitions) || maxPartitions < 1)) {
|
|
459
|
+
reject("partitionConfig maxPartitions must be a positive integer");
|
|
460
|
+
}
|
|
461
|
+
if (watermark !== void 0 && (typeof watermark !== "number" || !(watermark > 0) || watermark > 1)) {
|
|
462
|
+
reject("partitionConfig watermark must be above 0 and at most 1");
|
|
463
|
+
}
|
|
464
|
+
return {
|
|
465
|
+
...typeof maxDocsPerPartition === "number" ? { maxDocsPerPartition } : {},
|
|
466
|
+
...typeof maxPartitions === "number" ? { maxPartitions } : {},
|
|
467
|
+
...typeof watermark === "number" ? { watermark } : {}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
function restoredScoring(raw, reject) {
|
|
471
|
+
if (raw === void 0) {
|
|
472
|
+
return void 0;
|
|
473
|
+
}
|
|
474
|
+
if (raw !== "local" && raw !== "dfs" && raw !== "broadcast") {
|
|
475
|
+
reject("defaultScoring must be 'local', 'dfs', or 'broadcast'");
|
|
476
|
+
}
|
|
477
|
+
return raw;
|
|
478
|
+
}
|
|
479
|
+
function restoredBoolean(raw, field, reject) {
|
|
480
|
+
if (raw === void 0) {
|
|
481
|
+
return void 0;
|
|
482
|
+
}
|
|
483
|
+
if (typeof raw !== "boolean") {
|
|
484
|
+
reject(`${field} must be a boolean`);
|
|
485
|
+
}
|
|
486
|
+
return raw;
|
|
487
|
+
}
|
|
488
|
+
function restoredRequired(raw, reject) {
|
|
489
|
+
if (raw === void 0) {
|
|
490
|
+
return void 0;
|
|
491
|
+
}
|
|
492
|
+
if (!Array.isArray(raw) || !raw.every((field) => typeof field === "string")) {
|
|
493
|
+
reject("required must be a list of field paths");
|
|
494
|
+
}
|
|
495
|
+
return raw;
|
|
496
|
+
}
|
|
497
|
+
function restoredVectorPromotion(raw, reject) {
|
|
498
|
+
if (raw === void 0) {
|
|
499
|
+
return void 0;
|
|
500
|
+
}
|
|
501
|
+
if (!isPlainObject(raw) || raw.hnswConfig !== void 0 && !isPlainObject(raw.hnswConfig)) {
|
|
502
|
+
reject("vectorPromotion must be an object");
|
|
503
|
+
}
|
|
504
|
+
return raw;
|
|
505
|
+
}
|
|
506
|
+
function restoredEmbedding(raw, reject = rejectSnapshot) {
|
|
507
|
+
if (raw === void 0) {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
if (!isPlainObject(raw)) {
|
|
511
|
+
reject("embedding must be an object");
|
|
512
|
+
}
|
|
513
|
+
const { fields, adapter } = raw;
|
|
514
|
+
if (adapter !== void 0 && typeof adapter !== "string") {
|
|
515
|
+
reject("embedding adapter must be a name");
|
|
516
|
+
}
|
|
517
|
+
if (!isPlainObject(fields)) {
|
|
518
|
+
reject("embedding fields must be an object");
|
|
519
|
+
}
|
|
520
|
+
for (const value of Object.values(fields)) {
|
|
521
|
+
const isPath = typeof value === "string";
|
|
522
|
+
const isPathList = Array.isArray(value) && value.every((path) => typeof path === "string");
|
|
523
|
+
if (!isPath && !isPathList) {
|
|
524
|
+
reject("embedding fields must map vector fields to source paths");
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
fields,
|
|
529
|
+
...adapter !== void 0 ? { adapter } : {}
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
function readSharedConfigFields(source, reject) {
|
|
533
|
+
if (source.tokenizer !== void 0 && typeof source.tokenizer !== "string") {
|
|
534
|
+
reject("tokenizer must be a name");
|
|
535
|
+
}
|
|
536
|
+
const stopWords = restoredStopWords(source.stopWords, source.stopWordList, reject);
|
|
537
|
+
const bm25 = restoredBm25(source.bm25, reject);
|
|
538
|
+
const surfaceForms = restoredBoolean(source.surfaceForms, "surfaceForms", reject);
|
|
539
|
+
const defaultScoring = restoredScoring(source.defaultScoring, reject);
|
|
540
|
+
const trackPositions = restoredBoolean(source.trackPositions, "trackPositions", reject);
|
|
541
|
+
const strict = restoredBoolean(source.strict, "strict", reject);
|
|
542
|
+
const required = restoredRequired(source.required, reject);
|
|
543
|
+
const vectorPromotion = restoredVectorPromotion(source.vectorPromotion, reject);
|
|
544
|
+
if (source.patternValueLimit !== void 0 && typeof source.patternValueLimit !== "number") {
|
|
545
|
+
reject("patternValueLimit must be a number");
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
...typeof source.tokenizer === "string" ? { tokenizer: source.tokenizer } : {},
|
|
549
|
+
...stopWords !== void 0 ? { stopWords } : {},
|
|
550
|
+
...bm25 !== void 0 ? { bm25 } : {},
|
|
551
|
+
...surfaceForms !== void 0 ? { surfaceForms } : {},
|
|
552
|
+
...defaultScoring !== void 0 ? { defaultScoring } : {},
|
|
553
|
+
...trackPositions !== void 0 ? { trackPositions } : {},
|
|
554
|
+
...strict !== void 0 ? { strict } : {},
|
|
555
|
+
...required !== void 0 ? { required } : {},
|
|
556
|
+
...vectorPromotion !== void 0 ? { vectorPromotion } : {},
|
|
557
|
+
...typeof source.patternValueLimit === "number" ? { patternValueLimit: source.patternValueLimit } : {}
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
function restoredConfigFields(envelope) {
|
|
561
|
+
const shared = readSharedConfigFields(envelope, rejectSnapshot);
|
|
562
|
+
const partitions = restoredPartitionConfig(envelope.partitionConfig);
|
|
563
|
+
return {
|
|
564
|
+
...shared,
|
|
565
|
+
...partitions !== void 0 ? { partitions } : {}
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export { MAX_PARTITION_COUNT, MAX_REPLICATION_FACTOR, WIRE_BATCH_BUDGET, admitBufferedUpsert, admitInsert, asBatchInsertError, assertDocumentCarriesMappedVectors, bindEngineCore, collectRequiredFieldFailures, createPendingAdmissions, embedChunkDocuments, embedDocumentFields, engineCoreOf, providedDocId, readSharedConfigFields, recordPendingAdmission, resolveVectorText, restoredConfigFields, restoredEmbedding, restoredPartitionConfig };
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
import { english } from './chunk-TGP5M5R7.mjs';
|
|
2
|
+
import { NarsilError, ErrorCodes } from './chunk-USKFU7J5.mjs';
|
|
3
|
+
|
|
4
|
+
// src/languages/registry.ts
|
|
5
|
+
var languages = /* @__PURE__ */ new Map();
|
|
6
|
+
languages.set("english", english);
|
|
7
|
+
function registerLanguage(module) {
|
|
8
|
+
languages.set(module.name, module);
|
|
9
|
+
}
|
|
10
|
+
function getLanguage(name) {
|
|
11
|
+
const lang = languages.get(name);
|
|
12
|
+
if (!lang) {
|
|
13
|
+
throw new NarsilError(ErrorCodes.LANGUAGE_NOT_SUPPORTED, `Language "${name}" is not registered`, { language: name });
|
|
14
|
+
}
|
|
15
|
+
return lang;
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
// src/runtime/detect.ts
|
|
2
19
|
function detectRuntimeName() {
|
|
3
20
|
if ("Bun" in globalThis) {
|
|
@@ -32,4 +49,4 @@ function detectRuntime() {
|
|
|
32
49
|
};
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
export { detectRuntime };
|
|
52
|
+
export { detectRuntime, getLanguage, registerLanguage };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { compareCodePoints, sortModeOf, defaultSortMode, toReducedSortValue, readSortField, compareComparableKeys, toComparableSortValue, isSortMode, SORT_MODES,
|
|
1
|
+
import { isWordIndexedBase, flattenSchema, parsedTypeOf, isStringValuedBase, withSortableOption, isGeopointOrVectorType, MAX_SORT_FIELDS, MAX_SORT_FIELD_NAME_LENGTH, MAX_CURSOR_LENGTH, MAX_CURSOR_ANCHOR_CODE_POINTS, RESULT_WINDOW, DEFAULT_FUZZY_PREFIX_LENGTH, DEFAULT_PAGE_SIZE, PROTOTYPE_POLLUTION_KEYS, isWordIndexedFieldType, PREFIX_MAX_EXPANSIONS } from './chunk-653BNMAF.mjs';
|
|
2
|
+
import { compareCodePoints, sortModeOf, defaultSortMode, SORT_VALUE_MAX_CODE_POINTS, toReducedSortValue, readSortField, compareComparableKeys, toComparableSortValue, exceedsCodePoints, isSortMode, SORT_MODES, compareSortValues } from './chunk-OI42GWLR.mjs';
|
|
3
3
|
import { createNarsilError, ErrorCodes, NarsilError } from './chunk-USKFU7J5.mjs';
|
|
4
4
|
|
|
5
5
|
// src/core/tokenizer/constants.ts
|
|
@@ -762,12 +762,12 @@ function stringArraysEqual(a, b) {
|
|
|
762
762
|
}
|
|
763
763
|
return true;
|
|
764
764
|
}
|
|
765
|
-
function textFieldsChanged(oldDoc, newDoc,
|
|
766
|
-
for (const
|
|
767
|
-
if (!
|
|
765
|
+
function textFieldsChanged(oldDoc, newDoc, fields) {
|
|
766
|
+
for (const { path, base } of fields) {
|
|
767
|
+
if (!isWordIndexedBase(base)) continue;
|
|
768
768
|
const oldVal = getNestedValue(oldDoc, path);
|
|
769
769
|
const newVal = getNestedValue(newDoc, path);
|
|
770
|
-
if (
|
|
770
|
+
if (base === "string") {
|
|
771
771
|
if (oldVal !== newVal) return true;
|
|
772
772
|
} else {
|
|
773
773
|
if (!stringArraysEqual(oldVal, newVal)) return true;
|
|
@@ -1192,6 +1192,16 @@ function requireFieldKind(fieldPath, operator, type, accepted) {
|
|
|
1192
1192
|
operator
|
|
1193
1193
|
);
|
|
1194
1194
|
}
|
|
1195
|
+
function requireTextRangeField(fieldPath, operator, type) {
|
|
1196
|
+
const parsed = parsedTypeOf(type);
|
|
1197
|
+
if (parsed?.sortable && (parsed.base === "string" || parsed.base === "verbatim")) return;
|
|
1198
|
+
const declared = type === void 0 ? `the schema has no field "${fieldPath}"` : `field "${fieldPath}" has type "${type}"`;
|
|
1199
|
+
invalid(
|
|
1200
|
+
`The engine applies "${operator}" with a text bound to a "string" or "verbatim" field whose type includes "sortable", but ${declared}`,
|
|
1201
|
+
fieldPath,
|
|
1202
|
+
operator
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1195
1205
|
function requireRadius(fieldPath, radius) {
|
|
1196
1206
|
const circle = radius;
|
|
1197
1207
|
if (circle === null || typeof circle !== "object") {
|
|
@@ -1252,22 +1262,32 @@ function requireValidFilter(expression, fieldTypes, declaredOnly = false) {
|
|
|
1252
1262
|
}
|
|
1253
1263
|
function requireValidOperands(fieldPath, filter, type) {
|
|
1254
1264
|
for (const operator of RANGE_OPERATORS) {
|
|
1255
|
-
|
|
1256
|
-
if (
|
|
1257
|
-
|
|
1265
|
+
const bound = filter[operator];
|
|
1266
|
+
if (bound === void 0) continue;
|
|
1267
|
+
if (typeof bound === "string") {
|
|
1268
|
+
requireTextRangeField(fieldPath, operator, type);
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
if (!isFiniteNumber(bound)) {
|
|
1272
|
+
invalid(`"${operator}" on field "${fieldPath}" must be a finite number or a string`, fieldPath, operator);
|
|
1258
1273
|
}
|
|
1259
1274
|
requireFieldKind(fieldPath, operator, type, ["number"]);
|
|
1260
1275
|
}
|
|
1261
1276
|
if (filter.between !== void 0) {
|
|
1262
1277
|
const bounds = filter.between;
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1278
|
+
const isPair = Array.isArray(bounds) && bounds.length === 2;
|
|
1279
|
+
if (isPair && typeof bounds[0] === "string" && typeof bounds[1] === "string") {
|
|
1280
|
+
requireTextRangeField(fieldPath, "between", type);
|
|
1281
|
+
} else {
|
|
1282
|
+
if (!isPair || !isFiniteNumber(bounds[0]) || !isFiniteNumber(bounds[1])) {
|
|
1283
|
+
invalid(
|
|
1284
|
+
`"between" on field "${fieldPath}" must be two finite numbers or two strings, the lower bound first`,
|
|
1285
|
+
fieldPath,
|
|
1286
|
+
"between"
|
|
1287
|
+
);
|
|
1288
|
+
}
|
|
1289
|
+
requireFieldKind(fieldPath, "between", type, ["number"]);
|
|
1269
1290
|
}
|
|
1270
|
-
requireFieldKind(fieldPath, "between", type, ["number"]);
|
|
1271
1291
|
}
|
|
1272
1292
|
for (const operator of TEXT_OPERATORS) {
|
|
1273
1293
|
if (filter[operator] === void 0) continue;
|
|
@@ -1365,10 +1385,11 @@ function requireSortableFields(sort, schema, strict = false) {
|
|
|
1365
1385
|
);
|
|
1366
1386
|
}
|
|
1367
1387
|
requireSortMode(entry, fieldType);
|
|
1368
|
-
|
|
1388
|
+
const parsed = parsedTypeOf(fieldType);
|
|
1389
|
+
if (parsed !== void 0 && isStringValuedBase(parsed.base) && !parsed.sortable) {
|
|
1369
1390
|
throw new NarsilError(
|
|
1370
1391
|
ErrorCodes.SEARCH_INVALID_FIELD,
|
|
1371
|
-
`The engine sorts by text field "${entry.field}" only where
|
|
1392
|
+
`The engine sorts by text field "${entry.field}" only where its type includes "sortable", as in "${withSortableOption(parsed)}", because it keeps up to the first ${SORT_VALUE_MAX_CODE_POINTS} code points of every document's value in memory to sort by a text field`,
|
|
1372
1393
|
{ field: entry.field, fieldType }
|
|
1373
1394
|
);
|
|
1374
1395
|
}
|
|
@@ -1406,22 +1427,6 @@ function invalidCursor(cursor, reason) {
|
|
|
1406
1427
|
const shown = cursor.length > 100 ? `${cursor.slice(0, 100)}...` : cursor;
|
|
1407
1428
|
return new NarsilError(ErrorCodes.SEARCH_INVALID_CURSOR, `Failed to decode cursor: ${reason}`, { cursor: shown });
|
|
1408
1429
|
}
|
|
1409
|
-
function exceedsCodePoints(value, maximum) {
|
|
1410
|
-
if (value.length <= maximum) return false;
|
|
1411
|
-
let counted = 0;
|
|
1412
|
-
let i = 0;
|
|
1413
|
-
while (i < value.length) {
|
|
1414
|
-
const unit = value.charCodeAt(i);
|
|
1415
|
-
if (unit >= 55296 && unit < 56320 && i + 1 < value.length) {
|
|
1416
|
-
const low = value.charCodeAt(i + 1);
|
|
1417
|
-
if (low >= 56320 && low < 57344) i++;
|
|
1418
|
-
}
|
|
1419
|
-
i++;
|
|
1420
|
-
counted++;
|
|
1421
|
-
if (counted > maximum) return true;
|
|
1422
|
-
}
|
|
1423
|
-
return false;
|
|
1424
|
-
}
|
|
1425
1430
|
function sortSignatureOf(sort) {
|
|
1426
1431
|
const fields = normalizeSort(sort);
|
|
1427
1432
|
if (fields.length === 0) return null;
|
|
@@ -1750,7 +1755,7 @@ function validateSearchFields(fields, flatSchema) {
|
|
|
1750
1755
|
if (!fieldType) {
|
|
1751
1756
|
throw new NarsilError(ErrorCodes.SEARCH_INVALID_FIELD, `Field "${field}" does not exist in the schema`, { field });
|
|
1752
1757
|
}
|
|
1753
|
-
if (!
|
|
1758
|
+
if (!isWordIndexedFieldType(fieldType)) {
|
|
1754
1759
|
throw new NarsilError(
|
|
1755
1760
|
ErrorCodes.SEARCH_INVALID_FIELD,
|
|
1756
1761
|
`Field "${field}" has type "${fieldType}" which cannot be used for full-text search`,
|