ochre-sdk 0.20.23 → 0.20.24

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
@@ -674,9 +674,10 @@ type SetItemsSort = {
674
674
  * Represents a query for Set items
675
675
  */
676
676
  type Query = {
677
- target: "propertyValue";
677
+ target: "property";
678
+ propertyVariables: Array<string>;
678
679
  dataType: Exclude<Exclude<PropertyValueContentType, "coordinate">, "date" | "dateTime">;
679
- value: string;
680
+ propertyValues?: Array<string>;
680
681
  from?: never;
681
682
  to?: never;
682
683
  matchMode: "includes" | "exact";
@@ -685,9 +686,10 @@ type Query = {
685
686
  operator?: "AND" | "OR";
686
687
  isNegated?: boolean;
687
688
  } | {
688
- target: "propertyValue";
689
+ target: "property";
690
+ propertyVariables: Array<string>;
689
691
  dataType: "date" | "dateTime";
690
- value: string;
692
+ propertyValues?: never;
691
693
  from: string;
692
694
  to?: string;
693
695
  matchMode: "includes" | "exact";
@@ -696,9 +698,10 @@ type Query = {
696
698
  operator?: "AND" | "OR";
697
699
  isNegated?: boolean;
698
700
  } | {
699
- target: "propertyValue";
701
+ target: "property";
702
+ propertyVariables: Array<string>;
700
703
  dataType: "date" | "dateTime";
701
- value: string;
704
+ propertyValues?: never;
702
705
  from?: string;
703
706
  to: string;
704
707
  matchMode: "includes" | "exact";
@@ -1231,7 +1234,6 @@ declare function fetchItem<T extends DataCategory = DataCategory, U extends Data
1231
1234
  *
1232
1235
  * @param params - The parameters for the fetch
1233
1236
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
1234
- * @param params.propertyVariableUuids - The property variable UUIDs to filter by
1235
1237
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
1236
1238
  * @param params.sort - Optional sorting configuration applied before pagination.
1237
1239
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
@@ -1245,7 +1247,6 @@ declare function fetchItem<T extends DataCategory = DataCategory, U extends Data
1245
1247
  */
1246
1248
  declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategory>>(params: {
1247
1249
  setScopeUuids: Array<string>;
1248
- propertyVariableUuids: Array<string>;
1249
1250
  queries: Array<Query>;
1250
1251
  sort?: SetItemsSort;
1251
1252
  page: number;
@@ -1273,7 +1274,6 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1273
1274
  *
1274
1275
  * @param params - The parameters for the fetch
1275
1276
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
1276
- * @param params.propertyVariableUuids - The property variable UUIDs to query by
1277
1277
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
1278
1278
  * @param params.attributes - Whether to return values for bibliographies and periods
1279
1279
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
@@ -1287,7 +1287,6 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1287
1287
  */
1288
1288
  declare function fetchSetPropertyValuesByPropertyVariables(params: {
1289
1289
  setScopeUuids: Array<string>;
1290
- propertyVariableUuids: Array<string>;
1291
1290
  queries?: Array<Query>;
1292
1291
  attributes?: {
1293
1292
  bibliographies: boolean;
package/dist/index.mjs CHANGED
@@ -758,7 +758,8 @@ const boundsSchema = z.string().transform((str, ctx) => {
758
758
  */
759
759
  const setQuerySchema = z.union([
760
760
  z.object({
761
- target: z.literal("propertyValue"),
761
+ target: z.literal("property"),
762
+ propertyVariables: z.array(uuidSchema).min(1, "At least one property variable UUID is required"),
762
763
  dataType: z.enum([
763
764
  "string",
764
765
  "integer",
@@ -767,7 +768,7 @@ const setQuerySchema = z.union([
767
768
  "time",
768
769
  "IDREF"
769
770
  ]),
770
- value: z.string(),
771
+ propertyValues: z.array(z.string()).min(1, "At least one property value is required").optional(),
771
772
  matchMode: z.enum(["includes", "exact"]),
772
773
  isCaseSensitive: z.boolean(),
773
774
  language: z.string().default("eng"),
@@ -775,9 +776,9 @@ const setQuerySchema = z.union([
775
776
  isNegated: z.boolean().optional().default(false)
776
777
  }).strict(),
777
778
  z.object({
778
- target: z.literal("propertyValue"),
779
+ target: z.literal("property"),
780
+ propertyVariables: z.array(uuidSchema).min(1, "At least one property variable UUID is required"),
779
781
  dataType: z.enum(["date", "dateTime"]),
780
- value: z.string(),
781
782
  from: z.string(),
782
783
  to: z.string().optional(),
783
784
  matchMode: z.enum(["includes", "exact"]),
@@ -787,9 +788,9 @@ const setQuerySchema = z.union([
787
788
  isNegated: z.boolean().optional().default(false)
788
789
  }).strict(),
789
790
  z.object({
790
- target: z.literal("propertyValue"),
791
+ target: z.literal("property"),
792
+ propertyVariables: z.array(uuidSchema).min(1, "At least one property variable UUID is required"),
791
793
  dataType: z.enum(["date", "dateTime"]),
792
- value: z.string(),
793
794
  from: z.string().optional(),
794
795
  to: z.string(),
795
796
  matchMode: z.enum(["includes", "exact"]),
@@ -866,7 +867,6 @@ function validateSetQueriesOperators(queries, ctx) {
866
867
  const setPropertyValuesByPropertyVariablesParamsSchema = z.object({
867
868
  setScopeUuids: z.array(uuidSchema).min(1, "At least one set scope UUID is required"),
868
869
  belongsToCollectionScopeUuids: z.array(uuidSchema).default([]),
869
- propertyVariableUuids: z.array(uuidSchema).min(1, "At least one property variable UUID is required"),
870
870
  queries: setQueriesSchema,
871
871
  attributes: z.object({
872
872
  bibliographies: z.boolean().default(false),
@@ -878,11 +878,15 @@ const setPropertyValuesByPropertyVariablesParamsSchema = z.object({
878
878
  isLimitedToLeafPropertyValues: z.boolean().default(false)
879
879
  }).superRefine((value, ctx) => {
880
880
  validateSetQueriesOperators(value.queries, ctx);
881
+ if (!value.queries.some((query) => query.target === "property")) ctx.addIssue({
882
+ code: "custom",
883
+ path: ["queries"],
884
+ message: "At least one property query is required"
885
+ });
881
886
  });
882
887
  const setItemsParamsSchema = z.object({
883
888
  setScopeUuids: z.array(uuidSchema).min(1, "At least one set scope UUID is required"),
884
889
  belongsToCollectionScopeUuids: z.array(uuidSchema).default([]),
885
- propertyVariableUuids: z.array(uuidSchema).default([]),
886
890
  queries: setQueriesSchema,
887
891
  sort: setItemsSortSchema,
888
892
  page: z.number().min(1, "Page must be positive").default(1),
@@ -2141,24 +2145,31 @@ const CTS_INCLUDES_STOP_WORDS = [
2141
2145
  "to"
2142
2146
  ];
2143
2147
  const CTS_INCLUDES_STOP_WORDS_VAR = "$ctsIncludesStopWords";
2148
+ function buildFlattenedContentValuesExpression(contentNodesExpression) {
2149
+ return `for $content in ${contentNodesExpression}
2150
+ return string-join($content//text(), "")`;
2151
+ }
2144
2152
  /**
2145
2153
  * Build a string match predicate for an XQuery string.
2146
2154
  */
2147
2155
  function buildRawStringMatchPredicate(params) {
2148
- const { path, value, matchMode, isCaseSensitive } = params;
2149
- const comparedPath = isCaseSensitive ? path : `lower-case(${path})`;
2156
+ const { valueExpression, value, matchMode, isCaseSensitive } = params;
2150
2157
  const comparedValueLiteral = stringLiteral(isCaseSensitive ? value : value.toLowerCase());
2151
- if (matchMode === "includes") return `contains(${comparedPath}, ${comparedValueLiteral})`;
2152
- return `${comparedPath} = ${comparedValueLiteral}`;
2158
+ const candidateVar = "$candidate";
2159
+ const comparedCandidate = isCaseSensitive ? candidateVar : `lower-case(${candidateVar})`;
2160
+ if (matchMode === "includes") return `some ${candidateVar} in (${valueExpression})
2161
+ satisfies contains(${comparedCandidate}, ${comparedValueLiteral})`;
2162
+ return `some ${candidateVar} in (${valueExpression})
2163
+ satisfies ${comparedCandidate} = ${comparedValueLiteral}`;
2153
2164
  }
2154
2165
  /**
2155
2166
  * Build a combined raw string match predicate for multiple paths.
2156
2167
  */
2157
2168
  function buildCombinedRawStringMatchPredicate(params) {
2158
- const { paths, value, matchMode, isCaseSensitive } = params;
2169
+ const { valueExpressions, value, matchMode, isCaseSensitive } = params;
2159
2170
  const predicates = [];
2160
- for (const path of paths) predicates.push(buildRawStringMatchPredicate({
2161
- path,
2171
+ for (const valueExpression of valueExpressions) predicates.push(buildRawStringMatchPredicate({
2172
+ valueExpression,
2162
2173
  value,
2163
2174
  matchMode,
2164
2175
  isCaseSensitive
@@ -2187,10 +2198,10 @@ function buildCtsWordQueryExpression(params) {
2187
2198
  * Build tokenized search declarations for CTS-backed queries.
2188
2199
  */
2189
2200
  function buildTokenizedSearchDeclarations(params) {
2190
- const { value, isCaseSensitive, queryIndex } = params;
2191
- const searchStringVar = `$query${queryIndex}SearchString`;
2192
- const rawTermsVar = `$query${queryIndex}RawTerms`;
2193
- const termsVar = `$query${queryIndex}Terms`;
2201
+ const { value, isCaseSensitive, queryKey } = params;
2202
+ const searchStringVar = `$query${queryKey}SearchString`;
2203
+ const rawTermsVar = `$query${queryKey}RawTerms`;
2204
+ const termsVar = `$query${queryKey}Terms`;
2194
2205
  const tokenSourceExpression = isCaseSensitive ? searchStringVar : `fn:lower-case(${searchStringVar})`;
2195
2206
  return {
2196
2207
  declarations: [
@@ -2209,15 +2220,16 @@ function buildTokenizedSearchDeclarations(params) {
2209
2220
  * Build a CTS-backed field includes predicate for an XQuery string.
2210
2221
  */
2211
2222
  function buildCtsFieldIncludesPredicate(params) {
2212
- const { path, value, isCaseSensitive, queryIndex } = params;
2223
+ const { contentNodesExpression, valueExpression, value, isCaseSensitive, queryKey } = params;
2213
2224
  const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
2214
2225
  value,
2215
2226
  isCaseSensitive,
2216
- queryIndex
2227
+ queryKey
2217
2228
  });
2218
- const ctsQueryVar = `$query${queryIndex}CtsQuery`;
2229
+ const ctsQueryVar = `$query${queryKey}CtsQuery`;
2230
+ const contentNodeVar = `$query${queryKey}ContentNode`;
2219
2231
  const fallbackPredicate = buildRawStringMatchPredicate({
2220
- path,
2232
+ valueExpression,
2221
2233
  value,
2222
2234
  matchMode: "includes",
2223
2235
  isCaseSensitive
@@ -2238,14 +2250,17 @@ function buildCtsFieldIncludesPredicate(params) {
2238
2250
  })}
2239
2251
  ))
2240
2252
  else ()`],
2241
- predicate: `(if (exists(${ctsQueryVar})) then cts:contains(${path}, ${ctsQueryVar}) else ${fallbackPredicate})`
2253
+ predicate: `(if (exists(${ctsQueryVar}))
2254
+ then some ${contentNodeVar} in (${contentNodesExpression})
2255
+ satisfies cts:contains(${contentNodeVar}, ${ctsQueryVar})
2256
+ else ${fallbackPredicate})`
2242
2257
  };
2243
2258
  }
2244
2259
  /**
2245
2260
  * Build the raw search paths for item-level string search.
2246
2261
  */
2247
2262
  function buildItemStringSearchPaths(language) {
2248
- return [`string-join(identification/label/content[@xml:lang="${language}"]/string, "")`, `string-join(properties//property/value[not(@inherited="true")]/content[@xml:lang="${language}"]/string, "")`];
2263
+ return [buildFlattenedContentValuesExpression(`identification/label/content[@xml:lang="${language}"]`), buildFlattenedContentValuesExpression(`properties//property/value[not(@inherited="true")]/content[@xml:lang="${language}"]`)];
2249
2264
  }
2250
2265
  /**
2251
2266
  * Build the identification branch for an item-level CTS string search.
@@ -2290,9 +2305,9 @@ function buildItemStringPropertyValueBranch(params) {
2290
2305
  * Build an item-level CTS string search predicate.
2291
2306
  */
2292
2307
  function buildItemStringSearchPredicate(params) {
2293
- const { query, version, queryIndex } = params;
2308
+ const { query, version, queryKey } = params;
2294
2309
  const fallbackPredicate = buildCombinedRawStringMatchPredicate({
2295
- paths: buildItemStringSearchPaths(query.language),
2310
+ valueExpressions: buildItemStringSearchPaths(query.language),
2296
2311
  value: query.value,
2297
2312
  matchMode: query.matchMode,
2298
2313
  isCaseSensitive: query.isCaseSensitive
@@ -2304,10 +2319,10 @@ function buildItemStringSearchPredicate(params) {
2304
2319
  const tokenizedSearchDeclarations = buildTokenizedSearchDeclarations({
2305
2320
  value: query.value,
2306
2321
  isCaseSensitive: query.isCaseSensitive,
2307
- queryIndex
2322
+ queryKey
2308
2323
  });
2309
- const termQueriesVar = `$query${queryIndex}TermQueries`;
2310
- const ctsQueryVar = `$query${queryIndex}CtsQuery`;
2324
+ const termQueriesVar = `$query${queryKey}TermQueries`;
2325
+ const ctsQueryVar = `$query${queryKey}CtsQuery`;
2311
2326
  return {
2312
2327
  declarations: [
2313
2328
  ...tokenizedSearchDeclarations.declarations,
@@ -2340,23 +2355,33 @@ function buildItemStringSearchPredicate(params) {
2340
2355
  * Build a string match predicate for an XQuery string.
2341
2356
  */
2342
2357
  function buildStringMatchPredicate(params) {
2343
- const { path, value, matchMode, isCaseSensitive, version, queryIndex } = params;
2358
+ const { contentNodesExpression, value, matchMode, isCaseSensitive, version, queryKey } = params;
2359
+ const valueExpression = buildFlattenedContentValuesExpression(contentNodesExpression);
2344
2360
  if (matchMode === "includes" && version === 2) return buildCtsFieldIncludesPredicate({
2345
- path,
2361
+ contentNodesExpression,
2362
+ valueExpression,
2346
2363
  value,
2347
2364
  isCaseSensitive,
2348
- queryIndex
2365
+ queryKey
2349
2366
  });
2350
2367
  return {
2351
2368
  declarations: [],
2352
2369
  predicate: buildRawStringMatchPredicate({
2353
- path,
2370
+ valueExpression,
2354
2371
  value,
2355
2372
  matchMode,
2356
2373
  isCaseSensitive
2357
2374
  })
2358
2375
  };
2359
2376
  }
2377
+ function buildOrPredicate(predicates) {
2378
+ if (predicates.length === 1) return predicates[0] ?? "false()";
2379
+ return `(${predicates.join(" or ")})`;
2380
+ }
2381
+ function buildAndPredicate(predicates) {
2382
+ if (predicates.length === 1) return predicates[0] ?? "false()";
2383
+ return `(${predicates.join(" and ")})`;
2384
+ }
2360
2385
  /**
2361
2386
  * Build a date/dateTime range predicate for an XQuery string.
2362
2387
  */
@@ -2368,93 +2393,139 @@ function buildDateRangePredicate(params) {
2368
2393
  return conditions.join(" and ");
2369
2394
  }
2370
2395
  /**
2371
- * Build a property value predicate for an XQuery string.
2396
+ * Build a property label predicate for an XQuery string.
2372
2397
  */
2373
- function buildPropertyValuePredicate(params) {
2374
- const { query, version, queryIndex } = params;
2375
- if (query.dataType === "IDREF") return {
2376
- declarations: [],
2377
- predicate: `.//properties//property[value[@uuid=${stringLiteral(query.value)}]]`
2378
- };
2379
- if (query.dataType === "date" || query.dataType === "dateTime") return {
2380
- declarations: [],
2381
- predicate: `.//properties//property[(label/@uuid=${stringLiteral(query.value)}) and ${buildDateRangePredicate({
2382
- from: query.from,
2383
- to: query.to
2384
- })}]`
2385
- };
2386
- if (query.dataType === "time" || query.dataType === "integer" || query.dataType === "decimal" || query.dataType === "boolean") return {
2387
- declarations: [],
2388
- predicate: `.//properties//property[value[@rawValue=${stringLiteral(query.value)}]]`
2398
+ function buildPropertyLabelPredicate(propertyVariables) {
2399
+ const labelPredicates = [];
2400
+ for (const propertyVariable of propertyVariables) labelPredicates.push(`@uuid=${stringLiteral(propertyVariable)}`);
2401
+ return `label[${buildOrPredicate(labelPredicates)}]`;
2402
+ }
2403
+ function buildPropertyValueAttributePredicate(params) {
2404
+ const { propertyValues, attributeName } = params;
2405
+ const valuePredicates = [];
2406
+ for (const propertyValue of propertyValues) valuePredicates.push(`value[@${attributeName}=${stringLiteral(propertyValue)}]`);
2407
+ return buildOrPredicate(valuePredicates);
2408
+ }
2409
+ function buildPropertyStringValuePredicate(params) {
2410
+ const { query, version, queryKey } = params;
2411
+ const propertyContentNodesExpression = query.matchMode === "includes" && version === 2 ? `value[not(@inherited="true")]/content[@xml:lang="${query.language}"]` : `value/content[@xml:lang="${query.language}"]`;
2412
+ const declarations = [];
2413
+ const valuePredicates = [];
2414
+ for (const [propertyValueIndex, propertyValue] of query.propertyValues.entries()) {
2415
+ const compiledStringPredicate = buildStringMatchPredicate({
2416
+ contentNodesExpression: propertyContentNodesExpression,
2417
+ value: propertyValue,
2418
+ matchMode: query.matchMode,
2419
+ isCaseSensitive: query.isCaseSensitive,
2420
+ version,
2421
+ queryKey: `${queryKey}_${propertyValueIndex + 1}`
2422
+ });
2423
+ declarations.push(...compiledStringPredicate.declarations);
2424
+ valuePredicates.push(compiledStringPredicate.predicate);
2425
+ }
2426
+ return {
2427
+ declarations,
2428
+ predicate: buildOrPredicate(valuePredicates)
2389
2429
  };
2390
- const compiledStringPredicate = buildStringMatchPredicate({
2391
- path: query.matchMode === "includes" && version === 2 ? `string-join(value[not(@inherited="true")]/content[@xml:lang="${query.language}"]/string, "")` : `string-join(value/content[@xml:lang="${query.language}"]/string, "")`,
2392
- value: query.value,
2393
- matchMode: query.matchMode,
2394
- isCaseSensitive: query.isCaseSensitive,
2395
- version,
2396
- queryIndex
2397
- });
2430
+ }
2431
+ /**
2432
+ * Build a property predicate for an XQuery string.
2433
+ */
2434
+ function buildPropertyPredicate(params) {
2435
+ const { query, version, queryKey } = params;
2436
+ const predicateParts = [buildPropertyLabelPredicate(query.propertyVariables)];
2437
+ const declarations = [];
2438
+ if (query.dataType === "date" || query.dataType === "dateTime") predicateParts.push(buildDateRangePredicate({
2439
+ from: query.from,
2440
+ to: query.to
2441
+ }));
2442
+ else if (query.propertyValues != null) switch (query.dataType) {
2443
+ case "IDREF":
2444
+ predicateParts.push(buildPropertyValueAttributePredicate({
2445
+ propertyValues: query.propertyValues,
2446
+ attributeName: "uuid"
2447
+ }));
2448
+ break;
2449
+ case "integer":
2450
+ case "decimal":
2451
+ case "time":
2452
+ case "boolean":
2453
+ predicateParts.push(buildPropertyValueAttributePredicate({
2454
+ propertyValues: query.propertyValues,
2455
+ attributeName: "rawValue"
2456
+ }));
2457
+ break;
2458
+ case "string": {
2459
+ const compiledStringPredicate = buildPropertyStringValuePredicate({
2460
+ query,
2461
+ version,
2462
+ queryKey
2463
+ });
2464
+ declarations.push(...compiledStringPredicate.declarations);
2465
+ predicateParts.push(compiledStringPredicate.predicate);
2466
+ break;
2467
+ }
2468
+ }
2398
2469
  return {
2399
- declarations: compiledStringPredicate.declarations,
2400
- predicate: `.//properties//property[${compiledStringPredicate.predicate}]`
2470
+ declarations,
2471
+ predicate: `.//properties//property[${buildAndPredicate(predicateParts)}]`
2401
2472
  };
2402
2473
  }
2403
2474
  /**
2404
2475
  * Build a query predicate for an XQuery string.
2405
2476
  */
2406
2477
  function buildQueryPredicate(params) {
2407
- const { query, version, queryIndex } = params;
2478
+ const { query, version, queryKey } = params;
2408
2479
  switch (query.target) {
2409
2480
  case "string": return buildItemStringSearchPredicate({
2410
2481
  query,
2411
2482
  version,
2412
- queryIndex
2483
+ queryKey
2413
2484
  });
2414
2485
  case "title": return buildStringMatchPredicate({
2415
- path: `string-join(identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2486
+ contentNodesExpression: `identification/label/content[@xml:lang="${query.language}"]`,
2416
2487
  value: query.value,
2417
2488
  matchMode: query.matchMode,
2418
2489
  isCaseSensitive: query.isCaseSensitive,
2419
2490
  version,
2420
- queryIndex
2491
+ queryKey
2421
2492
  });
2422
2493
  case "description": return buildStringMatchPredicate({
2423
- path: `string-join(description/content[@xml:lang="${query.language}"]/string, "")`,
2494
+ contentNodesExpression: `description/content[@xml:lang="${query.language}"]`,
2424
2495
  value: query.value,
2425
2496
  matchMode: query.matchMode,
2426
2497
  isCaseSensitive: query.isCaseSensitive,
2427
2498
  version,
2428
- queryIndex
2499
+ queryKey
2429
2500
  });
2430
2501
  case "periods": return buildStringMatchPredicate({
2431
- path: `string-join(periods/period/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2502
+ contentNodesExpression: `periods/period/identification/label/content[@xml:lang="${query.language}"]`,
2432
2503
  value: query.value,
2433
2504
  matchMode: query.matchMode,
2434
2505
  isCaseSensitive: query.isCaseSensitive,
2435
2506
  version,
2436
- queryIndex
2507
+ queryKey
2437
2508
  });
2438
2509
  case "bibliography": return buildStringMatchPredicate({
2439
- path: `string-join(bibliographies/bibliography/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2510
+ contentNodesExpression: `bibliographies/bibliography/identification/label/content[@xml:lang="${query.language}"]`,
2440
2511
  value: query.value,
2441
2512
  matchMode: query.matchMode,
2442
2513
  isCaseSensitive: query.isCaseSensitive,
2443
2514
  version,
2444
- queryIndex
2515
+ queryKey
2445
2516
  });
2446
2517
  case "image": return buildStringMatchPredicate({
2447
- path: `string-join(image/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2518
+ contentNodesExpression: `image/identification/label/content[@xml:lang="${query.language}"]`,
2448
2519
  value: query.value,
2449
2520
  matchMode: query.matchMode,
2450
2521
  isCaseSensitive: query.isCaseSensitive,
2451
2522
  version,
2452
- queryIndex
2523
+ queryKey
2453
2524
  });
2454
- case "propertyValue": return buildPropertyValuePredicate({
2525
+ case "property": return buildPropertyPredicate({
2455
2526
  query,
2456
2527
  version,
2457
- queryIndex
2528
+ queryKey
2458
2529
  });
2459
2530
  }
2460
2531
  }
@@ -2462,11 +2533,11 @@ function buildQueryPredicate(params) {
2462
2533
  * Build a boolean query clause for an XQuery string.
2463
2534
  */
2464
2535
  function buildBooleanQueryClause(params) {
2465
- const { query, version, queryIndex } = params;
2536
+ const { query, version, queryKey } = params;
2466
2537
  const compiledQueryPredicate = buildQueryPredicate({
2467
2538
  query,
2468
2539
  version,
2469
- queryIndex
2540
+ queryKey
2470
2541
  });
2471
2542
  const baseClause = `(${compiledQueryPredicate.predicate})`;
2472
2543
  return {
@@ -2486,7 +2557,7 @@ function buildQueryFilters(params) {
2486
2557
  const compiledClause = buildBooleanQueryClause({
2487
2558
  query,
2488
2559
  version,
2489
- queryIndex: index + 1
2560
+ queryKey: `${index + 1}`
2490
2561
  });
2491
2562
  if (compiledClause.declarations.length > 0) {
2492
2563
  hasCtsIncludesClauses = true;
@@ -2581,7 +2652,6 @@ function buildOrderedItemsClause(sort) {
2581
2652
  * @param params - The parameters for the fetch
2582
2653
  * @param params.setScopeUuids - An array of Set scope UUIDs to filter by
2583
2654
  * @param params.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
2584
- * @param params.propertyVariableUuids - An array of property variable UUIDs to filter by
2585
2655
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2586
2656
  * @param params.sort - Optional sorting configuration applied before pagination.
2587
2657
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
@@ -2593,7 +2663,7 @@ function buildOrderedItemsClause(sort) {
2593
2663
  */
2594
2664
  function buildXQuery$1(params, options) {
2595
2665
  const version = options?.version ?? 2;
2596
- const { propertyVariableUuids, queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = params;
2666
+ const { queries, sort, setScopeUuids, belongsToCollectionScopeUuids, page, pageSize } = params;
2597
2667
  const startPosition = (page - 1) * pageSize + 1;
2598
2668
  const endPosition = page * pageSize;
2599
2669
  const setScopeFilter = `/set[(${setScopeUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ")})]/items/*`;
@@ -2607,10 +2677,6 @@ function buildXQuery$1(params, options) {
2607
2677
  const belongsToCollectionScopeValues = belongsToCollectionScopeUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ");
2608
2678
  filterPredicates.push(`.//properties[property[label/@uuid="${BELONGS_TO_COLLECTION_UUID}" and value/(${belongsToCollectionScopeValues})]]`);
2609
2679
  }
2610
- if (propertyVariableUuids.length > 0) {
2611
- const propertyVariables = propertyVariableUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ");
2612
- filterPredicates.push(`.//properties//property[label[${propertyVariables}]]`);
2613
- }
2614
2680
  if (compiledQueryFilters.predicate.length > 0) filterPredicates.push(`(${compiledQueryFilters.predicate})`);
2615
2681
  const itemFilters = filterPredicates.length > 0 ? `[${filterPredicates.join(" and ")}]` : "";
2616
2682
  const orderedItemsClause = buildOrderedItemsClause(sort);
@@ -2633,7 +2699,6 @@ function buildXQuery$1(params, options) {
2633
2699
  *
2634
2700
  * @param params - The parameters for the fetch
2635
2701
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
2636
- * @param params.propertyVariableUuids - The property variable UUIDs to filter by
2637
2702
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2638
2703
  * @param params.sort - Optional sorting configuration applied before pagination.
2639
2704
  * For propertyValue sorting, dataType is required and the sort key uses the first valid leaf value (value[not(@i)]).
@@ -2648,11 +2713,10 @@ function buildXQuery$1(params, options) {
2648
2713
  async function fetchSetItems(params, itemCategories, options) {
2649
2714
  try {
2650
2715
  const version = options?.version ?? 2;
2651
- const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, sort, page, pageSize } = setItemsParamsSchema.parse(params);
2716
+ const { setScopeUuids, belongsToCollectionScopeUuids, queries, sort, page, pageSize } = setItemsParamsSchema.parse(params);
2652
2717
  const xquery = buildXQuery$1({
2653
2718
  setScopeUuids,
2654
2719
  belongsToCollectionScopeUuids,
2655
- propertyVariableUuids,
2656
2720
  queries,
2657
2721
  sort,
2658
2722
  page,
@@ -2815,6 +2879,14 @@ function aggregateAttributeValues(values) {
2815
2879
  return a.content.localeCompare(b.content);
2816
2880
  });
2817
2881
  }
2882
+ function getPropertyVariableUuidsFromQueries(queries) {
2883
+ const propertyVariableUuids = /* @__PURE__ */ new Set();
2884
+ for (const query of queries) {
2885
+ if (query.target !== "property") continue;
2886
+ for (const propertyVariableUuid of query.propertyVariables) propertyVariableUuids.add(propertyVariableUuid);
2887
+ }
2888
+ return [...propertyVariableUuids];
2889
+ }
2818
2890
  /**
2819
2891
  * Schema for a single property value query item in the OCHRE API response
2820
2892
  */
@@ -2883,7 +2955,6 @@ const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
2883
2955
  * @param params - The parameters for the fetch
2884
2956
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
2885
2957
  * @param params.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
2886
- * @param params.propertyVariableUuids - An array of property variable UUIDs to fetch
2887
2958
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2888
2959
  * @param params.attributes - Whether to return values for bibliographies and periods
2889
2960
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
@@ -2895,10 +2966,10 @@ const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
2895
2966
  */
2896
2967
  function buildXQuery(params, options) {
2897
2968
  const version = options?.version ?? 2;
2898
- const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, attributes, isLimitedToLeafPropertyValues } = params;
2969
+ const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } = params;
2899
2970
  let setScopeFilter = "/set/items/*";
2900
2971
  if (setScopeUuids.length > 0) setScopeFilter = `/set[(${setScopeUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ")})]/items/*`;
2901
- const propertyVariableFilters = propertyVariableUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ");
2972
+ const propertyVariableFilters = getPropertyVariableUuidsFromQueries(queries).map((uuid) => `@uuid="${uuid}"`).join(" or ");
2902
2973
  const compiledQueryFilters = buildQueryFilters({
2903
2974
  queries,
2904
2975
  version
@@ -2919,14 +2990,14 @@ let $property-values :=
2919
2990
  let $item-uuid := $v/ancestor::*[parent::items]/@uuid
2920
2991
  let $variable-uuid := $p/label/@uuid
2921
2992
  return <propertyValue uuid="{$v/@uuid}" rawValue="{$v/@rawValue}" dataType="{$v/@dataType}" itemUuid="{$item-uuid}" variableUuid="{$variable-uuid}">{
2922
- if ($v/content) then string-join($v/content[@xml:lang="eng"]/string, "") else $v/text()
2993
+ if ($v/content) then string-join($v/content[@xml:lang="eng"]//text(), "") else $v/text()
2923
2994
  }</propertyValue>`];
2924
2995
  const returnedSequences = ["$property-values"];
2925
2996
  if (attributes.bibliographies) {
2926
2997
  queryBlocks.push(`let $bibliography-values :=
2927
2998
  for $item in $items
2928
2999
  for $bibliography in $item/bibliographies/bibliography
2929
- let $label := string-join($bibliography/identification/label/content[@xml:lang="eng"]/string, "")
3000
+ let $label := string-join($bibliography/identification/label/content[@xml:lang="eng"]//text(), "")
2930
3001
  where string-length($label) gt 0
2931
3002
  return <attributeValue attributeType="bibliographies" itemUuid="{$item/@uuid}" content="{$label}" />`);
2932
3003
  returnedSequences.push("$bibliography-values");
@@ -2935,7 +3006,7 @@ let $property-values :=
2935
3006
  queryBlocks.push(`let $period-values :=
2936
3007
  for $item in $items
2937
3008
  for $period in $item/periods/period
2938
- let $label := string-join($period/identification/label/content[@xml:lang="eng"]/string, "")
3009
+ let $label := string-join($period/identification/label/content[@xml:lang="eng"]//text(), "")
2939
3010
  where string-length($label) gt 0
2940
3011
  return <attributeValue attributeType="periods" itemUuid="{$item/@uuid}" content="{$label}" />`);
2941
3012
  returnedSequences.push("$period-values");
@@ -2953,7 +3024,6 @@ return (${returnedSequences.join(", ")})`}}</ochre>`;
2953
3024
  *
2954
3025
  * @param params - The parameters for the fetch
2955
3026
  * @param params.setScopeUuids - An array of set scope UUIDs to filter by
2956
- * @param params.propertyVariableUuids - The property variable UUIDs to query by
2957
3027
  * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2958
3028
  * @param params.attributes - Whether to return values for bibliographies and periods
2959
3029
  * @param params.attributes.bibliographies - Whether to return values for bibliographies
@@ -2968,11 +3038,10 @@ return (${returnedSequences.join(", ")})`}}</ochre>`;
2968
3038
  async function fetchSetPropertyValuesByPropertyVariables(params, options) {
2969
3039
  try {
2970
3040
  const version = options?.version ?? 2;
2971
- const { setScopeUuids, belongsToCollectionScopeUuids, propertyVariableUuids, queries, attributes, isLimitedToLeafPropertyValues } = setPropertyValuesByPropertyVariablesParamsSchema.parse(params);
3041
+ const { setScopeUuids, belongsToCollectionScopeUuids, queries, attributes, isLimitedToLeafPropertyValues } = setPropertyValuesByPropertyVariablesParamsSchema.parse(params);
2972
3042
  const xquery = buildXQuery({
2973
3043
  setScopeUuids,
2974
3044
  belongsToCollectionScopeUuids,
2975
- propertyVariableUuids,
2976
3045
  queries,
2977
3046
  attributes,
2978
3047
  isLimitedToLeafPropertyValues
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.20.23",
3
+ "version": "0.20.24",
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",
@@ -49,7 +49,7 @@
49
49
  "@antfu/eslint-config": "^7.7.3",
50
50
  "@types/node": "^24.12.0",
51
51
  "bumpp": "^11.0.1",
52
- "eslint": "^10.0.3",
52
+ "eslint": "^10.1.0",
53
53
  "prettier": "^3.8.1",
54
54
  "tsdown": "^0.21.4",
55
55
  "typescript": "^5.9.3"