@onchaindb/sdk 0.4.5 → 2.0.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/settings.local.json +10 -2
- package/README.md +422 -355
- package/dist/batch.d.ts +1 -10
- package/dist/batch.d.ts.map +1 -1
- package/dist/batch.js +4 -26
- package/dist/batch.js.map +1 -1
- package/dist/client.d.ts +31 -46
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +222 -357
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +14 -131
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +35 -131
- package/dist/database.js.map +1 -1
- package/dist/index.d.ts +10 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -18
- package/dist/index.js.map +1 -1
- package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
- package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
- package/dist/query-sdk/ConditionBuilder.js +10 -48
- package/dist/query-sdk/ConditionBuilder.js.map +1 -1
- package/dist/query-sdk/NestedBuilders.d.ts +33 -30
- package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
- package/dist/query-sdk/NestedBuilders.js +46 -43
- package/dist/query-sdk/NestedBuilders.js.map +1 -1
- package/{src/query-sdk/dist/OnChainDB.d.ts → dist/query-sdk/OnDB.d.ts} +10 -2
- package/dist/query-sdk/OnDB.d.ts.map +1 -0
- package/{src/query-sdk/dist/OnChainDB.js → dist/query-sdk/OnDB.js} +86 -18
- package/dist/query-sdk/OnDB.js.map +1 -0
- package/dist/query-sdk/QueryBuilder.d.ts +4 -2
- package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
- package/dist/query-sdk/QueryBuilder.js +47 -169
- package/dist/query-sdk/QueryBuilder.js.map +1 -1
- package/dist/query-sdk/QueryResult.d.ts +0 -38
- package/dist/query-sdk/QueryResult.d.ts.map +1 -1
- package/dist/query-sdk/QueryResult.js +1 -227
- package/dist/query-sdk/QueryResult.js.map +1 -1
- package/dist/query-sdk/index.d.ts +2 -2
- package/dist/query-sdk/index.d.ts.map +1 -1
- package/dist/query-sdk/index.js +3 -3
- package/dist/query-sdk/index.js.map +1 -1
- package/dist/query-sdk/operators.d.ts +32 -28
- package/dist/query-sdk/operators.d.ts.map +1 -1
- package/dist/query-sdk/operators.js +45 -155
- package/dist/query-sdk/operators.js.map +1 -1
- package/dist/types.d.ts +159 -36
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +8 -8
- package/dist/types.js.map +1 -1
- package/dist/x402/types.d.ts +1 -1
- package/dist/x402/types.d.ts.map +1 -1
- package/dist/x402/utils.js +2 -2
- package/dist/x402/utils.js.map +1 -1
- package/jest.config.js +4 -0
- package/package.json +1 -1
- package/skills.md +0 -1
- package/src/batch.d.ts +3 -3
- package/src/batch.js +1 -1
- package/src/client.ts +287 -823
- package/src/database.d.ts +1 -1
- package/src/database.js +4 -4
- package/src/database.ts +71 -494
- package/src/index.d.ts +18 -18
- package/src/index.js +16 -16
- package/src/index.ts +44 -198
- package/src/query-sdk/ConditionBuilder.ts +37 -89
- package/src/query-sdk/NestedBuilders.ts +90 -92
- package/src/query-sdk/{OnChainDB.ts → OnDB.ts} +1 -1
- package/src/query-sdk/QueryBuilder.ts +59 -218
- package/src/query-sdk/QueryResult.ts +4 -330
- package/src/query-sdk/README.md +218 -587
- package/src/query-sdk/index.ts +2 -2
- package/src/query-sdk/operators.ts +91 -200
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
- package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
- package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
- package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
- package/src/query-sdk/tests/QueryResult.test.ts +41 -435
- package/src/query-sdk/tests/comprehensive.test.ts +4 -185
- package/src/tests/client-requests.test.ts +280 -0
- package/src/tests/client-validation.test.ts +80 -0
- package/src/types.d.ts +6 -6
- package/src/types.js +8 -8
- package/src/types.ts +239 -54
- package/src/x402/types.ts +3 -3
- package/src/x402/utils.ts +3 -3
- package/examples/blob-upload-example.ts +0 -140
- package/src/batch.ts +0 -257
- package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
- package/src/query-sdk/dist/ConditionBuilder.js +0 -90
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
- package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
- package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
- package/src/query-sdk/dist/NestedBuilders.js +0 -144
- package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
- package/src/query-sdk/dist/QueryBuilder.js +0 -295
- package/src/query-sdk/dist/QueryResult.d.ts +0 -52
- package/src/query-sdk/dist/QueryResult.js +0 -293
- package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
- package/src/query-sdk/dist/SelectionBuilder.js +0 -80
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
- package/src/query-sdk/dist/index.d.ts +0 -36
- package/src/query-sdk/dist/index.js +0 -27
- package/src/query-sdk/dist/operators.d.ts +0 -56
- package/src/query-sdk/dist/operators.js +0 -289
- package/src/query-sdk/dist/tests/setup.d.ts +0 -15
- package/src/query-sdk/dist/tests/setup.js +0 -46
- package/src/query-sdk/jest.config.js +0 -25
- package/src/query-sdk/package.json +0 -46
- package/src/query-sdk/tests/aggregations.test.ts +0 -653
- package/src/query-sdk/tests/integration.test.ts +0 -608
- package/src/query-sdk/tests/operators.test.ts +0 -327
- package/src/query-sdk/tests/unit.test.ts +0 -794
- package/src/query-sdk/tsconfig.json +0 -26
- package/src/query-sdk/yarn.lock +0 -3092
|
@@ -2,320 +2,240 @@ import { NestedConditionBuilder, NestedFieldConditionBuilder } from '../NestedBu
|
|
|
2
2
|
import { LogicalOperator } from '../operators';
|
|
3
3
|
|
|
4
4
|
describe('NestedConditionBuilder', () => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
5
|
+
let nestedBuilder: NestedConditionBuilder;
|
|
6
|
+
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
nestedBuilder = new NestedConditionBuilder('user');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe('Basic nested building', () => {
|
|
12
|
+
test('should create nested field condition builder', () => {
|
|
13
|
+
const fieldBuilder = nestedBuilder.field('name');
|
|
14
|
+
expect(fieldBuilder).toBeInstanceOf(NestedFieldConditionBuilder);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should create condition with correct path', () => {
|
|
18
|
+
const condition = nestedBuilder.field('name').equals('John');
|
|
19
|
+
expect(condition.toComposable()).toEqual({ user: { name: { is: 'John' } } });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('should handle multi-level nesting', () => {
|
|
23
|
+
const condition = new NestedFieldConditionBuilder(['user', 'profile', 'bio']).contains('developer');
|
|
24
|
+
expect(condition.toComposable()).toEqual({ user: { profile: { bio: { includes: 'developer' } } } });
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
describe('Logical groups', () => {
|
|
29
|
+
test('should create AND groups', () => {
|
|
30
|
+
const andGroup = nestedBuilder.andGroup(builder => [
|
|
31
|
+
builder.field('name').equals('John'),
|
|
32
|
+
builder.field('age').greaterThan(25)
|
|
33
|
+
]);
|
|
34
|
+
expect(andGroup.type).toBe('and');
|
|
35
|
+
expect(andGroup.conditions).toHaveLength(2);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('should create OR groups', () => {
|
|
39
|
+
const orGroup = nestedBuilder.orGroup(builder => [
|
|
40
|
+
builder.field('status').equals('active'),
|
|
41
|
+
builder.field('status').equals('pending')
|
|
42
|
+
]);
|
|
43
|
+
expect(orGroup.type).toBe('or');
|
|
44
|
+
expect(orGroup.conditions).toHaveLength(2);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('should create NOT groups', () => {
|
|
48
|
+
const notGroup = nestedBuilder.notGroup(builder => [
|
|
49
|
+
builder.field('deleted').isTrue()
|
|
50
|
+
]);
|
|
51
|
+
expect(notGroup.type).toBe('not');
|
|
52
|
+
expect(notGroup.conditions).toHaveLength(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('variadic and/or/not methods', () => {
|
|
56
|
+
const and = nestedBuilder.and(
|
|
57
|
+
nestedBuilder.field('a').equals(1),
|
|
58
|
+
nestedBuilder.field('b').equals(2)
|
|
59
|
+
);
|
|
60
|
+
expect(and.type).toBe('and');
|
|
61
|
+
expect(and.conditions).toHaveLength(2);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('Nested structure creation', () => {
|
|
66
|
+
test('should create nested callback structure', () => {
|
|
67
|
+
const nested = nestedBuilder.nested('profile', nested =>
|
|
68
|
+
nested.field('bio').equals('Developer')
|
|
69
|
+
);
|
|
70
|
+
expect(nested.type).toBe('condition');
|
|
71
|
+
});
|
|
60
72
|
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('Nested structure creation', () => {
|
|
64
|
-
test('should create nested callback structure', () => {
|
|
65
|
-
const nested = nestedBuilder.nested('profile', nested =>
|
|
66
|
-
LogicalOperator.Condition(nested.field('bio').equals('Developer'))
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
expect(nested.type).toBe('condition');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
73
|
});
|
|
73
74
|
|
|
74
75
|
describe('NestedFieldConditionBuilder', () => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
76
|
+
let fieldBuilder: NestedFieldConditionBuilder;
|
|
77
|
+
|
|
78
|
+
beforeEach(() => {
|
|
79
|
+
fieldBuilder = new NestedFieldConditionBuilder(['user', 'profile', 'details']);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('Path construction', () => {
|
|
83
|
+
test('should construct correct field path', () => {
|
|
84
|
+
expect(fieldBuilder.equals('test').condition?.field).toBe('user.profile.details');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('should work with single-level path', () => {
|
|
88
|
+
const singleLevel = new NestedFieldConditionBuilder(['name']);
|
|
89
|
+
expect(singleLevel.equals('John').toComposable()).toEqual({ name: { is: 'John' } });
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('should work with deep nesting', () => {
|
|
93
|
+
const deepNesting = new NestedFieldConditionBuilder(['a', 'b', 'c', 'd', 'e']);
|
|
94
|
+
expect(deepNesting.contains('value').toComposable()).toEqual({
|
|
95
|
+
a: { b: { c: { d: { e: { includes: 'value' } } } } }
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('Basic operators', () => {
|
|
101
|
+
test('equals', () => {
|
|
102
|
+
expect(fieldBuilder.equals('value').toComposable()).toEqual({
|
|
103
|
+
user: { profile: { details: { is: 'value' } } }
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('notEquals', () => {
|
|
108
|
+
expect(fieldBuilder.notEquals('value').toComposable()).toEqual({
|
|
109
|
+
user: { profile: { details: { isNot: 'value' } } }
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('comparison operators', () => {
|
|
114
|
+
expect(fieldBuilder.greaterThan(10).condition?.operator).toBe('greaterThan');
|
|
115
|
+
expect(fieldBuilder.greaterThanOrEqual(10).condition?.operator).toBe('greaterThanOrEqual');
|
|
116
|
+
expect(fieldBuilder.lessThan(10).condition?.operator).toBe('lessThan');
|
|
117
|
+
expect(fieldBuilder.lessThanOrEqual(10).condition?.operator).toBe('lessThanOrEqual');
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe('String operators', () => {
|
|
122
|
+
test('string operations', () => {
|
|
123
|
+
expect(fieldBuilder.contains('test').condition?.operator).toBe('includes');
|
|
124
|
+
expect(fieldBuilder.startsWith('pre').condition?.operator).toBe('startsWith');
|
|
125
|
+
expect(fieldBuilder.endsWith('suf').condition?.operator).toBe('endsWith');
|
|
126
|
+
expect(fieldBuilder.regExpMatches('.*').condition?.operator).toBe('regExpMatches');
|
|
127
|
+
expect(fieldBuilder.includesCaseInsensitive('TEST').condition?.operator).toBe('includesCaseInsensitive');
|
|
128
|
+
expect(fieldBuilder.startsWithCaseInsensitive('PRE').condition?.operator).toBe('startsWithCaseInsensitive');
|
|
129
|
+
expect(fieldBuilder.endsWithCaseInsensitive('SUF').condition?.operator).toBe('endsWithCaseInsensitive');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('Array operators', () => {
|
|
134
|
+
test('in and notIn', () => {
|
|
135
|
+
const inCondition = fieldBuilder.in([1, 2, 3]);
|
|
136
|
+
expect(inCondition.condition?.operator).toBe('in');
|
|
137
|
+
expect(inCondition.condition?.value).toEqual([1, 2, 3]);
|
|
138
|
+
|
|
139
|
+
const notInCondition = fieldBuilder.notIn(['a', 'b']);
|
|
140
|
+
expect(notInCondition.condition?.operator).toBe('notIn');
|
|
141
|
+
expect(notInCondition.condition?.value).toEqual(['a', 'b']);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe('Existence operators', () => {
|
|
146
|
+
test('exists and notExists', () => {
|
|
147
|
+
expect(fieldBuilder.exists().toComposable()).toEqual({
|
|
148
|
+
user: { profile: { details: { exists: true } } }
|
|
149
|
+
});
|
|
150
|
+
expect(fieldBuilder.notExists().toComposable()).toEqual({
|
|
151
|
+
user: { profile: { details: { exists: false } } }
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('isNull and isNotNull', () => {
|
|
156
|
+
expect(fieldBuilder.isNull().toComposable()).toEqual({
|
|
157
|
+
user: { profile: { details: { isNull: true } } }
|
|
158
|
+
});
|
|
159
|
+
expect(fieldBuilder.isNotNull().toComposable()).toEqual({
|
|
160
|
+
user: { profile: { details: { isNull: false } } }
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('Numeric operators', () => {
|
|
166
|
+
test('between uses betweenOp with from/to', () => {
|
|
167
|
+
const betweenCondition = fieldBuilder.between(10, 20);
|
|
168
|
+
expect(betweenCondition.condition?.operator).toBe('betweenOp');
|
|
169
|
+
expect(betweenCondition.condition?.value).toEqual({ from: 10, to: 20 });
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
describe('Misc operators', () => {
|
|
174
|
+
test('b64, inCountry, inDataset, cidr', () => {
|
|
175
|
+
expect(fieldBuilder.b64('dGVzdA==').condition?.operator).toBe('b64');
|
|
176
|
+
expect(fieldBuilder.inCountry('US').condition?.operator).toBe('inCountry');
|
|
177
|
+
expect(fieldBuilder.inDataset('malware_ips').condition?.operator).toBe('inDataset');
|
|
178
|
+
expect(fieldBuilder.cidr('192.168.1.0/24').condition?.operator).toBe('CIDR');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
test('IP operators', () => {
|
|
182
|
+
expect(fieldBuilder.isLocalIp().condition?.operator).toBe('isLocalIp');
|
|
183
|
+
expect(fieldBuilder.isExternalIp().condition?.operator).toBe('isExternalIp');
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
describe('Boolean convenience', () => {
|
|
188
|
+
test('isTrue and isFalse', () => {
|
|
189
|
+
expect(fieldBuilder.isTrue().toComposable()).toEqual({
|
|
190
|
+
user: { profile: { details: { is: true } } }
|
|
191
|
+
});
|
|
192
|
+
expect(fieldBuilder.isFalse().toComposable()).toEqual({
|
|
193
|
+
user: { profile: { details: { is: false } } }
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe('Complex scenarios', () => {
|
|
199
|
+
test('should work with very deep nesting', () => {
|
|
200
|
+
const deepPath = ['level1', 'level2', 'level3', 'level4', 'level5', 'finalField'];
|
|
201
|
+
const deepBuilder = new NestedFieldConditionBuilder(deepPath);
|
|
202
|
+
const condition = deepBuilder.equals('deep_value');
|
|
203
|
+
expect(condition.condition?.field).toBe('level1.level2.level3.level4.level5.finalField');
|
|
204
|
+
expect(condition.condition?.value).toBe('deep_value');
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
test('should handle special characters in field names', () => {
|
|
208
|
+
const specialPath = ['user-profile', 'bio_text', 'data@field'];
|
|
209
|
+
const specialBuilder = new NestedFieldConditionBuilder(specialPath);
|
|
210
|
+
const condition = specialBuilder.contains('text');
|
|
211
|
+
expect(condition.condition?.field).toBe('user-profile.bio_text.data@field');
|
|
212
|
+
});
|
|
119
213
|
});
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
describe('String operators', () => {
|
|
123
|
-
test('string operations should work correctly', () => {
|
|
124
|
-
expect(fieldBuilder.contains('test').operator).toBe('includes');
|
|
125
|
-
expect(fieldBuilder.startsWith('pre').operator).toBe('startsWith');
|
|
126
|
-
expect(fieldBuilder.endsWith('suf').operator).toBe('endsWith');
|
|
127
|
-
expect(fieldBuilder.regExpMatches('.*').operator).toBe('regExpMatches');
|
|
128
|
-
expect(fieldBuilder.includesCaseInsensitive('TEST').operator).toBe('includesCaseInsensitive');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
test('wildcard operators should work correctly', () => {
|
|
132
|
-
expect(fieldBuilder.wildcard('*.txt').operator).toBe('wildcard');
|
|
133
|
-
expect(fieldBuilder.glob('**/*.js').operator).toBe('glob');
|
|
134
|
-
});
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
describe('Array operators', () => {
|
|
138
|
-
test('list operations should work correctly', () => {
|
|
139
|
-
const inCondition = fieldBuilder.in([1, 2, 3]);
|
|
140
|
-
expect(inCondition.operator).toBe('in');
|
|
141
|
-
expect(inCondition.value).toEqual([1, 2, 3]);
|
|
142
|
-
|
|
143
|
-
const notInCondition = fieldBuilder.notIn(['a', 'b']);
|
|
144
|
-
expect(notInCondition.operator).toBe('notIn');
|
|
145
|
-
expect(notInCondition.value).toEqual(['a', 'b']);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('base operators should work correctly', () => {
|
|
149
|
-
expect(fieldBuilder.equals('value').operator).toBe('is');
|
|
150
|
-
expect(fieldBuilder.notEquals('value').operator).toBe('isNot');
|
|
151
|
-
expect(fieldBuilder.isNull().operator).toBe('isNull');
|
|
152
|
-
expect(fieldBuilder.isNotNull().operator).toBe('isNull');
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
describe('Existence operators', () => {
|
|
157
|
-
test('existence checks should work correctly', () => {
|
|
158
|
-
expect(fieldBuilder.exists().operator).toBe('exists');
|
|
159
|
-
expect(fieldBuilder.exists().value).toBe(true);
|
|
160
|
-
|
|
161
|
-
expect(fieldBuilder.notExists().operator).toBe('exists');
|
|
162
|
-
expect(fieldBuilder.notExists().value).toBe(false);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
test('null checks should work correctly', () => {
|
|
166
|
-
expect(fieldBuilder.isNull().operator).toBe('isNull');
|
|
167
|
-
expect(fieldBuilder.isNull().value).toBe(true);
|
|
168
|
-
|
|
169
|
-
expect(fieldBuilder.isNotNull().operator).toBe('isNull');
|
|
170
|
-
expect(fieldBuilder.isNotNull().value).toBe(false);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test('empty checks should work correctly', () => {
|
|
174
|
-
expect(fieldBuilder.isEmpty().operator).toBe('isEmpty');
|
|
175
|
-
expect(fieldBuilder.isEmpty().value).toBe(true);
|
|
176
|
-
|
|
177
|
-
expect(fieldBuilder.isNotEmpty().operator).toBe('isEmpty');
|
|
178
|
-
expect(fieldBuilder.isNotEmpty().value).toBe(false);
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
describe('Numeric operators', () => {
|
|
183
|
-
test('number operations should work correctly', () => {
|
|
184
|
-
const betweenCondition = fieldBuilder.between(10, 20);
|
|
185
|
-
expect(betweenCondition.operator).toBe('betweenOp');
|
|
186
|
-
expect(betweenCondition.value).toEqual({ from: 10, to: 20 });
|
|
187
|
-
|
|
188
|
-
expect(fieldBuilder.greaterThan(100).operator).toBe('greaterThan');
|
|
189
|
-
expect(fieldBuilder.lessThan(500).operator).toBe('lessThan');
|
|
190
|
-
expect(fieldBuilder.greaterThanOrEqual(100).operator).toBe('greaterThanOrEqual');
|
|
191
|
-
expect(fieldBuilder.lessThanOrEqual(500).operator).toBe('lessThanOrEqual');
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
describe('Misc operators', () => {
|
|
196
|
-
test('misc operators should work correctly', () => {
|
|
197
|
-
expect(fieldBuilder.b64('dGVzdA==').operator).toBe('b64');
|
|
198
|
-
expect(fieldBuilder.inCountry('US').operator).toBe('inCountry');
|
|
199
|
-
expect(fieldBuilder.inDataset('malware_ips').operator).toBe('inDataset');
|
|
200
|
-
expect(fieldBuilder.cidr('192.168.1.0/24').operator).toBe('CIDR');
|
|
201
|
-
});
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
describe('Boolean operators', () => {
|
|
205
|
-
test('boolean checks should work correctly', () => {
|
|
206
|
-
const trueCondition = fieldBuilder.isTrue();
|
|
207
|
-
expect(trueCondition.operator).toBe('is');
|
|
208
|
-
expect(trueCondition.value).toBe(true);
|
|
209
|
-
|
|
210
|
-
const falseCondition = fieldBuilder.isFalse();
|
|
211
|
-
expect(falseCondition.operator).toBe('is');
|
|
212
|
-
expect(falseCondition.value).toBe(false);
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
describe('Type checking operators', () => {
|
|
217
|
-
test('type validation operators should work correctly', () => {
|
|
218
|
-
expect(fieldBuilder.isString().operator).toBe('isString');
|
|
219
|
-
expect(fieldBuilder.isNumber().operator).toBe('isNumber');
|
|
220
|
-
expect(fieldBuilder.isBoolean().operator).toBe('isBoolean');
|
|
221
|
-
expect(fieldBuilder.isArray().operator).toBe('isArray');
|
|
222
|
-
expect(fieldBuilder.isObject().operator).toBe('isObject');
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
describe('String operators', () => {
|
|
227
|
-
test('string operators should work correctly', () => {
|
|
228
|
-
expect(fieldBuilder.startsWith('prefix').operator).toBe('startsWith');
|
|
229
|
-
expect(fieldBuilder.endsWith('suffix').operator).toBe('endsWith');
|
|
230
|
-
expect(fieldBuilder.contains('substring').operator).toBe('includes');
|
|
231
|
-
expect(fieldBuilder.regExpMatches('^test.*').operator).toBe('regExpMatches');
|
|
232
|
-
expect(fieldBuilder.includesCaseInsensitive('Test').operator).toBe('includesCaseInsensitive');
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
describe('IP address operators', () => {
|
|
237
|
-
test('IP address operations should work correctly', () => {
|
|
238
|
-
expect(fieldBuilder.isLocalIp().operator).toBe('isLocalIp');
|
|
239
|
-
expect(fieldBuilder.isExternalIp().operator).toBe('isExternalIp');
|
|
240
|
-
expect(fieldBuilder.inCountry('US').operator).toBe('inCountry');
|
|
241
|
-
expect(fieldBuilder.cidr('192.168.1.0/24').operator).toBe('CIDR');
|
|
242
|
-
expect(fieldBuilder.b64('dGVzdA==').operator).toBe('b64');
|
|
243
|
-
expect(fieldBuilder.inDataset('malware_ips').operator).toBe('inDataset');
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
describe('Number operators', () => {
|
|
248
|
-
test('number operations should work correctly', () => {
|
|
249
|
-
expect(fieldBuilder.greaterThan(100).operator).toBe('greaterThan');
|
|
250
|
-
expect(fieldBuilder.lessThan(500).operator).toBe('lessThan');
|
|
251
|
-
expect(fieldBuilder.greaterThanOrEqual(100).operator).toBe('greaterThanOrEqual');
|
|
252
|
-
expect(fieldBuilder.lessThanOrEqual(500).operator).toBe('lessThanOrEqual');
|
|
253
|
-
expect(fieldBuilder.between(100, 500).operator).toBe('betweenOp');
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
describe('Complex scenarios', () => {
|
|
258
|
-
test('should work with very deep nesting', () => {
|
|
259
|
-
const deepPath = ['level1', 'level2', 'level3', 'level4', 'level5', 'finalField'];
|
|
260
|
-
const deepBuilder = new NestedFieldConditionBuilder(deepPath);
|
|
261
|
-
const condition = deepBuilder.equals('deep_value');
|
|
262
|
-
|
|
263
|
-
expect(condition.field).toBe('level1.level2.level3.level4.level5.finalField');
|
|
264
|
-
expect(condition.value).toBe('deep_value');
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
test('should handle special characters in field names', () => {
|
|
268
|
-
const specialPath = ['user-profile', 'bio_text', 'data@field'];
|
|
269
|
-
const specialBuilder = new NestedFieldConditionBuilder(specialPath);
|
|
270
|
-
const condition = specialBuilder.contains('text');
|
|
271
|
-
|
|
272
|
-
expect(condition.field).toBe('user-profile.bio_text.data@field');
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
test('should work with all operator types in nested context', () => {
|
|
276
|
-
const nestedBuilder = new NestedConditionBuilder('order');
|
|
277
|
-
const itemsBuilder = nestedBuilder.field('items');
|
|
278
|
-
|
|
279
|
-
// Test that we can chain multiple field levels
|
|
280
|
-
const priceCondition = itemsBuilder.field('price').greaterThan(100);
|
|
281
|
-
expect(priceCondition.field).toBe('order.items.price');
|
|
282
|
-
|
|
283
|
-
const categoryCondition = itemsBuilder.field('category').equals('electronics');
|
|
284
|
-
expect(categoryCondition.field).toBe('order.items.category');
|
|
285
|
-
|
|
286
|
-
const stockCondition = itemsBuilder.field('stock').exists();
|
|
287
|
-
expect(stockCondition.field).toBe('order.items.stock');
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
214
|
});
|
|
291
215
|
|
|
292
216
|
describe('Integration with LogicalOperator', () => {
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
expect(complexLogic.conditions[1].type).toBe('or');
|
|
319
|
-
expect(complexLogic.conditions[2].type).toBe('not');
|
|
320
|
-
});
|
|
321
|
-
});
|
|
217
|
+
test('should have correct type and condition from NestedFieldConditionBuilder', () => {
|
|
218
|
+
const condition = new NestedFieldConditionBuilder(['user', 'profile', 'name']).equals('John');
|
|
219
|
+
expect(condition.type).toBe('condition');
|
|
220
|
+
expect(condition.condition?.field).toBe('user.profile.name');
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('should work in complex logical structures', () => {
|
|
224
|
+
const nestedBuilder = new NestedConditionBuilder('user');
|
|
225
|
+
const complexLogic = LogicalOperator.And([
|
|
226
|
+
new NestedFieldConditionBuilder(['user', 'profile', 'name']).equals('John'),
|
|
227
|
+
LogicalOperator.Or([
|
|
228
|
+
nestedBuilder.field('status').equals('active'),
|
|
229
|
+
nestedBuilder.field('status').equals('pending')
|
|
230
|
+
]),
|
|
231
|
+
LogicalOperator.Not([
|
|
232
|
+
new NestedFieldConditionBuilder(['user', 'flags', 'deleted']).isTrue()
|
|
233
|
+
])
|
|
234
|
+
]);
|
|
235
|
+
|
|
236
|
+
expect(complexLogic.type).toBe('and');
|
|
237
|
+
expect(complexLogic.conditions).toHaveLength(3);
|
|
238
|
+
expect(complexLogic.conditions[1].type).toBe('or');
|
|
239
|
+
expect(complexLogic.conditions[2].type).toBe('not');
|
|
240
|
+
});
|
|
241
|
+
});
|
|
@@ -78,8 +78,8 @@ describe('QueryBuilder', () => {
|
|
|
78
78
|
.collection('users')
|
|
79
79
|
.find(builder =>
|
|
80
80
|
LogicalOperator.And([
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
new FieldConditionBuilder('name').equals('John'),
|
|
82
|
+
new FieldConditionBuilder('age').greaterThan(25)
|
|
83
83
|
])
|
|
84
84
|
)
|
|
85
85
|
.buildRawQuery();
|
|
@@ -97,8 +97,8 @@ describe('QueryBuilder', () => {
|
|
|
97
97
|
.collection('users')
|
|
98
98
|
.find(builder =>
|
|
99
99
|
LogicalOperator.Or([
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
new FieldConditionBuilder('role').equals('admin'),
|
|
101
|
+
new FieldConditionBuilder('role').equals('moderator')
|
|
102
102
|
])
|
|
103
103
|
)
|
|
104
104
|
.buildRawQuery();
|
|
@@ -116,7 +116,7 @@ describe('QueryBuilder', () => {
|
|
|
116
116
|
.collection('users')
|
|
117
117
|
.find(builder =>
|
|
118
118
|
LogicalOperator.Not([
|
|
119
|
-
|
|
119
|
+
new FieldConditionBuilder('status').equals('banned')
|
|
120
120
|
])
|
|
121
121
|
)
|
|
122
122
|
.buildRawQuery();
|