@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.
Files changed (98) hide show
  1. package/.DS_Store +0 -0
  2. package/.claude/settings.local.json +8 -0
  3. package/.gitignore +5 -0
  4. package/.idea/.gitignore +5 -0
  5. package/.idea/compiler.xml +6 -0
  6. package/.idea/inspectionProfiles/Project_Default.xml +6 -0
  7. package/.idea/jsLinters/eslint.xml +6 -0
  8. package/.idea/modules.xml +8 -0
  9. package/.idea/prettier.xml +7 -0
  10. package/.idea/sdk.iml +12 -0
  11. package/.idea/vcs.xml +6 -0
  12. package/.idea/workspace.xml +257 -0
  13. package/dist/client.d.ts.map +1 -1
  14. package/dist/client.js +11 -3
  15. package/dist/client.js.map +1 -1
  16. package/dist/database.d.ts +0 -20
  17. package/dist/database.d.ts.map +1 -1
  18. package/dist/database.js +0 -40
  19. package/dist/database.js.map +1 -1
  20. package/dist/query-sdk/tests/setup.d.ts +16 -0
  21. package/dist/query-sdk/tests/setup.d.ts.map +1 -0
  22. package/dist/query-sdk/tests/setup.js +49 -0
  23. package/dist/query-sdk/tests/setup.js.map +1 -0
  24. package/examples/basic-usage.ts +136 -0
  25. package/examples/blob-upload-example.ts +140 -0
  26. package/examples/collection-schema-example.ts +304 -0
  27. package/examples/server-side-joins.ts +201 -0
  28. package/examples/tweet-self-joins-example.ts +352 -0
  29. package/package-lock.json +3823 -0
  30. package/package.json +1 -1
  31. package/skills.md +1096 -0
  32. package/src/.env +1 -0
  33. package/src/batch.d.ts +121 -0
  34. package/src/batch.js +205 -0
  35. package/src/batch.ts +257 -0
  36. package/src/client.ts +1856 -0
  37. package/src/database.d.ts +268 -0
  38. package/src/database.js +294 -0
  39. package/src/database.ts +695 -0
  40. package/src/index.d.ts +160 -0
  41. package/src/index.js +186 -0
  42. package/src/index.ts +253 -0
  43. package/src/query-sdk/ConditionBuilder.ts +103 -0
  44. package/src/query-sdk/FieldConditionBuilder.ts +2 -0
  45. package/src/query-sdk/NestedBuilders.ts +186 -0
  46. package/src/query-sdk/OnChainDB.ts +294 -0
  47. package/src/query-sdk/QueryBuilder.ts +1191 -0
  48. package/src/query-sdk/QueryResult.ts +375 -0
  49. package/src/query-sdk/README.md +866 -0
  50. package/src/query-sdk/SelectionBuilder.ts +94 -0
  51. package/src/query-sdk/adapters/HttpClientAdapter.ts +249 -0
  52. package/src/query-sdk/dist/ConditionBuilder.d.ts +22 -0
  53. package/src/query-sdk/dist/ConditionBuilder.js +90 -0
  54. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +1 -0
  55. package/src/query-sdk/dist/FieldConditionBuilder.js +6 -0
  56. package/src/query-sdk/dist/NestedBuilders.d.ts +43 -0
  57. package/src/query-sdk/dist/NestedBuilders.js +144 -0
  58. package/src/query-sdk/dist/OnChainDB.d.ts +19 -0
  59. package/src/query-sdk/dist/OnChainDB.js +123 -0
  60. package/src/query-sdk/dist/QueryBuilder.d.ts +70 -0
  61. package/src/query-sdk/dist/QueryBuilder.js +295 -0
  62. package/src/query-sdk/dist/QueryResult.d.ts +52 -0
  63. package/src/query-sdk/dist/QueryResult.js +293 -0
  64. package/src/query-sdk/dist/SelectionBuilder.d.ts +20 -0
  65. package/src/query-sdk/dist/SelectionBuilder.js +80 -0
  66. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +27 -0
  67. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +170 -0
  68. package/src/query-sdk/dist/index.d.ts +36 -0
  69. package/src/query-sdk/dist/index.js +27 -0
  70. package/src/query-sdk/dist/operators.d.ts +56 -0
  71. package/src/query-sdk/dist/operators.js +289 -0
  72. package/src/query-sdk/dist/tests/setup.d.ts +15 -0
  73. package/src/query-sdk/dist/tests/setup.js +46 -0
  74. package/src/query-sdk/index.ts +59 -0
  75. package/src/query-sdk/jest.config.js +25 -0
  76. package/src/query-sdk/operators.ts +335 -0
  77. package/src/query-sdk/package.json +46 -0
  78. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +84 -0
  79. package/src/query-sdk/tests/LogicalOperator.test.ts +85 -0
  80. package/src/query-sdk/tests/NestedBuilders.test.ts +321 -0
  81. package/src/query-sdk/tests/QueryBuilder.test.ts +348 -0
  82. package/src/query-sdk/tests/QueryResult.test.ts +464 -0
  83. package/src/query-sdk/tests/aggregations.test.ts +653 -0
  84. package/src/query-sdk/tests/comprehensive.test.ts +279 -0
  85. package/src/query-sdk/tests/integration.test.ts +608 -0
  86. package/src/query-sdk/tests/operators.test.ts +327 -0
  87. package/src/query-sdk/tests/setup.ts +59 -0
  88. package/src/query-sdk/tests/unit.test.ts +794 -0
  89. package/src/query-sdk/tsconfig.json +26 -0
  90. package/src/query-sdk/yarn.lock +3092 -0
  91. package/src/types.d.ts +131 -0
  92. package/src/types.js +46 -0
  93. package/src/types.ts +534 -0
  94. package/src/x402/index.ts +12 -0
  95. package/src/x402/types.ts +250 -0
  96. package/src/x402/utils.ts +332 -0
  97. package/tsconfig.json +20 -0
  98. package/yarn.lock +2309 -0
