@onchaindb/sdk 0.4.0 → 0.4.2
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/.DS_Store +0 -0
- package/.claude/settings.local.json +8 -0
- package/.gitignore +5 -0
- package/.idea/.gitignore +5 -0
- package/.idea/compiler.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +6 -0
- package/.idea/jsLinters/eslint.xml +6 -0
- package/.idea/modules.xml +8 -0
- package/.idea/prettier.xml +7 -0
- package/.idea/sdk.iml +12 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/workspace.xml +257 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -3
- package/dist/client.js.map +1 -1
- package/dist/database.d.ts +0 -20
- package/dist/database.d.ts.map +1 -1
- package/dist/database.js +0 -40
- package/dist/database.js.map +1 -1
- package/dist/query-sdk/tests/setup.d.ts +16 -0
- package/dist/query-sdk/tests/setup.d.ts.map +1 -0
- package/dist/query-sdk/tests/setup.js +49 -0
- package/dist/query-sdk/tests/setup.js.map +1 -0
- package/examples/basic-usage.ts +136 -0
- package/examples/blob-upload-example.ts +140 -0
- package/examples/collection-schema-example.ts +304 -0
- package/examples/server-side-joins.ts +201 -0
- package/examples/tweet-self-joins-example.ts +352 -0
- package/package-lock.json +3823 -0
- package/package.json +1 -1
- package/skills.md +1096 -0
- package/src/.env +1 -0
- package/src/batch.d.ts +121 -0
- package/src/batch.js +205 -0
- package/src/batch.ts +257 -0
- package/src/client.ts +1856 -0
- package/src/database.d.ts +268 -0
- package/src/database.js +294 -0
- package/src/database.ts +695 -0
- package/src/index.d.ts +160 -0
- package/src/index.js +186 -0
- package/src/index.ts +253 -0
- package/src/query-sdk/ConditionBuilder.ts +103 -0
- package/src/query-sdk/FieldConditionBuilder.ts +2 -0
- package/src/query-sdk/NestedBuilders.ts +186 -0
- package/src/query-sdk/OnChainDB.ts +294 -0
- package/src/query-sdk/QueryBuilder.ts +1191 -0
- package/src/query-sdk/QueryResult.ts +375 -0
- package/src/query-sdk/README.md +866 -0
- package/src/query-sdk/SelectionBuilder.ts +94 -0
- package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
- package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
- package/src/query-sdk/dist/ConditionBuilder.js +90 -0
- package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
- package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
- package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
- package/src/query-sdk/dist/NestedBuilders.js +144 -0
- package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
- package/src/query-sdk/dist/OnChainDB.js +123 -0
- package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
- package/src/query-sdk/dist/QueryBuilder.js +295 -0
- package/src/query-sdk/dist/QueryResult.d.ts +52 -0
- package/src/query-sdk/dist/QueryResult.js +293 -0
- package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
- package/src/query-sdk/dist/SelectionBuilder.js +80 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
- package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
- package/src/query-sdk/dist/index.d.ts +36 -0
- package/src/query-sdk/dist/index.js +27 -0
- package/src/query-sdk/dist/operators.d.ts +56 -0
- package/src/query-sdk/dist/operators.js +289 -0
- package/src/query-sdk/dist/tests/setup.d.ts +15 -0
- package/src/query-sdk/dist/tests/setup.js +46 -0
- package/src/query-sdk/index.ts +59 -0
- package/src/query-sdk/jest.config.js +25 -0
- package/src/query-sdk/operators.ts +335 -0
- package/src/query-sdk/package.json +46 -0
- package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
- package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
- package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
- package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
- package/src/query-sdk/tests/QueryResult.test.ts +464 -0
- package/src/query-sdk/tests/aggregations.test.ts +653 -0
- package/src/query-sdk/tests/comprehensive.test.ts +279 -0
- package/src/query-sdk/tests/integration.test.ts +608 -0
- package/src/query-sdk/tests/operators.test.ts +327 -0
- package/src/query-sdk/tests/setup.ts +59 -0
- package/src/query-sdk/tests/unit.test.ts +794 -0
- package/src/query-sdk/tsconfig.json +26 -0
- package/src/query-sdk/yarn.lock +3092 -0
- package/src/types.d.ts +131 -0
- package/src/types.js +46 -0
- package/src/types.ts +534 -0
- package/src/x402/index.ts +12 -0
- package/src/x402/types.ts +250 -0
- package/src/x402/utils.ts +332 -0
- package/tsconfig.json +20 -0
- package/yarn.lock +2309 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { QueryBuilder, FieldConditionBuilder, LogicalOperator, createQueryResult } from '../index';
|
|
2
|
+
import { MockHttpClient, createMockResponse } from './setup';
|
|
3
|
+
|
|
4
|
+
describe('Comprehensive SDK Integration Tests', () => {
|
|
5
|
+
let mockClient: MockHttpClient;
|
|
6
|
+
let queryBuilder: QueryBuilder;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
mockClient = new MockHttpClient();
|
|
10
|
+
queryBuilder = new QueryBuilder(mockClient, 'http://localhost:3000', 'testApp');
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
mockClient.clear();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('Complete query building workflow', () => {
|
|
18
|
+
test('should build complex nested query with dot notation', () => {
|
|
19
|
+
const rawQuery = queryBuilder
|
|
20
|
+
.collection('users')
|
|
21
|
+
.whereField('user.profile.bio').contains('Developer')
|
|
22
|
+
.limit(10)
|
|
23
|
+
.selectFields(['id', 'name'])
|
|
24
|
+
.buildRawQuery();
|
|
25
|
+
|
|
26
|
+
expect(rawQuery.find).toEqual({
|
|
27
|
+
user: {
|
|
28
|
+
profile: {
|
|
29
|
+
bio: {
|
|
30
|
+
includes: 'Developer'
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(rawQuery.limit).toBe(10);
|
|
37
|
+
expect(rawQuery.select).toEqual({ fields: ['id', 'name'] });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('should handle deep nesting scenarios', () => {
|
|
41
|
+
const deepCondition = new FieldConditionBuilder('user.profile.settings.preferences.theme').equals('dark');
|
|
42
|
+
const logicalOp = LogicalOperator.Condition(deepCondition);
|
|
43
|
+
const composable = logicalOp.toComposable();
|
|
44
|
+
|
|
45
|
+
const expected = {
|
|
46
|
+
user: {
|
|
47
|
+
profile: {
|
|
48
|
+
settings: {
|
|
49
|
+
preferences: {
|
|
50
|
+
theme: {
|
|
51
|
+
is: 'dark'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
expect(composable).toEqual(expected);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('should execute full workflow with mock client', async () => {
|
|
63
|
+
const mockData = [
|
|
64
|
+
{ id: 1, name: 'John Doe', user: { profile: { bio: 'Developer' } } },
|
|
65
|
+
{ id: 2, name: 'Jane Smith', user: { profile: { bio: 'Designer' } } }
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
mockClient.setResponse('/list', createMockResponse(mockData));
|
|
69
|
+
|
|
70
|
+
const response = await queryBuilder
|
|
71
|
+
.collection('users')
|
|
72
|
+
.whereField('user.profile.bio').contains('Developer')
|
|
73
|
+
.limit(10)
|
|
74
|
+
.selectFields(['id', 'name'])
|
|
75
|
+
.execute();
|
|
76
|
+
|
|
77
|
+
expect(response.records).toEqual(mockData);
|
|
78
|
+
expect(response.total).toBe(2);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('QueryResult advanced operations', () => {
|
|
83
|
+
test('should perform complex join operations', () => {
|
|
84
|
+
const users = createQueryResult([
|
|
85
|
+
{ id: 1, name: 'John', departmentId: 1 },
|
|
86
|
+
{ id: 2, name: 'Jane', departmentId: 2 }
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
const departments = createQueryResult([
|
|
90
|
+
{ id: 1, name: 'Engineering' },
|
|
91
|
+
{ id: 2, name: 'Design' }
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
const joined = users.innerJoin(departments, 'departmentId', 'id');
|
|
95
|
+
expect(joined.length).toBe(2);
|
|
96
|
+
expect(joined[0].name).toBe('Engineering'); // Department name merged
|
|
97
|
+
expect(joined[1].name).toBe('Design');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('should export to CSV with proper formatting', () => {
|
|
101
|
+
const users = createQueryResult([
|
|
102
|
+
{ id: 1, name: 'John', age: 30, score: 95.5 },
|
|
103
|
+
{ id: 2, name: 'Jane', age: 25, score: 87.2 },
|
|
104
|
+
{ id: 3, name: 'Bob', age: 35, score: 92.8 }
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
const csv = users.toCsv();
|
|
108
|
+
const lines = csv.split('\n');
|
|
109
|
+
|
|
110
|
+
expect(lines.length).toBe(4); // header + 3 data rows
|
|
111
|
+
expect(lines[0]).toContain('id');
|
|
112
|
+
expect(lines[0]).toContain('name');
|
|
113
|
+
expect(lines[0]).toContain('age');
|
|
114
|
+
expect(lines[0]).toContain('score');
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('should provide comprehensive numeric summaries', () => {
|
|
118
|
+
const testData = [
|
|
119
|
+
{ id: 1, name: 'John', age: 30, score: 95.5 },
|
|
120
|
+
{ id: 2, name: 'Jane', age: 25, score: 87.2 },
|
|
121
|
+
{ id: 3, name: 'Bob', age: 35, score: 92.8 }
|
|
122
|
+
];
|
|
123
|
+
|
|
124
|
+
const result = createQueryResult(testData);
|
|
125
|
+
const scoreSummary = result.summarizeNumeric('score');
|
|
126
|
+
|
|
127
|
+
expect(scoreSummary).not.toBeNull();
|
|
128
|
+
expect(scoreSummary!.count).toBe(3);
|
|
129
|
+
expect(scoreSummary!.mean).toBeCloseTo((95.5 + 87.2 + 92.8) / 3, 2);
|
|
130
|
+
expect(scoreSummary!.min).toBe(87.2);
|
|
131
|
+
expect(scoreSummary!.max).toBe(95.5);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test('should handle sorting and filtering', () => {
|
|
135
|
+
const testData = [
|
|
136
|
+
{ id: 1, name: 'John', age: 30 },
|
|
137
|
+
{ id: 2, name: 'Jane', age: 25 },
|
|
138
|
+
{ id: 3, name: 'Bob', age: 35 }
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
const result = createQueryResult(testData);
|
|
142
|
+
|
|
143
|
+
const sortedByAge = result.sortBy('age');
|
|
144
|
+
expect(sortedByAge[0].age).toBe(25);
|
|
145
|
+
expect(sortedByAge[2].age).toBe(35);
|
|
146
|
+
|
|
147
|
+
const filtered = result.filter(item => item.age > 30);
|
|
148
|
+
expect(filtered.length).toBe(1);
|
|
149
|
+
expect(filtered[0].name).toBe('Bob');
|
|
150
|
+
|
|
151
|
+
const grouped = result.groupBy('age');
|
|
152
|
+
expect(Object.keys(grouped).length).toBe(3);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
describe('Error handling and validation', () => {
|
|
157
|
+
test('should handle empty QueryResult operations gracefully', () => {
|
|
158
|
+
const emptyResult = createQueryResult([]);
|
|
159
|
+
|
|
160
|
+
expect(emptyResult.isEmpty()).toBe(true);
|
|
161
|
+
expect(emptyResult.first()).toBeUndefined();
|
|
162
|
+
expect(emptyResult.len()).toBe(0);
|
|
163
|
+
expect(emptyResult.summarizeNumeric('field')).toBeNull();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test('should validate QueryBuilder state', () => {
|
|
167
|
+
const emptyBuilder = new QueryBuilder();
|
|
168
|
+
expect(emptyBuilder.isValid()).toBe(false);
|
|
169
|
+
|
|
170
|
+
const builderWithCondition = new QueryBuilder()
|
|
171
|
+
.whereField('name').equals('test');
|
|
172
|
+
expect(builderWithCondition.isValid()).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('should handle invalid field references', () => {
|
|
176
|
+
expect(() => {
|
|
177
|
+
const condition = new FieldConditionBuilder('').equals('test');
|
|
178
|
+
LogicalOperator.Condition(condition).toComposable();
|
|
179
|
+
}).not.toThrow();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('All operators comprehensive coverage', () => {
|
|
184
|
+
test('should support all field condition operators', () => {
|
|
185
|
+
const builder = new FieldConditionBuilder('test_field');
|
|
186
|
+
|
|
187
|
+
// Only test operators that actually exist in the Rust implementation
|
|
188
|
+
const operators = [
|
|
189
|
+
'equals', 'notEquals', 'greaterThan', 'lessThan', 'greaterThanOrEqual', 'lessThanOrEqual',
|
|
190
|
+
'contains', 'startsWith', 'endsWith', 'in', 'notIn', 'exists', 'notExists',
|
|
191
|
+
'isNull', 'isNotNull', 'regExpMatches', 'includesCaseInsensitive',
|
|
192
|
+
'startsWithCaseInsensitive', 'endsWithCaseInsensitive', 'between',
|
|
193
|
+
'isLocalIp', 'isExternalIp', 'b64', 'inDataset', 'inCountry', 'cidr',
|
|
194
|
+
'isTrue', 'isFalse'
|
|
195
|
+
];
|
|
196
|
+
|
|
197
|
+
operators.forEach(op => {
|
|
198
|
+
expect(typeof (builder as any)[op]).toBe('function');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test('should create correct conditions for advanced operators', () => {
|
|
203
|
+
const builder = new FieldConditionBuilder('test_field');
|
|
204
|
+
|
|
205
|
+
// String operators
|
|
206
|
+
const regexCondition = builder.regExpMatches('^test.*');
|
|
207
|
+
expect(regexCondition.operator).toBe('regExpMatches');
|
|
208
|
+
|
|
209
|
+
const caseInsensitiveCondition = builder.includesCaseInsensitive('Test');
|
|
210
|
+
expect(caseInsensitiveCondition.operator).toBe('includesCaseInsensitive');
|
|
211
|
+
|
|
212
|
+
// IP operators
|
|
213
|
+
const ipBuilder = new FieldConditionBuilder('ip_address');
|
|
214
|
+
const ipLocalCondition = ipBuilder.isLocalIp();
|
|
215
|
+
expect(ipLocalCondition.operator).toBe('isLocalIp');
|
|
216
|
+
|
|
217
|
+
const ipExternalCondition = ipBuilder.isExternalIp();
|
|
218
|
+
expect(ipExternalCondition.operator).toBe('isExternalIp');
|
|
219
|
+
|
|
220
|
+
// Misc operators
|
|
221
|
+
const b64Condition = builder.b64('dGVzdA==');
|
|
222
|
+
expect(b64Condition.operator).toBe('b64');
|
|
223
|
+
|
|
224
|
+
const countryCondition = builder.inCountry('US');
|
|
225
|
+
expect(countryCondition.operator).toBe('inCountry');
|
|
226
|
+
|
|
227
|
+
const cidrCondition = builder.cidr('192.168.1.0/24');
|
|
228
|
+
expect(cidrCondition.operator).toBe('CIDR');
|
|
229
|
+
|
|
230
|
+
const datasetCondition = builder.inDataset('malware_ips');
|
|
231
|
+
expect(datasetCondition.operator).toBe('inDataset');
|
|
232
|
+
|
|
233
|
+
const betweenCondition = builder.between(5, 15);
|
|
234
|
+
expect(betweenCondition.operator).toBe('betweenOp');
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
describe('Performance and memory scenarios', () => {
|
|
239
|
+
test('should handle large datasets efficiently', () => {
|
|
240
|
+
const largeDataset = Array.from({ length: 1000 }, (_, i) => ({
|
|
241
|
+
id: i,
|
|
242
|
+
name: `User${i}`,
|
|
243
|
+
value: Math.random() * 100
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
const result = createQueryResult(largeDataset);
|
|
247
|
+
expect(result.len()).toBe(1000);
|
|
248
|
+
|
|
249
|
+
const filtered = result.filter(item => item.value > 50);
|
|
250
|
+
expect(filtered.length).toBeGreaterThan(0);
|
|
251
|
+
|
|
252
|
+
const summary = result.summarizeNumeric('value');
|
|
253
|
+
expect(summary).not.toBeNull();
|
|
254
|
+
expect(summary!.count).toBe(1000);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('should handle complex nested structures', () => {
|
|
258
|
+
const complexData = Array.from({ length: 100 }, (_, i) => ({
|
|
259
|
+
id: i,
|
|
260
|
+
user: {
|
|
261
|
+
profile: {
|
|
262
|
+
details: {
|
|
263
|
+
settings: {
|
|
264
|
+
preferences: {
|
|
265
|
+
theme: i % 2 === 0 ? 'dark' : 'light'
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}));
|
|
272
|
+
|
|
273
|
+
const result = createQueryResult(complexData);
|
|
274
|
+
const themes = result.pluck('user.profile.details.settings.preferences.theme');
|
|
275
|
+
expect(themes.filter(theme => theme === 'dark')).toHaveLength(50);
|
|
276
|
+
expect(themes.filter(theme => theme === 'light')).toHaveLength(50);
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
});
|