bunsane 0.1.0 → 0.1.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 (82) hide show
  1. package/.github/workflows/deploy-docs.yml +57 -0
  2. package/LICENSE.md +1 -1
  3. package/README.md +2 -28
  4. package/TODO.md +8 -1
  5. package/bun.lock +3 -0
  6. package/config/upload.config.ts +135 -0
  7. package/core/App.ts +168 -4
  8. package/core/ArcheType.ts +122 -0
  9. package/core/BatchLoader.ts +100 -0
  10. package/core/ComponentRegistry.ts +4 -3
  11. package/core/Components.ts +2 -2
  12. package/core/Decorators.ts +15 -8
  13. package/core/Entity.ts +193 -14
  14. package/core/EntityCache.ts +15 -0
  15. package/core/EntityHookManager.ts +855 -0
  16. package/core/EntityManager.ts +12 -2
  17. package/core/ErrorHandler.ts +64 -7
  18. package/core/FileValidator.ts +284 -0
  19. package/core/Query.ts +503 -85
  20. package/core/RequestContext.ts +24 -0
  21. package/core/RequestLoaders.ts +89 -0
  22. package/core/SchedulerManager.ts +710 -0
  23. package/core/UploadManager.ts +261 -0
  24. package/core/components/UploadComponent.ts +206 -0
  25. package/core/decorators/EntityHooks.ts +190 -0
  26. package/core/decorators/ScheduledTask.ts +83 -0
  27. package/core/events/EntityLifecycleEvents.ts +177 -0
  28. package/core/processors/ImageProcessor.ts +423 -0
  29. package/core/storage/LocalStorageProvider.ts +290 -0
  30. package/core/storage/StorageProvider.ts +112 -0
  31. package/database/DatabaseHelper.ts +183 -58
  32. package/database/index.ts +5 -5
  33. package/database/sqlHelpers.ts +7 -0
  34. package/docs/README.md +149 -0
  35. package/docs/_coverpage.md +36 -0
  36. package/docs/_sidebar.md +23 -0
  37. package/docs/api/core.md +568 -0
  38. package/docs/api/hooks.md +554 -0
  39. package/docs/api/index.md +222 -0
  40. package/docs/api/query.md +678 -0
  41. package/docs/api/service.md +744 -0
  42. package/docs/core-concepts/archetypes.md +512 -0
  43. package/docs/core-concepts/components.md +498 -0
  44. package/docs/core-concepts/entity.md +314 -0
  45. package/docs/core-concepts/hooks.md +683 -0
  46. package/docs/core-concepts/query.md +588 -0
  47. package/docs/core-concepts/services.md +647 -0
  48. package/docs/examples/code-examples.md +425 -0
  49. package/docs/getting-started.md +337 -0
  50. package/docs/index.html +97 -0
  51. package/gql/Generator.ts +58 -35
  52. package/gql/decorators/Upload.ts +176 -0
  53. package/gql/helpers.ts +67 -0
  54. package/gql/index.ts +65 -31
  55. package/gql/types.ts +1 -1
  56. package/index.ts +79 -11
  57. package/package.json +19 -10
  58. package/rest/Generator.ts +3 -0
  59. package/rest/index.ts +22 -0
  60. package/service/Service.ts +1 -1
  61. package/service/ServiceRegistry.ts +10 -6
  62. package/service/index.ts +12 -1
  63. package/tests/bench/insert.bench.ts +59 -0
  64. package/tests/bench/relations.bench.ts +269 -0
  65. package/tests/bench/sorting.bench.ts +415 -0
  66. package/tests/component-hooks.test.ts +1409 -0
  67. package/tests/component.test.ts +338 -0
  68. package/tests/errorHandling.test.ts +155 -0
  69. package/tests/hooks.test.ts +666 -0
  70. package/tests/query-sorting.test.ts +101 -0
  71. package/tests/relations.test.ts +169 -0
  72. package/tests/scheduler.test.ts +724 -0
  73. package/tsconfig.json +35 -34
  74. package/types/graphql.types.ts +87 -0
  75. package/types/hooks.types.ts +141 -0
  76. package/types/scheduler.types.ts +165 -0
  77. package/types/upload.types.ts +184 -0
  78. package/upload/index.ts +140 -0
  79. package/utils/UploadHelper.ts +305 -0
  80. package/utils/cronParser.ts +366 -0
  81. package/utils/errorMessages.ts +151 -0
  82. package/core/Events.ts +0 -0
