@mastra/opensearch 0.0.0-pass-headers-for-create-mastra-client-20250530010057 → 0.0.0-remove-unused-import-20250909212718

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.
@@ -1,660 +0,0 @@
1
- import { beforeEach, describe, expect, it } from 'vitest';
2
-
3
- import { OpenSearchFilterTranslator } from './filter';
4
-
5
- describe('OpenSearchFilterTranslator', () => {
6
- let translator: OpenSearchFilterTranslator;
7
-
8
- beforeEach(() => {
9
- translator = new OpenSearchFilterTranslator();
10
- });
11
-
12
- // Basic Filter Operations
13
- describe('basic operations', () => {
14
- it('handles empty filters', () => {
15
- expect(translator.translate({})).toEqual(undefined);
16
- expect(translator.translate(null as any)).toEqual(undefined);
17
- expect(translator.translate(undefined as any)).toEqual(undefined);
18
- });
19
-
20
- it('translates simple field equality to term query', () => {
21
- const filter = { field: 'value' };
22
- expect(translator.translate(filter)).toEqual({
23
- term: { 'metadata.field.keyword': 'value' },
24
- });
25
- });
26
-
27
- it('translates multiple top-level fields to bool must', () => {
28
- const filter = { field1: 'value1', field2: 'value2' };
29
- expect(translator.translate(filter)).toEqual({
30
- bool: {
31
- must: [{ term: { 'metadata.field1.keyword': 'value1' } }, { term: { 'metadata.field2.keyword': 'value2' } }],
32
- },
33
- });
34
- });
35
-
36
- it('handles nested objects', () => {
37
- const filter = {
38
- user: {
39
- profile: {
40
- age: 25,
41
- name: 'John',
42
- },
43
- },
44
- };
45
- expect(translator.translate(filter)).toEqual({
46
- bool: {
47
- must: [
48
- {
49
- bool: {
50
- must: [
51
- { term: { 'metadata.user.profile.age': 25 } },
52
- { term: { 'metadata.user.profile.name.keyword': 'John' } },
53
- ],
54
- },
55
- },
56
- ],
57
- },
58
- });
59
- });
60
- });
61
-
62
- // Comparison Operators
63
- describe('comparison operators', () => {
64
- it('translates $eq operator', () => {
65
- const filter = { field: { $eq: 'value' } };
66
- expect(translator.translate(filter)).toEqual({
67
- term: { 'metadata.field.keyword': 'value' },
68
- });
69
- });
70
-
71
- it('translates $ne operator', () => {
72
- const filter = { field: { $ne: 'value' } };
73
- expect(translator.translate(filter)).toEqual({
74
- bool: {
75
- must_not: [{ term: { 'metadata.field.keyword': 'value' } }],
76
- },
77
- });
78
- });
79
-
80
- it('handles date values', () => {
81
- const date = new Date('2024-01-01');
82
- const filter = { timestamp: { $gt: date } };
83
- expect(translator.translate(filter)).toEqual({
84
- range: { 'metadata.timestamp': { gt: date.toISOString() } },
85
- });
86
- });
87
- });
88
-
89
- // Logical Operators
90
- describe('logical operators', () => {
91
- it('translates $and operator', () => {
92
- const filter = {
93
- $and: [{ field1: 'value1' }, { field2: 'value2' }],
94
- };
95
- expect(translator.translate(filter)).toEqual({
96
- bool: {
97
- must: [{ term: { 'metadata.field1.keyword': 'value1' } }, { term: { 'metadata.field2.keyword': 'value2' } }],
98
- },
99
- });
100
- });
101
-
102
- it('translates $or operator', () => {
103
- const filter = {
104
- $or: [{ field1: 'value1' }, { field2: 'value2' }],
105
- };
106
- expect(translator.translate(filter)).toEqual({
107
- bool: {
108
- should: [
109
- { term: { 'metadata.field1.keyword': 'value1' } },
110
- { term: { 'metadata.field2.keyword': 'value2' } },
111
- ],
112
- },
113
- });
114
- });
115
-
116
- it('translates $not operator', () => {
117
- const filter = {
118
- $not: { field: 'value' },
119
- };
120
- expect(translator.translate(filter)).toEqual({
121
- bool: {
122
- must_not: [{ term: { 'metadata.field.keyword': 'value' } }],
123
- },
124
- });
125
- });
126
-
127
- it('translates $not with $eq operator', () => {
128
- const filter = { field: { $not: { $eq: 'value' } } };
129
- expect(translator.translate(filter)).toEqual({
130
- bool: {
131
- must_not: [{ term: { 'metadata.field.keyword': 'value' } }],
132
- },
133
- });
134
- });
135
-
136
- it('translates $not with $ne operator', () => {
137
- const filter = { field: { $not: { $ne: 'value' } } };
138
- expect(translator.translate(filter)).toEqual({
139
- bool: {
140
- must_not: [
141
- {
142
- bool: {
143
- must_not: [{ term: { 'metadata.field.keyword': 'value' } }],
144
- },
145
- },
146
- ],
147
- },
148
- });
149
- });
150
-
151
- it('translates $not with $eq null', () => {
152
- const filter = { field: { $not: { $eq: null } } };
153
- expect(translator.translate(filter)).toEqual({
154
- exists: { field: 'metadata.field' },
155
- });
156
- });
157
-
158
- it('translates $not with $ne null', () => {
159
- const filter = { field: { $not: { $ne: null } } };
160
- expect(translator.translate(filter)).toEqual({
161
- bool: {
162
- must_not: [{ exists: { field: 'metadata.field' } }],
163
- },
164
- });
165
- });
166
-
167
- it('translates $not with nested fields', () => {
168
- const filter = { 'user.profile.age': { $not: { $gt: 25 } } };
169
- expect(translator.translate(filter)).toEqual({
170
- bool: {
171
- must_not: [
172
- {
173
- range: { 'metadata.user.profile.age': { gt: 25 } },
174
- },
175
- ],
176
- },
177
- });
178
- });
179
-
180
- it('translates $not with multiple operators', () => {
181
- const filter = { price: { $not: { $gte: 30, $lte: 70 } } };
182
- expect(translator.translate(filter)).toEqual({
183
- bool: {
184
- must_not: [
185
- {
186
- range: { 'metadata.price': { gte: 30, lte: 70 } },
187
- },
188
- ],
189
- },
190
- });
191
- });
192
-
193
- it('handles empty $and array', () => {
194
- const filter = {
195
- $and: [],
196
- };
197
- // Empty $and should match everything
198
- expect(translator.translate(filter)).toEqual({ match_all: {} });
199
- });
200
-
201
- it('handles empty $or array', () => {
202
- const filter = {
203
- $or: [],
204
- };
205
- // Empty $or should match nothing
206
- expect(translator.translate(filter)).toEqual({
207
- bool: {
208
- must_not: [{ match_all: {} }],
209
- },
210
- });
211
- });
212
-
213
- it('throws error for empty $not condition', () => {
214
- const filter = {
215
- $not: {},
216
- };
217
- expect(() => translator.translate(filter)).toThrow('not operator cannot be empty');
218
- });
219
-
220
- it('handles $not with comparison operators', () => {
221
- const filter = {
222
- price: { $not: { $gt: 100 } },
223
- };
224
- expect(translator.translate(filter)).toEqual({
225
- bool: {
226
- must_not: [{ range: { 'metadata.price': { gt: 100 } } }],
227
- },
228
- });
229
- });
230
-
231
- it('handles nested $not with $or', () => {
232
- const filter = {
233
- $not: { $or: [{ category: 'electronics' }, { category: 'books' }] },
234
- };
235
- expect(translator.translate(filter)).toEqual({
236
- bool: {
237
- must_not: [
238
- {
239
- bool: {
240
- should: [
241
- { term: { 'metadata.category.keyword': 'electronics' } },
242
- { term: { 'metadata.category.keyword': 'books' } },
243
- ],
244
- },
245
- },
246
- ],
247
- },
248
- });
249
- });
250
-
251
- it('handles $not with $not operator', () => {
252
- const filter = {
253
- $not: { $not: { category: 'electronics' } },
254
- };
255
- expect(translator.translate(filter)).toEqual({
256
- bool: {
257
- must_not: [
258
- {
259
- bool: {
260
- must_not: [{ term: { 'metadata.category.keyword': 'electronics' } }],
261
- },
262
- },
263
- ],
264
- },
265
- });
266
- });
267
-
268
- it('handles nested logical operators', () => {
269
- const filter = {
270
- $and: [
271
- { field1: 'value1' },
272
- {
273
- $or: [{ field2: 'value2' }, { field3: 'value3' }],
274
- },
275
- ],
276
- };
277
- expect(translator.translate(filter)).toEqual({
278
- bool: {
279
- must: [
280
- { term: { 'metadata.field1.keyword': 'value1' } },
281
- {
282
- bool: {
283
- should: [
284
- { term: { 'metadata.field2.keyword': 'value2' } },
285
- { term: { 'metadata.field3.keyword': 'value3' } },
286
- ],
287
- },
288
- },
289
- ],
290
- },
291
- });
292
- });
293
- });
294
-
295
- // Array Operators
296
- describe('array operators', () => {
297
- it('translates $in operator', () => {
298
- const filter = { field: { $in: ['value1', 'value2'] } };
299
- expect(translator.translate(filter)).toEqual({
300
- terms: { 'metadata.field.keyword': ['value1', 'value2'] },
301
- });
302
- });
303
-
304
- it('translates $nin operator', () => {
305
- const filter = { field: { $nin: ['value1', 'value2'] } };
306
- expect(translator.translate(filter)).toEqual({
307
- bool: {
308
- must_not: [{ terms: { 'metadata.field.keyword': ['value1', 'value2'] } }],
309
- },
310
- });
311
- });
312
-
313
- it('translates $all operator', () => {
314
- const filter = { field: { $all: ['value1', 'value2'] } };
315
- expect(translator.translate(filter)).toEqual({
316
- bool: {
317
- must: [{ term: { 'metadata.field.keyword': 'value1' } }, { term: { 'metadata.field.keyword': 'value2' } }],
318
- },
319
- });
320
- });
321
-
322
- it('handles empty $in array', () => {
323
- const filter = { field: { $in: [] } };
324
- // Empty $in should match nothing (empty terms)
325
- expect(translator.translate(filter)).toEqual({
326
- terms: { 'metadata.field.keyword': [] },
327
- });
328
- });
329
-
330
- it('handles empty $nin array', () => {
331
- const filter = { field: { $nin: [] } };
332
- // Empty $nin should match everything
333
- expect(translator.translate(filter)).toEqual({
334
- match_all: {},
335
- });
336
- });
337
-
338
- it('handles empty $all array', () => {
339
- const filter = { field: { $all: [] } };
340
- // Empty $all should match nothing
341
- expect(translator.translate(filter)).toEqual({
342
- bool: {
343
- must_not: [{ match_all: {} }],
344
- },
345
- });
346
- });
347
-
348
- it('handles $not with array operators', () => {
349
- const filter = { tags: { $not: { $in: ['premium', 'new'] } } };
350
- expect(translator.translate(filter)).toEqual({
351
- bool: {
352
- must_not: [
353
- {
354
- terms: { 'metadata.tags.keyword': ['premium', 'new'] },
355
- },
356
- ],
357
- },
358
- });
359
- });
360
-
361
- it('handles $not with empty array operators', () => {
362
- const filter = { tags: { $not: { $in: [] } } };
363
- expect(translator.translate(filter)).toEqual({
364
- bool: {
365
- must_not: [
366
- {
367
- terms: { 'metadata.tags.keyword': [] },
368
- },
369
- ],
370
- },
371
- });
372
- });
373
- });
374
-
375
- // Element Operators
376
- describe('element operators', () => {
377
- it('translates $exists operator', () => {
378
- const filter = { field: { $exists: true } };
379
- expect(translator.translate(filter)).toEqual({
380
- exists: { field: 'metadata.field' },
381
- });
382
- });
383
-
384
- it('translates $exists operator with false', () => {
385
- const filter = { field: { $exists: false } };
386
- expect(translator.translate(filter)).toEqual({
387
- bool: {
388
- must_not: [{ exists: { field: 'metadata.field' } }],
389
- },
390
- });
391
- });
392
- });
393
-
394
- // Regex Operators
395
- describe('regex operators', () => {
396
- it('translates $regex operator', () => {
397
- const filter = { field: { $regex: 'pattern' } };
398
- expect(translator.translate(filter)).toEqual({
399
- regexp: { 'metadata.field': 'pattern' },
400
- });
401
- });
402
-
403
- it('handles $regex with start anchor', () => {
404
- const filter = { category: { $regex: '^elect' } };
405
- // Should use wildcard for better anchor handling
406
- expect(translator.translate(filter)).toEqual({
407
- wildcard: { 'metadata.category': 'elect*' },
408
- });
409
- });
410
-
411
- it('handles $regex with end anchor', () => {
412
- const filter = { category: { $regex: 'nics$' } };
413
- // Should use wildcard for better anchor handling
414
- expect(translator.translate(filter)).toEqual({
415
- wildcard: { 'metadata.category': '*nics' },
416
- });
417
- });
418
-
419
- it('handles $regex with both anchors', () => {
420
- const filter = { category: { $regex: '^electronics$' } };
421
- // Should use exact match for both anchors
422
- expect(translator.translate(filter)).toEqual({
423
- wildcard: { 'metadata.category': 'electronics' },
424
- });
425
- });
426
-
427
- it('handles $not with $regex operator', () => {
428
- const filter = { category: { $not: { $regex: '^elect' } } };
429
- expect(translator.translate(filter)).toEqual({
430
- bool: {
431
- must_not: [
432
- {
433
- wildcard: { 'metadata.category': 'elect*' },
434
- },
435
- ],
436
- },
437
- });
438
- });
439
- });
440
-
441
- // Complex Queries
442
- describe('complex queries', () => {
443
- it('translates numeric operators', () => {
444
- const filter = { price: { $gt: 70, $lte: 100 } };
445
- expect(translator.translate(filter)).toEqual({
446
- range: { 'metadata.price': { gt: 70, lte: 100 } },
447
- });
448
- });
449
-
450
- it('translates multiple range operators on the same field', () => {
451
- const filter = { price: { $gte: 50, $lt: 200 } };
452
- expect(translator.translate(filter)).toEqual({
453
- range: { 'metadata.price': { gte: 50, lt: 200 } },
454
- });
455
- });
456
-
457
- it('translates all four range operators combined', () => {
458
- // This is an edge case that would never occur in practice, but tests the implementation
459
- const filter = { value: { $gt: 10, $gte: 20, $lt: 100, $lte: 90 } };
460
- expect(translator.translate(filter)).toEqual({
461
- range: { 'metadata.value': { gt: 10, gte: 20, lt: 100, lte: 90 } },
462
- });
463
- });
464
-
465
- it('translates mixed numeric and non-numeric operators', () => {
466
- const filter = { price: { $gt: 50, $exists: true } };
467
- expect(translator.translate(filter)).toEqual({
468
- bool: {
469
- must: [{ range: { 'metadata.price': { gt: 50 } } }, { exists: { field: 'metadata.price' } }],
470
- },
471
- });
472
- });
473
- it('translates mixed operators', () => {
474
- const filter = {
475
- $and: [{ field1: { $gt: 10 } }, { field2: { $in: ['value1', 'value2'] } }, { field3: { $exists: true } }],
476
- };
477
- expect(translator.translate(filter)).toEqual({
478
- bool: {
479
- must: [
480
- { range: { 'metadata.field1': { gt: 10 } } },
481
- { terms: { 'metadata.field2.keyword': ['value1', 'value2'] } },
482
- { exists: { field: 'metadata.field3' } },
483
- ],
484
- },
485
- });
486
- });
487
-
488
- it('translates complex nested queries', () => {
489
- const filter = {
490
- $and: [
491
- { status: 'active' },
492
- {
493
- $or: [{ age: { $gt: 25 } }, { role: { $in: ['admin', 'manager'] } }],
494
- },
495
- {
496
- $not: {
497
- $and: [{ deleted: true }, { archived: true }],
498
- },
499
- },
500
- ],
501
- };
502
- expect(translator.translate(filter)).toEqual({
503
- bool: {
504
- must: [
505
- { term: { 'metadata.status.keyword': 'active' } },
506
- {
507
- bool: {
508
- should: [
509
- { range: { 'metadata.age': { gt: 25 } } },
510
- { terms: { 'metadata.role.keyword': ['admin', 'manager'] } },
511
- ],
512
- },
513
- },
514
- {
515
- bool: {
516
- must_not: [
517
- {
518
- bool: {
519
- must: [{ term: { 'metadata.deleted': true } }, { term: { 'metadata.archived': true } }],
520
- },
521
- },
522
- ],
523
- },
524
- },
525
- ],
526
- },
527
- });
528
- });
529
- });
530
-
531
- // Error Cases
532
- describe('error cases', () => {
533
- it('throws error for unsupported operators', () => {
534
- const filter = { field: { $unsupported: 'value' } };
535
- expect(() => translator.translate(filter)).toThrow(/Unsupported operator/);
536
- });
537
-
538
- it('throws error for invalid logical operator structure', () => {
539
- const filter = { $and: 'invalid' };
540
- expect(() => translator.translate(filter)).toThrow();
541
- });
542
-
543
- it('throws error for invalid array operator values', () => {
544
- const filter = { field: { $in: 'not-an-array' } };
545
- expect(() => translator.translate(filter)).toThrow();
546
- });
547
-
548
- it('throws error for nested invalid operators', () => {
549
- const filter = { user: { profile: { age: { $invalid: 25 } } } };
550
- expect(() => translator.translate(filter)).toThrow();
551
- });
552
- });
553
-
554
- describe('special values', () => {
555
- it('handles boolean values', () => {
556
- const filter = { active: true, disabled: false };
557
- expect(translator.translate(filter)).toEqual({
558
- bool: {
559
- must: [{ term: { 'metadata.active': true } }, { term: { 'metadata.disabled': false } }],
560
- },
561
- });
562
- });
563
-
564
- it('handles null values', () => {
565
- const filter = { field: null };
566
- expect(translator.translate(filter)).toEqual({
567
- term: { 'metadata.field': null },
568
- });
569
- });
570
- });
571
-
572
- describe('array handling', () => {
573
- it('translates array values to terms query', () => {
574
- const filter = { tags: ['premium', 'new'] };
575
- expect(translator.translate(filter)).toEqual({
576
- terms: { 'metadata.tags.keyword': ['premium', 'new'] },
577
- });
578
- });
579
-
580
- it('translates numeric array values to terms query', () => {
581
- const filter = { scores: [90, 95, 100] };
582
- expect(translator.translate(filter)).toEqual({
583
- terms: { 'metadata.scores': [90, 95, 100] },
584
- });
585
- });
586
-
587
- it('translates empty array values to empty terms query', () => {
588
- const filter = { tags: [] };
589
- expect(translator.translate(filter)).toEqual({
590
- terms: { 'metadata.tags.keyword': [] },
591
- });
592
- });
593
-
594
- it('handles nested arrays in objects', () => {
595
- const filter = { user: { interests: ['sports', 'music'] } };
596
- expect(translator.translate(filter)).toEqual({
597
- bool: {
598
- must: [
599
- {
600
- term: {
601
- 'metadata.user.interests.keyword': ['sports', 'music'],
602
- },
603
- },
604
- ],
605
- },
606
- });
607
- });
608
- });
609
-
610
- describe('field type handling', () => {
611
- it('adds .keyword suffix for string fields', () => {
612
- const filter = { field: 'value' };
613
- expect(translator.translate(filter)).toEqual({
614
- term: { 'metadata.field.keyword': 'value' },
615
- });
616
- });
617
-
618
- it('adds .keyword suffix for string array fields', () => {
619
- const filter = { field: { $in: ['value1', 'value2'] } };
620
- expect(translator.translate(filter)).toEqual({
621
- terms: { 'metadata.field.keyword': ['value1', 'value2'] },
622
- });
623
- });
624
-
625
- it('does not add .keyword suffix for numeric fields', () => {
626
- const filter = { field: 123 };
627
- expect(translator.translate(filter)).toEqual({
628
- term: { 'metadata.field': 123 },
629
- });
630
- });
631
-
632
- it('does not add .keyword suffix for numeric array fields', () => {
633
- const filter = { field: { $in: [1, 2, 3] } };
634
- expect(translator.translate(filter)).toEqual({
635
- terms: { 'metadata.field': [1, 2, 3] },
636
- });
637
- });
638
-
639
- it('handles mixed field types in complex queries', () => {
640
- const filter = {
641
- $and: [
642
- { textField: 'value' },
643
- { numericField: 123 },
644
- { arrayField: { $in: ['a', 'b'] } },
645
- { numericArray: { $in: [1, 2] } },
646
- ],
647
- };
648
- expect(translator.translate(filter)).toEqual({
649
- bool: {
650
- must: [
651
- { term: { 'metadata.textField.keyword': 'value' } },
652
- { term: { 'metadata.numericField': 123 } },
653
- { terms: { 'metadata.arrayField.keyword': ['a', 'b'] } },
654
- { terms: { 'metadata.numericArray': [1, 2] } },
655
- ],
656
- },
657
- });
658
- });
659
- });
660
- });