ochre-sdk 0.20.23 → 0.20.25

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;
@@ -1267,13 +1268,12 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1267
1268
  error: string;
1268
1269
  }>;
1269
1270
  //#endregion
1270
- //#region src/utils/fetchers/set/property-values-by-property-variables.d.ts
1271
+ //#region src/utils/fetchers/set/property-values.d.ts
1271
1272
  /**
1272
- * Fetches and parses Set property values by property variables from the OCHRE API
1273
+ * Fetches and parses Set property values from the OCHRE API
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
@@ -1285,9 +1285,8 @@ declare function fetchSetItems<U extends Array<DataCategory> = Array<DataCategor
1285
1285
  * @returns Parsed Set property values and requested attribute values.
1286
1286
  * Returns empty arrays/objects when no matches are found, and null outputs on fetch/parse errors.
1287
1287
  */
1288
- declare function fetchSetPropertyValuesByPropertyVariables(params: {
1288
+ declare function fetchSetPropertyValues(params: {
1289
1289
  setScopeUuids: Array<string>;
1290
- propertyVariableUuids: Array<string>;
1291
1290
  queries?: Array<Query>;
1292
1291
  attributes?: {
1293
1292
  bibliographies: boolean;
@@ -1471,4 +1470,4 @@ declare const DEFAULT_PAGE_SIZE = 48;
1471
1470
  */
1472
1471
  declare function flattenItemProperties<T extends DataCategory = DataCategory, U extends DataCategory | Array<DataCategory> = (T extends "tree" ? Exclude<DataCategory, "tree"> : T extends "set" ? Array<DataCategory> : never)>(item: Item<T, U>): Item<T, U>;
1473
1472
  //#endregion
1474
- export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, LevelContext, LevelContextItem, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyContexts, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValuesByPropertyVariables, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
1473
+ export { ApiVersion, Bibliography, Concept, Context, ContextItem, ContextNode, Coordinate, DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, Data, DataCategory, Event, FileFormat, Gallery, Identification, Image, ImageMap, ImageMapArea, Interpretation, Item, LevelContext, LevelContextItem, License, Link, Metadata, Note, Observation, Period, Person, Property, PropertyContexts, PropertyValue, PropertyValueContent, PropertyValueContentType, PropertyValueQueryItem, PropertyVariable, Query, Resource, Scope, Section, Set, SetAttributeValueQueryItem, SetItemsSort, SetItemsSortDirection, SpatialUnit, Style, Text, Tree, WebBlock, WebBlockLayout, WebElement, WebElementComponent, WebImage, WebSegment, WebSegmentItem, WebTitle, Webpage, Website, WebsiteType, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
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"]),
@@ -860,13 +861,12 @@ function validateSetQueriesOperators(queries, ctx) {
860
861
  });
861
862
  }
862
863
  /**
863
- * Schema for validating the parameters for the Set property values by property variables fetching function
864
+ * Schema for validating the parameters for the Set property values fetching function
864
865
  * @internal
865
866
  */
866
- const setPropertyValuesByPropertyVariablesParamsSchema = z.object({
867
+ const setPropertyValuesParamsSchema = 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,
@@ -2743,7 +2807,7 @@ async function fetchSetItems(params, itemCategories, options) {
2743
2807
  }
2744
2808
  }
2745
2809
  //#endregion
2746
- //#region src/utils/fetchers/set/property-values-by-property-variables.ts
2810
+ //#region src/utils/fetchers/set/property-values.ts
2747
2811
  function parsePropertyValueLabel(content) {
2748
2812
  if (content == null || content === "") return null;
2749
2813
  if (typeof content === "object") return parseStringContent({ content });
@@ -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
  */
@@ -2872,18 +2944,17 @@ const attributeValueQueryItemSchema = z.object({
2872
2944
  content: val.content != null && val.content !== "" ? val.content : null
2873
2945
  }));
2874
2946
  /**
2875
- * Schema for the property values by property variables OCHRE API response
2947
+ * Schema for the property values OCHRE API response
2876
2948
  */
2877
2949
  const responseSchema = z.object({ result: z.union([z.object({ ochre: z.object({
2878
2950
  propertyValue: z.union([propertyValueQueryItemSchema, z.array(propertyValueQueryItemSchema)]).optional(),
2879
2951
  attributeValue: z.union([attributeValueQueryItemSchema, z.array(attributeValueQueryItemSchema)]).optional()
2880
2952
  }) }), z.array(z.unknown()).length(0)]) });
2881
2953
  /**
2882
- * Build an XQuery string to fetch property values by property variables from the OCHRE API
2954
+ * Build an XQuery string to fetch property values from the OCHRE API
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");
@@ -2949,11 +3020,10 @@ ${queryBlocks.join("\n\n")}
2949
3020
  return (${returnedSequences.join(", ")})`}}</ochre>`;
2950
3021
  }
2951
3022
  /**
2952
- * Fetches and parses Set property values by property variables from the OCHRE API
3023
+ * Fetches and parses Set property values from the OCHRE API
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
@@ -2965,14 +3035,13 @@ return (${returnedSequences.join(", ")})`}}</ochre>`;
2965
3035
  * @returns Parsed Set property values and requested attribute values.
2966
3036
  * Returns empty arrays/objects when no matches are found, and null outputs on fetch/parse errors.
2967
3037
  */
2968
- async function fetchSetPropertyValuesByPropertyVariables(params, options) {
3038
+ async function fetchSetPropertyValues(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 } = setPropertyValuesParamsSchema.parse(params);
2972
3042
  const xquery = buildXQuery({
2973
3043
  setScopeUuids,
2974
3044
  belongsToCollectionScopeUuids,
2975
- propertyVariableUuids,
2976
3045
  queries,
2977
3046
  attributes,
2978
3047
  isLimitedToLeafPropertyValues
@@ -3031,7 +3100,7 @@ async function fetchSetPropertyValuesByPropertyVariables(params, options) {
3031
3100
  propertyValues: null,
3032
3101
  propertyValuesByPropertyVariableUuid: null,
3033
3102
  attributeValues: null,
3034
- error: error instanceof Error ? error.message : "Failed to fetch property values by property variables"
3103
+ error: error instanceof Error ? error.message : "Failed to fetch property values"
3035
3104
  };
3036
3105
  }
3037
3106
  }
@@ -4631,4 +4700,4 @@ async function fetchWebsite(abbreviation, options) {
4631
4700
  }
4632
4701
  }
4633
4702
  //#endregion
4634
- export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValuesByPropertyVariables, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
4703
+ export { DEFAULT_API_VERSION, DEFAULT_PAGE_SIZE, fetchGallery, fetchItem, fetchSetItems, fetchSetPropertyValues, fetchWebsite, filterProperties, flattenItemProperties, getLeafPropertyValues, getPropertyByLabel, getPropertyByLabelAndValue, getPropertyByLabelAndValues, getPropertyByUuid, getPropertyValueByLabel, getPropertyValueByUuid, getPropertyValuesByLabel, getPropertyValuesByUuid, getUniqueProperties, getUniquePropertyLabels };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.20.23",
3
+ "version": "0.20.25",
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"