interaqt 0.3.0 → 0.3.1

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 (35) hide show
  1. package/agent/.claude/agents/code-generation-handler.md +2 -0
  2. package/agent/.claude/agents/computation-generation-handler.md +1 -0
  3. package/agent/.claude/agents/implement-design-handler.md +4 -13
  4. package/agent/.claude/agents/requirements-analysis-handler.md +46 -14
  5. package/agent/agentspace/knowledge/generator/api-reference.md +3378 -0
  6. package/agent/agentspace/knowledge/generator/basic-interaction-generation.md +377 -0
  7. package/agent/agentspace/knowledge/generator/computation-analysis.md +307 -0
  8. package/agent/agentspace/knowledge/generator/computation-implementation.md +959 -0
  9. package/agent/agentspace/knowledge/generator/data-analysis.md +463 -0
  10. package/agent/agentspace/knowledge/generator/entity-relation-generation.md +395 -0
  11. package/agent/agentspace/knowledge/generator/permission-implementation.md +460 -0
  12. package/agent/agentspace/knowledge/generator/permission-test-implementation.md +870 -0
  13. package/agent/agentspace/knowledge/generator/test-implementation.md +674 -0
  14. package/agent/agentspace/knowledge/usage/00-mindset-shift.md +322 -0
  15. package/agent/agentspace/knowledge/usage/01-core-concepts.md +131 -0
  16. package/agent/agentspace/knowledge/usage/02-define-entities-properties.md +407 -0
  17. package/agent/agentspace/knowledge/usage/03-entity-relations.md +599 -0
  18. package/agent/agentspace/knowledge/usage/04-reactive-computations.md +2186 -0
  19. package/agent/agentspace/knowledge/usage/05-interactions.md +1411 -0
  20. package/agent/agentspace/knowledge/usage/06-attributive-permissions.md +10 -0
  21. package/agent/agentspace/knowledge/usage/07-payload-parameters.md +593 -0
  22. package/agent/agentspace/knowledge/usage/08-activities.md +863 -0
  23. package/agent/agentspace/knowledge/usage/09-filtered-entities.md +784 -0
  24. package/agent/agentspace/knowledge/usage/10-async-computations.md +734 -0
  25. package/agent/agentspace/knowledge/usage/11-global-dictionaries.md +942 -0
  26. package/agent/agentspace/knowledge/usage/12-data-querying.md +1033 -0
  27. package/agent/agentspace/knowledge/usage/13-testing.md +1201 -0
  28. package/agent/agentspace/knowledge/usage/14-api-reference.md +1606 -0
  29. package/agent/agentspace/knowledge/usage/15-entity-crud-patterns.md +1122 -0
  30. package/agent/agentspace/knowledge/usage/16-frontend-page-design-guide.md +485 -0
  31. package/agent/agentspace/knowledge/usage/17-performance-optimization.md +283 -0
  32. package/agent/agentspace/knowledge/usage/18-api-exports-reference.md +176 -0
  33. package/agent/agentspace/knowledge/usage/19-common-anti-patterns.md +563 -0
  34. package/agent/agentspace/knowledge/usage/README.md +148 -0
  35. package/package.json +1 -1
