ochre-sdk 0.20.1 → 0.20.3

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
@@ -648,12 +648,37 @@ type PropertyValueQueryItem = {
648
648
  */
649
649
  type Query = {
650
650
  target: "propertyValue";
651
- dataType: Exclude<PropertyValueContentType, "coordinate">;
651
+ dataType: Exclude<Exclude<PropertyValueContentType, "coordinate">, "date" | "dateTime">;
652
+ value: string;
653
+ from?: never;
654
+ to?: never;
655
+ matchMode: "includes" | "exact";
656
+ isCaseSensitive: boolean;
657
+ language: string;
658
+ operator?: "AND" | "OR";
659
+ isNegated?: boolean;
660
+ } | {
661
+ target: "propertyValue";
662
+ dataType: "date" | "dateTime";
663
+ value: string;
664
+ from: string;
665
+ to?: string;
666
+ matchMode: "includes" | "exact";
667
+ isCaseSensitive: boolean;
668
+ language: string;
669
+ operator?: "AND" | "OR";
670
+ isNegated?: boolean;
671
+ } | {
672
+ target: "propertyValue";
673
+ dataType: "date" | "dateTime";
652
674
  value: string;
675
+ from?: string;
676
+ to: string;
653
677
  matchMode: "includes" | "exact";
654
678
  isCaseSensitive: boolean;
655
679
  language: string;
656
680
  operator?: "AND" | "OR";
681
+ isNegated?: boolean;
657
682
  } | {
658
683
  target: "title" | "description" | "image" | "periods" | "bibliography";
659
684
  value: string;
@@ -661,6 +686,7 @@ type Query = {
661
686
  isCaseSensitive: boolean;
662
687
  language: string;
663
688
  operator?: "AND" | "OR";
689
+ isNegated?: boolean;
664
690
  };
665
691
  //#endregion
666
692
  //#region src/types/website.d.ts
@@ -1171,7 +1197,7 @@ declare function fetchItem<T extends DataCategory = DataCategory, U extends Data
1171
1197
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
1172
1198
  * @param params.belongsToCollectionScopeUuids - The collection scope UUIDs to filter by
1173
1199
  * @param params.propertyVariableUuids - The property variable UUIDs to filter by
1174
- * @param params.queries - Ordered queries to combine with AND/OR
1200
+ * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
1175
1201
  * @param params.page - The page number (1-indexed)
1176
1202
  * @param params.pageSize - The number of items per page
1177
1203
  * @param itemCategories - The categories of the items to fetch
package/dist/index.mjs CHANGED
@@ -772,37 +772,64 @@ const setItemsParamsSchema = z.object({
772
772
  setScopeUuids: z.array(uuidSchema).min(1, "At least one set scope UUID is required"),
773
773
  belongsToCollectionScopeUuids: z.array(uuidSchema).default([]),
774
774
  propertyVariableUuids: z.array(uuidSchema).default([]),
775
- queries: z.array(z.discriminatedUnion("target", [z.object({
776
- target: z.literal("propertyValue"),
777
- dataType: z.enum([
778
- "string",
779
- "integer",
780
- "decimal",
781
- "boolean",
782
- "date",
783
- "dateTime",
784
- "time",
785
- "IDREF"
786
- ]),
787
- value: z.string(),
788
- matchMode: z.enum(["includes", "exact"]),
789
- isCaseSensitive: z.boolean(),
790
- language: z.string().default("eng"),
791
- operator: z.enum(["AND", "OR"]).optional()
792
- }), z.object({
793
- target: z.enum([
794
- "title",
795
- "description",
796
- "image",
797
- "periods",
798
- "bibliography"
799
- ]),
800
- value: z.string(),
801
- matchMode: z.enum(["includes", "exact"]),
802
- isCaseSensitive: z.boolean(),
803
- language: z.string().default("eng"),
804
- operator: z.enum(["AND", "OR"]).optional()
805
- })])).default([]),
775
+ queries: z.array(z.union([
776
+ z.object({
777
+ target: z.literal("propertyValue"),
778
+ dataType: z.enum([
779
+ "string",
780
+ "integer",
781
+ "decimal",
782
+ "boolean",
783
+ "time",
784
+ "IDREF"
785
+ ]),
786
+ value: z.string(),
787
+ matchMode: z.enum(["includes", "exact"]),
788
+ isCaseSensitive: z.boolean(),
789
+ language: z.string().default("eng"),
790
+ operator: z.enum(["AND", "OR"]).optional(),
791
+ isNegated: z.boolean().optional().default(false)
792
+ }).strict(),
793
+ z.object({
794
+ target: z.literal("propertyValue"),
795
+ dataType: z.enum(["date", "dateTime"]),
796
+ value: z.string(),
797
+ from: z.string(),
798
+ to: z.string().optional(),
799
+ matchMode: z.enum(["includes", "exact"]),
800
+ isCaseSensitive: z.boolean(),
801
+ language: z.string().default("eng"),
802
+ operator: z.enum(["AND", "OR"]).optional(),
803
+ isNegated: z.boolean().optional().default(false)
804
+ }).strict(),
805
+ z.object({
806
+ target: z.literal("propertyValue"),
807
+ dataType: z.enum(["date", "dateTime"]),
808
+ value: z.string(),
809
+ from: z.string().optional(),
810
+ to: z.string(),
811
+ matchMode: z.enum(["includes", "exact"]),
812
+ isCaseSensitive: z.boolean(),
813
+ language: z.string().default("eng"),
814
+ operator: z.enum(["AND", "OR"]).optional(),
815
+ isNegated: z.boolean().optional().default(false)
816
+ }).strict(),
817
+ z.object({
818
+ target: z.enum([
819
+ "title",
820
+ "description",
821
+ "image",
822
+ "periods",
823
+ "bibliography"
824
+ ]),
825
+ value: z.string(),
826
+ matchMode: z.enum(["includes", "exact"]),
827
+ isCaseSensitive: z.boolean(),
828
+ language: z.string().default("eng"),
829
+ operator: z.enum(["AND", "OR"]).optional(),
830
+ isNegated: z.boolean().optional().default(false)
831
+ }).strict()
832
+ ])).default([]),
806
833
  page: z.number().min(1, "Page must be positive").default(1),
807
834
  pageSize: z.number().min(1, "Page size must be positive").default(DEFAULT_PAGE_SIZE)
808
835
  }).superRefine((value, ctx) => {
@@ -2089,13 +2116,27 @@ function buildStringMatchPredicate(params) {
2089
2116
  return `${comparedPath} = ${comparedValueLiteral}`;
2090
2117
  }
2091
2118
  /**
2119
+ * Build a date/dateTime range predicate for an XQuery string.
2120
+ */
2121
+ function buildDateRangePredicate(params) {
2122
+ const { from, to } = params;
2123
+ const conditions = [];
2124
+ if (from != null) conditions.push(`(value/@rawValue ge ${stringLiteral(from)})`);
2125
+ if (to != null) conditions.push(`(value/@rawValue le ${stringLiteral(to)})`);
2126
+ return conditions.join(" and ");
2127
+ }
2128
+ /**
2092
2129
  * Build a property value predicate for an XQuery string
2093
2130
  * @param query - The propertyValue query
2094
2131
  * @returns The property value predicate
2095
2132
  */
2096
2133
  function buildPropertyValuePredicate(query) {
2097
2134
  if (query.dataType === "IDREF") return `.//properties//property[value[@uuid=${stringLiteral(query.value)}]]`;
2098
- if (query.dataType === "date" || query.dataType === "dateTime" || query.dataType === "time" || query.dataType === "integer" || query.dataType === "decimal" || query.dataType === "boolean") return `.//properties//property[value[@rawValue=${stringLiteral(query.value)}]]`;
2135
+ if (query.dataType === "date" || query.dataType === "dateTime") return `.//properties//property[(label/@uuid=${stringLiteral(query.value)}) and ${buildDateRangePredicate({
2136
+ from: query.from,
2137
+ to: query.to
2138
+ })}]`;
2139
+ if (query.dataType === "time" || query.dataType === "integer" || query.dataType === "decimal" || query.dataType === "boolean") return `.//properties//property[value[@rawValue=${stringLiteral(query.value)}]]`;
2099
2140
  return `.//properties//property[${buildStringMatchPredicate({
2100
2141
  path: `string-join(value/content[@xml:lang="${query.language}"]/string, "")`,
2101
2142
  value: query.value,
@@ -2109,43 +2150,54 @@ function buildPropertyValuePredicate(query) {
2109
2150
  * @returns The query predicate
2110
2151
  */
2111
2152
  function buildQueryPredicate(query) {
2112
- const stringMatchParams = {
2113
- value: query.value,
2114
- matchMode: query.matchMode,
2115
- isCaseSensitive: query.isCaseSensitive,
2116
- language: query.language
2117
- };
2118
2153
  switch (query.target) {
2119
2154
  case "title": return buildStringMatchPredicate({
2120
2155
  path: `string-join(identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2121
- ...stringMatchParams
2156
+ value: query.value,
2157
+ matchMode: query.matchMode,
2158
+ isCaseSensitive: query.isCaseSensitive
2122
2159
  });
2123
2160
  case "description": return buildStringMatchPredicate({
2124
2161
  path: `string-join(description/content[@xml:lang="${query.language}"]/string, "")`,
2125
- ...stringMatchParams
2162
+ value: query.value,
2163
+ matchMode: query.matchMode,
2164
+ isCaseSensitive: query.isCaseSensitive
2126
2165
  });
2127
2166
  case "periods": return buildStringMatchPredicate({
2128
2167
  path: `string-join(periods/period/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2129
- ...stringMatchParams
2168
+ value: query.value,
2169
+ matchMode: query.matchMode,
2170
+ isCaseSensitive: query.isCaseSensitive
2130
2171
  });
2131
2172
  case "bibliography": return buildStringMatchPredicate({
2132
2173
  path: `string-join(bibliographies/bibliography/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2133
- ...stringMatchParams
2174
+ value: query.value,
2175
+ matchMode: query.matchMode,
2176
+ isCaseSensitive: query.isCaseSensitive
2134
2177
  });
2135
2178
  case "image": return buildStringMatchPredicate({
2136
2179
  path: `string-join(image/identification/label/content[@xml:lang="${query.language}"]/string, "")`,
2137
- ...stringMatchParams
2180
+ value: query.value,
2181
+ matchMode: query.matchMode,
2182
+ isCaseSensitive: query.isCaseSensitive
2138
2183
  });
2139
2184
  case "propertyValue": return buildPropertyValuePredicate(query);
2140
2185
  }
2141
2186
  }
2142
2187
  /**
2188
+ * Build a boolean query clause for an XQuery string.
2189
+ */
2190
+ function buildBooleanQueryClause(query) {
2191
+ const baseClause = `(${buildQueryPredicate(query)})`;
2192
+ return query.isNegated ? `not(${baseClause})` : baseClause;
2193
+ }
2194
+ /**
2143
2195
  * Build an XQuery string to fetch Set items from the OCHRE API
2144
2196
  * @param params - The parameters for the fetch
2145
2197
  * @param params.setScopeUuids - An array of Set scope UUIDs to filter by
2146
2198
  * @param params.belongsToCollectionScopeUuids - An array of collection scope UUIDs to filter by
2147
2199
  * @param params.propertyVariableUuids - An array of property variable UUIDs to filter by
2148
- * @param params.queries - Ordered queries to combine with AND/OR
2200
+ * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2149
2201
  * @param params.page - The page number (1-indexed)
2150
2202
  * @param params.pageSize - The number of items per page
2151
2203
  * @param options - Options for the fetch
@@ -2159,9 +2211,9 @@ function buildXQuery$1(params, options) {
2159
2211
  const endPosition = page * pageSize;
2160
2212
  const setScopeFilter = `/set[(${setScopeUuids.map((uuid) => `@uuid="${uuid}"`).join(" or ")})]/items/*`;
2161
2213
  const queryFilters = queries.map((query, index) => {
2162
- const predicate = `(${buildQueryPredicate(query)})`;
2163
- if (index === 0) return predicate;
2164
- return `${query.operator === "OR" ? "or" : "and"} ${predicate}`;
2214
+ const clause = buildBooleanQueryClause(query);
2215
+ if (index === 0) return clause;
2216
+ return `${query.operator === "OR" ? "or" : "and"} ${clause}`;
2165
2217
  }).join(" ");
2166
2218
  const filterPredicates = [];
2167
2219
  if (belongsToCollectionScopeUuids.length > 0) {
@@ -2194,7 +2246,7 @@ function buildXQuery$1(params, options) {
2194
2246
  * @param params.setScopeUuids - The Set scope UUIDs to filter by
2195
2247
  * @param params.belongsToCollectionScopeUuids - The collection scope UUIDs to filter by
2196
2248
  * @param params.propertyVariableUuids - The property variable UUIDs to filter by
2197
- * @param params.queries - Ordered queries to combine with AND/OR
2249
+ * @param params.queries - Ordered queries to combine with AND/OR and optional NOT via negation
2198
2250
  * @param params.page - The page number (1-indexed)
2199
2251
  * @param params.pageSize - The number of items per page
2200
2252
  * @param itemCategories - The categories of the items to fetch
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ochre-sdk",
3
- "version": "0.20.1",
3
+ "version": "0.20.3",
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",
@@ -47,13 +47,12 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@antfu/eslint-config": "^7.6.1",
50
- "@types/node": "^24.10.13",
50
+ "@types/node": "^24.10.14",
51
51
  "bumpp": "^10.4.1",
52
52
  "eslint": "^10.0.2",
53
53
  "prettier": "^3.8.1",
54
54
  "tsdown": "^0.20.3",
55
- "typescript": "^5.9.3",
56
- "vitest": "^4.0.18"
55
+ "typescript": "^5.9.3"
57
56
  },
58
57
  "scripts": {
59
58
  "dev": "tsdown src/index.ts --watch",
@@ -65,7 +64,6 @@
65
64
  "format": "prettier --cache --check .",
66
65
  "format:fix": "prettier --cache --write --list-different .",
67
66
  "check-types": "tsc --noEmit",
68
- "test": "vitest run",
69
67
  "release": "bumpp"
70
68
  }
71
69
  }