@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/.claude/worktrees/flamboyant-cartwright/.claude/settings.local.json +18 -0
- package/.claude/worktrees/flamboyant-cartwright/IMPLEMENTATION_PROMPT.md +1137 -0
- package/.claude/worktrees/flamboyant-cartwright/LICENSE +201 -0
- package/.claude/worktrees/flamboyant-cartwright/README.md +491 -0
- package/.claude/worktrees/flamboyant-cartwright/examples/demo.js +402 -0
- package/.claude/worktrees/flamboyant-cartwright/package-lock.json +107 -0
- package/.claude/worktrees/flamboyant-cartwright/package.json +29 -0
- package/.claude/worktrees/flamboyant-cartwright/src/SimfinityClient.js +1398 -0
- package/README.md +100 -0
- package/examples/demo.js +52 -0
- package/package.json +1 -1
- package/src/SimfinityClient.js +56 -0
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
package/src/SimfinityClient.js
CHANGED
|
@@ -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
|
}
|