Skip to content

Commit 28fdaa2

Browse files
Copilothotlong
andcommitted
Update data-objectstack documentation and add connection tests
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent a5d8170 commit 28fdaa2

File tree

2 files changed

+189
-1
lines changed

2 files changed

+189
-1
lines changed

packages/data-objectstack/README.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ const dataSource = createObjectStackAdapter({
4949
cache: {
5050
maxSize: 100, // Maximum number of cached schemas (default: 100)
5151
ttl: 5 * 60 * 1000 // Time to live in ms (default: 5 minutes)
52-
}
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)
5357
});
5458
```
5559

@@ -61,6 +65,9 @@ const dataSource = createObjectStackAdapter({
6165
-**Query Translation**: Converts Object UI's OData-like query parameters to ObjectStack's native query format.
6266
-**Bulk Operations**: Supports optimized batch create/update/delete with detailed error reporting.
6367
-**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.
6471

6572
## Metadata Caching
6673

@@ -88,6 +95,77 @@ dataSource.clearCache();
8895
- **Memory Limits**: Configurable maximum cache size (default: 100 entries)
8996
- **Concurrent Access**: Handles async operations safely. Note that concurrent requests for the same uncached key may result in multiple fetcher calls.
9097

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+
91169
## Error Handling
92170

93171
The adapter provides a comprehensive error hierarchy for better error handling:
@@ -209,6 +287,9 @@ new ObjectStackAdapter(config: {
209287
maxSize?: number;
210288
ttl?: number;
211289
};
290+
autoReconnect?: boolean;
291+
maxReconnectAttempts?: number;
292+
reconnectDelay?: number;
212293
})
213294
```
214295

@@ -226,6 +307,10 @@ new ObjectStackAdapter(config: {
226307
- `invalidateCache(key?)` - Invalidate cache entries
227308
- `clearCache()` - Clear all cache entries
228309
- `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)
229314

230315
## Best Practices
231316

@@ -234,6 +319,9 @@ new ObjectStackAdapter(config: {
234319
3. **Batch Operations**: Use bulk methods for large datasets
235320
4. **Monitor Cache**: Check cache hit rates in production
236321
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
237325

238326
## Troubleshooting
239327

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/**
2+
* ObjectUI
3+
* Copyright (c) 2024-present ObjectStack Inc.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
import { describe, it, expect, beforeEach, vi } from 'vitest';
10+
import { ObjectStackAdapter, ConnectionState, ConnectionStateEvent, BatchProgressEvent } from './index';
11+
12+
describe('Connection State Monitoring', () => {
13+
let adapter: ObjectStackAdapter;
14+
15+
beforeEach(() => {
16+
adapter = new ObjectStackAdapter({
17+
baseUrl: 'http://localhost:3000',
18+
autoReconnect: false, // Disable auto-reconnect for testing
19+
});
20+
});
21+
22+
it('should initialize with disconnected state', () => {
23+
expect(adapter.getConnectionState()).toBe('disconnected');
24+
expect(adapter.isConnected()).toBe(false);
25+
});
26+
27+
it('should allow subscribing to connection state changes', () => {
28+
const listener = vi.fn();
29+
const unsubscribe = adapter.onConnectionStateChange(listener);
30+
31+
expect(typeof unsubscribe).toBe('function');
32+
expect(listener).not.toHaveBeenCalled();
33+
34+
// Cleanup
35+
unsubscribe();
36+
});
37+
38+
it('should allow subscribing to batch progress events', () => {
39+
const listener = vi.fn();
40+
const unsubscribe = adapter.onBatchProgress(listener);
41+
42+
expect(typeof unsubscribe).toBe('function');
43+
expect(listener).not.toHaveBeenCalled();
44+
45+
// Cleanup
46+
unsubscribe();
47+
});
48+
49+
it('should unsubscribe connection state listener', () => {
50+
const listener = vi.fn();
51+
const unsubscribe = adapter.onConnectionStateChange(listener);
52+
53+
// Unsubscribe
54+
unsubscribe();
55+
56+
// Listener should not be called after unsubscribe
57+
// (We can't easily test this without triggering a connection state change)
58+
});
59+
60+
it('should unsubscribe batch progress listener', () => {
61+
const listener = vi.fn();
62+
const unsubscribe = adapter.onBatchProgress(listener);
63+
64+
// Unsubscribe
65+
unsubscribe();
66+
67+
// Listener should not be called after unsubscribe
68+
});
69+
70+
it('should support auto-reconnect configuration', () => {
71+
const adapterWithReconnect = new ObjectStackAdapter({
72+
baseUrl: 'http://localhost:3000',
73+
autoReconnect: true,
74+
maxReconnectAttempts: 5,
75+
reconnectDelay: 2000,
76+
});
77+
78+
expect(adapterWithReconnect.getConnectionState()).toBe('disconnected');
79+
});
80+
});
81+
82+
describe('Batch Progress Events', () => {
83+
let adapter: ObjectStackAdapter;
84+
85+
beforeEach(() => {
86+
adapter = new ObjectStackAdapter({
87+
baseUrl: 'http://localhost:3000',
88+
});
89+
});
90+
91+
it('should allow subscribing to batch progress', () => {
92+
const listener = vi.fn();
93+
const unsubscribe = adapter.onBatchProgress(listener);
94+
95+
expect(typeof unsubscribe).toBe('function');
96+
97+
// Cleanup
98+
unsubscribe();
99+
});
100+
});

0 commit comments

Comments
 (0)