@fjell/cache 4.6.10 → 4.6.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/dist/Aggregator.cjs.js +26 -20
- package/dist/Aggregator.d.ts +17 -1
- package/dist/Aggregator.es.js +26 -20
- package/dist/Cache.cjs.js +22 -345
- package/dist/Cache.d.ts +25 -20
- package/dist/Cache.es.js +22 -346
- package/dist/Instance.cjs.js +7 -11
- package/dist/Instance.d.ts +5 -8
- package/dist/Instance.es.js +6 -10
- package/dist/InstanceFactory.cjs.js +17 -5
- package/dist/InstanceFactory.d.ts +3 -3
- package/dist/InstanceFactory.es.js +17 -5
- package/dist/Operations.cjs.js +43 -0
- package/dist/Operations.d.ts +70 -0
- package/dist/Operations.es.js +39 -0
- package/dist/index.cjs +416 -369
- package/dist/index.cjs.js +4 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.js +3 -2
- package/dist/ops/action.cjs.js +28 -0
- package/dist/ops/action.d.ts +4 -0
- package/dist/ops/action.es.js +24 -0
- package/dist/ops/all.cjs.js +33 -0
- package/dist/ops/all.d.ts +4 -0
- package/dist/ops/all.es.js +29 -0
- package/dist/ops/allAction.cjs.js +35 -0
- package/dist/ops/allAction.d.ts +4 -0
- package/dist/ops/allAction.es.js +31 -0
- package/dist/ops/allFacet.cjs.js +22 -0
- package/dist/ops/allFacet.d.ts +4 -0
- package/dist/ops/allFacet.es.js +18 -0
- package/dist/ops/create.cjs.js +23 -0
- package/dist/ops/create.d.ts +4 -0
- package/dist/ops/create.es.js +19 -0
- package/dist/ops/facet.cjs.js +21 -0
- package/dist/ops/facet.d.ts +4 -0
- package/dist/ops/facet.es.js +17 -0
- package/dist/ops/find.cjs.js +26 -0
- package/dist/ops/find.d.ts +4 -0
- package/dist/ops/find.es.js +22 -0
- package/dist/ops/findOne.cjs.js +24 -0
- package/dist/ops/findOne.d.ts +4 -0
- package/dist/ops/findOne.es.js +20 -0
- package/dist/ops/get.cjs.js +38 -0
- package/dist/ops/get.d.ts +4 -0
- package/dist/ops/get.es.js +34 -0
- package/dist/ops/one.cjs.js +33 -0
- package/dist/ops/one.d.ts +4 -0
- package/dist/ops/one.es.js +29 -0
- package/dist/ops/remove.cjs.js +30 -0
- package/dist/ops/remove.d.ts +4 -0
- package/dist/ops/remove.es.js +26 -0
- package/dist/ops/reset.cjs.js +15 -0
- package/dist/ops/reset.d.ts +4 -0
- package/dist/ops/reset.es.js +11 -0
- package/dist/ops/retrieve.cjs.js +37 -0
- package/dist/ops/retrieve.d.ts +4 -0
- package/dist/ops/retrieve.es.js +33 -0
- package/dist/ops/set.cjs.js +71 -0
- package/dist/ops/set.d.ts +3 -0
- package/dist/ops/set.es.js +67 -0
- package/dist/ops/update.cjs.js +34 -0
- package/dist/ops/update.d.ts +4 -0
- package/dist/ops/update.es.js +30 -0
- package/docs/docs.config.ts +75 -0
- package/docs/index.html +18 -0
- package/docs/package.json +34 -0
- package/docs/public/README.md +96 -0
- package/docs/public/examples-README.md +302 -0
- package/docs/public/test.txt +0 -0
- package/docs/src/index.css +3 -0
- package/docs/src/main.tsx +12 -0
- package/docs/src/test/setup.ts +1 -0
- package/docs/tsconfig.node.json +15 -0
- package/examples/README.md +34 -39
- package/examples/aggregator-example.ts +9 -14
- package/examples/basic-cache-example.ts +18 -21
- package/package.json +16 -11
- package/vitest.config.ts +1 -1
|
@@ -0,0 +1,302 @@
|
|
|
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 with coordinates and registries, use operations API
|
|
10
|
+
- **Simple data models** - User and Task entities with mock storage
|
|
11
|
+
- **Cache-as-Instance architecture** - Caches extend Instance from fjell-registry
|
|
12
|
+
- **Cache hits vs misses** - Understand cache behavior and performance benefits
|
|
13
|
+
- **Cache management** - Updates, deletions, and data consistency through operations
|
|
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 } from '@fjell/cache';
|
|
43
|
+
import { createCoordinate, createRegistry } from '@fjell/registry';
|
|
44
|
+
import { ClientApi } from '@fjell/client-api';
|
|
45
|
+
|
|
46
|
+
// Create a registry for cache management
|
|
47
|
+
const registry = createRegistry();
|
|
48
|
+
|
|
49
|
+
// Create a cache instance with API integration
|
|
50
|
+
const userApi = createUserApi(); // Your API implementation
|
|
51
|
+
const userCache = await createCache(userApi, createCoordinate('user'), registry);
|
|
52
|
+
|
|
53
|
+
// Cache is now an instance - no need for separate createInstance call
|
|
54
|
+
// Perform cache operations through the operations API
|
|
55
|
+
const [cacheMap, allUsers] = await userCache.operations.all();
|
|
56
|
+
const [, cachedUser] = await userCache.operations.get(userKey);
|
|
57
|
+
const [, retrievedUser] = await userCache.operations.retrieve(userKey); // Cache hit!
|
|
58
|
+
|
|
59
|
+
await userCache.operations.set(userKey, updatedUser);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Advanced Aggregation (aggregator-example.ts)
|
|
63
|
+
```typescript
|
|
64
|
+
// Create aggregated cache with relationships
|
|
65
|
+
const orderAggregator = await createAggregator(orderCache, {
|
|
66
|
+
aggregates: {
|
|
67
|
+
customer: { cache: customerCache, optional: false }, // Required reference
|
|
68
|
+
product: { cache: productCache, optional: true }, // Optional reference
|
|
69
|
+
},
|
|
70
|
+
events: {}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Automatically populate related entities
|
|
74
|
+
const populatedOrder = await orderAggregator.populate(order);
|
|
75
|
+
if (populatedOrder.aggs?.customer?.item) {
|
|
76
|
+
const customer = populatedOrder.aggs.customer.item;
|
|
77
|
+
console.log(`Order for: ${customer.name} (${customer.email})`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Aggregator is now itself an instance - access operations directly
|
|
81
|
+
const [, orders] = await orderAggregator.all();
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Direct Cache Management (cache-map-example.ts)
|
|
85
|
+
```typescript
|
|
86
|
+
// Create CacheMap instances directly
|
|
87
|
+
const documentCacheMap = new CacheMap<Document, 'document'>(['document']);
|
|
88
|
+
const commentCacheMap = new CacheMap<Comment, 'comment', 'document'>(['comment', 'document']);
|
|
89
|
+
|
|
90
|
+
// Basic operations
|
|
91
|
+
documentCacheMap.set(documentKey, document);
|
|
92
|
+
const retrievedDoc = documentCacheMap.get(documentKey);
|
|
93
|
+
const hasDoc = documentCacheMap.includesKey(documentKey);
|
|
94
|
+
|
|
95
|
+
// Bulk operations
|
|
96
|
+
const allDocuments = documentCacheMap.allIn([]);
|
|
97
|
+
const allKeys = documentCacheMap.keys();
|
|
98
|
+
const allValues = documentCacheMap.values();
|
|
99
|
+
|
|
100
|
+
// Location-based filtering for contained items
|
|
101
|
+
const commentsInDoc = commentCacheMap.allIn([{ kt: 'document', lk: documentId }]);
|
|
102
|
+
|
|
103
|
+
// Performance operations
|
|
104
|
+
const clonedCache = documentCacheMap.clone();
|
|
105
|
+
documentCacheMap.delete(documentKey);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Data Model Patterns
|
|
109
|
+
|
|
110
|
+
#### Primary Items
|
|
111
|
+
- Standalone entities (User, Customer, Document)
|
|
112
|
+
- No location hierarchy constraints
|
|
113
|
+
- Simple key structure: `Item<'keyType'>`
|
|
114
|
+
|
|
115
|
+
#### Contained Items
|
|
116
|
+
- Nested within other entities or locations
|
|
117
|
+
- Multi-level location keys for organization
|
|
118
|
+
- Complex key structure: `Item<'keyType', 'location1', 'location2', ...>`
|
|
119
|
+
|
|
120
|
+
#### Aggregated Items
|
|
121
|
+
- Items with automatic reference population
|
|
122
|
+
- Business relationships through cache aggregation
|
|
123
|
+
- Performance optimized through cached references
|
|
124
|
+
|
|
125
|
+
## Running Examples
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Start with the basic example (recommended)
|
|
129
|
+
npx tsx examples/basic-cache-example.ts
|
|
130
|
+
|
|
131
|
+
# Run the aggregator example
|
|
132
|
+
npx tsx examples/aggregator-example.ts
|
|
133
|
+
|
|
134
|
+
# Run the cache map example
|
|
135
|
+
npx tsx examples/cache-map-example.ts
|
|
136
|
+
|
|
137
|
+
# Or with Node.js
|
|
138
|
+
node -r esbuild-register examples/basic-cache-example.ts
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Integration with Real Applications
|
|
142
|
+
|
|
143
|
+
All examples use the actual fjell-cache functionality! In production applications:
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { createCache, createRegistry, createInstance, createAggregator } from '@fjell/cache';
|
|
147
|
+
import { ClientApi } from '@fjell/client-api';
|
|
148
|
+
|
|
149
|
+
// Basic cache setup
|
|
150
|
+
const registry = createRegistry();
|
|
151
|
+
|
|
152
|
+
const userCache = await createCache(userApi, 'user');
|
|
153
|
+
const userInstance = createInstance(registry, createCoordinate('user'), userCache);
|
|
154
|
+
|
|
155
|
+
// With aggregation for business relationships
|
|
156
|
+
const orderAggregator = await createAggregator(orderCache, {
|
|
157
|
+
aggregates: {
|
|
158
|
+
customer: { cache: customerCache, optional: false },
|
|
159
|
+
items: { cache: productCache, optional: true }
|
|
160
|
+
},
|
|
161
|
+
events: {
|
|
162
|
+
orderUpdated: async (key, item) => {
|
|
163
|
+
// Custom event handling
|
|
164
|
+
await notifyCustomer(item);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Advanced cache configuration
|
|
170
|
+
const options = {
|
|
171
|
+
cacheSize: 10000,
|
|
172
|
+
ttl: 3600000, // 1 hour
|
|
173
|
+
refreshThreshold: 0.8,
|
|
174
|
+
compression: true
|
|
175
|
+
};
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Cache Operation Types
|
|
179
|
+
|
|
180
|
+
### Basic Operations
|
|
181
|
+
- **all()**: Get all items and update cache
|
|
182
|
+
- **get()**: Get item by key, fetch from API if not cached
|
|
183
|
+
- **retrieve()**: Get item by key, return null if not cached
|
|
184
|
+
- **set()**: Store item in cache
|
|
185
|
+
- **one()**: Get single item
|
|
186
|
+
- **find()**: Search items with finder methods
|
|
187
|
+
|
|
188
|
+
### Aggregation Operations
|
|
189
|
+
- **populate()**: Automatically populate item with related entities
|
|
190
|
+
- **populateAggregate()**: Populate specific aggregate relationship
|
|
191
|
+
- **populateEvent()**: Handle population events
|
|
192
|
+
|
|
193
|
+
### Cache Management
|
|
194
|
+
- **allIn()**: Get items by location (for contained items)
|
|
195
|
+
- **queryIn()**: Query items by location with filtering
|
|
196
|
+
- **clone()**: Create independent cache copy
|
|
197
|
+
- **delete()**: Remove item from cache
|
|
198
|
+
- **clear()**: Clear all cache contents
|
|
199
|
+
|
|
200
|
+
### Business Operations
|
|
201
|
+
```typescript
|
|
202
|
+
// Cache with business logic integration
|
|
203
|
+
const cache = await createCache(api, 'order', {
|
|
204
|
+
hooks: {
|
|
205
|
+
beforeGet: async (key) => { /* validation */ },
|
|
206
|
+
afterSet: async (key, item) => { /* notifications */ }
|
|
207
|
+
},
|
|
208
|
+
validators: {
|
|
209
|
+
status: (status) => ['pending', 'shipped', 'delivered'].includes(status)
|
|
210
|
+
},
|
|
211
|
+
aggregates: {
|
|
212
|
+
customer: customerCache,
|
|
213
|
+
items: productCache
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## When to Use What
|
|
219
|
+
|
|
220
|
+
**Use `basic-cache-example.ts` approach when:**
|
|
221
|
+
- Learning fjell-cache fundamentals
|
|
222
|
+
- Building simple applications with caching needs
|
|
223
|
+
- Need basic get/set cache operations
|
|
224
|
+
- Working with independent data models
|
|
225
|
+
|
|
226
|
+
**Use `aggregator-example.ts` approach when:**
|
|
227
|
+
- Managing complex business relationships
|
|
228
|
+
- Need automatic population of related entities
|
|
229
|
+
- Building enterprise applications with interconnected data
|
|
230
|
+
- Require performance optimization through aggregated caching
|
|
231
|
+
- Working with customer/order/product type relationships
|
|
232
|
+
|
|
233
|
+
**Use `cache-map-example.ts` approach when:**
|
|
234
|
+
- Need direct control over cache operations
|
|
235
|
+
- Building custom caching solutions
|
|
236
|
+
- Working with contained items and location hierarchies
|
|
237
|
+
- Require maximum performance and minimal overhead
|
|
238
|
+
- Implementing cache-based data structures
|
|
239
|
+
|
|
240
|
+
## Advanced Features
|
|
241
|
+
|
|
242
|
+
### Cache Aggregation
|
|
243
|
+
```typescript
|
|
244
|
+
// Complex aggregation with optional and required references
|
|
245
|
+
const ticketAggregator = await createAggregator(ticketCache, {
|
|
246
|
+
aggregates: {
|
|
247
|
+
customer: { cache: customerCache, optional: false }, // Always populated
|
|
248
|
+
order: { cache: orderCache, optional: true }, // Only if orderId exists
|
|
249
|
+
assignee: { cache: userCache, optional: true } // Only if assigned
|
|
250
|
+
},
|
|
251
|
+
events: {
|
|
252
|
+
ticketAssigned: async (key, ticket) => {
|
|
253
|
+
await notifyAssignee(ticket);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Automatic population includes all available references
|
|
259
|
+
const populatedTicket = await ticketAggregator.populate(ticket);
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### Performance Optimization
|
|
263
|
+
```typescript
|
|
264
|
+
// Cache with coordinate and registry
|
|
265
|
+
const cache = await createCache(api, createCoordinate('product'), registry);
|
|
266
|
+
|
|
267
|
+
// Bulk operations for efficiency
|
|
268
|
+
const [cacheMap, allProducts] = await cache.operations.all();
|
|
269
|
+
const productMap = new Map(allProducts.map(p => [p.id, p]));
|
|
270
|
+
|
|
271
|
+
// Access cache properties for optimization
|
|
272
|
+
console.log(`Cache coordinate: ${cache.coordinate.kta.join(', ')}`);
|
|
273
|
+
console.log(`Cached items: ${cache.cacheMap.size()}`);
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Storage Integration
|
|
277
|
+
Fjell-cache works with any storage backend through the ClientApi interface:
|
|
278
|
+
- SQL databases (PostgreSQL, MySQL, SQLite)
|
|
279
|
+
- NoSQL databases (MongoDB, DynamoDB, Redis)
|
|
280
|
+
- REST APIs and GraphQL endpoints
|
|
281
|
+
- In-memory stores and mock data
|
|
282
|
+
- File systems and cloud storage
|
|
283
|
+
- Custom data sources
|
|
284
|
+
|
|
285
|
+
### Error Handling and Resilience
|
|
286
|
+
```typescript
|
|
287
|
+
// Cache with proper error handling through the API layer
|
|
288
|
+
const resilientCache = await createCache(api, createCoordinate('user'), registry);
|
|
289
|
+
|
|
290
|
+
// Error handling in operations
|
|
291
|
+
try {
|
|
292
|
+
const [, user] = await resilientCache.operations.get(userKey);
|
|
293
|
+
return user;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
// Handle cache errors gracefully
|
|
296
|
+
console.error('Cache operation failed:', error);
|
|
297
|
+
// Fallback to direct API call
|
|
298
|
+
return await api.get(userKey);
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
This provides the foundation for building scalable, maintainable applications with intelligent caching using fjell-cache.
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import ReactDOM from 'react-dom/client'
|
|
3
|
+
import { DocsApp } from '@fjell/docs-template'
|
|
4
|
+
import '@fjell/docs-template/dist/index.css'
|
|
5
|
+
import config from '../docs.config'
|
|
6
|
+
import './index.css'
|
|
7
|
+
|
|
8
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
9
|
+
<React.StrictMode>
|
|
10
|
+
<DocsApp config={config} />
|
|
11
|
+
</React.StrictMode>
|
|
12
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"composite": true,
|
|
4
|
+
"skipLibCheck": true,
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"allowSyntheticDefaultImports": true,
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noEmit": true
|
|
10
|
+
},
|
|
11
|
+
"include": [
|
|
12
|
+
"vite.config.ts",
|
|
13
|
+
"docs.config.ts"
|
|
14
|
+
]
|
|
15
|
+
}
|
package/examples/README.md
CHANGED
|
@@ -6,11 +6,11 @@ This directory contains examples demonstrating how to use fjell-cache for cachin
|
|
|
6
6
|
|
|
7
7
|
### 1. `basic-cache-example.ts` ⭐ **Start Here!**
|
|
8
8
|
**Perfect for beginners!** Demonstrates the fundamental way to use fjell-cache for data caching:
|
|
9
|
-
- **Basic cache operations** - Create caches
|
|
9
|
+
- **Basic cache operations** - Create caches with coordinates and registries, use operations API
|
|
10
10
|
- **Simple data models** - User and Task entities with mock storage
|
|
11
|
-
- **
|
|
11
|
+
- **Cache-as-Instance architecture** - Caches extend Instance from fjell-registry
|
|
12
12
|
- **Cache hits vs misses** - Understand cache behavior and performance benefits
|
|
13
|
-
- **Cache management** - Updates, deletions, and data consistency
|
|
13
|
+
- **Cache management** - Updates, deletions, and data consistency through operations
|
|
14
14
|
|
|
15
15
|
Great for understanding the fundamentals of fjell-cache data management.
|
|
16
16
|
|
|
@@ -39,7 +39,8 @@ Perfect for understanding the underlying cache mechanisms and advanced use cases
|
|
|
39
39
|
### Basic Caching Operations (basic-cache-example.ts)
|
|
40
40
|
```typescript
|
|
41
41
|
// Import fjell-cache functionality
|
|
42
|
-
import { createCache
|
|
42
|
+
import { createCache } from '@fjell/cache';
|
|
43
|
+
import { createCoordinate, createRegistry } from '@fjell/registry';
|
|
43
44
|
import { ClientApi } from '@fjell/client-api';
|
|
44
45
|
|
|
45
46
|
// Create a registry for cache management
|
|
@@ -47,17 +48,15 @@ const registry = createRegistry();
|
|
|
47
48
|
|
|
48
49
|
// Create a cache instance with API integration
|
|
49
50
|
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);
|
|
51
|
+
const userCache = await createCache(userApi, createCoordinate('user'), registry);
|
|
54
52
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
const [,
|
|
58
|
-
const [,
|
|
53
|
+
// Cache is now an instance - no need for separate createInstance call
|
|
54
|
+
// Perform cache operations through the operations API
|
|
55
|
+
const [cacheMap, allUsers] = await userCache.operations.all();
|
|
56
|
+
const [, cachedUser] = await userCache.operations.get(userKey);
|
|
57
|
+
const [, retrievedUser] = await userCache.operations.retrieve(userKey); // Cache hit!
|
|
59
58
|
|
|
60
|
-
await
|
|
59
|
+
await userCache.operations.set(userKey, updatedUser);
|
|
61
60
|
```
|
|
62
61
|
|
|
63
62
|
### Advanced Aggregation (aggregator-example.ts)
|
|
@@ -78,8 +77,8 @@ if (populatedOrder.aggs?.customer?.item) {
|
|
|
78
77
|
console.log(`Order for: ${customer.name} (${customer.email})`);
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
//
|
|
82
|
-
const
|
|
80
|
+
// Aggregator is now itself an instance - access operations directly
|
|
81
|
+
const [, orders] = await orderAggregator.all();
|
|
83
82
|
```
|
|
84
83
|
|
|
85
84
|
### Direct Cache Management (cache-map-example.ts)
|
|
@@ -262,18 +261,16 @@ const populatedTicket = await ticketAggregator.populate(ticket);
|
|
|
262
261
|
|
|
263
262
|
### Performance Optimization
|
|
264
263
|
```typescript
|
|
265
|
-
// Cache with
|
|
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
|
-
});
|
|
264
|
+
// Cache with coordinate and registry
|
|
265
|
+
const cache = await createCache(api, createCoordinate('product'), registry);
|
|
273
266
|
|
|
274
267
|
// Bulk operations for efficiency
|
|
275
|
-
const [cacheMap, allProducts] = await cache.all();
|
|
268
|
+
const [cacheMap, allProducts] = await cache.operations.all();
|
|
276
269
|
const productMap = new Map(allProducts.map(p => [p.id, p]));
|
|
270
|
+
|
|
271
|
+
// Access cache properties for optimization
|
|
272
|
+
console.log(`Cache coordinate: ${cache.coordinate.kta.join(', ')}`);
|
|
273
|
+
console.log(`Cached items: ${cache.cacheMap.size()}`);
|
|
277
274
|
```
|
|
278
275
|
|
|
279
276
|
### Storage Integration
|
|
@@ -287,21 +284,19 @@ Fjell-cache works with any storage backend through the ClientApi interface:
|
|
|
287
284
|
|
|
288
285
|
### Error Handling and Resilience
|
|
289
286
|
```typescript
|
|
290
|
-
// Cache with error handling
|
|
291
|
-
const resilientCache = await createCache(api, 'user',
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
});
|
|
287
|
+
// Cache with proper error handling through the API layer
|
|
288
|
+
const resilientCache = await createCache(api, createCoordinate('user'), registry);
|
|
289
|
+
|
|
290
|
+
// Error handling in operations
|
|
291
|
+
try {
|
|
292
|
+
const [, user] = await resilientCache.operations.get(userKey);
|
|
293
|
+
return user;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
// Handle cache errors gracefully
|
|
296
|
+
console.error('Cache operation failed:', error);
|
|
297
|
+
// Fallback to direct API call
|
|
298
|
+
return await api.get(userKey);
|
|
299
|
+
}
|
|
305
300
|
```
|
|
306
301
|
|
|
307
302
|
This provides the foundation for building scalable, maintainable applications with intelligent caching using fjell-cache.
|
|
@@ -128,6 +128,7 @@ const createSupportTicket = (
|
|
|
128
128
|
priority: 'low' | 'medium' | 'high' | 'urgent',
|
|
129
129
|
status: 'open' | 'in-progress' | 'resolved' | 'closed',
|
|
130
130
|
description: string,
|
|
131
|
+
// eslint-disable-next-line max-params
|
|
131
132
|
orderId?: string): SupportTicket => {
|
|
132
133
|
const ticket: SupportTicket = {
|
|
133
134
|
id, customerId, subject, priority, status, description, orderId,
|
|
@@ -181,10 +182,10 @@ export const runAggregatorExample = async (): Promise<void> => {
|
|
|
181
182
|
const productApi = createMockApi(mockProducts) as ClientApi<Product, 'product'>;
|
|
182
183
|
const ticketApi = createMockApi(mockTickets) as ClientApi<SupportTicket, 'ticket'>;
|
|
183
184
|
|
|
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');
|
|
185
|
+
const customerCache = await createCache(customerApi, createCoordinate('customer'), registry);
|
|
186
|
+
const orderCache = await createCache(orderApi, createCoordinate('order'), registry);
|
|
187
|
+
const productCache = await createCache(productApi, createCoordinate('product'), registry);
|
|
188
|
+
const ticketCache = await createCache(ticketApi, createCoordinate('ticket'), registry);
|
|
188
189
|
|
|
189
190
|
console.log('✅ Created individual caches for each entity type');
|
|
190
191
|
|
|
@@ -209,19 +210,13 @@ export const runAggregatorExample = async (): Promise<void> => {
|
|
|
209
210
|
events: {}
|
|
210
211
|
});
|
|
211
212
|
|
|
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');
|
|
213
|
+
console.log('✅ Created aggregated caches with relationship mappings (aggregators are now instances)\n');
|
|
219
214
|
|
|
220
215
|
// Step 4: Basic aggregation - Fetch orders with customer data
|
|
221
216
|
console.log('Step 4: Order aggregation with customer data');
|
|
222
217
|
console.log('--------------------------------------------');
|
|
223
218
|
|
|
224
|
-
const [, orders] = await
|
|
219
|
+
const [, orders] = await orderAggregator.all();
|
|
225
220
|
console.log(`📋 Fetched ${orders.length} orders`);
|
|
226
221
|
|
|
227
222
|
for (const order of orders) {
|
|
@@ -243,7 +238,7 @@ export const runAggregatorExample = async (): Promise<void> => {
|
|
|
243
238
|
console.log('\n\nStep 5: Support ticket aggregation with multiple references');
|
|
244
239
|
console.log('----------------------------------------------------------');
|
|
245
240
|
|
|
246
|
-
const [, tickets] = await
|
|
241
|
+
const [, tickets] = await ticketAggregator.all();
|
|
247
242
|
console.log(`🎫 Fetched ${tickets.length} support tickets`);
|
|
248
243
|
|
|
249
244
|
for (const ticket of tickets) {
|
|
@@ -275,7 +270,7 @@ export const runAggregatorExample = async (): Promise<void> => {
|
|
|
275
270
|
console.log('\n\nStep 6: Individual item retrieval with aggregation');
|
|
276
271
|
console.log('-------------------------------------------------');
|
|
277
272
|
|
|
278
|
-
const [, specificOrder] = await
|
|
273
|
+
const [, specificOrder] = await orderAggregator.get(order1.key);
|
|
279
274
|
if (specificOrder) {
|
|
280
275
|
console.log(`🔍 Retrieved specific order: ${specificOrder.id}`);
|
|
281
276
|
|
|
@@ -146,12 +146,9 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
146
146
|
const taskApi = createTaskApi() as ClientApi<Task, 'task'>;
|
|
147
147
|
console.log('✅ Created mock APIs for users and tasks');
|
|
148
148
|
|
|
149
|
-
const userCache = await createCache(userApi, 'user');
|
|
150
|
-
const taskCache = await createCache(taskApi, 'task');
|
|
151
|
-
console.log('✅ Created cache instances');
|
|
152
|
-
|
|
153
|
-
const userInstance = createInstance(registry, createCoordinate('user'), userCache);
|
|
154
|
-
const taskInstance = createInstance(registry, createCoordinate('task'), taskCache);
|
|
149
|
+
const userCache = await createCache(userApi, createCoordinate('user'), registry);
|
|
150
|
+
const taskCache = await createCache(taskApi, createCoordinate('task'), registry);
|
|
151
|
+
console.log('✅ Created cache instances (which are now also instances)');
|
|
155
152
|
console.log('✅ Created cache model instances\n');
|
|
156
153
|
|
|
157
154
|
// Step 2: Create some test data
|
|
@@ -170,21 +167,21 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
170
167
|
console.log('Step 3: Cache operations - Fetching all items');
|
|
171
168
|
console.log('----------------------------------------------');
|
|
172
169
|
|
|
173
|
-
const [, allUsers] = await
|
|
174
|
-
console.log(`📋 Cached ${allUsers.length} users:`, allUsers.map(u => u.name));
|
|
170
|
+
const [, allUsers] = await userCache.operations.all();
|
|
171
|
+
console.log(`📋 Cached ${allUsers.length} users:`, allUsers.map((u: User) => u.name));
|
|
175
172
|
|
|
176
|
-
const [, allTasks] = await
|
|
177
|
-
console.log(`📋 Cached ${allTasks.length} tasks:`, allTasks.map(t => t.title));
|
|
173
|
+
const [, allTasks] = await taskCache.operations.all();
|
|
174
|
+
console.log(`📋 Cached ${allTasks.length} tasks:`, allTasks.map((t: Task) => t.title));
|
|
178
175
|
console.log('');
|
|
179
176
|
|
|
180
177
|
// Step 4: Individual item retrieval from cache
|
|
181
178
|
console.log('Step 4: Individual item retrieval');
|
|
182
179
|
console.log('---------------------------------');
|
|
183
180
|
|
|
184
|
-
const [, cachedUser1] = await
|
|
181
|
+
const [, cachedUser1] = await userCache.operations.get(user1.key);
|
|
185
182
|
console.log(`👤 Retrieved from cache: ${cachedUser1?.name} (${cachedUser1?.email})`);
|
|
186
183
|
|
|
187
|
-
const [, cachedTask1] = await
|
|
184
|
+
const [, cachedTask1] = await taskCache.operations.get(task1.key);
|
|
188
185
|
console.log(`📝 Retrieved from cache: ${cachedTask1?.title} - Status: ${cachedTask1?.status}`);
|
|
189
186
|
console.log('');
|
|
190
187
|
|
|
@@ -194,14 +191,14 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
194
191
|
|
|
195
192
|
// This should hit the cache (no API call)
|
|
196
193
|
console.log('🎯 Second retrieval (should hit cache):');
|
|
197
|
-
const [, cachedUser1Again] = await
|
|
194
|
+
const [, cachedUser1Again] = await userCache.operations.retrieve(user1.key);
|
|
198
195
|
console.log(`👤 Retrieved: ${cachedUser1Again?.name} (cache hit)`);
|
|
199
196
|
|
|
200
197
|
// Create a new user and demonstrate cache miss
|
|
201
198
|
const user3 = createTestUser('user-3', 'Charlie Brown', 'charlie@example.com', 'guest');
|
|
202
199
|
|
|
203
200
|
console.log('🎯 New item retrieval (cache miss, will fetch from API):');
|
|
204
|
-
const [, cachedUser3] = await
|
|
201
|
+
const [, cachedUser3] = await userCache.operations.get(user3.key);
|
|
205
202
|
console.log(`👤 Retrieved: ${cachedUser3?.name} (fetched from API and cached)`);
|
|
206
203
|
console.log('');
|
|
207
204
|
|
|
@@ -213,7 +210,7 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
213
210
|
mockTaskStorage.set(task2.id, updatedTask2);
|
|
214
211
|
|
|
215
212
|
// Update cache with new version
|
|
216
|
-
await
|
|
213
|
+
await taskCache.operations.set(updatedTask2.key, updatedTask2);
|
|
217
214
|
console.log(`🔄 Updated task in cache: ${updatedTask2.title} - New status: ${updatedTask2.status}`);
|
|
218
215
|
console.log('');
|
|
219
216
|
|
|
@@ -221,10 +218,10 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
221
218
|
console.log('Step 7: Query operations');
|
|
222
219
|
console.log('-----------------------');
|
|
223
220
|
|
|
224
|
-
const [, foundTasks] = await
|
|
221
|
+
const [, foundTasks] = await taskCache.operations.find('all');
|
|
225
222
|
console.log(`🔍 Found ${foundTasks.length} tasks through cache query`);
|
|
226
223
|
|
|
227
|
-
const [, oneTask] = await
|
|
224
|
+
const [, oneTask] = await taskCache.operations.one();
|
|
228
225
|
console.log(`📝 Retrieved one task: ${oneTask?.title}`);
|
|
229
226
|
console.log('');
|
|
230
227
|
|
|
@@ -235,8 +232,8 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
235
232
|
console.log('📊 Cache Statistics:');
|
|
236
233
|
console.log(` 👥 Users in cache: ${allUsers.length}`);
|
|
237
234
|
console.log(` 📝 Tasks in cache: ${allTasks.length}`);
|
|
238
|
-
console.log(` 🎯 User cache coordinate: ${
|
|
239
|
-
console.log(` 🎯 Task cache coordinate: ${
|
|
235
|
+
console.log(` 🎯 User cache coordinate: ${userCache.coordinate.kta[0]}`);
|
|
236
|
+
console.log(` 🎯 Task cache coordinate: ${taskCache.coordinate.kta[0]}`);
|
|
240
237
|
console.log('');
|
|
241
238
|
|
|
242
239
|
// Step 9: Cleanup demonstration
|
|
@@ -247,11 +244,11 @@ export const runBasicCacheExample = async (): Promise<void> => {
|
|
|
247
244
|
console.log('🗑️ Removed user from storage');
|
|
248
245
|
|
|
249
246
|
// Cache still has the old data until next fetch
|
|
250
|
-
const [, stillCachedUser3] = await
|
|
247
|
+
const [, stillCachedUser3] = await userCache.operations.retrieve(user3.key);
|
|
251
248
|
console.log(`🎯 Cache still contains removed user: ${stillCachedUser3?.name || 'null'}`);
|
|
252
249
|
|
|
253
250
|
// Fresh fetch will update cache
|
|
254
|
-
const [, freshAllUsers] = await
|
|
251
|
+
const [, freshAllUsers] = await userCache.operations.all();
|
|
255
252
|
console.log(`📋 Fresh fetch shows ${freshAllUsers.length} users (cache updated)`);
|
|
256
253
|
console.log('');
|
|
257
254
|
|