@adobe/spacecat-shared-data-access 4.18.0 → 4.20.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [@adobe/spacecat-shared-data-access-v4.20.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.19.0...@adobe/spacecat-shared-data-access-v4.20.0) (2026-08-12)
2
+
3
+ ### Features
4
+
5
+ * **data-access:** compound AND filter and orderBy column for postgrest queries ([#1874](https://github.com/adobe/spacecat-shared/issues/1874)) ([620b37e](https://github.com/adobe/spacecat-shared/commit/620b37eb1bc252c9bdd01661037de6fd7e0bfe35))
6
+
7
+ ## [@adobe/spacecat-shared-data-access-v4.19.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.18.0...@adobe/spacecat-shared-data-access-v4.19.0) (2026-08-11)
8
+
9
+ ### Features
10
+
11
+ * add support for searching trial users by external user id ([#1869](https://github.com/adobe/spacecat-shared/issues/1869)) ([ec48340](https://github.com/adobe/spacecat-shared/commit/ec483403ac2b118abea814309079716fc516042a))
12
+
1
13
  ## [@adobe/spacecat-shared-data-access-v4.18.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v4.17.0...@adobe/spacecat-shared-data-access-v4.18.0) (2026-08-11)
2
14
 
3
15
  ### Features
package/CLAUDE.md CHANGED
@@ -178,7 +178,7 @@ This is the same client instance used internally by entity collections — same
178
178
  async findByStatus(status) {
179
179
  return this.all(
180
180
  (attrs, op) => op.eq(attrs.status, status),
181
- { limit: 100, order: { field: 'createdAt', direction: 'desc' } }
181
+ { limit: 100, orderBy: { attribute: 'createdAt', direction: 'desc' } }
182
182
  );
183
183
  }
184
184
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "4.18.0",
3
+ "version": "4.20.0",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "engines": {
@@ -428,8 +428,25 @@ class BaseCollection {
428
428
  this.#logAndThrowError(`Failed to query [${this.entityName}]: query proxy [${options.index}] not found`);
429
429
  }
430
430
 
431
- const orderFields = this.#getOrderFields(indexName, keys);
432
- const ascending = options.order === 'asc';
431
+ const hasExplicitOrderBy = isObject(options.orderBy) && hasText(options.orderBy.attribute);
432
+ let explicitAscending;
433
+ if (hasExplicitOrderBy) {
434
+ const { toDbMap } = this.fieldMaps;
435
+ if (!Object.prototype.hasOwnProperty.call(toDbMap, options.orderBy.attribute)) {
436
+ this.#logAndThrowError(`Failed to query [${this.entityName}]: unknown orderBy attribute [${options.orderBy.attribute}]`);
437
+ }
438
+ const direction = options.orderBy.direction === undefined
439
+ ? 'asc'
440
+ : String(options.orderBy.direction).toLowerCase();
441
+ if (direction !== 'asc' && direction !== 'desc') {
442
+ this.#logAndThrowError(`Failed to query [${this.entityName}]: invalid orderBy direction [${options.orderBy.direction}]`);
443
+ }
444
+ explicitAscending = direction === 'asc';
445
+ }
446
+ const orderFields = hasExplicitOrderBy
447
+ ? [this.#toDbField(options.orderBy.attribute)]
448
+ : this.#getOrderFields(indexName, keys);
449
+ const ascending = hasExplicitOrderBy ? explicitAscending : options.order === 'asc';
433
450
  let query = this.postgrestService
434
451
  .from(this.tableName)
435
452
  .select(select);
@@ -33,6 +33,7 @@ export interface QueryOptions {
33
33
  index?: string;
34
34
  limit?: number;
35
35
  order?: string;
36
+ orderBy?: { attribute: string; direction?: 'asc' | 'desc' };
36
37
  attributes?: string[];
37
38
  cursor?: string;
38
39
  /**
@@ -52,6 +52,10 @@ const schema = new SchemaBuilder(TrialUser, TrialUserCollection)
52
52
  .addIndex(
53
53
  { composite: ['organizationId'] },
54
54
  { composite: ['updatedAt'] },
55
+ )
56
+ .addIndex(
57
+ { composite: ['externalUserId'] },
58
+ { composite: ['updatedAt'] },
55
59
  );
56
60
 
57
61
  export default schema.build();
@@ -152,6 +152,7 @@ const applyWhere = (query, whereFn, toDbMap) => {
152
152
  like: (field, value) => ({ type: 'like', field, value }),
153
153
  ilike: (field, value) => ({ type: 'ilike', field, value }),
154
154
  contains: (field, value) => ({ type: 'contains', field, value }),
155
+ and: (...conditions) => ({ type: 'and', conditions: conditions.filter(Boolean) }),
155
156
  };
156
157
 
157
158
  const expression = whereFn(attrs, op);
@@ -159,37 +160,43 @@ const applyWhere = (query, whereFn, toDbMap) => {
159
160
  return query;
160
161
  }
161
162
 
162
- switch (expression.type) {
163
- case 'eq':
164
- return query.eq(expression.field, expression.value);
165
- case 'ne':
166
- return query.neq(expression.field, expression.value);
167
- case 'gt':
168
- return query.gt(expression.field, expression.value);
169
- case 'gte':
170
- return query.gte(expression.field, expression.value);
171
- case 'lt':
172
- return query.lt(expression.field, expression.value);
173
- case 'lte':
174
- return query.lte(expression.field, expression.value);
175
- case 'in':
176
- return query.in(
177
- expression.field,
178
- Array.isArray(expression.value) ? expression.value : [expression.value],
179
- );
180
- case 'is':
181
- return query.is(expression.field, expression.value);
182
- case 'like':
183
- return query.like(expression.field, expression.value);
184
- case 'ilike':
185
- return query.ilike(expression.field, expression.value);
186
- case 'contains': {
187
- const value = Array.isArray(expression.value) ? expression.value : [expression.value];
188
- return query.contains(expression.field, value);
163
+ const applyExpr = (q, expr) => {
164
+ switch (expr.type) {
165
+ case 'and':
166
+ return (expr.conditions || []).reduce((acc, cond) => applyExpr(acc, cond), q);
167
+ case 'eq':
168
+ return q.eq(expr.field, expr.value);
169
+ case 'ne':
170
+ return q.neq(expr.field, expr.value);
171
+ case 'gt':
172
+ return q.gt(expr.field, expr.value);
173
+ case 'gte':
174
+ return q.gte(expr.field, expr.value);
175
+ case 'lt':
176
+ return q.lt(expr.field, expr.value);
177
+ case 'lte':
178
+ return q.lte(expr.field, expr.value);
179
+ case 'in':
180
+ return q.in(
181
+ expr.field,
182
+ Array.isArray(expr.value) ? expr.value : [expr.value],
183
+ );
184
+ case 'is':
185
+ return q.is(expr.field, expr.value);
186
+ case 'like':
187
+ return q.like(expr.field, expr.value);
188
+ case 'ilike':
189
+ return q.ilike(expr.field, expr.value);
190
+ case 'contains': {
191
+ const value = Array.isArray(expr.value) ? expr.value : [expr.value];
192
+ return q.contains(expr.field, value);
193
+ }
194
+ default:
195
+ throw new Error(`Unsupported where operator: ${expr.type}`);
189
196
  }
190
- default:
191
- throw new Error(`Unsupported where operator: ${expression.type}`);
192
- }
197
+ };
198
+
199
+ return applyExpr(query, expression);
193
200
  };
194
201
 
195
202
  export {