@dwtechs/antity-pgsql 0.10.0 → 0.11.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/README.md CHANGED
@@ -160,10 +160,14 @@ type MatchMode =
160
160
  "st_dwithin";
161
161
 
162
162
 
163
+ type Filters = {
164
+ [key: string]: Filter | Filter[]; // Supports both simple (object) and complex (array) formats
165
+ }
166
+
163
167
  type Filter = {
164
168
  value: string | number | boolean | Date | number[];
165
- subProps?: string[];
166
169
  matchMode?: MatchMode;
170
+ operator?: string; // 'and' | 'or' - Used when multiple filters apply to the same property
167
171
  }
168
172
 
169
173
  type ExpressMiddleware = (req: Request, res: Response, next: NextFunction) => void;
@@ -278,6 +282,56 @@ Using substacks simplifies your route definitions and ensures consistent data pr
278
282
  - **deleteArchive()**: Deletes archived rows that were archived before a specific date using a PostgreSQL SECURITY DEFINER function. Expects `req.body.date` to be a Date object.
279
283
  - **getHistory()**: Retrieves modification history for rows from the `log.history` table. Expects `req.body.rows` to be an array of objects with `id` property. Returns all historical records for the specified entity IDs.
280
284
 
285
+ ### Filters
286
+
287
+ Filters support two formats for maximum flexibility:
288
+
289
+ #### Simple Format (Single Filter per Property)
290
+
291
+ Backward-compatible format using a single filter object:
292
+
293
+ ```javascript
294
+ const filters = {
295
+ name: { value: 'John', matchMode: 'contains' },
296
+ age: { value: 30, matchMode: 'equals' },
297
+ archived: { value: false, matchMode: 'equals' }
298
+ };
299
+ ```
300
+
301
+ #### Complex Format (Multiple Filters per Property)
302
+
303
+ Array-based format supporting multiple filters with logical operators:
304
+
305
+ ```javascript
306
+ const filters = {
307
+ // Multiple filters on the same property with OR operator
308
+ name: [
309
+ { value: 'John', matchMode: 'contains', operator: 'or' },
310
+ { value: 'Jane', matchMode: 'contains', operator: 'or' }
311
+ ],
312
+ // Age range with AND operator
313
+ age: [
314
+ { value: 18, matchMode: 'gte', operator: 'and' },
315
+ { value: 65, matchMode: 'lte', operator: 'and' }
316
+ ],
317
+ // Single filter in array format
318
+ archived: [{ value: false, matchMode: 'equals' }]
319
+ };
320
+ ```
321
+
322
+ This generates SQL like:
323
+ ```sql
324
+ WHERE (name LIKE '%John%' OR name LIKE '%Jane%')
325
+ AND (age >= 18 AND age <= 65)
326
+ AND archived = false
327
+ ```
328
+
329
+ **Notes:**
330
+ - Both formats can be mixed in the same filters object
331
+ - When using arrays with a single filter, the operator is optional
332
+ - Default operator is 'AND' if not specified
333
+ - The operator field is case-insensitive
334
+
281
335
 
282
336
  ## Match modes
283
337
 
@@ -36,13 +36,13 @@ export type Filters = {
36
36
  };
37
37
  export type Filter = {
38
38
  value: string | number | boolean | Date | number[];
39
- subProps?: string[];
40
39
  matchMode?: MatchMode;
40
+ operator?: string;
41
41
  };
42
42
  export type { Type };
43
43
 
44
44
  export declare class Property extends BaseProperty {
45
- filter: boolean;
45
+ isFilterable: boolean;
46
46
  operations: Operation[];
47
47
  constructor(
48
48
  key: string,
@@ -160,20 +160,33 @@ function comparator(matchMode) {
160
160
  }
161
161
 
162
162
  function add(filters) {
163
+ var _a, _b;
163
164
  const conditions = [];
164
165
  const args = [];
165
166
  if (filters) {
166
167
  let i = 1;
167
168
  for (const k in filters) {
168
- const { value, matchMode } = filters[k];
169
- const indexes = isArray(value) ? value.map(() => i++) : [i++];
170
- const cond = addOne(k, indexes, matchMode);
171
- if (cond) {
172
- conditions.push(cond);
173
- if (isArray(value))
174
- args.push(...value);
175
- else
176
- args.push(value);
169
+ const filterValue = filters[k];
170
+ const filterArray = isArray(filterValue) ? filterValue : [filterValue];
171
+ const groupConditions = [];
172
+ for (const filter of filterArray) {
173
+ const { value, matchMode } = filter;
174
+ const indexes = isArray(value) ? value.map(() => i++) : [i++];
175
+ const cond = addOne(k, indexes, matchMode);
176
+ if (cond) {
177
+ groupConditions.push(cond);
178
+ if (isArray(value))
179
+ args.push(...value);
180
+ else
181
+ args.push(value);
182
+ }
183
+ }
184
+ if (groupConditions.length > 0) {
185
+ const operator = ((_b = (_a = filterArray[0]) === null || _a === void 0 ? void 0 : _a.operator) === null || _b === void 0 ? void 0 : _b.toUpperCase()) || 'AND';
186
+ const combined = groupConditions.length > 1
187
+ ? `(${groupConditions.join(` ${operator} `)})`
188
+ : groupConditions[0];
189
+ conditions.push(combined);
177
190
  }
178
191
  }
179
192
  }
@@ -465,12 +478,20 @@ function cleanFilters(filters, properties) {
465
478
  continue;
466
479
  }
467
480
  const type$1 = type(prop.type);
468
- const { matchMode: matchMode$1 } = filters[k];
469
- if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
470
- log.warn(`${LOGS_PREFIX}Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
481
+ const filterValue = filters[k];
482
+ const filterArray = isArray(filterValue) ? filterValue : [filterValue];
483
+ const validFilters = filterArray.filter((f) => {
484
+ const { matchMode: matchMode$1 } = f;
485
+ if (!matchMode$1 || !matchMode(type$1, matchMode$1)) {
486
+ log.warn(`${LOGS_PREFIX}Filters: skipping invalid match mode: "${matchMode$1}" for type: "${type$1}" at property: "${k}"`);
487
+ return false;
488
+ }
489
+ return true;
490
+ });
491
+ if (!validFilters.length)
471
492
  delete filters[k];
472
- continue;
473
- }
493
+ else
494
+ filters[k] = validFilters;
474
495
  }
475
496
  }
476
497
  return filters;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dwtechs/antity-pgsql",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Open source library to add PostgreSQL support to @dwtechs/Antity entities.",
5
5
  "keywords": [
6
6
  "entities"