@fjell/cache 4.6.7 → 4.6.10

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.
@@ -0,0 +1,307 @@
1
+ # Fjell-Cache Examples
2
+
3
+ This directory contains examples demonstrating how to use fjell-cache for caching data models and managing complex business relationships with different patterns and complexity levels.
4
+
5
+ ## Examples
6
+
7
+ ### 1. `basic-cache-example.ts` ⭐ **Start Here!**
8
+ **Perfect for beginners!** Demonstrates the fundamental way to use fjell-cache for data caching:
9
+ - **Basic cache operations** - Create caches, get/set items, manage cache lifecycle
10
+ - **Simple data models** - User and Task entities with mock storage
11
+ - **Registry and Instance creation** - Set up cache model instances
12
+ - **Cache hits vs misses** - Understand cache behavior and performance benefits
13
+ - **Cache management** - Updates, deletions, and data consistency
14
+
15
+ Great for understanding the fundamentals of fjell-cache data management.
16
+
17
+ ### 2. `aggregator-example.ts` šŸ—ļø **Advanced Business Relationships**
18
+ **Complete business relationship management!** Demonstrates advanced caching patterns with entity relationships:
19
+ - **Multiple interconnected models**: Customer, Order, Product, SupportTicket
20
+ - **Automatic reference population**: Orders automatically include customer data
21
+ - **Required vs optional aggregates**: Flexible relationship management
22
+ - **Complex business scenarios**: E-commerce platform with customer management
23
+ - **Performance optimization**: Cache efficiency through aggregated data
24
+
25
+ Shows how fjell-cache handles enterprise data relationship patterns.
26
+
27
+ ### 3. `cache-map-example.ts` šŸ”§ **Low-Level Cache Operations**
28
+ **Direct cache management!** Demonstrates lower-level CacheMap functionality:
29
+ - **Direct CacheMap usage**: Create and manage cache maps without higher-level abstractions
30
+ - **Primary and composite keys**: Handle both simple and complex key structures
31
+ - **Location-based operations**: Filter contained items by location hierarchy
32
+ - **Performance characteristics**: Bulk operations and efficiency testing
33
+ - **Cache lifecycle**: Cloning, cleanup, and memory management
34
+
35
+ Perfect for understanding the underlying cache mechanisms and advanced use cases.
36
+
37
+ ## Key Concepts Demonstrated
38
+
39
+ ### Basic Caching Operations (basic-cache-example.ts)
40
+ ```typescript
41
+ // Import fjell-cache functionality
42
+ import { createCache, createRegistry, createInstance } from '@fjell/cache';
43
+ import { ClientApi } from '@fjell/client-api';
44
+
45
+ // Create a registry for cache management
46
+ const registry = createRegistry();
47
+
48
+ // Create a cache instance with API integration
49
+ const userApi = createUserApi(); // Your API implementation
50
+ const userCache = await createCache(userApi, 'user');
51
+
52
+ // Create cache model instance
53
+ const userInstance = createInstance(registry, createCoordinate('user'), userCache);
54
+
55
+ // Perform cache operations
56
+ const [cacheMap, allUsers] = await userInstance.cache.all();
57
+ const [, cachedUser] = await userInstance.cache.get(userKey);
58
+ const [, retrievedUser] = await userInstance.cache.retrieve(userKey); // Cache hit!
59
+
60
+ await userInstance.cache.set(userKey, updatedUser);
61
+ ```
62
+
63
+ ### Advanced Aggregation (aggregator-example.ts)
64
+ ```typescript
65
+ // Create aggregated cache with relationships
66
+ const orderAggregator = await createAggregator(orderCache, {
67
+ aggregates: {
68
+ customer: { cache: customerCache, optional: false }, // Required reference
69
+ product: { cache: productCache, optional: true }, // Optional reference
70
+ },
71
+ events: {}
72
+ });
73
+
74
+ // Automatically populate related entities
75
+ const populatedOrder = await orderAggregator.populate(order);
76
+ if (populatedOrder.aggs?.customer?.item) {
77
+ const customer = populatedOrder.aggs.customer.item;
78
+ console.log(`Order for: ${customer.name} (${customer.email})`);
79
+ }
80
+
81
+ // Create aggregated cache instance
82
+ const orderInstance = createInstance(registry, createCoordinate('order'), orderAggregator);
83
+ ```
84
+
85
+ ### Direct Cache Management (cache-map-example.ts)
86
+ ```typescript
87
+ // Create CacheMap instances directly
88
+ const documentCacheMap = new CacheMap<Document, 'document'>(['document']);
89
+ const commentCacheMap = new CacheMap<Comment, 'comment', 'document'>(['comment', 'document']);
90
+
91
+ // Basic operations
92
+ documentCacheMap.set(documentKey, document);
93
+ const retrievedDoc = documentCacheMap.get(documentKey);
94
+ const hasDoc = documentCacheMap.includesKey(documentKey);
95
+
96
+ // Bulk operations
97
+ const allDocuments = documentCacheMap.allIn([]);
98
+ const allKeys = documentCacheMap.keys();
99
+ const allValues = documentCacheMap.values();
100
+
101
+ // Location-based filtering for contained items
102
+ const commentsInDoc = commentCacheMap.allIn([{ kt: 'document', lk: documentId }]);
103
+
104
+ // Performance operations
105
+ const clonedCache = documentCacheMap.clone();
106
+ documentCacheMap.delete(documentKey);
107
+ ```
108
+
109
+ ### Data Model Patterns
110
+
111
+ #### Primary Items
112
+ - Standalone entities (User, Customer, Document)
113
+ - No location hierarchy constraints
114
+ - Simple key structure: `Item<'keyType'>`
115
+
116
+ #### Contained Items
117
+ - Nested within other entities or locations
118
+ - Multi-level location keys for organization
119
+ - Complex key structure: `Item<'keyType', 'location1', 'location2', ...>`
120
+
121
+ #### Aggregated Items
122
+ - Items with automatic reference population
123
+ - Business relationships through cache aggregation
124
+ - Performance optimized through cached references
125
+
126
+ ## Running Examples
127
+
128
+ ```bash
129
+ # Start with the basic example (recommended)
130
+ npx tsx examples/basic-cache-example.ts
131
+
132
+ # Run the aggregator example
133
+ npx tsx examples/aggregator-example.ts
134
+
135
+ # Run the cache map example
136
+ npx tsx examples/cache-map-example.ts
137
+
138
+ # Or with Node.js
139
+ node -r esbuild-register examples/basic-cache-example.ts
140
+ ```
141
+
142
+ ## Integration with Real Applications
143
+
144
+ All examples use the actual fjell-cache functionality! In production applications:
145
+
146
+ ```typescript
147
+ import { createCache, createRegistry, createInstance, createAggregator } from '@fjell/cache';
148
+ import { ClientApi } from '@fjell/client-api';
149
+
150
+ // Basic cache setup
151
+ const registry = createRegistry();
152
+
153
+ const userCache = await createCache(userApi, 'user');
154
+ const userInstance = createInstance(registry, createCoordinate('user'), userCache);
155
+
156
+ // With aggregation for business relationships
157
+ const orderAggregator = await createAggregator(orderCache, {
158
+ aggregates: {
159
+ customer: { cache: customerCache, optional: false },
160
+ items: { cache: productCache, optional: true }
161
+ },
162
+ events: {
163
+ orderUpdated: async (key, item) => {
164
+ // Custom event handling
165
+ await notifyCustomer(item);
166
+ }
167
+ }
168
+ });
169
+
170
+ // Advanced cache configuration
171
+ const options = {
172
+ cacheSize: 10000,
173
+ ttl: 3600000, // 1 hour
174
+ refreshThreshold: 0.8,
175
+ compression: true
176
+ };
177
+ ```
178
+
179
+ ## Cache Operation Types
180
+
181
+ ### Basic Operations
182
+ - **all()**: Get all items and update cache
183
+ - **get()**: Get item by key, fetch from API if not cached
184
+ - **retrieve()**: Get item by key, return null if not cached
185
+ - **set()**: Store item in cache
186
+ - **one()**: Get single item
187
+ - **find()**: Search items with finder methods
188
+
189
+ ### Aggregation Operations
190
+ - **populate()**: Automatically populate item with related entities
191
+ - **populateAggregate()**: Populate specific aggregate relationship
192
+ - **populateEvent()**: Handle population events
193
+
194
+ ### Cache Management
195
+ - **allIn()**: Get items by location (for contained items)
196
+ - **queryIn()**: Query items by location with filtering
197
+ - **clone()**: Create independent cache copy
198
+ - **delete()**: Remove item from cache
199
+ - **clear()**: Clear all cache contents
200
+
201
+ ### Business Operations
202
+ ```typescript
203
+ // Cache with business logic integration
204
+ const cache = await createCache(api, 'order', {
205
+ hooks: {
206
+ beforeGet: async (key) => { /* validation */ },
207
+ afterSet: async (key, item) => { /* notifications */ }
208
+ },
209
+ validators: {
210
+ status: (status) => ['pending', 'shipped', 'delivered'].includes(status)
211
+ },
212
+ aggregates: {
213
+ customer: customerCache,
214
+ items: productCache
215
+ }
216
+ });
217
+ ```
218
+
219
+ ## When to Use What
220
+
221
+ **Use `basic-cache-example.ts` approach when:**
222
+ - Learning fjell-cache fundamentals
223
+ - Building simple applications with caching needs
224
+ - Need basic get/set cache operations
225
+ - Working with independent data models
226
+
227
+ **Use `aggregator-example.ts` approach when:**
228
+ - Managing complex business relationships
229
+ - Need automatic population of related entities
230
+ - Building enterprise applications with interconnected data
231
+ - Require performance optimization through aggregated caching
232
+ - Working with customer/order/product type relationships
233
+
234
+ **Use `cache-map-example.ts` approach when:**
235
+ - Need direct control over cache operations
236
+ - Building custom caching solutions
237
+ - Working with contained items and location hierarchies
238
+ - Require maximum performance and minimal overhead
239
+ - Implementing cache-based data structures
240
+
241
+ ## Advanced Features
242
+
243
+ ### Cache Aggregation
244
+ ```typescript
245
+ // Complex aggregation with optional and required references
246
+ const ticketAggregator = await createAggregator(ticketCache, {
247
+ aggregates: {
248
+ customer: { cache: customerCache, optional: false }, // Always populated
249
+ order: { cache: orderCache, optional: true }, // Only if orderId exists
250
+ assignee: { cache: userCache, optional: true } // Only if assigned
251
+ },
252
+ events: {
253
+ ticketAssigned: async (key, ticket) => {
254
+ await notifyAssignee(ticket);
255
+ }
256
+ }
257
+ });
258
+
259
+ // Automatic population includes all available references
260
+ const populatedTicket = await ticketAggregator.populate(ticket);
261
+ ```
262
+
263
+ ### Performance Optimization
264
+ ```typescript
265
+ // Cache with performance tuning
266
+ const cache = await createCache(api, 'product', {
267
+ batchSize: 100, // Batch operations
268
+ prefetch: true, // Prefetch related items
269
+ compression: true, // Compress cached data
270
+ ttl: 3600000, // 1 hour cache lifetime
271
+ maxSize: 10000 // Maximum cached items
272
+ });
273
+
274
+ // Bulk operations for efficiency
275
+ const [cacheMap, allProducts] = await cache.all();
276
+ const productMap = new Map(allProducts.map(p => [p.id, p]));
277
+ ```
278
+
279
+ ### Storage Integration
280
+ Fjell-cache works with any storage backend through the ClientApi interface:
281
+ - SQL databases (PostgreSQL, MySQL, SQLite)
282
+ - NoSQL databases (MongoDB, DynamoDB, Redis)
283
+ - REST APIs and GraphQL endpoints
284
+ - In-memory stores and mock data
285
+ - File systems and cloud storage
286
+ - Custom data sources
287
+
288
+ ### Error Handling and Resilience
289
+ ```typescript
290
+ // Cache with error handling
291
+ const resilientCache = await createCache(api, 'user', {
292
+ fallback: async (key) => {
293
+ // Fallback to secondary storage
294
+ return await secondaryStorage.get(key);
295
+ },
296
+ retryPolicy: {
297
+ attempts: 3,
298
+ backoff: 'exponential'
299
+ },
300
+ circuit: {
301
+ failureThreshold: 5,
302
+ resetTimeout: 30000
303
+ }
304
+ });
305
+ ```
306
+
307
+ This provides the foundation for building scalable, maintainable applications with intelligent caching using fjell-cache.
@@ -0,0 +1,334 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /**
3
+ * Aggregator Example
4
+ *
5
+ * This example demonstrates advanced fjell-cache functionality using the Aggregator
6
+ * for managing related entities with automatic population of references.
7
+ *
8
+ * Shows how to:
9
+ * - Create aggregated caches with references between entities
10
+ * - Populate items with their related data automatically
11
+ * - Handle optional vs required aggregates
12
+ * - Manage complex business relationships through caching
13
+ */
14
+
15
+ import { createAggregator } from '../src/Aggregator';
16
+ import { createCache } from '../src/Cache';
17
+ import { createInstance } from '../src/Instance';
18
+ import { createRegistry } from '../src/Registry';
19
+ import { ClientApi } from '@fjell/client-api';
20
+ import { Item, PriKey } from '@fjell/core';
21
+ import { createCoordinate } from '@fjell/registry';
22
+
23
+ // Define our business models with relationships
24
+ interface Customer extends Item<'customer'> {
25
+ id: string;
26
+ name: string;
27
+ email: string;
28
+ company: string;
29
+ tier: 'bronze' | 'silver' | 'gold' | 'platinum';
30
+ }
31
+
32
+ interface Order extends Item<'order'> {
33
+ id: string;
34
+ customerId: string;
35
+ total: number;
36
+ status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
37
+ items: string[]; // Array of product IDs
38
+ orderDate: Date;
39
+ }
40
+
41
+ interface Product extends Item<'product'> {
42
+ id: string;
43
+ name: string;
44
+ price: number;
45
+ category: string;
46
+ inStock: boolean;
47
+ }
48
+
49
+ interface SupportTicket extends Item<'ticket'> {
50
+ id: string;
51
+ customerId: string;
52
+ orderId?: string; // Optional reference to order
53
+ subject: string;
54
+ priority: 'low' | 'medium' | 'high' | 'urgent';
55
+ status: 'open' | 'in-progress' | 'resolved' | 'closed';
56
+ description: string;
57
+ }
58
+
59
+ // Mock storage
60
+ const mockCustomers = new Map<string, Customer>();
61
+ const mockOrders = new Map<string, Order>();
62
+ const mockProducts = new Map<string, Product>();
63
+ const mockTickets = new Map<string, SupportTicket>();
64
+
65
+ // Helper to create mock APIs
66
+ const createMockApi = <T extends Item<any>>(storage: Map<string, T>) => {
67
+ return {
68
+ async all(_query = {}) {
69
+ console.log(`šŸ“¦ Fetching all items from ${storage.constructor.name}...`);
70
+ return Array.from(storage.values());
71
+ },
72
+ async one(query = {}) {
73
+ const items = await this.all!(query);
74
+ return items[0] || null;
75
+ },
76
+ async get(key: PriKey<any>) {
77
+ const item = storage.get(String(key.pk));
78
+ if (!item) {
79
+ throw new Error(`Item not found: ${key.pk}`);
80
+ }
81
+ return item;
82
+ },
83
+ async find(_finder = 'all') {
84
+ return await this.all!({});
85
+ }
86
+ } as Partial<ClientApi<T, any>>;
87
+ };
88
+
89
+ // Test data creation helpers
90
+ const createCustomer = (id: string, name: string, email: string, company: string, tier: 'bronze' | 'silver' | 'gold' | 'platinum'): Customer => {
91
+ const customer: Customer = {
92
+ id, name, email, company, tier,
93
+ key: { kt: 'customer', pk: id },
94
+ events: { created: { at: new Date() }, updated: { at: new Date() }, deleted: { at: null } }
95
+ };
96
+ mockCustomers.set(id, customer);
97
+ return customer;
98
+ };
99
+
100
+ const createProduct = (id: string, name: string, price: number, category: string, inStock: boolean): Product => {
101
+ const product: Product = {
102
+ id, name, price, category, inStock,
103
+ key: { kt: 'product', pk: id },
104
+ events: { created: { at: new Date() }, updated: { at: new Date() }, deleted: { at: null } }
105
+ };
106
+ mockProducts.set(id, product);
107
+ return product;
108
+ };
109
+
110
+ const createOrder = (id: string, customerId: string, total: number, status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled', items: string[]): Order => {
111
+ const order: Order = {
112
+ id, customerId, total, status, items, orderDate: new Date(),
113
+ key: { kt: 'order', pk: id },
114
+ events: { created: { at: new Date() }, updated: { at: new Date() }, deleted: { at: null } },
115
+ // Add references for aggregation
116
+ refs: {
117
+ customer: { kt: 'customer', pk: customerId }
118
+ }
119
+ };
120
+ mockOrders.set(id, order);
121
+ return order;
122
+ };
123
+
124
+ const createSupportTicket = (
125
+ id: string,
126
+ customerId: string,
127
+ subject: string,
128
+ priority: 'low' | 'medium' | 'high' | 'urgent',
129
+ status: 'open' | 'in-progress' | 'resolved' | 'closed',
130
+ description: string,
131
+ orderId?: string): SupportTicket => {
132
+ const ticket: SupportTicket = {
133
+ id, customerId, subject, priority, status, description, orderId,
134
+ key: { kt: 'ticket', pk: id },
135
+ events: { created: { at: new Date() }, updated: { at: new Date() }, deleted: { at: null } },
136
+ // Add references for aggregation
137
+ refs: {
138
+ customer: { kt: 'customer', pk: customerId },
139
+ ...(orderId && { order: { kt: 'order', pk: orderId } })
140
+ }
141
+ };
142
+ mockTickets.set(id, ticket);
143
+ return ticket;
144
+ };
145
+
146
+ export const runAggregatorExample = async (): Promise<void> => {
147
+ console.log('\nšŸš€ Fjell-Cache Aggregator Example');
148
+ console.log('=================================\n');
149
+
150
+ console.log('This example demonstrates advanced caching with entity relationships and aggregation.\n');
151
+
152
+ // Step 1: Create test data
153
+ console.log('Step 1: Creating business entities');
154
+ console.log('----------------------------------');
155
+
156
+ const customer1 = createCustomer('cust-1', 'Acme Corp', 'contact@acme.com', 'Acme Corporation', 'gold');
157
+ const customer2 = createCustomer('cust-2', 'TechStart Inc', 'hello@techstart.io', 'TechStart Inc', 'silver');
158
+
159
+ const product1 = createProduct('prod-1', 'Premium Widget', 299.99, 'widgets', true);
160
+ const product2 = createProduct('prod-2', 'Standard Widget', 199.99, 'widgets', true);
161
+ const product3 = createProduct('prod-3', 'Budget Widget', 99.99, 'widgets', false);
162
+
163
+ const order1 = createOrder('order-1', customer1.id, 499.98, 'shipped', [product1.id, product2.id]);
164
+ const order2 = createOrder('order-2', customer2.id, 199.99, 'pending', [product2.id]);
165
+
166
+ const ticket1 = createSupportTicket('ticket-1', customer1.id, 'Widget not working', 'high', 'open', 'The premium widget stopped working after 2 days', order1.id);
167
+ const ticket2 = createSupportTicket('ticket-2', customer2.id, 'General inquiry', 'low', 'resolved', 'Question about widget compatibility');
168
+
169
+ console.log(`āœ… Created ${mockCustomers.size} customers, ${mockProducts.size} products, ${mockOrders.size} orders, ${mockTickets.size} tickets\n`);
170
+
171
+ // Step 2: Set up cache infrastructure
172
+ console.log('Step 2: Setting up cache infrastructure');
173
+ console.log('--------------------------------------');
174
+
175
+ const registry = createRegistry();
176
+ console.log('āœ… Created registry');
177
+
178
+ // Create individual caches for each entity type
179
+ const customerApi = createMockApi(mockCustomers) as ClientApi<Customer, 'customer'>;
180
+ const orderApi = createMockApi(mockOrders) as ClientApi<Order, 'order'>;
181
+ const productApi = createMockApi(mockProducts) as ClientApi<Product, 'product'>;
182
+ const ticketApi = createMockApi(mockTickets) as ClientApi<SupportTicket, 'ticket'>;
183
+
184
+ const customerCache = await createCache(customerApi, 'customer');
185
+ const orderCache = await createCache(orderApi, 'order');
186
+ const productCache = await createCache(productApi, 'product');
187
+ const ticketCache = await createCache(ticketApi, 'ticket');
188
+
189
+ console.log('āœ… Created individual caches for each entity type');
190
+
191
+ // Step 3: Create aggregated caches
192
+ console.log('\nStep 3: Creating aggregated caches');
193
+ console.log('----------------------------------');
194
+
195
+ // Create order aggregator that automatically populates customer data
196
+ const orderAggregator = await createAggregator(orderCache, {
197
+ aggregates: {
198
+ customer: { cache: customerCache, optional: false }, // Required reference
199
+ },
200
+ events: {}
201
+ });
202
+
203
+ // Create support ticket aggregator with both customer and order references
204
+ const ticketAggregator = await createAggregator(ticketCache, {
205
+ aggregates: {
206
+ customer: { cache: customerCache, optional: false }, // Required reference
207
+ order: { cache: orderCache, optional: true }, // Optional reference (not all tickets relate to orders)
208
+ },
209
+ events: {}
210
+ });
211
+
212
+ console.log('āœ… Created aggregated caches with relationship mappings');
213
+
214
+ // Create instances for easier management
215
+ const orderInstance = createInstance(registry, createCoordinate('order'), orderAggregator);
216
+ const ticketInstance = createInstance(registry, createCoordinate('ticket'), ticketAggregator);
217
+
218
+ console.log('āœ… Created aggregated cache instances\n');
219
+
220
+ // Step 4: Basic aggregation - Fetch orders with customer data
221
+ console.log('Step 4: Order aggregation with customer data');
222
+ console.log('--------------------------------------------');
223
+
224
+ const [, orders] = await orderInstance.cache.all();
225
+ console.log(`šŸ“‹ Fetched ${orders.length} orders`);
226
+
227
+ for (const order of orders) {
228
+ console.log(`\nšŸ“¦ Order ${order.id}:`);
229
+ console.log(` Amount: $${order.total}`);
230
+ console.log(` Status: ${order.status}`);
231
+ console.log(` Items: ${order.items.join(', ')}`);
232
+
233
+ // Populate the order with customer data
234
+ const populatedOrder = await orderAggregator.populate(order);
235
+ if (populatedOrder.aggs?.customer?.item) {
236
+ const customer = populatedOrder.aggs.customer.item;
237
+ console.log(` šŸ‘¤ Customer: ${customer.name} (${customer.email})`);
238
+ console.log(` šŸ¢ Company: ${customer.company} - ${customer.tier} tier`);
239
+ }
240
+ }
241
+
242
+ // Step 5: Complex aggregation - Support tickets with multiple references
243
+ console.log('\n\nStep 5: Support ticket aggregation with multiple references');
244
+ console.log('----------------------------------------------------------');
245
+
246
+ const [, tickets] = await ticketInstance.cache.all();
247
+ console.log(`šŸŽ« Fetched ${tickets.length} support tickets`);
248
+
249
+ for (const ticket of tickets) {
250
+ console.log(`\nšŸŽ« Ticket ${ticket.id}:`);
251
+ console.log(` Subject: ${ticket.subject}`);
252
+ console.log(` Priority: ${ticket.priority}`);
253
+ console.log(` Status: ${ticket.status}`);
254
+ console.log(` Description: ${ticket.description}`);
255
+
256
+ // Populate the ticket with all related data
257
+ const populatedTicket = await ticketAggregator.populate(ticket);
258
+
259
+ // Customer data (required reference)
260
+ if (populatedTicket.aggs?.customer?.item) {
261
+ const customer = populatedTicket.aggs.customer.item;
262
+ console.log(` šŸ‘¤ Customer: ${customer.name} (${customer.email}) - ${customer.tier} tier`);
263
+ }
264
+
265
+ // Order data (optional reference)
266
+ if (populatedTicket.aggs?.order?.item) {
267
+ const order = populatedTicket.aggs.order.item;
268
+ console.log(` šŸ“¦ Related Order: ${order.id} - $${order.total} (${order.status})`);
269
+ } else {
270
+ console.log(` šŸ“¦ No related order`);
271
+ }
272
+ }
273
+
274
+ // Step 6: Individual item retrieval with aggregation
275
+ console.log('\n\nStep 6: Individual item retrieval with aggregation');
276
+ console.log('-------------------------------------------------');
277
+
278
+ const [, specificOrder] = await orderInstance.cache.get(order1.key);
279
+ if (specificOrder) {
280
+ console.log(`šŸ” Retrieved specific order: ${specificOrder.id}`);
281
+
282
+ const populatedSpecificOrder = await orderAggregator.populate(specificOrder);
283
+ if (populatedSpecificOrder.aggs?.customer?.item) {
284
+ const customer = populatedSpecificOrder.aggs.customer.item;
285
+ console.log(` Automatically populated customer: ${customer.name}`);
286
+ }
287
+ }
288
+
289
+ // Step 7: Demonstrating cache efficiency with aggregation
290
+ console.log('\n\nStep 7: Cache efficiency demonstration');
291
+ console.log('-------------------------------------');
292
+
293
+ console.log('šŸŽÆ First population (will fetch from storage):');
294
+ const startTime1 = Date.now();
295
+ const populated1 = await orderAggregator.populate(order1);
296
+ const time1 = Date.now() - startTime1;
297
+ console.log(` Populated order with customer data in ${time1}ms`);
298
+
299
+ console.log('šŸŽÆ Second population (should use cached data):');
300
+ const startTime2 = Date.now();
301
+ const populated2 = await orderAggregator.populate(order1);
302
+ const time2 = Date.now() - startTime2;
303
+ console.log(` Populated same order in ${time2}ms (cached)`);
304
+
305
+ console.log(` šŸ“Š Cache efficiency: ${Math.round(((time1 - time2) / time1) * 100)}% faster on second call`);
306
+
307
+ // Step 8: Aggregate management and statistics
308
+ console.log('\n\nStep 8: Aggregate management and statistics');
309
+ console.log('------------------------------------------');
310
+
311
+ console.log('šŸ“Š Cache Statistics:');
312
+ console.log(` šŸ‘„ Customers cached: ${mockCustomers.size}`);
313
+ console.log(` šŸ“¦ Orders cached: ${mockOrders.size}`);
314
+ console.log(` šŸ“¦ Products cached: ${mockProducts.size}`);
315
+ console.log(` šŸŽ« Tickets cached: ${mockTickets.size}`);
316
+ console.log(` šŸ”— Order aggregator references: customer (required)`);
317
+ console.log(` šŸ”— Ticket aggregator references: customer (required), order (optional)`);
318
+
319
+ console.log('\nšŸŽ‰ Aggregator Example Complete!');
320
+ console.log('===============================\n');
321
+
322
+ console.log('Key concepts demonstrated:');
323
+ console.log('• Creating aggregated caches with entity relationships');
324
+ console.log('• Automatic population of referenced entities');
325
+ console.log('• Required vs optional aggregate references');
326
+ console.log('• Cache efficiency through aggregation');
327
+ console.log('• Complex business model relationships');
328
+ console.log('• Performance benefits of cached aggregates\n');
329
+ };
330
+
331
+ // Run the example if this file is executed directly
332
+ if (import.meta.url === `file://${process.argv[1]}`) {
333
+ runAggregatorExample().catch(console.error);
334
+ }