@@ -0,0 +1,1033 @@
1
+ # 11. How to Handle Data Querying
2
+
3
+ Data querying is one of the core functionalities in the interaqt framework, providing powerful and flexible data retrieval capabilities. The framework supports advanced features such as complex query conditions, relational queries, and deep queries, enabling developers to efficiently obtain the required data.
4
+
5
+ ## 11.1 Basic Query Operations
6
+
7
+ ### 11.1.1 findOne - Query Single Record
8
+
9
+ ```typescript
10
+ import { MatchExp } from 'interaqt';
11
+
12
+ // Basic single record query
13
+ const user = await system.storage.findOne(
14
+ 'User', // Entity name
15
+ MatchExp.atom({ key: 'id', value: ['=', 123] }), // Query condition
16
+ {}, // Modifier (optional)
17
+ ['name', 'email', 'age'] // Attribute query (optional)
18
+ );
19
+
20
+ // Query by username
21
+ const userByName = await system.storage.findOne(
22
+ 'User',
23
+ MatchExp.atom({ key: 'username', value: ['=', 'alice'] }),
24
+ {},
25
+ ['id', 'username', 'email', 'isActive']
26
+ );
27
+
28
+ // Query by email (case insensitive)
29
+ const userByEmail = await system.storage.findOne(
30
+ 'User',
31
+ MatchExp.atom({ key: 'email', value: ['like', '%@example.com'] }),
32
+ {},
33
+ ['*'] // Query all attributes
34
+ );
35
+
36
+ console.log('Found user:', user);
37
+ ```
38
+
39
+ ### 11.1.2 find - Query Multiple Records
40
+
41
+ ```typescript
42
+ // Query all active users
43
+ const activeUsers = await system.storage.find(
44
+ 'User',
45
+ MatchExp.atom({ key: 'isActive', value: ['=', true] }),
46
+ {},
47
+ ['id', 'username', 'email']
48
+ );
49
+
50
+ // Query users older than 18
51
+ const adultUsers = await system.storage.find(
52
+ 'User',
53
+ MatchExp.atom({ key: 'age', value: ['>', 18] }),
54
+ {},
55
+ ['id', 'username', 'age']
56
+ );
57
+
58
+ // Query all users (no conditions)
59
+ const allUsers = await system.storage.find(
60
+ 'User',
61
+ undefined, // No query conditions
62
+ {},
63
+ ['id', 'username', 'createdAt']
64
+ );
65
+
66
+ console.log(`Found ${activeUsers.length} active users`);
67
+ ```
68
+
69
+ ### 11.1.3 Building Conditions with MatchExp
70
+
71
+ ```typescript
72
+ // Create basic match condition
73
+ const basicMatch = MatchExp.atom({
74
+ key: 'status',
75
+ value: ['=', 'active']
76
+ });
77
+
78
+ // Create match condition from object
79
+ const objectMatch = MatchExp.fromObject({
80
+ isActive: true,
81
+ role: 'admin'
82
+ });
83
+
84
+ // Using factory method
85
+ const factoryMatch = system.storage.createMatchFromAtom({
86
+ key: 'createdAt',
87
+ value: ['>', '2023-01-01']
88
+ });
89
+
90
+ // Chain complex conditions
91
+ const complexMatch = MatchExp.atom({ key: 'age', value: ['>=', 18] })
92
+ .and({ key: 'isActive', value: ['=', true] })
93
+ .and({ key: 'role', value: ['in', ['user', 'admin']] });
94
+ ```
95
+
96
+ ## 11.2 Complex Query Conditions
97
+
98
+ ### 11.2.1 Comparison Operators
99
+
100
+ ```typescript
101
+ // Equals
102
+ const equalMatch = MatchExp.atom({ key: 'status', value: ['=', 'active'] });
103
+
104
+ // Not equals
105
+ const notEqualMatch = MatchExp.atom({ key: 'status', value: ['!=', 'deleted'] });
106
+
107
+ // Greater than
108
+ const greaterMatch = MatchExp.atom({ key: 'age', value: ['>', 18] });
109
+
110
+ // Greater than or equal
111
+ const greaterEqualMatch = MatchExp.atom({ key: 'score', value: ['>=', 80] });
112
+
113
+ // Less than
114
+ const lessMatch = MatchExp.atom({ key: 'price', value: ['<', 100] });
115
+
116
+ // Less than or equal
117
+ const lessEqualMatch = MatchExp.atom({ key: 'discount', value: ['<=', 0.5] });
118
+
119
+ // Like pattern matching
120
+ const likeMatch = MatchExp.atom({ key: 'email', value: ['like', '%@gmail.com'] });
121
+
122
+ // Range query
123
+ const betweenMatch = MatchExp.atom({
124
+ key: 'createdAt',
125
+ value: ['between', ['2023-01-01', '2023-12-31']]
126
+ });
127
+
128
+ // IN query
129
+ const inMatch = MatchExp.atom({
130
+ key: 'category',
131
+ value: ['in', ['electronics', 'books', 'clothing']]
132
+ });
133
+
134
+ // Not null check
135
+ const notNullMatch = MatchExp.atom({ key: 'email', value: ['not', null] });
136
+ ```
137
+
138
+ ### 11.2.2 Logical Combinations (AND/OR)
139
+
140
+ ```typescript
141
+ // AND logical combination
142
+ const andCondition = MatchExp.atom({ key: 'age', value: ['>=', 18] })
143
+ .and({ key: 'isActive', value: ['=', true] })
144
+ .and({ key: 'role', value: ['!=', 'guest'] });
145
+
146
+ const adultActiveUsers = await system.storage.find(
147
+ 'User',
148
+ andCondition,
149
+ {},
150
+ ['id', 'username', 'age', 'role']
151
+ );
152
+
153
+ // OR logical combination (implemented through multiple queries)
154
+ const adminUsers = await system.storage.find(
155
+ 'User',
156
+ MatchExp.atom({ key: 'role', value: ['=', 'admin'] }),
157
+ {},
158
+ ['id', 'username', 'role']
159
+ );
160
+
161
+ const moderatorUsers = await system.storage.find(
162
+ 'User',
163
+ MatchExp.atom({ key: 'role', value: ['=', 'moderator'] }),
164
+ {},
165
+ ['id', 'username', 'role']
166
+ );
167
+
168
+ // Merge results
169
+ const privilegedUsers = [...adminUsers, ...moderatorUsers];
170
+
171
+ // Complex nested conditions
172
+ const complexCondition = MatchExp.atom({ key: 'isActive', value: ['=', true] })
173
+ .and(
174
+ MatchExp.atom({ key: 'age', value: ['>=', 18] })
175
+ .and({ key: 'age', value: ['<=', 65] })
176
+ )
177
+ .and({ key: 'email', value: ['not', null] });
178
+ ```
179
+
180
+ ### 11.2.3 Relational Queries
181
+
182
+ ```typescript
183
+ // Query through related entity properties
184
+ const usersWithGmailProfile = await system.storage.find(
185
+ 'User',
186
+ MatchExp.atom({ key: 'profile.email', value: ['like', '%@gmail.com'] }),
187
+ {},
188
+ ['id', 'username', ['profile', { attributeQuery: ['email', 'firstName'] }]]
189
+ );
190
+
191
+ // Query through multi-level related entity properties
192
+ const usersWithSpecificProfileTitle = await system.storage.find(
193
+ 'User',
194
+ MatchExp.atom({ key: 'profile.settings.title', value: ['=', 'VIP'] }),
195
+ {},
196
+ ['id', 'username']
197
+ );
198
+
199
+ // Query users with specific tags
200
+ const usersWithTags = await system.storage.find(
201
+ 'User',
202
+ MatchExp.atom({ key: 'tags.name', value: ['=', 'premium'] }),
203
+ {},
204
+ ['id', 'username', ['tags', { attributeQuery: ['name', 'category'] }]]
205
+ );
206
+ ```
207
+
208
+ ### 11.2.4 Nested Conditions
209
+
210
+ ```typescript
211
+ // Existence query (EXIST)
212
+ const usersWithPosts = await system.storage.find(
213
+ 'User',
214
+ MatchExp.atom({
215
+ key: 'posts',
216
+ value: ['exist', { key: 'status', value: ['=', 'published'] }]
217
+ }),
218
+ {},
219
+ ['id', 'username']
220
+ );
221
+
222
+ // Complex existence query
223
+ const usersWithRecentPosts = await system.storage.find(
224
+ 'User',
225
+ MatchExp.atom({
226
+ key: 'posts',
227
+ value: ['exist', MatchExp.atom({ key: 'publishedAt', value: ['>', '2023-01-01'] })
228
+ .and({ key: 'status', value: ['=', 'published'] })]
229
+ }),
230
+ {},
231
+ ['id', 'username', 'email']
232
+ );
233
+
234
+ // Reference value query (compare different fields in same record)
235
+ const usersWithHighScore = await system.storage.find(
236
+ 'User',
237
+ MatchExp.atom({
238
+ key: 'currentScore',
239
+ value: ['>', 'bestScore'],
240
+ isReferenceValue: true
241
+ }),
242
+ {},
243
+ ['id', 'username', 'currentScore', 'bestScore']
244
+ );
245
+ ```
246
+
247
+ ## 11.3 Modifiers and Sorting
248
+
249
+ ### 11.3.1 Pagination
250
+
251
+ ```typescript
252
+ // Basic pagination
253
+ const firstPage = await system.storage.find(
254
+ 'User',
255
+ MatchExp.atom({ key: 'isActive', value: ['=', true] }),
256
+ {
257
+ limit: 10, // 10 records per page
258
+ offset: 0 // Start from record 0
259
+ },
260
+ ['id', 'username', 'email']
261
+ );
262
+
263
+ const secondPage = await system.storage.find(
264
+ 'User',
265
+ MatchExp.atom({ key: 'isActive', value: ['=', true] }),
266
+ {
267
+ limit: 10,
268
+ offset: 10 // Start from record 10
269
+ },
270
+ ['id', 'username', 'email']
271
+ );
272
+
273
+ // Pagination utility function
274
+ async function getPaginatedUsers(page: number, pageSize: number = 10) {
275
+ const offset = (page - 1) * pageSize;
276
+
277
+ const users = await system.storage.find(
278
+ 'User',
279
+ undefined,
280
+ { limit: pageSize, offset },
281
+ ['id', 'username', 'email', 'createdAt']
282
+ );
283
+
284
+ // Get total count (requires separate query)
285
+ const totalUsers = await system.storage.find(
286
+ 'User',
287
+ undefined,
288
+ {},
289
+ ['id'] // Only query ID for performance
290
+ );
291
+
292
+ return {
293
+ data: users,
294
+ pagination: {
295
+ page,
296
+ pageSize,
297
+ total: totalUsers.length,
298
+ totalPages: Math.ceil(totalUsers.length / pageSize)
299
+ }
300
+ };
301
+ }
302
+
303
+ // Use pagination query
304
+ const result = await getPaginatedUsers(1, 20);
305
+ console.log(`Page 1 of ${result.pagination.totalPages}, showing ${result.data.length} users`);
306
+ ```
307
+
308
+ ### 11.3.2 Sorting
309
+
310
+ ```typescript
311
+ // Single field sorting
312
+ const usersSortedByAge = await system.storage.find(
313
+ 'User',
314
+ undefined,
315
+ { orderBy: { age: 'ASC' } },
316
+ ['id', 'username', 'age']
317
+ );
318
+
319
+ const usersSortedByNameDesc = await system.storage.find(
320
+ 'User',
321
+ undefined,
322
+ { orderBy: { username: 'DESC' } },
323
+ ['id', 'username', 'createdAt']
324
+ );
325
+
326
+ // Multi-field sorting
327
+ const usersSortedMultiple = await system.storage.find(
328
+ 'User',
329
+ undefined,
330
+ {
331
+ orderBy: {
332
+ isActive: 'DESC', // First by active status descending
333
+ age: 'ASC', // Then by age ascending
334
+ username: 'ASC' // Finally by username ascending
335
+ }
336
+ },
337
+ ['id', 'username', 'age', 'isActive']
338
+ );
339
+
340
+ // Combine pagination and sorting
341
+ const topUsers = await system.storage.find(
342
+ 'User',
343
+ MatchExp.atom({ key: 'score', value: ['>', 0] }),
344
+ {
345
+ orderBy: { score: 'DESC' },
346
+ limit: 10,
347
+ offset: 0
348
+ },
349
+ ['id', 'username', 'score']
350
+ );
351
+ ```
352
+
353
+ ### 11.3.3 Combined Modifiers
354
+
355
+ ```typescript
356
+ // Complete query example
357
+ async function searchUsers(criteria: {
358
+ keyword?: string;
359
+ minAge?: number;
360
+ maxAge?: number;
361
+ isActive?: boolean;
362
+ roles?: string[];
363
+ page?: number;
364
+ pageSize?: number;
365
+ sortBy?: string;
366
+ sortOrder?: 'ASC' | 'DESC';
367
+ }) {
368
+ // Build query conditions
369
+ let matchCondition = undefined;
370
+
371
+ if (criteria.keyword) {
372
+ matchCondition = MatchExp.atom({
373
+ key: 'username',
374
+ value: ['like', `%${criteria.keyword}%`]
375
+ });
376
+ }
377
+
378
+ if (criteria.minAge !== undefined) {
379
+ const ageCondition = MatchExp.atom({ key: 'age', value: ['>=', criteria.minAge] });
380
+ matchCondition = matchCondition ? matchCondition.and(ageCondition) : ageCondition;
381
+ }
382
+
383
+ if (criteria.maxAge !== undefined) {
384
+ const ageCondition = MatchExp.atom({ key: 'age', value: ['<=', criteria.maxAge] });
385
+ matchCondition = matchCondition ? matchCondition.and(ageCondition) : ageCondition;
386
+ }
387
+
388
+ if (criteria.isActive !== undefined) {
389
+ const activeCondition = MatchExp.atom({ key: 'isActive', value: ['=', criteria.isActive] });
390
+ matchCondition = matchCondition ? matchCondition.and(activeCondition) : activeCondition;
391
+ }
392
+
393
+ if (criteria.roles && criteria.roles.length > 0) {
394
+ const roleCondition = MatchExp.atom({ key: 'role', value: ['in', criteria.roles] });
395
+ matchCondition = matchCondition ? matchCondition.and(roleCondition) : roleCondition;
396
+ }
397
+
398
+ // Build modifiers
399
+ const modifier: any = {};
400
+
401
+ if (criteria.sortBy) {
402
+ modifier.orderBy = { [criteria.sortBy]: criteria.sortOrder || 'ASC' };
403
+ }
404
+
405
+ if (criteria.page && criteria.pageSize) {
406
+ modifier.limit = criteria.pageSize;
407
+ modifier.offset = (criteria.page - 1) * criteria.pageSize;
408
+ }
409
+
410
+ // Execute query
411
+ const users = await system.storage.find(
412
+ 'User',
413
+ matchCondition,
414
+ modifier,
415
+ ['id', 'username', 'email', 'age', 'role', 'isActive', 'createdAt']
416
+ );
417
+
418
+ return users;
419
+ }
420
+
421
+ // Use search function
422
+ const searchResults = await searchUsers({
423
+ keyword: 'john',
424
+ minAge: 18,
425
+ maxAge: 65,
426
+ isActive: true,
427
+ roles: ['user', 'admin'],
428
+ page: 1,
429
+ pageSize: 20,
430
+ sortBy: 'createdAt',
431
+ sortOrder: 'DESC'
432
+ });
433
+ ```
434
+
435
+ ## 11.4 Attribute Queries
436
+
437
+ ### 11.4.1 Basic Attribute Selection
438
+
439
+ ```typescript
440
+ // Select specific attributes
441
+ const basicUsers = await system.storage.find(
442
+ 'User',
443
+ undefined,
444
+ {},
445
+ ['id', 'username', 'email'] // Only return these attributes
446
+ );
447
+
448
+ // Query all attributes
449
+ const fullUsers = await system.storage.find(
450
+ 'User',
451
+ undefined,
452
+ {},
453
+ ['*'] // Return all attributes
454
+ );
455
+
456
+ // Exclude sensitive attributes
457
+ const publicUsers = await system.storage.find(
458
+ 'User',
459
+ undefined,
460
+ {},
461
+ ['id', 'username', 'avatar', 'createdAt'] // Don't include email, password etc.
462
+ );
463
+ ```
464
+
465
+ ### 11.4.2 Nested Attribute Selection
466
+
467
+ ```typescript
468
+ // Query users with their profiles
469
+ const usersWithProfiles = await system.storage.find(
470
+ 'User',
471
+ undefined,
472
+ {},
473
+ [
474
+ 'id',
475
+ 'username',
476
+ ['profile', {
477
+ attributeQuery: ['firstName', 'lastName', 'avatar']
478
+ }]
479
+ ]
480
+ );
481
+
482
+ // Multi-level nested queries
483
+ const usersWithDetailedInfo = await system.storage.find(
484
+ 'User',
485
+ undefined,
486
+ {},
487
+ [
488
+ 'id',
489
+ 'username',
490
+ 'email',
491
+ ['profile', {
492
+ attributeQuery: [
493
+ 'firstName',
494
+ 'lastName',
495
+ ['settings', {
496
+ attributeQuery: ['theme', 'language', 'notifications']
497
+ }]
498
+ ]
499
+ }],
500
+ ['posts', {
501
+ attributeQuery: ['id', 'title', 'publishedAt']
502
+ }]
503
+ ]
504
+ );
505
+
506
+ // Conditional nested queries
507
+ const usersWithPublishedPosts = await system.storage.find(
508
+ 'User',
509
+ undefined,
510
+ {},
511
+ [
512
+ 'id',
513
+ 'username',
514
+ ['posts', {
515
+ attributeQuery: ['id', 'title', 'content', 'publishedAt'],
516
+ matchExpression: MatchExp.atom({ key: 'status', value: ['=', 'published'] })
517
+ }]
518
+ ]
519
+ );
520
+ ```
521
+
522
+ ### 11.4.3 Relationship Attribute Queries
523
+
524
+ ```typescript
525
+ // Query user friendship relations
526
+ const usersWithFriends = await system.storage.find(
527
+ 'User',
528
+ undefined,
529
+ {},
530
+ [
531
+ 'id',
532
+ 'username',
533
+ ['friends', {
534
+ attributeQuery: [
535
+ 'id',
536
+ 'username',
537
+ 'avatar',
538
+ ['&', { attributeQuery: ['since', 'closeness'] }] // Relationship attributes
539
+ ]
540
+ }]
541
+ ]
542
+ );
543
+
544
+ // Query orders with items
545
+ const ordersWithItems = await system.storage.find(
546
+ 'Order',
547
+ undefined,
548
+ {},
549
+ [
550
+ 'id',
551
+ 'orderNumber',
552
+ 'totalAmount',
553
+ 'status',
554
+ ['items', {
555
+ attributeQuery: [
556
+ ['product', { attributeQuery: ['name', 'price', 'category'] }],
557
+ ['&', { attributeQuery: ['quantity', 'unitPrice', 'discount'] }] // Order item attributes
558
+ ]
559
+ }]
560
+ ]
561
+ );
562
+
563
+ // Complex relationship queries
564
+ const teamProjectInfo = await system.storage.find(
565
+ 'Team',
566
+ undefined,
567
+ {},
568
+ [
569
+ 'id',
570
+ 'name',
571
+ 'description',
572
+ ['members', {
573
+ attributeQuery: [
574
+ 'id',
575
+ 'username',
576
+ 'email',
577
+ ['&', { attributeQuery: ['role', 'joinedAt'] }], // Team member relationship attributes
578
+ ['profile', { attributeQuery: ['firstName', 'lastName'] }] // Member profile
579
+ ]
580
+ }],
581
+ ['projects', {
582
+ attributeQuery: [
583
+ 'id',
584
+ 'name',
585
+ 'status',
586
+ 'deadline',
587
+ ['&', { attributeQuery: ['priority', 'assignedAt'] }] // Project assignment relationship attributes
588
+ ]
589
+ }]
590
+ ]
591
+ );
592
+ ```
593
+
594
+ ## 11.5 Querying Relationship Data
595
+
596
+ ### 11.5.1 Preloading Related Data
597
+
598
+ ```typescript
599
+ // One-to-one relationship preloading
600
+ const usersWithProfiles = await system.storage.find(
601
+ 'User',
602
+ MatchExp.atom({ key: 'isActive', value: ['=', true] }),
603
+ {},
604
+ [
605
+ 'id',
606
+ 'username',
607
+ 'email',
608
+ ['profile', {
609
+ attributeQuery: ['firstName', 'lastName', 'bio', 'avatar']
610
+ }]
611
+ ]
612
+ );
613
+
614
+ // One-to-many relationship preloading
615
+ const usersWithPosts = await system.storage.find(
616
+ 'User',
617
+ undefined,
618
+ { limit: 10 },
619
+ [
620
+ 'id',
621
+ 'username',
622
+ ['posts', {
623
+ attributeQuery: ['id', 'title', 'excerpt', 'publishedAt', 'status'],
624
+ // Can filter related data
625
+ matchExpression: MatchExp.atom({ key: 'status', value: ['=', 'published'] })
626
+ }]
627
+ ]
628
+ );
629
+
630
+ // Many-to-many relationship preloading
631
+ const usersWithTeams = await system.storage.find(
632
+ 'User',
633
+ undefined,
634
+ {},
635
+ [
636
+ 'id',
637
+ 'username',
638
+ ['teams', {
639
+ attributeQuery: [
640
+ 'id',
641
+ 'name',
642
+ 'description',
643
+ ['&', { attributeQuery: ['role', 'joinedAt'] }] // Relationship attributes
644
+ ]
645
+ }]
646
+ ]
647
+ );
648
+ ```
649
+
650
+ ### 11.5.2 Deep Queries
651
+
652
+ ```typescript
653
+ // Multi-level relationship queries
654
+ const deepRelationQuery = await system.storage.find(
655
+ 'User',
656
+ undefined,
657
+ { limit: 5 },
658
+ [
659
+ 'id',
660
+ 'username',
661
+ ['posts', {
662
+ attributeQuery: [
663
+ 'id',
664
+ 'title',
665
+ 'content',
666
+ ['comments', {
667
+ attributeQuery: [
668
+ 'id',
669
+ 'content',
670
+ 'createdAt',
671
+ ['author', {
672
+ attributeQuery: ['id', 'username', 'avatar']
673
+ }],
674
+ ['replies', {
675
+ attributeQuery: [
676
+ 'id',
677
+ 'content',
678
+ ['author', { attributeQuery: ['username'] }]
679
+ ]
680
+ }]
681
+ ]
682
+ }],
683
+ ['tags', {
684
+ attributeQuery: ['name', 'category']
685
+ }]
686
+ ]
687
+ }]
688
+ ]
689
+ );
690
+
691
+ // Complex business query: get user's complete social network info
692
+ const socialNetworkInfo = await system.storage.find(
693
+ 'User',
694
+ MatchExp.atom({ key: 'id', value: ['=', userId] }),
695
+ {},
696
+ [
697
+ 'id',
698
+ 'username',
699
+ 'email',
700
+ ['profile', {
701
+ attributeQuery: ['firstName', 'lastName', 'bio', 'location']
702
+ }],
703
+ ['friends', {
704
+ attributeQuery: [
705
+ 'id',
706
+ 'username',
707
+ ['profile', { attributeQuery: ['firstName', 'lastName'] }],
708
+ ['&', { attributeQuery: ['since', 'closeness'] }]
709
+ ]
710
+ }],
711
+ ['posts', {
712
+ attributeQuery: [
713
+ 'id',
714
+ 'title',
715
+ 'content',
716
+ 'publishedAt',
717
+ ['likes', {
718
+ attributeQuery: [
719
+ ['user', { attributeQuery: ['username'] }],
720
+ ['&', { attributeQuery: ['likedAt'] }]
721
+ ]
722
+ }],
723
+ ['comments', {
724
+ attributeQuery: [
725
+ 'content',
726
+ 'createdAt',
727
+ ['author', { attributeQuery: ['username'] }]
728
+ ]
729
+ }]
730
+ ],
731
+ matchExpression: MatchExp.atom({ key: 'status', value: ['=', 'published'] })
732
+ }],
733
+ ['groups', {
734
+ attributeQuery: [
735
+ 'id',
736
+ 'name',
737
+ 'description',
738
+ ['&', { attributeQuery: ['role', 'joinedAt'] }],
739
+ ['members', {
740
+ attributeQuery: ['username'],
741
+ // Limit returned member count
742
+ limit: 10
743
+ }]
744
+ ]
745
+ }]
746
+ ]
747
+ );
748
+ ```
749
+
750
+ ### 11.5.3 Handling Circular References
751
+
752
+ ```typescript
753
+ // Handle potential circular references
754
+ const usersWithLimitedFriends = await system.storage.find(
755
+ 'User',
756
+ undefined,
757
+ { limit: 10 },
758
+ [
759
+ 'id',
760
+ 'username',
761
+ ['friends', {
762
+ attributeQuery: [
763
+ 'id',
764
+ 'username',
765
+ // Don't query friends of friends to avoid circular references
766
+ ['&', { attributeQuery: ['since', 'closeness'] }]
767
+ ]
768
+ }]
769
+ ]
770
+ );
771
+
772
+ // Use depth limits to avoid infinite recursion
773
+ const limitedDepthQuery = await system.storage.find(
774
+ 'Category',
775
+ undefined,
776
+ {},
777
+ [
778
+ 'id',
779
+ 'name',
780
+ ['parent', {
781
+ attributeQuery: [
782
+ 'id',
783
+ 'name',
784
+ // Only query one level of parent to avoid excessive depth
785
+ ]
786
+ }],
787
+ ['children', {
788
+ attributeQuery: [
789
+ 'id',
790
+ 'name',
791
+ // Only query one level of children
792
+ ]
793
+ }]
794
+ ]
795
+ );
796
+ ```
797
+
798
+ ## 11.6 Advanced Query Techniques
799
+
800
+ ### 11.6.1 Dynamic Query Building
801
+
802
+ ```typescript
803
+ // Dynamic query builder
804
+ class QueryBuilder {
805
+ private matchCondition?: MatchExpressionData;
806
+ private modifier: any = {};
807
+ private attributes: string[] = [];
808
+
809
+ constructor(private entityName: string) {}
810
+
811
+ where(key: string, operator: string, value: any): this {
812
+ const condition = MatchExp.atom({ key, value: [operator, value] });
813
+ this.matchCondition = this.matchCondition ? this.matchCondition.and(condition) : condition;
814
+ return this;
815
+ }
816
+
817
+ whereIn(key: string, values: any[]): this {
818
+ return this.where(key, 'in', values);
819
+ }
820
+
821
+ whereLike(key: string, pattern: string): this {
822
+ return this.where(key, 'like', pattern);
823
+ }
824
+
825
+ whereBetween(key: string, min: any, max: any): this {
826
+ return this.where(key, 'between', [min, max]);
827
+ }
828
+
829
+ orderBy(field: string, direction: 'ASC' | 'DESC' = 'ASC'): this {
830
+ this.modifier.orderBy = { ...this.modifier.orderBy, [field]: direction };
831
+ return this;
832
+ }
833
+
834
+ limit(count: number): this {
835
+ this.modifier.limit = count;
836
+ return this;
837
+ }
838
+
839
+ offset(count: number): this {
840
+ this.modifier.offset = count;
841
+ return this;
842
+ }
843
+
844
+ select(...attributes: string[]): this {
845
+ this.attributes = attributes;
846
+ return this;
847
+ }
848
+
849
+ async execute(): Promise<any[]> {
850
+ return await system.storage.find(
851
+ this.entityName,
852
+ this.matchCondition,
853
+ this.modifier,
854
+ this.attributes.length > 0 ? this.attributes : ['*']
855
+ );
856
+ }
857
+
858
+ async first(): Promise<any> {
859
+ this.limit(1);
860
+ const results = await this.execute();
861
+ return results[0] || null;
862
+ }
863
+ }
864
+
865
+ // Use query builder
866
+ const activeAdultUsers = await new QueryBuilder('User')
867
+ .where('isActive', '=', true)
868
+ .where('age', '>=', 18)
869
+ .whereIn('role', ['user', 'admin'])
870
+ .orderBy('createdAt', 'DESC')
871
+ .limit(20)
872
+ .select('id', 'username', 'email', 'age', 'role')
873
+ .execute();
874
+
875
+ // Complex dynamic query
876
+ const searchResults = await new QueryBuilder('Product')
877
+ .where('isActive', '=', true)
878
+ .whereLike('name', '%laptop%')
879
+ .whereBetween('price', 500, 2000)
880
+ .whereIn('category', ['electronics', 'computers'])
881
+ .orderBy('price', 'ASC')
882
+ .orderBy('rating', 'DESC')
883
+ .limit(50)
884
+ .select('id', 'name', 'price', 'category', 'rating', 'description')
885
+ .execute();
886
+ ```
887
+
888
+ ### 11.6.2 Query Optimization
889
+
890
+ ```typescript
891
+ // Index-friendly queries
892
+ const optimizedQuery = await system.storage.find(
893
+ 'User',
894
+ MatchExp.atom({ key: 'email', value: ['=', 'user@example.com'] }), // Assuming email has index
895
+ {},
896
+ ['id', 'username', 'isActive'] // Only query needed fields
897
+ );
898
+
899
+ // Batch query optimization
900
+ async function getUsersByIds(userIds: string[]) {
901
+ // Use IN query instead of multiple individual queries
902
+ return await system.storage.find(
903
+ 'User',
904
+ MatchExp.atom({ key: 'id', value: ['in', userIds] }),
905
+ {},
906
+ ['id', 'username', 'email', 'avatar']
907
+ );
908
+ }
909
+
910
+ // Pagination query optimization
911
+ async function getOptimizedPaginatedUsers(page: number, pageSize: number) {
912
+ // Use cursor-based pagination instead of offset pagination (for large datasets)
913
+ const lastUserId = page > 1 ? await getLastUserIdFromPreviousPage(page - 1, pageSize) : null;
914
+
915
+ let matchCondition = undefined;
916
+ if (lastUserId) {
917
+ matchCondition = MatchExp.atom({ key: 'id', value: ['>', lastUserId] });
918
+ }
919
+
920
+ return await system.storage.find(
921
+ 'User',
922
+ matchCondition,
923
+ {
924
+ orderBy: { id: 'ASC' },
925
+ limit: pageSize
926
+ },
927
+ ['id', 'username', 'email', 'createdAt']
928
+ );
929
+ }
930
+
931
+ // Preloading optimization
932
+ async function getUsersWithOptimizedRelations(userIds: string[]) {
933
+ // Get users and related data in one go, avoid N+1 problem
934
+ return await system.storage.find(
935
+ 'User',
936
+ MatchExp.atom({ key: 'id', value: ['in', userIds] }),
937
+ {},
938
+ [
939
+ 'id',
940
+ 'username',
941
+ 'email',
942
+ ['profile', {
943
+ attributeQuery: ['firstName', 'lastName', 'avatar']
944
+ }],
945
+ ['posts', {
946
+ attributeQuery: ['id', 'title', 'publishedAt'],
947
+ matchExpression: MatchExp.atom({ key: 'status', value: ['=', 'published'] }),
948
+ limit: 5 // Limit related data count
949
+ }]
950
+ ]
951
+ );
952
+ }
953
+ ```
954
+
955
+ ### 11.6.3 Caching Query Results
956
+
957
+ ```typescript
958
+ // Query result caching
959
+ class CachedQueryService {
960
+ private cache = new Map<string, { data: any, timestamp: number }>();
961
+ private ttl = 300000; // 5-minute TTL
962
+
963
+ private generateCacheKey(entityName: string, matchCondition: any, modifier: any, attributes: any): string {
964
+ return JSON.stringify({ entityName, matchCondition, modifier, attributes });
965
+ }
966
+
967
+ private isCacheValid(cacheEntry: { data: any, timestamp: number }): boolean {
968
+ return Date.now() - cacheEntry.timestamp < this.ttl;
969
+ }
970
+
971
+ async find(entityName: string, matchCondition?: any, modifier: any = {}, attributes?: any): Promise<any[]> {
972
+ const cacheKey = this.generateCacheKey(entityName, matchCondition, modifier, attributes);
973
+
974
+ // Check cache
975
+ const cached = this.cache.get(cacheKey);
976
+ if (cached && this.isCacheValid(cached)) {
977
+ console.log('Cache hit');
978
+ return cached.data;
979
+ }
980
+
981
+ // Execute query
982
+ console.log('Cache miss, executing query');
983
+ const result = await system.storage.find(entityName, matchCondition, modifier, attributes);
984
+
985
+ // Store in cache
986
+ this.cache.set(cacheKey, {
987
+ data: result,
988
+ timestamp: Date.now()
989
+ });
990
+
991
+ return result;
992
+ }
993
+
994
+ async findOne(entityName: string, matchCondition?: any, modifier: any = {}, attributes?: any): Promise<any> {
995
+ const results = await this.find(entityName, matchCondition, { ...modifier, limit: 1 }, attributes);
996
+ return results[0] || null;
997
+ }
998
+
999
+ clearCache(): void {
1000
+ this.cache.clear();
1001
+ }
1002
+
1003
+ invalidateCache(pattern?: string): void {
1004
+ if (!pattern) {
1005
+ this.clearCache();
1006
+ return;
1007
+ }
1008
+
1009
+ for (const key of this.cache.keys()) {
1010
+ if (key.includes(pattern)) {
1011
+ this.cache.delete(key);
1012
+ }
1013
+ }
1014
+ }
1015
+ }
1016
+
1017
+ // Use cached query service
1018
+ const cachedQuery = new CachedQueryService();
1019
+
1020
+ // First query will execute actual query
1021
+ const users1 = await cachedQuery.find('User', undefined, {}, ['id', 'username']);
1022
+
1023
+ // Second query will use cache
1024
+ const users2 = await cachedQuery.find('User', undefined, {}, ['id', 'username']);
1025
+
1026
+ // When user data changes, clear related cache
1027
+ // Can be integrated into data change events
1028
+ async function onUserDataChanged() {
1029
+ cachedQuery.invalidateCache('User');
1030
+ }
1031
+ ```
1032
+
1033
+ Data querying is key to building efficient applications. By mastering the query capabilities provided by the interaqt framework, developers can flexibly obtain required data while maintaining good performance. Proper use of query conditions, attribute selection, relationship preloading, and caching strategies can significantly improve application response speed and user experience.