@simtlix/simfinity-js-client 1.0.6 → 1.1.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
@@ -83,6 +83,106 @@ Filter by a collection field using an array of term objects:
83
83
  ])
84
84
  ```
85
85
 
86
+ #### `.or(groups)` / `.and(groups)`
87
+
88
+ Add AND/OR logical filter groups for complex boolean conditions. Each method accepts an array of `QLFilterGroup` objects and can be called multiple times (groups accumulate). These combine with existing flat `.where()` filters via AND at the top level.
89
+
90
+ A `QLFilterGroup` is a plain object with optional `AND`, `OR`, and `conditions` fields:
91
+
92
+ ```js
93
+ {
94
+ conditions: [{ field: 'category', operator: 'EQ', value: 'Drama' }],
95
+ AND: [/* nested QLFilterGroup objects */],
96
+ OR: [/* nested QLFilterGroup objects */],
97
+ }
98
+ ```
99
+
100
+ **Simple OR** -- return series in either Drama or Comedy:
101
+
102
+ ```js
103
+ const results = await client.find('serie')
104
+ .or([
105
+ SimfinityClient.condition('categories', 'EQ', 'Drama'),
106
+ SimfinityClient.condition('categories', 'EQ', 'Comedy'),
107
+ ])
108
+ .fields('id name categories')
109
+ .exec();
110
+ ```
111
+
112
+ **Flat filters combined with OR** -- flat `.where()` is ANDed with the OR group:
113
+
114
+ ```js
115
+ const results = await client.find('serie')
116
+ .where('categories', 'NE', 'Horror')
117
+ .or([
118
+ SimfinityClient.condition('name', 'LIKE', 'Breaking'),
119
+ SimfinityClient.condition('name', 'LIKE', 'Game'),
120
+ ])
121
+ .fields('id name categories')
122
+ .exec();
123
+ // Equivalent to: categories != "Horror" AND (name LIKE "Breaking" OR name LIKE "Game")
124
+ ```
125
+
126
+ **Nested AND inside OR**:
127
+
128
+ ```js
129
+ const results = await client.find('serie')
130
+ .or([
131
+ { AND: [
132
+ SimfinityClient.condition('categories', 'EQ', 'Drama'),
133
+ SimfinityClient.condition('year', 'GTE', 2020),
134
+ ]},
135
+ { AND: [
136
+ SimfinityClient.condition('categories', 'EQ', 'Comedy'),
137
+ SimfinityClient.condition('year', 'GTE', 2015),
138
+ ]},
139
+ ])
140
+ .exec();
141
+ // Equivalent to: (categories = "Drama" AND year >= 2020) OR (categories = "Comedy" AND year >= 2015)
142
+ ```
143
+
144
+ **AND with nested OR groups**:
145
+
146
+ ```js
147
+ const results = await client.find('serie')
148
+ .where('year', 'GTE', 2000)
149
+ .and([
150
+ { OR: [
151
+ SimfinityClient.condition('categories', 'EQ', 'Drama'),
152
+ SimfinityClient.condition('categories', 'EQ', 'Comedy'),
153
+ ]},
154
+ { OR: [
155
+ SimfinityClient.condition('director', 'EQ', 'UK', 'country'),
156
+ SimfinityClient.condition('director', 'EQ', 'US', 'country'),
157
+ ]},
158
+ ])
159
+ .exec();
160
+ // Equivalent to: year >= 2000 AND (Drama OR Comedy) AND (UK OR US director)
161
+ ```
162
+
163
+ **Relationship path filtering** -- use the `path` parameter for object field conditions:
164
+
165
+ ```js
166
+ .or([
167
+ SimfinityClient.condition('director', 'LIKE', 'Adams', 'name'),
168
+ SimfinityClient.condition('director', 'LIKE', 'Nolan', 'name'),
169
+ ])
170
+ ```
171
+
172
+ The Aggregate Builder also supports `.or()` and `.and()` with identical behavior. The server enforces a maximum nesting depth of 5 levels.
173
+
174
+ #### `SimfinityClient.condition(field, operator, value [, path])`
175
+
176
+ Static convenience factory for creating a filter group with a single condition. Returns a `QLFilterGroup` object:
177
+
178
+ ```js
179
+ SimfinityClient.condition('category', 'EQ', 'Drama')
180
+ // Equivalent to: { conditions: [{ field: 'category', operator: 'EQ', value: 'Drama' }] }
181
+
182
+ SimfinityClient.condition('author', 'LIKE', 'Adams', 'name')
183
+ // Equivalent to: { conditions: [{ field: 'author', operator: 'LIKE', value: 'Adams', path: 'name' }] }
184
+ ```
185
+
86
186
  #### `.joinObject(path, fields)`
87
187
 
88
188
  Include a related object's fields in the selection.
package/examples/demo.js CHANGED
@@ -344,6 +344,58 @@ const log = (label, data) => {
344
344
  totalCount: extensions?.count,
345
345
  });
346
346
 
347
+ // -----------------------------------------------------------------------
348
+ // 28. find() with OR filter
349
+ // -----------------------------------------------------------------------
350
+ const orResults = await client.find(serieType)
351
+ .or([
352
+ SimfinityClient.condition('categories', 'EQ', 'Drama'),
353
+ SimfinityClient.condition('categories', 'EQ', 'Comedy'),
354
+ ])
355
+ .fields('id name categories')
356
+ .exec();
357
+ log('28. find() -- OR filter (Drama OR Comedy)', orResults);
358
+
359
+ // -----------------------------------------------------------------------
360
+ // 29. find() with flat where + OR combined
361
+ // -----------------------------------------------------------------------
362
+ const combinedOrResults = await client.find(serieType)
363
+ .where('categories', 'NE', 'Horror')
364
+ .or([
365
+ SimfinityClient.condition('name', 'LIKE', 'Breaking'),
366
+ SimfinityClient.condition('name', 'LIKE', 'Game'),
367
+ ])
368
+ .fields('id name categories')
369
+ .exec();
370
+ log('29. find() -- flat where + OR (not Horror AND (name LIKE Breaking OR Game))', combinedOrResults);
371
+
372
+ // -----------------------------------------------------------------------
373
+ // 30. find() with AND containing nested OR
374
+ // -----------------------------------------------------------------------
375
+ const nestedAndOrResults = await client.find(serieType)
376
+ .and([
377
+ { OR: [
378
+ SimfinityClient.condition('categories', 'EQ', 'Drama'),
379
+ SimfinityClient.condition('categories', 'EQ', 'Comedy'),
380
+ ]},
381
+ ])
382
+ .fields('id name categories')
383
+ .exec();
384
+ log('30. find() -- AND with nested OR groups', nestedAndOrResults);
385
+
386
+ // -----------------------------------------------------------------------
387
+ // 31. aggregate() with OR filter
388
+ // -----------------------------------------------------------------------
389
+ const aggOrResults = await client.aggregate(seasonType)
390
+ .groupBy('serie')
391
+ .fact('COUNT', 'seasonCount', 'id')
392
+ .or([
393
+ SimfinityClient.condition('year', 'GTE', 2020),
394
+ SimfinityClient.condition('year', 'LTE', 2010),
395
+ ])
396
+ .exec();
397
+ log('31. aggregate() -- OR filter (year >= 2020 OR year <= 2010)', aggOrResults);
398
+
347
399
  console.log('\n' + '='.repeat(60));
348
400
  console.log('Demo complete.');
349
401
  console.log('='.repeat(60));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simtlix/simfinity-js-client",
3
- "version": "1.0.6",
3
+ "version": "1.1.0",
4
4
  "description": "Introspection-driven GraphQL client for simfinity-js APIs",
5
5
  "type": "module",
6
6
  "main": "src/SimfinityClient.js",
@@ -227,6 +227,30 @@ class QueryBuilder {
227
227
  return this;
228
228
  }
229
229
 
230
+ or(groups) {
231
+ if (!Array.isArray(groups)) {
232
+ throw new Error('or() expects an array of QLFilterGroup objects');
233
+ }
234
+ if (this._variables.OR) {
235
+ this._variables.OR.push(...groups);
236
+ } else {
237
+ this._variables.OR = [...groups];
238
+ }
239
+ return this;
240
+ }
241
+
242
+ and(groups) {
243
+ if (!Array.isArray(groups)) {
244
+ throw new Error('and() expects an array of QLFilterGroup objects');
245
+ }
246
+ if (this._variables.AND) {
247
+ this._variables.AND.push(...groups);
248
+ } else {
249
+ this._variables.AND = [...groups];
250
+ }
251
+ return this;
252
+ }
253
+
230
254
  // -- Relation Field Selection --------------------------------------------
231
255
 
232
256
  joinCollection(path, fields, filter) {
@@ -418,6 +442,30 @@ class AggregateBuilder {
418
442
  return this;
419
443
  }
420
444
 
445
+ or(groups) {
446
+ if (!Array.isArray(groups)) {
447
+ throw new Error('or() expects an array of QLFilterGroup objects');
448
+ }
449
+ if (this._variables.OR) {
450
+ this._variables.OR.push(...groups);
451
+ } else {
452
+ this._variables.OR = [...groups];
453
+ }
454
+ return this;
455
+ }
456
+
457
+ and(groups) {
458
+ if (!Array.isArray(groups)) {
459
+ throw new Error('and() expects an array of QLFilterGroup objects');
460
+ }
461
+ if (this._variables.AND) {
462
+ this._variables.AND.push(...groups);
463
+ } else {
464
+ this._variables.AND = [...groups];
465
+ }
466
+ return this;
467
+ }
468
+
421
469
  page(page, size, count) {
422
470
  const pagination = { page, size };
423
471
  if (count !== undefined) pagination.count = count;
@@ -1339,4 +1387,12 @@ export default class SimfinityClient {
1339
1387
  throw new Error('Client not initialized. Call init() first.');
1340
1388
  }
1341
1389
  }
1390
+
1391
+ // -- Static Helpers -------------------------------------------------------
1392
+
1393
+ static condition(field, operator, value, path) {
1394
+ const cond = { field, operator, value };
1395
+ if (path !== undefined) cond.path = path;
1396
+ return { conditions: [cond] };
1397
+ }
1342
1398
  }