@@ -0,0 +1,678 @@
1
+ # Query API Reference
2
+
3
+ This page provides detailed API reference for BunSane's query system and database operations.
4
+
5
+ ## 🔍 Query Class
6
+
7
+ The `Query` class provides a fluent interface for building database queries based on Entity-Component-System (ECS) architecture.
8
+
9
+ ### Constructor
10
+
11
+ ```typescript
12
+ new Query()
13
+ ```
14
+
15
+ Creates a new query instance. Queries are built by chaining methods to specify which components are required, optional filters, sorting, and pagination.
16
+
17
+ **Returns:** `Query` - New query instance
18
+
19
+ **Example:**
20
+ ```typescript
21
+ const query = new Query();
22
+ ```
23
+
24
+ ### Static Filter Methods
25
+
26
+ #### `Query.filter(field, operator, value)`
27
+
28
+ Creates a filter object for use with component queries.
29
+
30
+ ```typescript
31
+ static filter(field: string, operator: FilterOperator, value: any): QueryFilter
32
+ ```
33
+
34
+ **Parameters:**
35
+ - `field`: String - The component data field name
36
+ - `operator`: FilterOperator - Comparison operator (`=`, `>`, `<`, `>=`, `<=`, `!=`, `LIKE`, `IN`, `NOT IN`)
37
+ - `value`: Any - Value to compare against
38
+
39
+ **Returns:** `QueryFilter` - Filter configuration object
40
+
41
+ **Example:**
42
+ ```typescript
43
+ const emailFilter = Query.filter("value", Query.filterOp.EQ, "user@example.com");
44
+ ```
45
+
46
+ #### `Query.typedFilter(componentCtor, field, operator, value)`
47
+
48
+ Creates a type-safe filter for a specific component.
49
+
50
+ ```typescript
51
+ static typedFilter<T extends BaseComponent>(
52
+ componentCtor: new (...args: any[]) => T,
53
+ field: keyof ComponentDataType<T>,
54
+ operator: FilterOperator,
55
+ value: any
56
+ ): QueryFilter
57
+ ```
58
+
59
+ **Type Parameters:**
60
+ - `T`: Component class extending BaseComponent
61
+
62
+ **Parameters:**
63
+ - `componentCtor`: Component constructor
64
+ - `field`: keyof ComponentDataType<T> - Component data field
65
+ - `operator`: FilterOperator - Comparison operator
66
+ - `value`: Any - Value to compare against
67
+
68
+ **Returns:** `QueryFilter` - Filter configuration object
69
+
70
+ **Example:**
71
+ ```typescript
72
+ const nameFilter = Query.typedFilter(NameComponent, "value", Query.filterOp.LIKE, "John%");
73
+ ```
74
+
75
+ #### `Query.filters(...filters)`
76
+
77
+ Creates filter options from multiple filter objects.
78
+
79
+ ```typescript
80
+ static filters(...filters: QueryFilter[]): QueryFilterOptions
81
+ ```
82
+
83
+ **Parameters:**
84
+ - `filters`: QueryFilter[] - Array of filter objects
85
+
86
+ **Returns:** `QueryFilterOptions` - Filter options for component queries
87
+
88
+ **Example:**
89
+ ```typescript
90
+ const filterOptions = Query.filters(
91
+ Query.filter("value", Query.filterOp.EQ, "active"),
92
+ Query.filter("value", Query.filterOp.GT, 100)
93
+ );
94
+ ```
95
+
96
+ ### Filter Operators
97
+
98
+ The `FilterOp` object provides constants for filter operators:
99
+
100
+ ```typescript
101
+ FilterOp.EQ // "="
102
+ FilterOp.GT // ">"
103
+ FilterOp.LT // "<"
104
+ FilterOp.GTE // ">="
105
+ FilterOp.LTE // "<="
106
+ FilterOp.NEQ // "!="
107
+ FilterOp.LIKE // "LIKE"
108
+ FilterOp.IN // "IN"
109
+ FilterOp.NOT_IN // "NOT IN"
110
+ ```
111
+
112
+ ### Instance Methods
113
+
114
+ #### `query.with(componentCtor, options?)`
115
+
116
+ Adds a required component to the query. Entities must have this component to be included in results.
117
+
118
+ ```typescript
119
+ with<T extends BaseComponent>(
120
+ ctor: new (...args: any[]) => T,
121
+ options?: QueryFilterOptions
122
+ ): this
123
+ ```
124
+
125
+ **Type Parameters:**
126
+ - `T`: Component class extending BaseComponent
127
+
128
+ **Parameters:**
129
+ - `ctor`: Component constructor - The component class that entities must have
130
+ - `options` (optional): QueryFilterOptions - Filters to apply to this component
131
+
132
+ **Returns:** `this` - Query instance for chaining
133
+
134
+ **Example:**
135
+ ```typescript
136
+ const users = await new Query()
137
+ .with(UserTag)
138
+ .with(EmailComponent, Query.filters(
139
+ Query.filter("value", Query.filterOp.LIKE, "%@example.com")
140
+ ))
141
+ .exec();
142
+ ```
143
+
144
+ #### `query.without(componentCtor)`
145
+
146
+ Excludes entities that have the specified component.
147
+
148
+ ```typescript
149
+ without<T extends BaseComponent>(ctor: new (...args: any[]) => T): this
150
+ ```
151
+
152
+ **Type Parameters:**
153
+ - `T`: Component class extending BaseComponent
154
+
155
+ **Parameters:**
156
+ - `ctor`: Component constructor - The component that entities must NOT have
157
+
158
+ **Returns:** `this` - Query instance for chaining
159
+
160
+ **Example:**
161
+ ```typescript
162
+ const activeUsers = await new Query()
163
+ .with(UserTag)
164
+ .without(BannedComponent)
165
+ .exec();
166
+ ```
167
+
168
+ #### `query.eagerLoadComponents(componentCtors)`
169
+
170
+ Eager loads the specified components for all matching entities. This improves performance by batch loading component data.
171
+
172
+ ```typescript
173
+ eagerLoadComponents(ctors: Array<new () => BaseComponent>): this
174
+ ```
175
+
176
+ **Parameters:**
177
+ - `ctors`: Array<new () => BaseComponent> - Array of component constructors to eager load
178
+
179
+ **Returns:** `this` - Query instance for chaining
180
+
181
+ **Example:**
182
+ ```typescript
183
+ const users = await new Query()
184
+ .with(UserTag)
185
+ .eagerLoadComponents([NameComponent, EmailComponent, PhoneComponent])
186
+ .exec();
187
+ ```
188
+
189
+ #### `query.populate()`
190
+
191
+ Fully populates all components for matching entities. This is equivalent to calling `Entity.LoadMultiple()` on the results.
192
+
193
+ ```typescript
194
+ populate(): this
195
+ ```
196
+
197
+ **Returns:** `this` - Query instance for chaining
198
+
199
+ **Example:**
200
+ ```typescript
201
+ const fullUsers = await new Query()
202
+ .with(UserTag)
203
+ .populate()
204
+ .exec(); // Returns fully loaded Entity objects
205
+ ```
206
+
207
+ #### `query.findById(id)`
208
+
209
+ Filters results to only include the entity with the specified ID.
210
+
211
+ ```typescript
212
+ findById(id: string): this
213
+ ```
214
+
215
+ **Parameters:**
216
+ - `id`: String - Entity ID to find
217
+
218
+ **Returns:** `this` - Query instance for chaining
219
+
220
+ **Example:**
221
+ ```typescript
222
+ const user = await new Query()
223
+ .with(UserTag)
224
+ .findById("01HXXX...")
225
+ .exec();
226
+ ```
227
+
228
+ #### `query.take(limit)`
229
+
230
+ Limits the number of results returned.
231
+
232
+ ```typescript
233
+ take(limit: number): this
234
+ ```
235
+
236
+ **Parameters:**
237
+ - `limit`: Number - Maximum number of entities to return
238
+
239
+ **Returns:** `this` - Query instance for chaining
240
+
241
+ **Example:**
242
+ ```typescript
243
+ const firstTenUsers = await new Query()
244
+ .with(UserTag)
245
+ .take(10)
246
+ .exec();
247
+ ```
248
+
249
+ #### `query.offset(offset)`
250
+
251
+ Skips the first N results (for pagination).
252
+
253
+ ```typescript
254
+ offset(offset: number): this
255
+ ```
256
+
257
+ **Parameters:**
258
+ - `offset`: Number - Number of results to skip
259
+
260
+ **Returns:** `this` - Query instance for chaining
261
+
262
+ **Example:**
263
+ ```typescript
264
+ const pageTwoUsers = await new Query()
265
+ .with(UserTag)
266
+ .take(10)
267
+ .offset(10) // Skip first 10, get next 10
268
+ .exec();
269
+ ```
270
+
271
+ #### `query.sortBy(componentCtor, property, direction?, nullsFirst?)`
272
+
273
+ Sorts results by a component property.
274
+
275
+ ```typescript
276
+ sortBy<T extends BaseComponent>(
277
+ componentCtor: new (...args: any[]) => T,
278
+ property: keyof ComponentDataType<T>,
279
+ direction?: SortDirection,
280
+ nullsFirst?: boolean
281
+ ): this
282
+ ```
283
+
284
+ **Type Parameters:**
285
+ - `T`: Component class extending BaseComponent
286
+
287
+ **Parameters:**
288
+ - `componentCtor`: Component constructor - Component to sort by
289
+ - `property`: keyof ComponentDataType<T> - Property name to sort by
290
+ - `direction` (optional): "ASC" | "DESC" - Sort direction (default: "ASC")
291
+ - `nullsFirst` (optional): Boolean - Whether nulls should appear first (default: false)
292
+
293
+ **Returns:** `this` - Query instance for chaining
294
+
295
+ **Example:**
296
+ ```typescript
297
+ const sortedUsers = await new Query()
298
+ .with(UserTag)
299
+ .with(NameComponent)
300
+ .sortBy(NameComponent, "value", "ASC")
301
+ .exec();
302
+ ```
303
+
304
+ #### `query.orderBy(orders)`
305
+
306
+ Sorts results by multiple criteria using SortOrder objects.
307
+
308
+ ```typescript
309
+ orderBy(orders: SortOrder[]): this
310
+ ```
311
+
312
+ **Parameters:**
313
+ - `orders`: SortOrder[] - Array of sort specifications
314
+
315
+ **Returns:** `this` - Query instance for chaining
316
+
317
+ **Example:**
318
+ ```typescript
319
+ const sortedUsers = await new Query()
320
+ .with(UserTag)
321
+ .with(NameComponent)
322
+ .with(EmailComponent)
323
+ .orderBy([
324
+ { component: "NameComponent", property: "value", direction: "ASC" },
325
+ { component: "EmailComponent", property: "value", direction: "DESC" }
326
+ ])
327
+ .exec();
328
+ ```
329
+
330
+ #### `query.exec()`
331
+
332
+ Executes the query and returns matching entities.
333
+
334
+ ```typescript
335
+ async exec(): Promise<Entity[]>
336
+ ```
337
+
338
+ **Returns:** `Promise<Entity[]>` - Array of Entity objects matching the query criteria
339
+
340
+ **Example:**
341
+ ```typescript
342
+ const users = await new Query()
343
+ .with(UserTag)
344
+ .exec();
345
+ ```
346
+
347
+ #### `query.findOneById(id)`
348
+
349
+ Convenience method to find and return a single entity by ID.
350
+
351
+ ```typescript
352
+ async findOneById(id: string): Promise<Entity | null>
353
+ ```
354
+
355
+ **Parameters:**
356
+ - `id`: String - Entity ID to find
357
+
358
+ **Returns:** `Promise<Entity | null>` - Single entity or null if not found
359
+
360
+ **Example:**
361
+ ```typescript
362
+ const user = await new Query()
363
+ .findOneById("01HXXX...");
364
+ ```
365
+
366
+ ## 📋 QueryCondition & Filter Types
367
+
368
+ ### QueryFilter
369
+
370
+ Interface for defining component filters.
371
+
372
+ ```typescript
373
+ interface QueryFilter {
374
+ field: string;
375
+ operator: FilterOperator;
376
+ value: any;
377
+ }
378
+ ```
379
+
380
+ ### QueryFilterOptions
381
+
382
+ Interface for filter options.
383
+
384
+ ```typescript
385
+ interface QueryFilterOptions {
386
+ filters: QueryFilter[];
387
+ }
388
+ ```
389
+
390
+ ### SortOrder
391
+
392
+ Interface for sort specifications.
393
+
394
+ ```typescript
395
+ interface SortOrder {
396
+ component: string;
397
+ property: string;
398
+ direction: SortDirection;
399
+ nullsFirst?: boolean;
400
+ }
401
+ ```
402
+
403
+ ### FilterOperator
404
+
405
+ Supported filter operators:
406
+
407
+ ```typescript
408
+ type FilterOperator = "=" | ">" | "<" | ">=" | "<=" | "!=" | "LIKE" | "IN" | "NOT IN";
409
+ ```
410
+
411
+ ## 🔍 Query Examples
412
+
413
+ ### Basic Component Queries
414
+
415
+ #### Find all users
416
+ ```typescript
417
+ const users = await new Query()
418
+ .with(UserTag)
419
+ .exec();
420
+ ```
421
+
422
+ #### Find users with specific email
423
+ ```typescript
424
+ const users = await new Query()
425
+ .with(UserTag)
426
+ .with(EmailComponent, Query.filters(
427
+ Query.filter("value", Query.filterOp.EQ, "john@example.com")
428
+ ))
429
+ .exec();
430
+ ```
431
+
432
+ #### Find active users (exclude banned)
433
+ ```typescript
434
+ const activeUsers = await new Query()
435
+ .with(UserTag)
436
+ .without(BannedComponent)
437
+ .exec();
438
+ ```
439
+
440
+ ### Filtering Examples
441
+
442
+ #### Multiple filters on same component
443
+ ```typescript
444
+ const filteredUsers = await new Query()
445
+ .with(UserTag)
446
+ .with(NameComponent, Query.filters(
447
+ Query.filter("value", Query.filterOp.LIKE, "John%")
448
+ ))
449
+ .with(EmailComponent, Query.filters(
450
+ Query.filter("value", Query.filterOp.LIKE, "%@example.com")
451
+ ))
452
+ .exec();
453
+ ```
454
+
455
+ #### Using IN operator
456
+ ```typescript
457
+ const admins = await new Query()
458
+ .with(UserTag)
459
+ .with(RoleComponent, Query.filters(
460
+ Query.filter("value", Query.filterOp.IN, ["admin", "moderator"])
461
+ ))
462
+ .exec();
463
+ ```
464
+
465
+ #### Range queries
466
+ ```typescript
467
+ const recentUsers = await new Query()
468
+ .with(UserTag)
469
+ .with(CreatedAtComponent, Query.filters(
470
+ Query.filter("value", Query.filterOp.GTE, new Date('2024-01-01'))
471
+ ))
472
+ .exec();
473
+ ```
474
+
475
+ ### Eager Loading
476
+
477
+ #### Load multiple components efficiently
478
+ ```typescript
479
+ const usersWithDetails = await new Query()
480
+ .with(UserTag)
481
+ .eagerLoadComponents([NameComponent, EmailComponent, PhoneComponent])
482
+ .exec();
483
+ ```
484
+
485
+ #### Full entity population
486
+ ```typescript
487
+ const fullUsers = await new Query()
488
+ .with(UserTag)
489
+ .populate() // Loads all components for each entity
490
+ .exec();
491
+ ```
492
+
493
+ ### Sorting and Pagination
494
+
495
+ #### Sort by name
496
+ ```typescript
497
+ const sortedUsers = await new Query()
498
+ .with(UserTag)
499
+ .with(NameComponent)
500
+ .sortBy(NameComponent, "value", "ASC")
501
+ .exec();
502
+ ```
503
+
504
+ #### Multiple sort criteria
505
+ ```typescript
506
+ const sortedUsers = await new Query()
507
+ .with(UserTag)
508
+ .with(NameComponent)
509
+ .with(CreatedAtComponent)
510
+ .orderBy([
511
+ { component: "NameComponent", property: "value", direction: "ASC" },
512
+ { component: "CreatedAtComponent", property: "value", direction: "DESC" }
513
+ ])
514
+ .exec();
515
+ ```
516
+
517
+ #### Pagination
518
+ ```typescript
519
+ const pageSize = 20;
520
+ const page = 2;
521
+
522
+ const users = await new Query()
523
+ .with(UserTag)
524
+ .take(pageSize)
525
+ .offset((page - 1) * pageSize)
526
+ .exec();
527
+ ```
528
+
529
+ ### Real-world Usage Patterns
530
+
531
+ #### User Service Query (from UserService.ts)
532
+ ```typescript
533
+ const query = new Query()
534
+ .with(UserTag)
535
+ .with(EmailComponent,
536
+ Query.filters(
537
+ Query.filter("value", Query.filterOp.EQ, input.email)
538
+ )
539
+ )
540
+ .exec();
541
+ ```
542
+
543
+ #### Post Service Query with Relationships (from PostService.ts)
544
+ ```typescript
545
+ const query = new Query()
546
+ .with(PostTag)
547
+ .with(AuthorComponent,
548
+ Query.filters(
549
+ Query.filter("value", Query.filterOp.IN, userIds)
550
+ )
551
+ )
552
+ .eagerLoadComponents(postComponentsToLoad)
553
+ .exec();
554
+ ```
555
+
556
+ #### Finding by ID
557
+ ```typescript
558
+ const user = await new Query()
559
+ .with(UserTag)
560
+ .findById(userId)
561
+ .exec();
562
+ ```
563
+
564
+ ## 🔗 Advanced Query Features
565
+
566
+ ### Component Archetypes
567
+
568
+ Queries work with component archetypes - groups of components that define entity types:
569
+
570
+ ```typescript
571
+ const UserArcheType = new ArcheType([
572
+ UserTag,
573
+ NameComponent,
574
+ EmailComponent,
575
+ PasswordComponent
576
+ ]);
577
+ ```
578
+
579
+ ### Batch Loading Relationships
580
+
581
+ For efficient relationship loading, use batch loaders:
582
+
583
+ ```typescript
584
+ // Preload related entities
585
+ context.authors = await BatchLoader.loadRelatedEntitiesBatched(
586
+ posts,
587
+ AuthorComponent,
588
+ Entity.LoadMultiple
589
+ );
590
+ ```
591
+
592
+ ### Performance Optimization
593
+
594
+ #### Use eager loading for frequently accessed components
595
+ ```typescript
596
+ const users = await new Query()
597
+ .with(UserTag)
598
+ .eagerLoadComponents([NameComponent, EmailComponent]) // Batch load
599
+ .exec();
600
+ ```
601
+
602
+ #### Filter early to reduce data transfer
603
+ ```typescript
604
+ const activeUsers = await new Query()
605
+ .with(UserTag)
606
+ .with(StatusComponent, Query.filters(
607
+ Query.filter("value", Query.filterOp.EQ, "active")
608
+ ))
609
+ .exec();
610
+ ```
611
+
612
+ #### Use pagination for large result sets
613
+ ```typescript
614
+ const users = await new Query()
615
+ .with(UserTag)
616
+ .take(50)
617
+ .offset(0)
618
+ .exec();
619
+ ```
620
+
621
+ ## 🚀 Performance Optimization
622
+
623
+ ### Indexing Strategy
624
+
625
+ Components are automatically indexed by entity_id and type_id. For optimal performance:
626
+
627
+ - Filter on component data fields that are frequently queried
628
+ - Use `eagerLoadComponents()` for components accessed together
629
+ - Prefer `populate()` only when you need all component data
630
+
631
+ ### Query Optimization Tips
632
+
633
+ - **Use specific component requirements** - only include components you need with `.with()`
634
+ - **Eager load related components** - use `.eagerLoadComponents()` to batch load component data
635
+ - **Filter at the component level** - apply filters to specific components rather than post-processing
636
+ - **Use pagination** - always use `.take()` and `.offset()` for large datasets
637
+ - **Batch operations** - load related entities in batches using BatchLoader
638
+
639
+ ### Execution Time Monitoring
640
+
641
+ ```typescript
642
+ const startTime = Date.now();
643
+
644
+ const results = await new Query()
645
+ .with(UserTag)
646
+ .exec();
647
+
648
+ const executionTime = Date.now() - startTime;
649
+ console.log(`Query executed in ${executionTime}ms`);
650
+ ```
651
+
652
+ ## 📊 Query Statistics
653
+
654
+ ### Result Analysis
655
+
656
+ ```typescript
657
+ const query = new Query().with(UserTag);
658
+
659
+ const results = await query.take(10).exec();
660
+ console.log(`Found ${results.length} users (limited to 10)`);
661
+ ```
662
+
663
+ ### Memory Considerations
664
+
665
+ - `exec()` returns lightweight Entity objects by default
666
+ - Use `eagerLoadComponents()` to load component data efficiently
667
+ - Use `populate()` sparingly as it loads all components for each entity
668
+
669
+ ## 🔗 Related APIs
670
+
671
+ - **[Entity API](entity.md)** - Entity operations and lifecycle
672
+ - **[Component API](components.md)** - Component management and data access
673
+ - **[Service API](service.md)** - Business logic layer using queries
674
+ - **[BatchLoader API](batch-loader.md)** - Efficient relationship loading
675
+
676
+ ---
677
+
678
+ *Need more details? Check the [Service API](service.md) for real-world query usage patterns!* 🚀