ochre-sdk 0.21.5 → 0.21.7

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/index.d.mts CHANGED
@@ -677,7 +677,7 @@ type QueryLeaf = {
677
677
  target: "property";
678
678
  propertyVariable?: string;
679
679
  dataType: Exclude<Exclude<PropertyValueContentType, "coordinate">, "date" | "dateTime">;
680
- propertyValues?: Array<string>;
680
+ value?: string;
681
681
  from?: never;
682
682
  to?: never;
683
683
  matchMode: "includes" | "exact";
@@ -688,7 +688,6 @@ type QueryLeaf = {
688
688
  target: "property";
689
689
  propertyVariable: string;
690
690
  dataType: "date" | "dateTime";
691
- propertyValues?: never;
692
691
  value: string;
693
692
  from?: never;
694
693
  to?: never;
@@ -700,7 +699,6 @@ type QueryLeaf = {
700
699
  target: "property";
701
700
  propertyVariable: string;
702
701
  dataType: "date" | "dateTime";
703
- propertyValues?: never;
704
702
  value?: never;
705
703
  from: string;
706
704
  to?: string;
@@ -712,7 +710,6 @@ type QueryLeaf = {
712
710
  target: "property";
713
711
  propertyVariable: string;
714
712
  dataType: "date" | "dateTime";
715
- propertyValues?: never;
716
713
  value?: never;
717
714
  from?: string;
718
715
  to: string;
@@ -720,6 +717,15 @@ type QueryLeaf = {
720
717
  isCaseSensitive: boolean;
721
718
  language: string;
722
719
  isNegated?: boolean;
720
+ } | {
721
+ target: "property";
722
+ propertyVariable?: string;
723
+ dataType: "all";
724
+ value: string;
725
+ matchMode: "includes" | "exact";
726
+ isCaseSensitive: boolean;
727
+ language: string;
728
+ isNegated?: boolean;
723
729
  } | {
724
730
  target: "string";
725
731
  value: string;
package/dist/index.mjs CHANGED
@@ -768,15 +768,15 @@ const setQueryLeafSchema = z.union([
768
768
  "time",
769
769
  "IDREF"
770
770
  ]),
771
- propertyValues: z.array(z.string()).min(1, "At least one property value is required").optional(),
771
+ value: z.string().optional(),
772
772
  matchMode: z.enum(["includes", "exact"]),
773
773
  isCaseSensitive: z.boolean(),
774
774
  language: z.string().default("eng"),
775
775
  isNegated: z.boolean().optional().default(false)
776
776
  }).strict().superRefine((value, ctx) => {
777
- if (value.propertyVariable == null && value.propertyValues == null) ctx.addIssue({
777
+ if (value.propertyVariable == null && value.value == null) ctx.addIssue({
778
778
  code: "custom",
779
- message: "Property queries must include at least one propertyVariable or propertyValue"
779
+ message: "Property queries must include at least one propertyVariable or value"
780
780
  });
781
781
  }),
782
782
  z.object({
@@ -815,6 +815,16 @@ const setQueryLeafSchema = z.union([
815
815
  language: z.string().default("eng"),
816
816
  isNegated: z.boolean().optional().default(false)
817
817
  }).strict(),
818
+ z.object({
819
+ target: z.literal("property"),
820
+ propertyVariable: uuidSchema.optional(),
821
+ dataType: z.literal("all"),
822
+ value: z.string(),
823
+ matchMode: z.enum(["includes", "exact"]),
824
+ isCaseSensitive: z.boolean(),
825
+ language: z.string().default("eng"),
826
+ isNegated: z.boolean().optional().default(false)
827
+ }).strict(),
818
828
  z.object({
819
829
  target: z.literal("string"),
820
830
  value: z.string(),
@@ -2172,10 +2182,6 @@ function buildFlattenedContentValuesExpression(contentNodesExpression) {
2172
2182
  return `for $content in ${contentNodesExpression}
2173
2183
  return string-join($content//text(), "")`;
2174
2184
  }
2175
- function buildNodeStringValuesExpression(nodesExpression) {
2176
- return `for $node in ${nodesExpression}
2177
- return string($node)`;
2178
- }
2179
2185
  function buildSearchableContentNodesExpression(contentNodesExpression) {
2180
2186
  return `for $content in ${contentNodesExpression}
2181
2187
  return (
@@ -2190,17 +2196,46 @@ function buildCombinedSearchableContentNodesExpression(contentNodesExpressions)
2190
2196
  if (searchableExpressions.length === 1) return searchableExpressions[0] ?? "()";
2191
2197
  return `(${searchableExpressions.join(", ")})`;
2192
2198
  }
2193
- function buildTokenizedSearchPredicate(params) {
2194
- const { searchableNodesExpression, termsExpression, isCaseSensitive } = params;
2195
- return `(every $term in ${termsExpression}
2196
- satisfies some $searchNode in (${searchableNodesExpression})
2197
- satisfies cts:contains(
2198
- $searchNode,
2199
- ${buildCtsWordQueryExpression({
2200
- termExpression: "$term",
2201
- isCaseSensitive
2202
- })}
2203
- ))`;
2199
+ function buildPropertyValueNodesExpression(params) {
2200
+ const predicates = [];
2201
+ if (params?.excludeInherited) predicates.push(`not(@inherited="true")`);
2202
+ for (const excludedDataType of params?.excludedDataTypes ?? []) predicates.push(`not(@dataType=${stringLiteral(excludedDataType)})`);
2203
+ if (predicates.length === 0) return "value";
2204
+ return `value[${predicates.join(" and ")}]`;
2205
+ }
2206
+ function buildPropertyValueContentNodesExpression(params) {
2207
+ const { language, excludeInherited, excludedDataTypes } = params;
2208
+ return `${buildPropertyValueNodesExpression({
2209
+ excludeInherited,
2210
+ excludedDataTypes
2211
+ })}/content[@xml:lang="${language}"]`;
2212
+ }
2213
+ function buildPropertyValueContentValuesExpression(params) {
2214
+ return buildFlattenedContentValuesExpression(buildPropertyValueContentNodesExpression(params));
2215
+ }
2216
+ function buildPropertyValueRawValuesExpression(params) {
2217
+ return `for $value in ${buildPropertyValueNodesExpression(params)}[@rawValue]
2218
+ return string($value/@rawValue)`;
2219
+ }
2220
+ function buildPropertyValueDirectTextValuesExpression(params) {
2221
+ return `for $value in ${buildPropertyValueNodesExpression(params)}
2222
+ let $candidate := string-join($value/text(), "")
2223
+ where normalize-space($candidate) != ""
2224
+ return $candidate`;
2225
+ }
2226
+ function buildPropertyScalarValueExpressions() {
2227
+ return [buildPropertyValueRawValuesExpression(), buildPropertyValueDirectTextValuesExpression()];
2228
+ }
2229
+ function buildAllPropertyValueExpressions(language) {
2230
+ const params = { excludedDataTypes: ["IDREF"] };
2231
+ return [
2232
+ buildPropertyValueRawValuesExpression(params),
2233
+ buildPropertyValueContentValuesExpression({
2234
+ language,
2235
+ ...params
2236
+ }),
2237
+ buildPropertyValueDirectTextValuesExpression(params)
2238
+ ];
2204
2239
  }
2205
2240
  /**
2206
2241
  * Build a string match predicate for an XQuery string.
@@ -2210,10 +2245,16 @@ function buildRawStringMatchPredicate(params) {
2210
2245
  const comparedValueLiteral = stringLiteral(isCaseSensitive ? value : value.toLowerCase());
2211
2246
  const candidateVar = "$candidate";
2212
2247
  const comparedCandidate = isCaseSensitive ? candidateVar : `lower-case(${candidateVar})`;
2213
- if (matchMode === "includes") return `some ${candidateVar} in (${valueExpression})
2214
- satisfies contains(${comparedCandidate}, ${comparedValueLiteral})`;
2215
- return `some ${candidateVar} in (${valueExpression})
2216
- satisfies ${comparedCandidate} = ${comparedValueLiteral}`;
2248
+ if (matchMode === "includes") return `exists(
2249
+ for ${candidateVar} in (${valueExpression})
2250
+ where contains(${comparedCandidate}, ${comparedValueLiteral})
2251
+ return ${candidateVar}
2252
+ )`;
2253
+ return `exists(
2254
+ for ${candidateVar} in (${valueExpression})
2255
+ where ${comparedCandidate} = ${comparedValueLiteral}
2256
+ return ${candidateVar}
2257
+ )`;
2217
2258
  }
2218
2259
  /**
2219
2260
  * Build a combined raw string match predicate for multiple paths.
@@ -2221,30 +2262,53 @@ function buildRawStringMatchPredicate(params) {
2221
2262
  function buildCombinedRawStringMatchPredicate(params) {
2222
2263
  const { valueExpressions, value, matchMode, isCaseSensitive } = params;
2223
2264
  const predicates = [];
2224
- for (const valueExpression of valueExpressions) predicates.push(buildRawStringMatchPredicate({
2265
+ for (const valueExpression of valueExpressions) predicates.push(`(${buildRawStringMatchPredicate({
2225
2266
  valueExpression,
2226
2267
  value,
2227
2268
  matchMode,
2228
2269
  isCaseSensitive
2229
- }));
2270
+ })})`);
2230
2271
  return buildOrPredicate(predicates);
2231
2272
  }
2232
2273
  /**
2233
2274
  * Build CTS word-query options for API v2 includes search.
2234
2275
  */
2235
- function buildCtsQueryOptionsExpression(isCaseSensitive) {
2236
- return `(${[
2276
+ function buildCtsQueryOptionsExpression(params) {
2277
+ const { isCaseSensitive, isWildcarded } = params;
2278
+ const options = [
2237
2279
  isCaseSensitive ? "case-sensitive" : "case-insensitive",
2238
2280
  "diacritic-insensitive",
2239
2281
  "punctuation-insensitive"
2240
- ].map((option) => stringLiteral(option)).join(", ")})`;
2282
+ ];
2283
+ if (isWildcarded) options.push("wildcarded");
2284
+ return `(${options.map((option) => stringLiteral(option)).join(", ")})`;
2285
+ }
2286
+ function buildWildcardedTermExpression(termExpression) {
2287
+ return `fn:concat("*", ${termExpression}, "*")`;
2241
2288
  }
2242
2289
  /**
2243
2290
  * Build a CTS word-query expression for an XQuery term.
2244
2291
  */
2245
2292
  function buildCtsWordQueryExpression(params) {
2246
- const { termExpression, isCaseSensitive } = params;
2247
- return `cts:word-query(${termExpression}, ${buildCtsQueryOptionsExpression(isCaseSensitive)})`;
2293
+ const { termExpression, isCaseSensitive, isWildcarded } = params;
2294
+ return `cts:word-query(${isWildcarded ? buildWildcardedTermExpression(termExpression) : termExpression}, ${buildCtsQueryOptionsExpression({
2295
+ isCaseSensitive,
2296
+ isWildcarded
2297
+ })})`;
2298
+ }
2299
+ function buildCtsElementWordQueryExpression(params) {
2300
+ const { elementName, termExpression, isCaseSensitive, isWildcarded } = params;
2301
+ return `cts:element-word-query(xs:QName("${elementName}"), ${isWildcarded ? buildWildcardedTermExpression(termExpression) : termExpression}, ${buildCtsQueryOptionsExpression({
2302
+ isCaseSensitive,
2303
+ isWildcarded
2304
+ })})`;
2305
+ }
2306
+ function buildCtsElementAttributeWordQueryExpression(params) {
2307
+ const { elementName, attributeName, termExpression, isCaseSensitive, isWildcarded } = params;
2308
+ return `cts:element-attribute-word-query(xs:QName("${elementName}"), xs:QName("${attributeName}"), ${isWildcarded ? buildWildcardedTermExpression(termExpression) : termExpression}, ${buildCtsQueryOptionsExpression({
2309
+ isCaseSensitive,
2310
+ isWildcarded
2311
+ })})`;
2248
2312
  }
2249
2313
  /**
2250
2314
  * Build tokenized search declarations for CTS-backed queries.
@@ -2268,8 +2332,8 @@ function buildTokenizedSearchDeclarations(params) {
2268
2332
  termsVar
2269
2333
  };
2270
2334
  }
2271
- function buildCtsIncludesPredicate(params) {
2272
- const { searchableNodesExpression, fallbackValueExpression, value, isCaseSensitive, queryKey, buildCandidateTermQuery } = params;
2335
+ function buildCtsCandidateQuery(params) {
2336
+ const { value, isCaseSensitive, queryKey, buildCandidateTermQuery } = params;
2273
2337
  const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
2274
2338
  value,
2275
2339
  isCaseSensitive,
@@ -2277,18 +2341,12 @@ function buildCtsIncludesPredicate(params) {
2277
2341
  });
2278
2342
  const termQueriesVar = `$query${queryKey}TermQueries`;
2279
2343
  const candidateQueryVar = `$query${queryKey}CandidateQuery`;
2280
- const fallbackPredicate = buildRawStringMatchPredicate({
2281
- valueExpression: fallbackValueExpression,
2282
- value,
2283
- matchMode: "includes",
2284
- isCaseSensitive
2285
- });
2286
2344
  if (tokenizeIncludesSearchValue({
2287
2345
  value,
2288
2346
  isCaseSensitive
2289
2347
  }).length === 0) return {
2290
2348
  declarations: [],
2291
- predicate: fallbackPredicate,
2349
+ termsVar: tokenizedSearchDeclarations.termsVar,
2292
2350
  candidateQueryVar: null
2293
2351
  };
2294
2352
  return {
@@ -2304,14 +2362,43 @@ function buildCtsIncludesPredicate(params) {
2304
2362
  then cts:and-query(${termQueriesVar})
2305
2363
  else ()`
2306
2364
  ],
2307
- predicate: buildTokenizedSearchPredicate({
2308
- searchableNodesExpression,
2309
- termsExpression: tokenizedSearchDeclarations.termsVar,
2310
- isCaseSensitive
2311
- }),
2365
+ termsVar: tokenizedSearchDeclarations.termsVar,
2312
2366
  candidateQueryVar
2313
2367
  };
2314
2368
  }
2369
+ function buildCtsIncludesPredicate(params) {
2370
+ const { searchableNodesExpression, fallbackValueExpression, value, isCaseSensitive, queryKey, buildCandidateTermQuery } = params;
2371
+ const candidateQuery = buildCtsCandidateQuery({
2372
+ value,
2373
+ isCaseSensitive,
2374
+ queryKey,
2375
+ buildCandidateTermQuery
2376
+ });
2377
+ const fallbackPredicate = buildRawStringMatchPredicate({
2378
+ valueExpression: fallbackValueExpression,
2379
+ value,
2380
+ matchMode: "includes",
2381
+ isCaseSensitive
2382
+ });
2383
+ if (candidateQuery.candidateQueryVar == null) return {
2384
+ declarations: [],
2385
+ predicate: fallbackPredicate,
2386
+ candidateQueryVar: null
2387
+ };
2388
+ return {
2389
+ declarations: candidateQuery.declarations,
2390
+ predicate: `(every $term in ${candidateQuery.termsVar}
2391
+ satisfies some $searchNode in (${searchableNodesExpression})
2392
+ satisfies cts:contains(
2393
+ $searchNode,
2394
+ ${buildCtsWordQueryExpression({
2395
+ termExpression: "$term",
2396
+ isCaseSensitive
2397
+ })}
2398
+ ))`,
2399
+ candidateQueryVar: candidateQuery.candidateQueryVar
2400
+ };
2401
+ }
2315
2402
  /**
2316
2403
  * Build the raw search paths for item-level string search.
2317
2404
  */
@@ -2364,14 +2451,14 @@ function buildItemStringPropertyValueBranch(params) {
2364
2451
  * Build an item-level CTS string search predicate.
2365
2452
  */
2366
2453
  function buildItemStringSearchClause(params) {
2367
- const { query, version, queryKey } = params;
2454
+ const { query, version, queryKey, allowCtsPredicates } = params;
2368
2455
  const fallbackPredicate = buildCombinedRawStringMatchPredicate({
2369
2456
  valueExpressions: buildItemStringSearchPaths(query.language),
2370
2457
  value: query.value,
2371
2458
  matchMode: query.matchMode,
2372
2459
  isCaseSensitive: query.isCaseSensitive
2373
2460
  });
2374
- if (query.matchMode !== "includes" || version !== 2) return {
2461
+ if (!allowCtsPredicates || query.matchMode !== "includes" || version !== 2) return {
2375
2462
  declarations: [],
2376
2463
  predicate: fallbackPredicate,
2377
2464
  candidateQueryVar: null
@@ -2468,75 +2555,28 @@ function buildPropertyStringCandidateBranch(params) {
2468
2555
  )
2469
2556
  )`;
2470
2557
  }
2471
- function buildPropertyRawValueCandidateBranch(params) {
2558
+ function buildPropertyScalarCandidateBranch(params) {
2472
2559
  const { termExpression, isCaseSensitive } = params;
2473
2560
  return `cts:element-query(xs:QName("properties"),
2474
2561
  cts:element-query(xs:QName("property"),
2475
- cts:element-attribute-word-query(
2476
- xs:QName("value"),
2477
- xs:QName("rawValue"),
2478
- ${termExpression},
2479
- ${buildCtsQueryOptionsExpression(isCaseSensitive)}
2480
- )
2481
- )
2482
- )`;
2483
- }
2484
- function buildPropertySimpleValueTextCandidateBranch(params) {
2485
- const { termExpression, isCaseSensitive } = params;
2486
- return `cts:element-query(xs:QName("properties"),
2487
- cts:element-query(xs:QName("property"),
2488
- cts:element-word-query(
2489
- xs:QName("value"),
2490
- ${termExpression},
2491
- ${buildCtsQueryOptionsExpression(isCaseSensitive)}
2492
- )
2562
+ cts:or-query((
2563
+ ${buildCtsElementAttributeWordQueryExpression({
2564
+ elementName: "value",
2565
+ attributeName: "rawValue",
2566
+ termExpression,
2567
+ isCaseSensitive,
2568
+ isWildcarded: true
2569
+ })},
2570
+ ${buildCtsElementWordQueryExpression({
2571
+ elementName: "value",
2572
+ termExpression,
2573
+ isCaseSensitive,
2574
+ isWildcarded: true
2575
+ })}
2576
+ ))
2493
2577
  )
2494
2578
  )`;
2495
2579
  }
2496
- function buildPropertySimpleValueRawValueExpression() {
2497
- return buildNodeStringValuesExpression("value/@rawValue");
2498
- }
2499
- function buildPropertySimpleValueTextExpression() {
2500
- return buildNodeStringValuesExpression("value[not(*)]/text()");
2501
- }
2502
- function buildPropertySimpleValueSearchableNodesExpression() {
2503
- return "value[not(*)]";
2504
- }
2505
- function buildPropertyRawValueOrTextRawPredicate(params) {
2506
- const { value, matchMode, isCaseSensitive } = params;
2507
- return buildOrPredicate([buildRawStringMatchPredicate({
2508
- valueExpression: buildPropertySimpleValueRawValueExpression(),
2509
- value,
2510
- matchMode,
2511
- isCaseSensitive
2512
- }), buildRawStringMatchPredicate({
2513
- valueExpression: buildPropertySimpleValueTextExpression(),
2514
- value,
2515
- matchMode,
2516
- isCaseSensitive
2517
- })]);
2518
- }
2519
- function buildPropertyRawValueOrTextTokenPredicate(params) {
2520
- const { termsExpression, isCaseSensitive } = params;
2521
- const rawValueQuery = `cts:element-attribute-word-query(
2522
- xs:QName("value"),
2523
- xs:QName("rawValue"),
2524
- $term,
2525
- ${buildCtsQueryOptionsExpression(isCaseSensitive)}
2526
- )`;
2527
- const textQuery = `cts:element-word-query(
2528
- xs:QName("value"),
2529
- $term,
2530
- ${buildCtsQueryOptionsExpression(isCaseSensitive)}
2531
- )`;
2532
- return `(every $term in ${termsExpression}
2533
- satisfies some $searchNode in (${buildPropertySimpleValueSearchableNodesExpression()})
2534
- satisfies (
2535
- cts:contains($searchNode, ${rawValueQuery})
2536
- or
2537
- cts:contains($searchNode, ${textQuery})
2538
- ))`;
2539
- }
2540
2580
  function getGroupableIncludesValue(query) {
2541
2581
  switch (query.target) {
2542
2582
  case "string":
@@ -2546,14 +2586,8 @@ function getGroupableIncludesValue(query) {
2546
2586
  case "periods":
2547
2587
  case "bibliography": return query.value;
2548
2588
  case "property":
2549
- if (query.dataType === "string") {
2550
- if (query.propertyValues?.length !== 1) return null;
2551
- return query.propertyValues[0] ?? null;
2552
- }
2553
- if (query.dataType === "IDREF") return null;
2554
- if (query.dataType === "date" || query.dataType === "dateTime") return "value" in query && query.value != null ? query.value : null;
2555
- if (query.propertyValues?.length !== 1) return null;
2556
- return query.propertyValues[0] ?? null;
2589
+ if (query.dataType !== "string" || query.value == null) return null;
2590
+ return query.value;
2557
2591
  }
2558
2592
  }
2559
2593
  function isCompatibleIncludesGroupQuery(params) {
@@ -2571,11 +2605,6 @@ function buildContentTargetIncludesGroupMember(params) {
2571
2605
  matchMode: "includes",
2572
2606
  isCaseSensitive
2573
2607
  }),
2574
- buildTokenPredicate: (termsExpression) => buildTokenizedSearchPredicate({
2575
- searchableNodesExpression: buildSearchableContentNodesExpression(contentNodesExpression),
2576
- termsExpression,
2577
- isCaseSensitive
2578
- }),
2579
2608
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
2580
2609
  containerElementName,
2581
2610
  termExpression,
@@ -2592,11 +2621,6 @@ function buildItemStringIncludesGroupMember(query) {
2592
2621
  matchMode: "includes",
2593
2622
  isCaseSensitive: query.isCaseSensitive
2594
2623
  }),
2595
- buildTokenPredicate: (termsExpression) => buildTokenizedSearchPredicate({
2596
- searchableNodesExpression: buildItemStringSearchableNodesExpression(query.language),
2597
- termsExpression,
2598
- isCaseSensitive: query.isCaseSensitive
2599
- }),
2600
2624
  buildCandidateTermQuery: (termExpression) => `cts:or-query((
2601
2625
  ${buildItemStringIdentificationBranch({
2602
2626
  termExpression,
@@ -2614,22 +2638,18 @@ function buildItemStringIncludesGroupMember(query) {
2614
2638
  function buildPropertyStringIncludesGroupMember(query) {
2615
2639
  const propertyVariable = query.propertyVariable;
2616
2640
  const predicateParts = [];
2617
- const propertyContentNodesExpression = `value[not(@inherited="true")]/content[@xml:lang="${query.language}"]`;
2618
- const valueExpression = buildFlattenedContentValuesExpression(propertyContentNodesExpression);
2619
- const propertyValue = query.propertyValues[0] ?? "";
2641
+ const valueExpression = buildPropertyValueContentValuesExpression({
2642
+ language: query.language,
2643
+ excludeInherited: true
2644
+ });
2620
2645
  if (propertyVariable != null) predicateParts.push(buildPropertyLabelPredicate(propertyVariable));
2621
2646
  return {
2622
2647
  rawPredicate: buildPropertyPredicateExpression([...predicateParts, buildRawStringMatchPredicate({
2623
2648
  valueExpression,
2624
- value: propertyValue,
2649
+ value: query.value,
2625
2650
  matchMode: "includes",
2626
2651
  isCaseSensitive: query.isCaseSensitive
2627
2652
  })]),
2628
- buildTokenPredicate: (termsExpression) => buildPropertyPredicateExpression([...predicateParts, buildTokenizedSearchPredicate({
2629
- searchableNodesExpression: buildSearchableContentNodesExpression(propertyContentNodesExpression),
2630
- termsExpression,
2631
- isCaseSensitive: query.isCaseSensitive
2632
- })]),
2633
2653
  buildCandidateTermQuery: (termExpression) => buildPropertyStringCandidateBranch({
2634
2654
  termExpression,
2635
2655
  isCaseSensitive: query.isCaseSensitive,
@@ -2637,31 +2657,6 @@ function buildPropertyStringIncludesGroupMember(query) {
2637
2657
  })
2638
2658
  };
2639
2659
  }
2640
- function buildPropertyRawValueOrTextIncludesGroupMember(query) {
2641
- const propertyVariable = query.propertyVariable;
2642
- const predicateParts = [];
2643
- const propertyValue = getGroupableIncludesValue(query);
2644
- if (propertyValue == null) throw new Error("Cannot build a rawValue/text includes group without a search value");
2645
- if (propertyVariable != null) predicateParts.push(buildPropertyLabelPredicate(propertyVariable));
2646
- return {
2647
- rawPredicate: buildPropertyPredicateExpression([...predicateParts, buildPropertyRawValueOrTextRawPredicate({
2648
- value: propertyValue,
2649
- matchMode: "includes",
2650
- isCaseSensitive: query.isCaseSensitive
2651
- })]),
2652
- buildTokenPredicate: (termsExpression) => buildPropertyPredicateExpression([...predicateParts, buildPropertyRawValueOrTextTokenPredicate({
2653
- termsExpression,
2654
- isCaseSensitive: query.isCaseSensitive
2655
- })]),
2656
- buildCandidateTermQuery: (termExpression) => buildOrCtsQueryExpression([buildPropertyRawValueCandidateBranch({
2657
- termExpression,
2658
- isCaseSensitive: query.isCaseSensitive
2659
- }), buildPropertySimpleValueTextCandidateBranch({
2660
- termExpression,
2661
- isCaseSensitive: query.isCaseSensitive
2662
- })])
2663
- };
2664
- }
2665
2660
  function buildIncludesGroupMember(query) {
2666
2661
  switch (query.target) {
2667
2662
  case "string": return buildItemStringIncludesGroupMember(query);
@@ -2701,8 +2696,8 @@ function buildIncludesGroupMember(query) {
2701
2696
  containerElementName: "image"
2702
2697
  });
2703
2698
  case "property":
2704
- if (query.dataType === "string") return buildPropertyStringIncludesGroupMember(query);
2705
- return buildPropertyRawValueOrTextIncludesGroupMember(query);
2699
+ if (query.dataType === "all") throw new Error(`Property queries with dataType "all" are not compatible with includes-group optimization`);
2700
+ return buildPropertyStringIncludesGroupMember(query);
2706
2701
  }
2707
2702
  }
2708
2703
  function getCompatibleIncludesGroupLeaves(params) {
@@ -2768,7 +2763,7 @@ function buildIncludesGroupClause(params) {
2768
2763
  then cts:and-query(${termQueriesVar})
2769
2764
  else ()`
2770
2765
  ],
2771
- predicate: buildOrPredicate(members.map((member) => member.buildTokenPredicate(tokenizedSearchDeclarations.termsVar))),
2766
+ predicate: `cts:contains(., ${candidateQueryVar})`,
2772
2767
  candidateQueryVar
2773
2768
  };
2774
2769
  }
@@ -2776,9 +2771,9 @@ function buildIncludesGroupClause(params) {
2776
2771
  * Build a string match predicate for an XQuery string.
2777
2772
  */
2778
2773
  function buildStringMatchClause(params) {
2779
- const { contentNodesExpression, value, matchMode, isCaseSensitive, version, queryKey, buildCandidateTermQuery } = params;
2774
+ const { contentNodesExpression, value, matchMode, isCaseSensitive, version, queryKey, allowCtsPredicates, buildCandidateTermQuery } = params;
2780
2775
  const valueExpression = buildFlattenedContentValuesExpression(contentNodesExpression);
2781
- if (matchMode === "includes" && version === 2 && buildCandidateTermQuery != null) return buildCtsIncludesPredicate({
2776
+ if (allowCtsPredicates && matchMode === "includes" && version === 2 && buildCandidateTermQuery != null) return buildCtsIncludesPredicate({
2782
2777
  searchableNodesExpression: buildSearchableContentNodesExpression(contentNodesExpression),
2783
2778
  fallbackValueExpression: valueExpression,
2784
2779
  value,
@@ -2797,163 +2792,113 @@ function buildStringMatchClause(params) {
2797
2792
  candidateQueryVar: null
2798
2793
  };
2799
2794
  }
2800
- function buildPropertyValueAttributePredicate(params) {
2801
- const { propertyValues, attributeName } = params;
2802
- const valuePredicates = [];
2803
- for (const propertyValue of propertyValues) valuePredicates.push(`value[@${attributeName}=${stringLiteral(propertyValue)}]`);
2804
- return buildOrPredicate(valuePredicates);
2805
- }
2806
- function buildPropertyRawValueOrTextMatchClause(params) {
2807
- const { value, matchMode, isCaseSensitive, version, queryKey } = params;
2808
- const fallbackPredicate = buildPropertyRawValueOrTextRawPredicate({
2795
+ function buildCombinedRawStringMatchClause(params) {
2796
+ const { valueExpressions, value, matchMode, isCaseSensitive, version, queryKey, allowCtsPredicates, buildCandidateTermQuery } = params;
2797
+ const predicate = buildCombinedRawStringMatchPredicate({
2798
+ valueExpressions,
2809
2799
  value,
2810
2800
  matchMode,
2811
2801
  isCaseSensitive
2812
2802
  });
2813
- if (matchMode !== "includes" || version !== 2) return {
2814
- declarations: [],
2815
- predicate: fallbackPredicate,
2816
- candidateQueryVar: null
2817
- };
2818
- const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
2819
- value,
2820
- isCaseSensitive,
2821
- queryKey
2822
- });
2823
- const tokenizedTerms = tokenizeIncludesSearchValue({
2824
- value,
2825
- isCaseSensitive
2826
- });
2827
- const termQueriesVar = `$query${queryKey}TermQueries`;
2828
- const candidateQueryVar = `$query${queryKey}CandidateQuery`;
2829
- if (tokenizedTerms.length === 0) return {
2830
- declarations: [],
2831
- predicate: fallbackPredicate,
2832
- candidateQueryVar: null
2833
- };
2834
- return {
2835
- declarations: [
2836
- ...tokenizedSearchDeclarations.declarations,
2837
- `let ${termQueriesVar} :=
2838
- for $term in ${tokenizedSearchDeclarations.termsVar}
2839
- return ${buildOrCtsQueryExpression([buildPropertyRawValueCandidateBranch({
2840
- termExpression: "$term",
2841
- isCaseSensitive
2842
- }), buildPropertySimpleValueTextCandidateBranch({
2843
- termExpression: "$term",
2844
- isCaseSensitive
2845
- })])}`,
2846
- `let ${candidateQueryVar} :=
2847
- if (count(${tokenizedSearchDeclarations.termsVar}) = 1)
2848
- then ${termQueriesVar}[1]
2849
- else if (count(${tokenizedSearchDeclarations.termsVar}) gt 1)
2850
- then cts:and-query(${termQueriesVar})
2851
- else ()`
2852
- ],
2853
- predicate: buildPropertyRawValueOrTextTokenPredicate({
2854
- termsExpression: tokenizedSearchDeclarations.termsVar,
2855
- isCaseSensitive
2856
- }),
2857
- candidateQueryVar
2858
- };
2859
- }
2860
- function buildPropertyRawValueOrTextClause(params) {
2861
- const { values, matchMode, isCaseSensitive, version, queryKey } = params;
2862
- const declarations = [];
2863
- const valuePredicates = [];
2864
- const candidateQueryVars = [];
2865
- for (const [valueIndex, value] of values.entries()) {
2866
- const compiledClause = buildPropertyRawValueOrTextMatchClause({
2803
+ if (allowCtsPredicates && matchMode === "includes" && version === 2 && buildCandidateTermQuery != null) {
2804
+ const candidateQuery = buildCtsCandidateQuery({
2867
2805
  value,
2868
- matchMode,
2869
2806
  isCaseSensitive,
2870
- version,
2871
- queryKey: `${queryKey}_${valueIndex + 1}`
2807
+ queryKey,
2808
+ buildCandidateTermQuery
2872
2809
  });
2873
- declarations.push(...compiledClause.declarations);
2874
- valuePredicates.push(compiledClause.predicate);
2875
- if (compiledClause.candidateQueryVar != null) candidateQueryVars.push(compiledClause.candidateQueryVar);
2876
- }
2877
- let candidateQueryVar = null;
2878
- if (candidateQueryVars.length > 0) {
2879
- const candidateQueriesExpression = `(${candidateQueryVars.join(", ")})`;
2880
- candidateQueryVar = `$query${queryKey}CandidateQuery`;
2881
- declarations.push(`let ${candidateQueryVar} :=
2882
- if (count(${candidateQueriesExpression}) = 1)
2883
- then ${candidateQueriesExpression}[1]
2884
- else if (count(${candidateQueriesExpression}) gt 1)
2885
- then cts:or-query(${candidateQueriesExpression})
2886
- else ()`);
2810
+ return {
2811
+ declarations: candidateQuery.declarations,
2812
+ predicate,
2813
+ candidateQueryVar: candidateQuery.candidateQueryVar
2814
+ };
2887
2815
  }
2888
2816
  return {
2889
- declarations,
2890
- predicate: buildOrPredicate(valuePredicates),
2891
- candidateQueryVar
2817
+ declarations: [],
2818
+ predicate,
2819
+ candidateQueryVar: null
2892
2820
  };
2893
2821
  }
2822
+ function buildPropertyValueAttributePredicate(params) {
2823
+ const { propertyValue, attributeName } = params;
2824
+ return `value[@${attributeName}=${stringLiteral(propertyValue)}]`;
2825
+ }
2894
2826
  function buildPropertyPredicateExpression(propertyPredicates) {
2895
2827
  let propertyExpression = ".//properties//property";
2896
2828
  for (const propertyPredicate of propertyPredicates) propertyExpression += `[${propertyPredicate}]`;
2897
2829
  return propertyExpression;
2898
2830
  }
2899
2831
  function buildPropertyStringValueClause(params) {
2900
- const { query, version, queryKey } = params;
2901
- const propertyContentNodesExpression = query.matchMode === "includes" && version === 2 ? `value[not(@inherited="true")]/content[@xml:lang="${query.language}"]` : `value/content[@xml:lang="${query.language}"]`;
2902
- const declarations = [];
2903
- const valuePredicates = [];
2904
- const candidateQueryVars = [];
2905
- for (const [propertyValueIndex, propertyValue] of query.propertyValues.entries()) {
2906
- const compiledStringClause = buildStringMatchClause({
2907
- contentNodesExpression: propertyContentNodesExpression,
2908
- value: propertyValue,
2909
- matchMode: query.matchMode,
2832
+ const { query, version, queryKey, allowCtsPredicates } = params;
2833
+ return buildStringMatchClause({
2834
+ contentNodesExpression: buildPropertyValueContentNodesExpression({
2835
+ language: query.language,
2836
+ excludeInherited: allowCtsPredicates && query.matchMode === "includes" && version === 2
2837
+ }),
2838
+ value: query.value,
2839
+ matchMode: query.matchMode,
2840
+ isCaseSensitive: query.isCaseSensitive,
2841
+ version,
2842
+ queryKey,
2843
+ allowCtsPredicates,
2844
+ buildCandidateTermQuery: (termExpression) => buildPropertyStringCandidateBranch({
2845
+ termExpression,
2910
2846
  isCaseSensitive: query.isCaseSensitive,
2911
- version,
2912
- queryKey: `${queryKey}_${propertyValueIndex + 1}`,
2913
- buildCandidateTermQuery: (termExpression) => buildPropertyStringCandidateBranch({
2914
- termExpression,
2915
- isCaseSensitive: query.isCaseSensitive,
2916
- language: query.language
2917
- })
2918
- });
2919
- declarations.push(...compiledStringClause.declarations);
2920
- valuePredicates.push(compiledStringClause.predicate);
2921
- if (compiledStringClause.candidateQueryVar != null) candidateQueryVars.push(compiledStringClause.candidateQueryVar);
2922
- }
2923
- let candidateQueryVar = null;
2924
- if (candidateQueryVars.length > 0) {
2925
- const candidateQueriesExpression = `(${candidateQueryVars.join(", ")})`;
2926
- candidateQueryVar = `$query${queryKey}CandidateQuery`;
2927
- declarations.push(`let ${candidateQueryVar} :=
2928
- if (count(${candidateQueriesExpression}) = 1)
2929
- then ${candidateQueriesExpression}[1]
2930
- else if (count(${candidateQueriesExpression}) gt 1)
2931
- then cts:or-query(${candidateQueriesExpression})
2932
- else ()`);
2933
- }
2847
+ language: query.language
2848
+ })
2849
+ });
2850
+ }
2851
+ function buildPropertyScalarValueClause(params) {
2852
+ const { value, matchMode, isCaseSensitive, version, queryKey, allowCtsPredicates } = params;
2853
+ return buildCombinedRawStringMatchClause({
2854
+ valueExpressions: buildPropertyScalarValueExpressions(),
2855
+ value,
2856
+ matchMode,
2857
+ isCaseSensitive,
2858
+ version,
2859
+ queryKey,
2860
+ allowCtsPredicates,
2861
+ buildCandidateTermQuery: (termExpression) => buildPropertyScalarCandidateBranch({
2862
+ termExpression,
2863
+ isCaseSensitive
2864
+ })
2865
+ });
2866
+ }
2867
+ function buildPropertyAllValueClause(query) {
2934
2868
  return {
2935
- declarations,
2936
- predicate: buildOrPredicate(valuePredicates),
2937
- candidateQueryVar
2869
+ declarations: [],
2870
+ predicate: buildCombinedRawStringMatchPredicate({
2871
+ valueExpressions: buildAllPropertyValueExpressions(query.language),
2872
+ value: query.value,
2873
+ matchMode: query.matchMode,
2874
+ isCaseSensitive: query.isCaseSensitive
2875
+ }),
2876
+ candidateQueryVar: null
2938
2877
  };
2939
2878
  }
2940
2879
  /**
2941
2880
  * Build a property predicate for an XQuery string.
2942
2881
  */
2943
2882
  function buildPropertyClause(params) {
2944
- const { query, version, queryKey } = params;
2883
+ const { query, version, queryKey, allowCtsPredicates } = params;
2945
2884
  const predicateParts = [];
2946
2885
  const declarations = [];
2947
2886
  const propertyVariable = query.propertyVariable;
2948
2887
  let candidateQueryVar = null;
2949
2888
  if (propertyVariable != null) predicateParts.push(buildPropertyLabelPredicate(propertyVariable));
2950
- if (query.dataType === "date" || query.dataType === "dateTime") if ("value" in query && query.value != null) {
2951
- const compiledScalarClause = buildPropertyRawValueOrTextClause({
2952
- values: [query.value],
2889
+ if (query.dataType === "all") {
2890
+ const compiledAllClause = buildPropertyAllValueClause(query);
2891
+ declarations.push(...compiledAllClause.declarations);
2892
+ predicateParts.push(compiledAllClause.predicate);
2893
+ candidateQueryVar = compiledAllClause.candidateQueryVar;
2894
+ } else if (query.dataType === "date" || query.dataType === "dateTime") if ("value" in query && query.value != null) {
2895
+ const compiledScalarClause = buildPropertyScalarValueClause({
2896
+ value: query.value,
2953
2897
  matchMode: query.matchMode,
2954
2898
  isCaseSensitive: query.isCaseSensitive,
2955
2899
  version,
2956
- queryKey
2900
+ queryKey,
2901
+ allowCtsPredicates
2957
2902
  });
2958
2903
  declarations.push(...compiledScalarClause.declarations);
2959
2904
  predicateParts.push(compiledScalarClause.predicate);
@@ -2962,10 +2907,10 @@ function buildPropertyClause(params) {
2962
2907
  from: query.from,
2963
2908
  to: query.to
2964
2909
  }));
2965
- else if (query.propertyValues != null) switch (query.dataType) {
2910
+ else if (query.value != null) switch (query.dataType) {
2966
2911
  case "IDREF":
2967
2912
  predicateParts.push(buildPropertyValueAttributePredicate({
2968
- propertyValues: query.propertyValues,
2913
+ propertyValue: query.value,
2969
2914
  attributeName: "uuid"
2970
2915
  }));
2971
2916
  break;
@@ -2973,12 +2918,13 @@ function buildPropertyClause(params) {
2973
2918
  case "decimal":
2974
2919
  case "time":
2975
2920
  case "boolean": {
2976
- const compiledScalarClause = buildPropertyRawValueOrTextClause({
2977
- values: query.propertyValues,
2921
+ const compiledScalarClause = buildPropertyScalarValueClause({
2922
+ value: query.value,
2978
2923
  matchMode: query.matchMode,
2979
2924
  isCaseSensitive: query.isCaseSensitive,
2980
2925
  version,
2981
- queryKey
2926
+ queryKey,
2927
+ allowCtsPredicates
2982
2928
  });
2983
2929
  declarations.push(...compiledScalarClause.declarations);
2984
2930
  predicateParts.push(compiledScalarClause.predicate);
@@ -2989,7 +2935,8 @@ function buildPropertyClause(params) {
2989
2935
  const compiledStringClause = buildPropertyStringValueClause({
2990
2936
  query,
2991
2937
  version,
2992
- queryKey
2938
+ queryKey,
2939
+ allowCtsPredicates
2993
2940
  });
2994
2941
  declarations.push(...compiledStringClause.declarations);
2995
2942
  predicateParts.push(compiledStringClause.predicate);
@@ -3007,12 +2954,13 @@ function buildPropertyClause(params) {
3007
2954
  * Build a query predicate for an XQuery string.
3008
2955
  */
3009
2956
  function buildQueryClause(params) {
3010
- const { query, version, queryKey } = params;
2957
+ const { query, version, queryKey, allowCtsPredicates } = params;
3011
2958
  switch (query.target) {
3012
2959
  case "string": return buildItemStringSearchClause({
3013
2960
  query,
3014
2961
  version,
3015
- queryKey
2962
+ queryKey,
2963
+ allowCtsPredicates
3016
2964
  });
3017
2965
  case "title": return buildStringMatchClause({
3018
2966
  contentNodesExpression: `identification/label/content[@xml:lang="${query.language}"]`,
@@ -3021,6 +2969,7 @@ function buildQueryClause(params) {
3021
2969
  isCaseSensitive: query.isCaseSensitive,
3022
2970
  version,
3023
2971
  queryKey,
2972
+ allowCtsPredicates,
3024
2973
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
3025
2974
  containerElementName: "identification",
3026
2975
  termExpression,
@@ -3035,6 +2984,7 @@ function buildQueryClause(params) {
3035
2984
  isCaseSensitive: query.isCaseSensitive,
3036
2985
  version,
3037
2986
  queryKey,
2987
+ allowCtsPredicates,
3038
2988
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
3039
2989
  containerElementName: "description",
3040
2990
  termExpression,
@@ -3049,6 +2999,7 @@ function buildQueryClause(params) {
3049
2999
  isCaseSensitive: query.isCaseSensitive,
3050
3000
  version,
3051
3001
  queryKey,
3002
+ allowCtsPredicates,
3052
3003
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
3053
3004
  containerElementName: "period",
3054
3005
  termExpression,
@@ -3063,6 +3014,7 @@ function buildQueryClause(params) {
3063
3014
  isCaseSensitive: query.isCaseSensitive,
3064
3015
  version,
3065
3016
  queryKey,
3017
+ allowCtsPredicates,
3066
3018
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
3067
3019
  containerElementName: "bibliography",
3068
3020
  termExpression,
@@ -3077,6 +3029,7 @@ function buildQueryClause(params) {
3077
3029
  isCaseSensitive: query.isCaseSensitive,
3078
3030
  version,
3079
3031
  queryKey,
3032
+ allowCtsPredicates,
3080
3033
  buildCandidateTermQuery: (termExpression) => buildContentTargetCandidateBranch({
3081
3034
  containerElementName: "image",
3082
3035
  termExpression,
@@ -3087,7 +3040,8 @@ function buildQueryClause(params) {
3087
3040
  case "property": return buildPropertyClause({
3088
3041
  query,
3089
3042
  version,
3090
- queryKey
3043
+ queryKey,
3044
+ allowCtsPredicates
3091
3045
  });
3092
3046
  }
3093
3047
  }
@@ -3095,11 +3049,12 @@ function buildQueryClause(params) {
3095
3049
  * Build a boolean query clause for an XQuery string.
3096
3050
  */
3097
3051
  function buildBooleanQueryNode(params) {
3098
- const { query, version, queryKey } = params;
3052
+ const { query, version, queryKey, allowCtsPredicates } = params;
3099
3053
  const compiledQueryClause = buildQueryClause({
3100
3054
  query,
3101
3055
  version,
3102
- queryKey
3056
+ queryKey,
3057
+ allowCtsPredicates
3103
3058
  });
3104
3059
  const baseClause = `(${compiledQueryClause.predicate})`;
3105
3060
  return {
@@ -3109,11 +3064,12 @@ function buildBooleanQueryNode(params) {
3109
3064
  };
3110
3065
  }
3111
3066
  function buildQueryNode(params) {
3112
- const { query, version, queryKey } = params;
3067
+ const { query, version, queryKey, allowCtsPredicates } = params;
3113
3068
  if (isQueryLeaf(query)) return buildBooleanQueryNode({
3114
3069
  query,
3115
3070
  version,
3116
- queryKey
3071
+ queryKey,
3072
+ allowCtsPredicates
3117
3073
  });
3118
3074
  const groupQueries = getQueryGroupChildren(query);
3119
3075
  const optimizedIncludesGroupQueries = getCompatibleIncludesGroupLeaves({
@@ -3130,10 +3086,11 @@ function buildQueryNode(params) {
3130
3086
  return buildQueryNode({
3131
3087
  query: onlyQuery,
3132
3088
  version,
3133
- queryKey
3089
+ queryKey,
3090
+ allowCtsPredicates
3134
3091
  });
3135
3092
  }
3136
- if (optimizedIncludesGroupQueries != null) {
3093
+ if (allowCtsPredicates && optimizedIncludesGroupQueries != null) {
3137
3094
  const compiledClause = buildIncludesGroupClause({
3138
3095
  queries: optimizedIncludesGroupQueries,
3139
3096
  queryKey
@@ -3146,20 +3103,29 @@ function buildQueryNode(params) {
3146
3103
  }
3147
3104
  const declarations = [];
3148
3105
  const predicates = [];
3149
- const candidateQueryVars = [];
3150
- for (const [groupIndex, groupQuery] of groupQueries.entries()) {
3151
- const compiledQueryNode = buildQueryNode({
3152
- query: groupQuery,
3153
- version,
3154
- queryKey: `${queryKey}_${groupIndex + 1}`
3155
- });
3106
+ const groupOperator = getQueryGroupOperator(query);
3107
+ let compiledChildNodes = groupQueries.map((groupQuery, groupIndex) => buildQueryNode({
3108
+ query: groupQuery,
3109
+ version,
3110
+ queryKey: `${queryKey}_${groupIndex + 1}`,
3111
+ allowCtsPredicates
3112
+ }));
3113
+ if (allowCtsPredicates && groupOperator === "or" && compiledChildNodes.some((node) => node.candidateQueryVars.length === 0)) compiledChildNodes = groupQueries.map((groupQuery, groupIndex) => buildQueryNode({
3114
+ query: groupQuery,
3115
+ version,
3116
+ queryKey: `${queryKey}_${groupIndex + 1}`,
3117
+ allowCtsPredicates: false
3118
+ }));
3119
+ const candidateQueryVarsByChild = [];
3120
+ for (const compiledQueryNode of compiledChildNodes) {
3156
3121
  declarations.push(...compiledQueryNode.declarations);
3157
3122
  predicates.push(compiledQueryNode.predicate);
3158
- candidateQueryVars.push(...compiledQueryNode.candidateQueryVars);
3123
+ candidateQueryVarsByChild.push(compiledQueryNode.candidateQueryVars);
3159
3124
  }
3125
+ const candidateQueryVars = groupOperator === "and" ? candidateQueryVarsByChild.flat() : candidateQueryVarsByChild.every((vars) => vars.length > 0) ? candidateQueryVarsByChild.flat() : [];
3160
3126
  return {
3161
3127
  declarations,
3162
- predicate: getQueryGroupOperator(query) === "and" ? buildAndPredicate(predicates) : buildOrPredicate(predicates),
3128
+ predicate: groupOperator === "and" ? buildAndPredicate(predicates) : buildOrPredicate(predicates),
3163
3129
  candidateQueryVars
3164
3130
  };
3165
3131
  }
@@ -3172,7 +3138,8 @@ function buildQueryPlan(params) {
3172
3138
  const compiledQueryNode = buildQueryNode({
3173
3139
  query: queries,
3174
3140
  version,
3175
- queryKey: "1"
3141
+ queryKey: "1",
3142
+ allowCtsPredicates: true
3176
3143
  });
3177
3144
  if (compiledQueryNode.declarations.length > 0) declarations.push(`let ${CTS_INCLUDES_STOP_WORDS_VAR} := (${CTS_INCLUDES_STOP_WORDS.map((stopWord) => stringLiteral(stopWord)).join(", ")})`, ...compiledQueryNode.declarations);
3178
3145
  predicate = compiledQueryNode.predicate;
@@ -3353,7 +3320,7 @@ async function fetchSetItems(params, itemCategories, options) {
3353
3320
  else response = await (options?.fetch ?? fetch)(`https://ochre.lib.uchicago.edu/ochre?xquery=${encodeURIComponent(xquery)}&format=json&lang="*"`);
3354
3321
  if (!response.ok) throw new Error(`OCHRE API responded with status: ${response.status}`);
3355
3322
  const data = await response.json();
3356
- if (Array.isArray(data.result) || Object.keys(data.result).length === 0) throw new Error("No items found");
3323
+ if (Array.isArray(data.result) || Object.keys(data.result).length === 0) throw new Error("Invalid OCHRE API response");
3357
3324
  if (itemCategories != null) {
3358
3325
  const itemCategoriesSet = new Set(Object.keys(data.result.ochre.items));
3359
3326
  const missingCategories = itemCategories.filter((category) => !itemCategoriesSet.has(category));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.21.5",
3
+ "version": "0.21.7",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Node.js library for working with OCHRE (Online Cultural and Historical Research Environment) data",
@@ -46,8 +46,8 @@
46
46
  "zod": "^4.3.6"
47
47
  },
48
48
  "devDependencies": {
49
- "@antfu/eslint-config": "^7.7.3",
50
- "@types/node": "^24.12.0",
49
+ "@antfu/eslint-config": "^8.0.0",
50
+ "@types/node": "^24.12.2",
51
51
  "bumpp": "^11.0.1",
52
52
  "eslint": "^10.1.0",
53
53
  "prettier": "^3.8.1",