Skip to content

Commit 1c4a536

Browse files
authored
Merge pull request #277 from objectstack-ai/copilot/implement-metadata-caching
2 parents bac0a4d + de7fe20 commit 1c4a536

File tree

7 files changed

+1799
-37
lines changed

7 files changed

+1799
-37
lines changed

packages/data-objectstack/README.md

Lines changed: 229 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ npm install @object-ui/data-objectstack @objectstack/client
1616

1717
## Usage
1818

19+
### Basic Setup
20+
1921
```typescript
2022
import { createObjectStackAdapter } from '@object-ui/data-objectstack';
2123
import { SchemaRenderer } from '@object-ui/react';
@@ -37,9 +39,235 @@ function App() {
3739
}
3840
```
3941

42+
### Advanced Configuration
43+
44+
```typescript
45+
const dataSource = createObjectStackAdapter({
46+
baseUrl: 'https://api.example.com',
47+
token: 'your-api-token',
48+
// Configure metadata cache
49+
cache: {
50+
maxSize: 100, // Maximum number of cached schemas (default: 100)
51+
ttl: 5 * 60 * 1000 // Time to live in ms (default: 5 minutes)
52+
}
53+
});
54+
```
55+
4056
## Features
4157

4258
-**CRUD Operations**: Implements `find`, `findOne`, `create`, `update`, `delete`.
59+
-**Metadata Caching**: Automatic LRU caching of schema metadata with TTL expiration.
4360
-**Metadata Fetching**: Implements `getObjectSchema` to power auto-generated forms and grids.
4461
-**Query Translation**: Converts Object UI's OData-like query parameters to ObjectStack's native query format.
45-
-**Bulk Operations**: Supports batch create/update/delete.
62+
-**Bulk Operations**: Supports optimized batch create/update/delete with detailed error reporting.
63+
-**Error Handling**: Comprehensive error hierarchy with unique error codes and debugging details.
64+
65+
## Metadata Caching
66+
67+
The adapter includes built-in metadata caching to improve performance when fetching schemas:
68+
69+
```typescript
70+
// Get cache statistics
71+
const stats = dataSource.getCacheStats();
72+
console.log(`Cache hit rate: ${stats.hitRate * 100}%`);
73+
console.log(`Cache size: ${stats.size}/${stats.maxSize}`);
74+
75+
// Manually invalidate cache entries
76+
dataSource.invalidateCache('users'); // Invalidate specific schema
77+
dataSource.invalidateCache(); // Invalidate all cached schemas
78+
79+
// Clear cache and statistics
80+
dataSource.clearCache();
81+
```
82+
83+
### Cache Configuration
84+
85+
- **LRU Eviction**: Automatically evicts least recently used entries when cache is full
86+
- **TTL Expiration**: Entries expire after the configured time-to-live from creation (default: 5 minutes)
87+
- Note: TTL is fixed from creation time, not sliding based on access
88+
- **Memory Limits**: Configurable maximum cache size (default: 100 entries)
89+
- **Concurrent Access**: Handles async operations safely. Note that concurrent requests for the same uncached key may result in multiple fetcher calls.
90+
91+
## Error Handling
92+
93+
The adapter provides a comprehensive error hierarchy for better error handling:
94+
95+
### Error Types
96+
97+
```typescript
98+
import {
99+
ObjectStackError, // Base error class
100+
MetadataNotFoundError, // Schema/metadata not found (404)
101+
BulkOperationError, // Bulk operation failures with partial results
102+
ConnectionError, // Network/connection errors (503/504)
103+
AuthenticationError, // Authentication failures (401/403)
104+
ValidationError, // Data validation errors (400)
105+
} from '@object-ui/data-objectstack';
106+
```
107+
108+
### Error Handling Example
109+
110+
```typescript
111+
try {
112+
const schema = await dataSource.getObjectSchema('users');
113+
} catch (error) {
114+
if (error instanceof MetadataNotFoundError) {
115+
console.error(`Schema not found: ${error.details.objectName}`);
116+
} else if (error instanceof ConnectionError) {
117+
console.error(`Connection failed to: ${error.url}`);
118+
} else if (error instanceof AuthenticationError) {
119+
console.error('Authentication required');
120+
}
121+
122+
// All errors have consistent structure
123+
console.error({
124+
code: error.code,
125+
message: error.message,
126+
statusCode: error.statusCode,
127+
details: error.details
128+
});
129+
}
130+
```
131+
132+
### Bulk Operation Errors
133+
134+
Bulk operations provide detailed error reporting with partial success information:
135+
136+
```typescript
137+
try {
138+
await dataSource.bulk('users', 'update', records);
139+
} catch (error) {
140+
if (error instanceof BulkOperationError) {
141+
const summary = error.getSummary();
142+
console.log(`${summary.successful} succeeded, ${summary.failed} failed`);
143+
console.log(`Failure rate: ${summary.failureRate * 100}%`);
144+
145+
// Inspect individual failures
146+
summary.errors.forEach(({ index, error }) => {
147+
console.error(`Record ${index} failed:`, error);
148+
});
149+
}
150+
}
151+
```
152+
153+
### Error Codes
154+
155+
All errors include unique error codes for programmatic handling:
156+
157+
- `METADATA_NOT_FOUND` - Schema/metadata not found
158+
- `BULK_OPERATION_ERROR` - Bulk operation failure
159+
- `CONNECTION_ERROR` - Connection/network error
160+
- `AUTHENTICATION_ERROR` - Authentication failure
161+
- `VALIDATION_ERROR` - Data validation error
162+
- `UNSUPPORTED_OPERATION` - Unsupported operation
163+
- `NOT_FOUND` - Resource not found
164+
- `UNKNOWN_ERROR` - Unknown error
165+
166+
## Batch Operations
167+
168+
The adapter supports optimized batch operations with automatic fallback:
169+
170+
```typescript
171+
// Batch create
172+
const newUsers = await dataSource.bulk('users', 'create', [
173+
{ name: 'Alice', email: 'alice@example.com' },
174+
{ name: 'Bob', email: 'bob@example.com' },
175+
]);
176+
177+
// Batch update (uses updateMany if available, falls back to individual updates)
178+
const updated = await dataSource.bulk('users', 'update', [
179+
{ id: '1', name: 'Alice Smith' },
180+
{ id: '2', name: 'Bob Jones' },
181+
]);
182+
183+
// Batch delete
184+
await dataSource.bulk('users', 'delete', [
185+
{ id: '1' },
186+
{ id: '2' },
187+
]);
188+
```
189+
190+
### Performance Optimizations
191+
192+
- Automatically uses `createMany`, `updateMany`, `deleteMany` when available
193+
- Falls back to individual operations with detailed error tracking
194+
- Provides partial success reporting for resilient error handling
195+
- Atomic operations where supported by the backend
196+
197+
## API Reference
198+
199+
### ObjectStackAdapter
200+
201+
#### Constructor
202+
203+
```typescript
204+
new ObjectStackAdapter(config: {
205+
baseUrl: string;
206+
token?: string;
207+
fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
208+
cache?: {
209+
maxSize?: number;
210+
ttl?: number;
211+
};
212+
})
213+
```
214+
215+
#### Methods
216+
217+
- `connect()` - Establish connection to ObjectStack server
218+
- `find(resource, params?)` - Query multiple records
219+
- `findOne(resource, id, params?)` - Get a single record by ID
220+
- `create(resource, data)` - Create a new record
221+
- `update(resource, id, data)` - Update an existing record
222+
- `delete(resource, id)` - Delete a record
223+
- `bulk(resource, operation, data)` - Batch operations (create/update/delete)
224+
- `getObjectSchema(objectName)` - Get schema metadata (cached)
225+
- `getCacheStats()` - Get cache statistics
226+
- `invalidateCache(key?)` - Invalidate cache entries
227+
- `clearCache()` - Clear all cache entries
228+
- `getClient()` - Access underlying ObjectStack client
229+
230+
## Best Practices
231+
232+
1. **Enable Caching**: Use default cache settings for optimal performance
233+
2. **Handle Errors**: Use typed error handling for better user experience
234+
3. **Batch Operations**: Use bulk methods for large datasets
235+
4. **Monitor Cache**: Check cache hit rates in production
236+
5. **Invalidate Wisely**: Clear cache after schema changes
237+
238+
## Troubleshooting
239+
240+
### Common Issues
241+
242+
#### Schema Not Found
243+
244+
```typescript
245+
// Error: MetadataNotFoundError
246+
// Solution: Verify object name and ensure schema exists on server
247+
const schema = await dataSource.getObjectSchema('correct_object_name');
248+
```
249+
250+
#### Connection Errors
251+
252+
```typescript
253+
// Error: ConnectionError
254+
// Solution: Check baseUrl and network connectivity
255+
const dataSource = createObjectStackAdapter({
256+
baseUrl: 'https://correct-url.example.com',
257+
token: 'valid-token'
258+
});
259+
```
260+
261+
#### Cache Issues
262+
263+
```typescript
264+
// Clear cache if stale data is being returned
265+
dataSource.clearCache();
266+
267+
// Or invalidate specific entries
268+
dataSource.invalidateCache('users');
269+
```
270+
271+
## License
272+
273+
MIT

0 commit comments

Comments
 (0)