@object-ui/data-objectstack 0.3.1 → 2.0.0
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 +317 -1
- package/dist/index.cjs +814 -39
- package/dist/index.d.cts +337 -8
- package/dist/index.d.ts +337 -8
- package/dist/index.js +804 -38
- package/package.json +5 -5
- package/src/cache/MetadataCache.test.ts +426 -0
- package/src/cache/MetadataCache.ts +229 -0
- package/src/connection.test.ts +141 -0
- package/src/errors.test.ts +426 -0
- package/src/errors.ts +275 -0
- package/src/index.ts +679 -48
- package/src/upload.test.ts +112 -0
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ npm install @object-ui/data-objectstack @objectstack/client
|
|
|
16
16
|
|
|
17
17
|
## Usage
|
|
18
18
|
|
|
19
|
+
### Basic Setup
|
|
20
|
+
|
|
19
21
|
```typescript
|
|
20
22
|
import { createObjectStackAdapter } from '@object-ui/data-objectstack';
|
|
21
23
|
import { SchemaRenderer } from '@object-ui/react';
|
|
@@ -37,9 +39,323 @@ function App() {
|
|
|
37
39
|
}
|
|
38
40
|
```
|
|
39
41
|
|
|
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
|
+
// Configure auto-reconnect
|
|
54
|
+
autoReconnect: true, // Enable auto-reconnect (default: true)
|
|
55
|
+
maxReconnectAttempts: 5, // Max reconnection attempts (default: 3)
|
|
56
|
+
reconnectDelay: 2000 // Initial delay between reconnects in ms (default: 1000)
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
40
60
|
## Features
|
|
41
61
|
|
|
42
62
|
- ✅ **CRUD Operations**: Implements `find`, `findOne`, `create`, `update`, `delete`.
|
|
63
|
+
- ✅ **Metadata Caching**: Automatic LRU caching of schema metadata with TTL expiration.
|
|
43
64
|
- ✅ **Metadata Fetching**: Implements `getObjectSchema` to power auto-generated forms and grids.
|
|
44
65
|
- ✅ **Query Translation**: Converts Object UI's OData-like query parameters to ObjectStack's native query format.
|
|
45
|
-
- ✅ **Bulk Operations**: Supports batch create/update/delete.
|
|
66
|
+
- ✅ **Bulk Operations**: Supports optimized batch create/update/delete with detailed error reporting.
|
|
67
|
+
- ✅ **Error Handling**: Comprehensive error hierarchy with unique error codes and debugging details.
|
|
68
|
+
- ✅ **Connection Monitoring**: Real-time connection state tracking with event listeners.
|
|
69
|
+
- ✅ **Auto-Reconnect**: Automatic reconnection with exponential backoff on connection failures.
|
|
70
|
+
- ✅ **Batch Progress**: Progress events for tracking bulk operation status.
|
|
71
|
+
|
|
72
|
+
## Metadata Caching
|
|
73
|
+
|
|
74
|
+
The adapter includes built-in metadata caching to improve performance when fetching schemas:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Get cache statistics
|
|
78
|
+
const stats = dataSource.getCacheStats();
|
|
79
|
+
console.log(`Cache hit rate: ${stats.hitRate * 100}%`);
|
|
80
|
+
console.log(`Cache size: ${stats.size}/${stats.maxSize}`);
|
|
81
|
+
|
|
82
|
+
// Manually invalidate cache entries
|
|
83
|
+
dataSource.invalidateCache('users'); // Invalidate specific schema
|
|
84
|
+
dataSource.invalidateCache(); // Invalidate all cached schemas
|
|
85
|
+
|
|
86
|
+
// Clear cache and statistics
|
|
87
|
+
dataSource.clearCache();
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Cache Configuration
|
|
91
|
+
|
|
92
|
+
- **LRU Eviction**: Automatically evicts least recently used entries when cache is full
|
|
93
|
+
- **TTL Expiration**: Entries expire after the configured time-to-live from creation (default: 5 minutes)
|
|
94
|
+
- Note: TTL is fixed from creation time, not sliding based on access
|
|
95
|
+
- **Memory Limits**: Configurable maximum cache size (default: 100 entries)
|
|
96
|
+
- **Concurrent Access**: Handles async operations safely. Note that concurrent requests for the same uncached key may result in multiple fetcher calls.
|
|
97
|
+
|
|
98
|
+
## Connection State Monitoring
|
|
99
|
+
|
|
100
|
+
The adapter provides real-time connection state monitoring with automatic reconnection:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
// Monitor connection state changes
|
|
104
|
+
const unsubscribe = dataSource.onConnectionStateChange((event) => {
|
|
105
|
+
console.log('Connection state:', event.state);
|
|
106
|
+
console.log('Timestamp:', new Date(event.timestamp));
|
|
107
|
+
|
|
108
|
+
if (event.error) {
|
|
109
|
+
console.error('Connection error:', event.error);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// Check current connection state
|
|
114
|
+
console.log(dataSource.getConnectionState()); // 'disconnected' | 'connecting' | 'connected' | 'reconnecting' | 'error'
|
|
115
|
+
|
|
116
|
+
// Check if connected
|
|
117
|
+
if (dataSource.isConnected()) {
|
|
118
|
+
console.log('Adapter is connected');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Unsubscribe from events when done
|
|
122
|
+
unsubscribe();
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Connection States
|
|
126
|
+
|
|
127
|
+
- `disconnected` - Not connected to server
|
|
128
|
+
- `connecting` - Attempting initial connection
|
|
129
|
+
- `connected` - Successfully connected
|
|
130
|
+
- `reconnecting` - Attempting to reconnect after failure
|
|
131
|
+
- `error` - Connection failed (check event.error for details)
|
|
132
|
+
|
|
133
|
+
### Auto-Reconnect
|
|
134
|
+
|
|
135
|
+
The adapter automatically attempts to reconnect on connection failures:
|
|
136
|
+
|
|
137
|
+
- **Exponential Backoff**: Delay increases with each attempt (delay × 2^(attempts-1))
|
|
138
|
+
- **Configurable Attempts**: Set `maxReconnectAttempts` (default: 3)
|
|
139
|
+
- **Configurable Delay**: Set `reconnectDelay` for initial delay (default: 1000ms)
|
|
140
|
+
- **Automatic**: Enabled by default, disable with `autoReconnect: false`
|
|
141
|
+
|
|
142
|
+
## Batch Operation Progress
|
|
143
|
+
|
|
144
|
+
Track progress of bulk operations in real-time:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Monitor batch operation progress
|
|
148
|
+
const unsubscribe = dataSource.onBatchProgress((event) => {
|
|
149
|
+
console.log(`${event.operation}: ${event.percentage.toFixed(1)}%`);
|
|
150
|
+
console.log(`Completed: ${event.completed}/${event.total}`);
|
|
151
|
+
console.log(`Failed: ${event.failed}`);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Perform bulk operation
|
|
155
|
+
const users = await dataSource.bulk('users', 'create', largeDataset);
|
|
156
|
+
|
|
157
|
+
// Unsubscribe when done
|
|
158
|
+
unsubscribe();
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Progress Event Properties
|
|
162
|
+
|
|
163
|
+
- `operation` - Operation type ('create' | 'update' | 'delete')
|
|
164
|
+
- `total` - Total number of items
|
|
165
|
+
- `completed` - Number of successfully completed items
|
|
166
|
+
- `failed` - Number of failed items
|
|
167
|
+
- `percentage` - Completion percentage (0-100)
|
|
168
|
+
|
|
169
|
+
## Error Handling
|
|
170
|
+
|
|
171
|
+
The adapter provides a comprehensive error hierarchy for better error handling:
|
|
172
|
+
|
|
173
|
+
### Error Types
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import {
|
|
177
|
+
ObjectStackError, // Base error class
|
|
178
|
+
MetadataNotFoundError, // Schema/metadata not found (404)
|
|
179
|
+
BulkOperationError, // Bulk operation failures with partial results
|
|
180
|
+
ConnectionError, // Network/connection errors (503/504)
|
|
181
|
+
AuthenticationError, // Authentication failures (401/403)
|
|
182
|
+
ValidationError, // Data validation errors (400)
|
|
183
|
+
} from '@object-ui/data-objectstack';
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Error Handling Example
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
try {
|
|
190
|
+
const schema = await dataSource.getObjectSchema('users');
|
|
191
|
+
} catch (error) {
|
|
192
|
+
if (error instanceof MetadataNotFoundError) {
|
|
193
|
+
console.error(`Schema not found: ${error.details.objectName}`);
|
|
194
|
+
} else if (error instanceof ConnectionError) {
|
|
195
|
+
console.error(`Connection failed to: ${error.url}`);
|
|
196
|
+
} else if (error instanceof AuthenticationError) {
|
|
197
|
+
console.error('Authentication required');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// All errors have consistent structure
|
|
201
|
+
console.error({
|
|
202
|
+
code: error.code,
|
|
203
|
+
message: error.message,
|
|
204
|
+
statusCode: error.statusCode,
|
|
205
|
+
details: error.details
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Bulk Operation Errors
|
|
211
|
+
|
|
212
|
+
Bulk operations provide detailed error reporting with partial success information:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
try {
|
|
216
|
+
await dataSource.bulk('users', 'update', records);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
if (error instanceof BulkOperationError) {
|
|
219
|
+
const summary = error.getSummary();
|
|
220
|
+
console.log(`${summary.successful} succeeded, ${summary.failed} failed`);
|
|
221
|
+
console.log(`Failure rate: ${summary.failureRate * 100}%`);
|
|
222
|
+
|
|
223
|
+
// Inspect individual failures
|
|
224
|
+
summary.errors.forEach(({ index, error }) => {
|
|
225
|
+
console.error(`Record ${index} failed:`, error);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Error Codes
|
|
232
|
+
|
|
233
|
+
All errors include unique error codes for programmatic handling:
|
|
234
|
+
|
|
235
|
+
- `METADATA_NOT_FOUND` - Schema/metadata not found
|
|
236
|
+
- `BULK_OPERATION_ERROR` - Bulk operation failure
|
|
237
|
+
- `CONNECTION_ERROR` - Connection/network error
|
|
238
|
+
- `AUTHENTICATION_ERROR` - Authentication failure
|
|
239
|
+
- `VALIDATION_ERROR` - Data validation error
|
|
240
|
+
- `UNSUPPORTED_OPERATION` - Unsupported operation
|
|
241
|
+
- `NOT_FOUND` - Resource not found
|
|
242
|
+
- `UNKNOWN_ERROR` - Unknown error
|
|
243
|
+
|
|
244
|
+
## Batch Operations
|
|
245
|
+
|
|
246
|
+
The adapter supports optimized batch operations with automatic fallback:
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
// Batch create
|
|
250
|
+
const newUsers = await dataSource.bulk('users', 'create', [
|
|
251
|
+
{ name: 'Alice', email: 'alice@example.com' },
|
|
252
|
+
{ name: 'Bob', email: 'bob@example.com' },
|
|
253
|
+
]);
|
|
254
|
+
|
|
255
|
+
// Batch update (uses updateMany if available, falls back to individual updates)
|
|
256
|
+
const updated = await dataSource.bulk('users', 'update', [
|
|
257
|
+
{ id: '1', name: 'Alice Smith' },
|
|
258
|
+
{ id: '2', name: 'Bob Jones' },
|
|
259
|
+
]);
|
|
260
|
+
|
|
261
|
+
// Batch delete
|
|
262
|
+
await dataSource.bulk('users', 'delete', [
|
|
263
|
+
{ id: '1' },
|
|
264
|
+
{ id: '2' },
|
|
265
|
+
]);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Performance Optimizations
|
|
269
|
+
|
|
270
|
+
- Automatically uses `createMany`, `updateMany`, `deleteMany` when available
|
|
271
|
+
- Falls back to individual operations with detailed error tracking
|
|
272
|
+
- Provides partial success reporting for resilient error handling
|
|
273
|
+
- Atomic operations where supported by the backend
|
|
274
|
+
|
|
275
|
+
## API Reference
|
|
276
|
+
|
|
277
|
+
### ObjectStackAdapter
|
|
278
|
+
|
|
279
|
+
#### Constructor
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
new ObjectStackAdapter(config: {
|
|
283
|
+
baseUrl: string;
|
|
284
|
+
token?: string;
|
|
285
|
+
fetch?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
286
|
+
cache?: {
|
|
287
|
+
maxSize?: number;
|
|
288
|
+
ttl?: number;
|
|
289
|
+
};
|
|
290
|
+
autoReconnect?: boolean;
|
|
291
|
+
maxReconnectAttempts?: number;
|
|
292
|
+
reconnectDelay?: number;
|
|
293
|
+
})
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
#### Methods
|
|
297
|
+
|
|
298
|
+
- `connect()` - Establish connection to ObjectStack server
|
|
299
|
+
- `find(resource, params?)` - Query multiple records
|
|
300
|
+
- `findOne(resource, id, params?)` - Get a single record by ID
|
|
301
|
+
- `create(resource, data)` - Create a new record
|
|
302
|
+
- `update(resource, id, data)` - Update an existing record
|
|
303
|
+
- `delete(resource, id)` - Delete a record
|
|
304
|
+
- `bulk(resource, operation, data)` - Batch operations (create/update/delete)
|
|
305
|
+
- `getObjectSchema(objectName)` - Get schema metadata (cached)
|
|
306
|
+
- `getCacheStats()` - Get cache statistics
|
|
307
|
+
- `invalidateCache(key?)` - Invalidate cache entries
|
|
308
|
+
- `clearCache()` - Clear all cache entries
|
|
309
|
+
- `getClient()` - Access underlying ObjectStack client
|
|
310
|
+
- `getConnectionState()` - Get current connection state
|
|
311
|
+
- `isConnected()` - Check if adapter is connected
|
|
312
|
+
- `onConnectionStateChange(listener)` - Subscribe to connection state changes (returns unsubscribe function)
|
|
313
|
+
- `onBatchProgress(listener)` - Subscribe to batch operation progress (returns unsubscribe function)
|
|
314
|
+
|
|
315
|
+
## Best Practices
|
|
316
|
+
|
|
317
|
+
1. **Enable Caching**: Use default cache settings for optimal performance
|
|
318
|
+
2. **Handle Errors**: Use typed error handling for better user experience
|
|
319
|
+
3. **Batch Operations**: Use bulk methods for large datasets
|
|
320
|
+
4. **Monitor Cache**: Check cache hit rates in production
|
|
321
|
+
5. **Invalidate Wisely**: Clear cache after schema changes
|
|
322
|
+
6. **Connection Monitoring**: Subscribe to connection state changes for better UX
|
|
323
|
+
7. **Auto-Reconnect**: Use default auto-reconnect settings for resilient applications
|
|
324
|
+
8. **Batch Progress**: Monitor progress for long-running bulk operations
|
|
325
|
+
|
|
326
|
+
## Troubleshooting
|
|
327
|
+
|
|
328
|
+
### Common Issues
|
|
329
|
+
|
|
330
|
+
#### Schema Not Found
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// Error: MetadataNotFoundError
|
|
334
|
+
// Solution: Verify object name and ensure schema exists on server
|
|
335
|
+
const schema = await dataSource.getObjectSchema('correct_object_name');
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### Connection Errors
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
// Error: ConnectionError
|
|
342
|
+
// Solution: Check baseUrl and network connectivity
|
|
343
|
+
const dataSource = createObjectStackAdapter({
|
|
344
|
+
baseUrl: 'https://correct-url.example.com',
|
|
345
|
+
token: 'valid-token'
|
|
346
|
+
});
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Cache Issues
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// Clear cache if stale data is being returned
|
|
353
|
+
dataSource.clearCache();
|
|
354
|
+
|
|
355
|
+
// Or invalidate specific entries
|
|
356
|
+
dataSource.invalidateCache('users');
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
## License
|
|
360
|
+
|
|
361
|
+
MIT
|