@@ -0,0 +1,608 @@
1
+ // Integration tests for TypeScript SDK - Complete workflows
2
+ import {
3
+ QueryBuilder,
4
+ ConditionBuilder,
5
+ NestedConditionBuilder,
6
+ LogicalOperator,
7
+ FieldConditionBuilder,
8
+ QueryResult,
9
+ createQueryResult
10
+ } from '../index';
11
+
12
+ // Mock HTTP client that simulates real API responses
13
+ class MockHttpClient {
14
+ private responses: Record<string, any> = {
15
+ '/list': {
16
+ records: [
17
+ {
18
+ id: 1,
19
+ name: 'John Doe',
20
+ email: 'john@example.com',
21
+ age: 30,
22
+ department: 'Engineering',
23
+ user: {
24
+ profile: {
25
+ bio: 'Senior Developer',
26
+ settings: {
27
+ theme: 'dark',
28
+ notifications: true
29
+ }
30
+ },
31
+ metadata: {
32
+ lastLogin: '2024-01-15T10:30:00Z',
33
+ ipAddress: '192.168.1.100'
34
+ }
35
+ },
36
+ scores: [95, 87, 92],
37
+ active: true,
38
+ location: { lat: 40.7128, lng: -74.0060 }
39
+ },
40
+ {
41
+ id: 2,
42
+ name: 'Jane Smith',
43
+ email: 'jane@example.com',
44
+ age: 28,
45
+ department: 'Design',
46
+ user: {
47
+ profile: {
48
+ bio: 'UI/UX Designer',
49
+ settings: {
50
+ theme: 'light',
51
+ notifications: false
52
+ }
53
+ },
54
+ metadata: {
55
+ lastLogin: '2024-01-14T16:45:00Z',
56
+ ipAddress: '10.0.0.50'
57
+ }
58
+ },
59
+ scores: [88, 94, 90],
60
+ active: true,
61
+ location: { lat: 34.0522, lng: -118.2437 }
62
+ },
63
+ {
64
+ id: 3,
65
+ name: 'Bob Johnson',
66
+ email: 'bob@example.com',
67
+ age: 35,
68
+ department: 'Engineering',
69
+ user: {
70
+ profile: {
71
+ bio: 'DevOps Engineer',
72
+ settings: {
73
+ theme: 'dark',
74
+ notifications: true
75
+ }
76
+ },
77
+ metadata: {
78
+ lastLogin: '2024-01-13T09:15:00Z',
79
+ ipAddress: '192.168.1.101'
80
+ }
81
+ },
82
+ scores: [92, 85, 97],
83
+ active: false,
84
+ location: { lat: 41.8781, lng: -87.6298 }
85
+ }
86
+ ],
87
+ total: 3,
88
+ page: 1,
89
+ limit: 10
90
+ }
91
+ };
92
+
93
+ async post(url: string, data: any, headers?: Record<string, string>) {
94
+ // Simulate network delay
95
+ await new Promise(resolve => setTimeout(resolve, 10));
96
+
97
+ const response = this.responses[url.split('http://localhost:3000')[1] || url];
98
+ return { data: response };
99
+ }
100
+ }
101
+
102
+ // Test framework
103
+ interface IntegrationTest {
104
+ name: string;
105
+ test: () => Promise<void>;
106
+ }
107
+
108
+ class IntegrationTestRunner {
109
+ private tests: IntegrationTest[] = [];
110
+ private passed = 0;
111
+ private failed = 0;
112
+
113
+ add(name: string, test: () => Promise<void>) {
114
+ this.tests.push({ name, test });
115
+ }
116
+
117
+ async run() {
118
+ console.log(`🧪 Running ${this.tests.length} integration tests...\n`);
119
+
120
+ for (const testCase of this.tests) {
121
+ try {
122
+ await testCase.test();
123
+ console.log(`✅ ${testCase.name}`);
124
+ this.passed++;
125
+ } catch (error) {
126
+ console.error(`❌ ${testCase.name}: ${error instanceof Error ? error.message : error}`);
127
+ this.failed++;
128
+ }
129
+ }
130
+
131
+ console.log(`\n📊 Integration Test Results: ${this.passed} passed, ${this.failed} failed`);
132
+ if (this.failed > 0) {
133
+ process.exit(1);
134
+ }
135
+ }
136
+ }
137
+
138
+ // Helper functions
139
+ function assertEqual<T>(actual: T, expected: T, message?: string) {
140
+ const actualStr = JSON.stringify(actual);
141
+ const expectedStr = JSON.stringify(expected);
142
+ if (actualStr !== expectedStr) {
143
+ throw new Error(`${message || 'Values not equal'}\nExpected: ${expectedStr}\nActual: ${actualStr}`);
144
+ }
145
+ }
146
+
147
+ function assertTrue(condition: boolean, message?: string) {
148
+ if (!condition) {
149
+ throw new Error(message || 'Condition is false');
150
+ }
151
+ }
152
+
153
+ // Initialize test runner
154
+ const runner = new IntegrationTestRunner();
155
+
156
+ // ===== COMPLETE WORKFLOW TESTS =====
157
+
158
+ runner.add('Complete Query Workflow - Simple field query', async () => {
159
+ const client = new MockHttpClient();
160
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
161
+
162
+ const response = await queryBuilder
163
+ .collection('users')
164
+ .whereField('name').equals('John Doe')
165
+ .limit(10)
166
+ .selectFields(['id', 'name', 'email'])
167
+ .execute();
168
+
169
+ assertTrue(response.records.length > 0);
170
+ assertEqual(response.records[0].name, 'John Doe');
171
+ });
172
+
173
+ runner.add('Complete Query Workflow - Nested field query with dot notation', async () => {
174
+ const client = new MockHttpClient();
175
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
176
+
177
+ const response = await queryBuilder
178
+ .collection('users')
179
+ .whereField('user.profile.bio').contains('Developer')
180
+ .execute();
181
+
182
+ assertTrue(response.records.length >= 1);
183
+
184
+ // Verify the raw query structure includes nested fields
185
+ const rawQuery = queryBuilder.buildRawQuery();
186
+ assertTrue(typeof rawQuery.find === 'object');
187
+ });
188
+
189
+ runner.add('Complete Query Workflow - Complex logical conditions', async () => {
190
+ const client = new MockHttpClient();
191
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
192
+
193
+ const response = await queryBuilder
194
+ .collection('users')
195
+ .find(builder =>
196
+ builder.andGroup(() => [
197
+ LogicalOperator.Condition(new FieldConditionBuilder('age').greaterThan(25)),
198
+ LogicalOperator.Condition(new FieldConditionBuilder('department').equals('Engineering'))
199
+ ])
200
+ )
201
+ .limit(5)
202
+ .execute();
203
+
204
+ assertTrue(response.records.length > 0);
205
+ assertEqual(response.limit, 5);
206
+ });
207
+
208
+ runner.add('Complete Query Workflow - Nested builder with ORM-like syntax', async () => {
209
+ const client = new MockHttpClient();
210
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
211
+
212
+ const response = await queryBuilder
213
+ .collection('users')
214
+ .find(builder =>
215
+ builder.nested('user', nested =>
216
+ nested.andGroup(() => [
217
+ LogicalOperator.Condition(nested.field('profile').field('bio').contains('Engineer')),
218
+ LogicalOperator.Condition(nested.field('metadata').field('ipAddress').startsWith('192.168'))
219
+ ])
220
+ )
221
+ )
222
+ .execute();
223
+
224
+ assertTrue(response.records.length >= 0);
225
+
226
+ // Verify the query structure
227
+ const rawQuery = queryBuilder.buildRawQuery();
228
+ assertTrue(typeof rawQuery.find === 'object');
229
+ });
230
+
231
+ runner.add('Complete Query Workflow - Advanced operators', async () => {
232
+ const client = new MockHttpClient();
233
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
234
+
235
+ const response = await queryBuilder
236
+ .collection('users')
237
+ .whereField('age').between(25, 40)
238
+ .limit(10)
239
+ .execute();
240
+
241
+ assertTrue(response.records.length > 0);
242
+
243
+ // Test with date operators
244
+ const dateQuery = new QueryBuilder(client, 'http://localhost:3000', 'testApp')
245
+ .collection('users')
246
+ .whereField('user.metadata.lastLogin').dateAfter('2024-01-01')
247
+ .execute();
248
+
249
+ const dateResponse = await dateQuery;
250
+ assertTrue(dateResponse.records.length >= 0);
251
+ });
252
+
253
+ runner.add('Complete Query Workflow - IP and geographical queries', async () => {
254
+ const client = new MockHttpClient();
255
+
256
+ // Test IP range query
257
+ const ipQuery = new QueryBuilder(client, 'http://localhost:3000', 'testApp')
258
+ .collection('users')
259
+ .whereField('user.metadata.ipAddress').ipInRange('192.168.1.0/24')
260
+ .execute();
261
+
262
+ const ipResponse = await ipQuery;
263
+ assertTrue(ipResponse.records.length >= 0);
264
+
265
+ // Test geographical query
266
+ const geoQuery = new QueryBuilder(client, 'http://localhost:3000', 'testApp')
267
+ .collection('users')
268
+ .whereField('location').geoWithinRadius(40.7128, -74.0060, 100)
269
+ .execute();
270
+
271
+ const geoResponse = await geoQuery;
272
+ assertTrue(geoResponse.records.length >= 0);
273
+ });
274
+
275
+ runner.add('Complete Query Workflow - Array and type checking operators', async () => {
276
+ const client = new MockHttpClient();
277
+
278
+ // Test array operators
279
+ const arrayQuery = new QueryBuilder(client, 'http://localhost:3000', 'testApp')
280
+ .collection('users')
281
+ .whereField('scores').arrayLength(3)
282
+ .execute();
283
+
284
+ const arrayResponse = await arrayQuery;
285
+ assertTrue(arrayResponse.records.length >= 0);
286
+
287
+ // Test type checking
288
+ const typeQuery = new QueryBuilder(client, 'http://localhost:3000', 'testApp')
289
+ .collection('users')
290
+ .whereField('active').isBoolean()
291
+ .execute();
292
+
293
+ const typeResponse = await typeQuery;
294
+ assertTrue(typeResponse.records.length >= 0);
295
+ });
296
+
297
+ // ===== QUERY RESULT PROCESSING WORKFLOWS =====
298
+
299
+ runner.add('QueryResult Processing Workflow - Complete data analysis', async () => {
300
+ const client = new MockHttpClient();
301
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
302
+
303
+ const response = await queryBuilder
304
+ .collection('users')
305
+ .selectAll()
306
+ .execute();
307
+
308
+ const result = createQueryResult(response.records);
309
+
310
+ // Basic analysis
311
+ assertTrue(result.len() > 0);
312
+ assertTrue(!result.isEmpty());
313
+
314
+ // Pluck and analyze ages
315
+ const ages = result.pluckNumbers('age');
316
+ const ageSummary = result.summarizeNumeric('age');
317
+
318
+ assertTrue(ageSummary !== null);
319
+ assertTrue(ageSummary.mean > 0);
320
+ assertTrue(ageSummary.min <= ageSummary.max);
321
+
322
+ // Group by department
323
+ const byDepartment = result.groupBy('department');
324
+ assertTrue('Engineering' in byDepartment);
325
+ assertTrue('Design' in byDepartment);
326
+
327
+ // Sort by age
328
+ const sortedByAge = result.sortBy('age');
329
+ assertTrue(sortedByAge.length === result.len());
330
+
331
+ // Filter active users
332
+ const activeUsers = result.filter(user => user.active);
333
+ assertTrue(activeUsers.length >= 0);
334
+ });
335
+
336
+ runner.add('QueryResult Processing Workflow - Nested field analysis', async () => {
337
+ const client = new MockHttpClient();
338
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
339
+
340
+ const response = await queryBuilder
341
+ .collection('users')
342
+ .selectAll()
343
+ .execute();
344
+
345
+ const result = createQueryResult(response.records);
346
+
347
+ // Analyze nested profile data
348
+ const themes = result.pluck('user.profile.settings.theme');
349
+ const themeGroups = result.groupBy('user.profile.settings.theme');
350
+
351
+ assertTrue(themes.length > 0);
352
+ assertTrue('dark' in themeGroups || 'light' in themeGroups);
353
+
354
+ // Sort by nested field
355
+ const sortedByBio = result.sortBy('user.profile.bio');
356
+ assertTrue(sortedByBio.length === result.len());
357
+
358
+ // Count by nested boolean
359
+ const notificationCounts = result.countBy('user.profile.settings.notifications');
360
+ assertTrue('true' in notificationCounts || 'false' in notificationCounts);
361
+ });
362
+
363
+ runner.add('QueryResult Processing Workflow - Advanced aggregations', async () => {
364
+ const client = new MockHttpClient();
365
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
366
+
367
+ const response = await queryBuilder
368
+ .collection('users')
369
+ .selectAll()
370
+ .execute();
371
+
372
+ const result = createQueryResult(response.records);
373
+
374
+ // Multi-field sorting
375
+ const sortedMultiple = result.sortByMultiple([
376
+ { field: 'department', ascending: true },
377
+ { field: 'age', ascending: false }
378
+ ]);
379
+ assertTrue(sortedMultiple.length === result.len());
380
+
381
+ // Pagination
382
+ const page1 = result.paginate(1, 2);
383
+ const page2 = result.paginate(2, 2);
384
+ assertTrue(page1.length <= 2);
385
+ assertTrue(page2.length >= 0);
386
+
387
+ // Chunking
388
+ const chunks = result.chunk(2);
389
+ assertTrue(chunks.length >= 1);
390
+
391
+ // Distinct values
392
+ const distinctDepts = result.distinctBy('department');
393
+ assertTrue(distinctDepts.length <= result.len());
394
+ });
395
+
396
+ runner.add('QueryResult Processing Workflow - Data export and joins', async () => {
397
+ const client = new MockHttpClient();
398
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
399
+
400
+ const response = await queryBuilder
401
+ .collection('users')
402
+ .selectAll()
403
+ .execute();
404
+
405
+ const users = createQueryResult(response.records);
406
+
407
+ // Create mock departments for join
408
+ const departments = createQueryResult([
409
+ { name: 'Engineering', budget: 100000 },
410
+ { name: 'Design', budget: 75000 }
411
+ ]);
412
+
413
+ // Test join operations
414
+ const joinedData = users.innerJoin(departments, 'department', 'name');
415
+ assertTrue(joinedData.length >= 0);
416
+
417
+ // Test CSV export
418
+ const csv = users.toCsv();
419
+ const lines = csv.split('\n');
420
+ assertTrue(lines.length > 1); // At least header + 1 row
421
+ assertTrue(lines[0].includes('id'));
422
+ assertTrue(lines[0].includes('name'));
423
+
424
+ // Test JSON export
425
+ const json = users.toJSON();
426
+ const parsed = JSON.parse(json);
427
+ assertTrue(Array.isArray(parsed));
428
+ assertTrue(parsed.length > 0);
429
+ });
430
+
431
+ // ===== ERROR HANDLING AND EDGE CASE WORKFLOWS =====
432
+
433
+ runner.add('Error Handling Workflow - Missing HTTP client', async () => {
434
+ const queryBuilder = new QueryBuilder(); // No HTTP client
435
+
436
+ try {
437
+ await queryBuilder
438
+ .collection('users')
439
+ .whereField('name').equals('John')
440
+ .execute();
441
+
442
+ throw new Error('Should have thrown error for missing HTTP client');
443
+ } catch (error) {
444
+ assertTrue(error instanceof Error);
445
+ assertTrue(error.message.includes('HTTP client'));
446
+ }
447
+ });
448
+
449
+ runner.add('Error Handling Workflow - Missing server URL', async () => {
450
+ const client = new MockHttpClient();
451
+ const queryBuilder = new QueryBuilder(client); // No server URL
452
+
453
+ try {
454
+ await queryBuilder
455
+ .collection('users')
456
+ .whereField('name').equals('John')
457
+ .execute();
458
+
459
+ throw new Error('Should have thrown error for missing server URL');
460
+ } catch (error) {
461
+ assertTrue(error instanceof Error);
462
+ assertTrue(error.message.includes('Server URL'));
463
+ }
464
+ });
465
+
466
+ runner.add('Edge Case Workflow - Empty result processing', async () => {
467
+ // Simulate empty response
468
+ class EmptyMockClient {
469
+ async post() {
470
+ return {
471
+ data: {
472
+ records: [],
473
+ total: 0,
474
+ page: 1,
475
+ limit: 10
476
+ }
477
+ };
478
+ }
479
+ }
480
+
481
+ const client = new EmptyMockClient();
482
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
483
+
484
+ const response = await queryBuilder
485
+ .collection('users')
486
+ .whereField('nonexistent').equals('value')
487
+ .execute();
488
+
489
+ assertEqual(response.records.length, 0);
490
+
491
+ const result = createQueryResult(response.records);
492
+ assertTrue(result.isEmpty());
493
+ assertEqual(result.first(), undefined);
494
+ assertEqual(result.summarizeNumeric('age'), null);
495
+ });
496
+
497
+ runner.add('Edge Case Workflow - Complex nested queries with missing fields', async () => {
498
+ const client = new MockHttpClient();
499
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
500
+
501
+ // Query with deeply nested field that might not exist
502
+ const response = await queryBuilder
503
+ .collection('users')
504
+ .find(builder =>
505
+ builder.nested('user', nested =>
506
+ nested.field('profile').field('settings').field('advanced').field('feature').equals('enabled')
507
+ )
508
+ )
509
+ .execute();
510
+
511
+ // Should not throw error even if nested field doesn't exist
512
+ assertTrue(response.records.length >= 0);
513
+
514
+ const result = createQueryResult(response.records);
515
+
516
+ // Test accessing missing nested fields
517
+ const missingValues = result.pluck('user.profile.settings.advanced.feature');
518
+ assertTrue(Array.isArray(missingValues));
519
+ });
520
+
521
+ runner.add('Performance Workflow - Large dataset simulation', async () => {
522
+ // Create a mock client that returns larger dataset
523
+ class LargeDataMockClient {
524
+ async post() {
525
+ const records = Array.from({ length: 100 }, (_, i) => ({
526
+ id: i + 1,
527
+ name: `User ${i + 1}`,
528
+ age: Math.floor(Math.random() * 50) + 20,
529
+ department: ['Engineering', 'Design', 'Marketing'][i % 3],
530
+ user: {
531
+ profile: {
532
+ bio: `Bio for user ${i + 1}`,
533
+ settings: {
534
+ theme: ['dark', 'light'][i % 2],
535
+ notifications: i % 2 === 0
536
+ }
537
+ }
538
+ },
539
+ scores: [
540
+ Math.floor(Math.random() * 100),
541
+ Math.floor(Math.random() * 100),
542
+ Math.floor(Math.random() * 100)
543
+ ],
544
+ active: i % 3 !== 0
545
+ }));
546
+
547
+ return {
548
+ data: {
549
+ records,
550
+ total: 1000,
551
+ page: 1,
552
+ limit: 100
553
+ }
554
+ };
555
+ }
556
+ }
557
+
558
+ const client = new LargeDataMockClient();
559
+ const queryBuilder = new QueryBuilder(client, 'http://localhost:3000', 'testApp');
560
+
561
+ const startTime = Date.now();
562
+
563
+ const response = await queryBuilder
564
+ .collection('users')
565
+ .find(builder =>
566
+ builder.andGroup(() => [
567
+ LogicalOperator.Condition(new FieldConditionBuilder('age').between(25, 45)),
568
+ LogicalOperator.Condition(new FieldConditionBuilder('active').isTrue())
569
+ ])
570
+ )
571
+ .limit(50)
572
+ .execute();
573
+
574
+ const queryTime = Date.now() - startTime;
575
+
576
+ const result = createQueryResult(response.records);
577
+
578
+ const processingStartTime = Date.now();
579
+
580
+ // Perform various operations on the large dataset
581
+ const summary = result.summarizeNumeric('age');
582
+ const grouped = result.groupBy('department');
583
+ const sorted = result.sortByMultiple([
584
+ { field: 'department', ascending: true },
585
+ { field: 'age', ascending: false }
586
+ ]);
587
+ const filtered = result.filter(user => user.active);
588
+ const csv = result.toCsv();
589
+
590
+ const processingTime = Date.now() - processingStartTime;
591
+
592
+ console.log(` Query time: ${queryTime}ms, Processing time: ${processingTime}ms`);
593
+
594
+ // Verify results
595
+ assertTrue(response.records.length > 0);
596
+ assertTrue(summary !== null);
597
+ assertTrue(Object.keys(grouped).length > 0);
598
+ assertTrue(sorted.length > 0);
599
+ assertTrue(filtered.length >= 0);
600
+ assertTrue(csv.length > 0);
601
+
602
+ // Performance should be reasonable (adjust thresholds as needed)
603
+ assertTrue(queryTime < 1000, 'Query should complete in reasonable time');
604
+ assertTrue(processingTime < 1000, 'Processing should complete in reasonable time');
605
+ });
606
+
607
+ // Run all integration tests
608
+ runner.run();