@rljson/io 0.0.63 → 0.0.65
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.architecture.md +465 -0
- package/README.public.md +635 -3
- package/dist/README.architecture.md +465 -0
- package/dist/README.public.md +635 -3
- package/dist/directional-socket-mock.d.ts +44 -0
- package/dist/example.d.ts +15 -0
- package/dist/index.d.ts +1 -0
- package/dist/io.js +147 -0
- package/dist/io.js.map +1 -1
- package/dist/socket.d.ts +1 -1
- package/dist/src/example.ts +246 -1
- package/package.json +14 -14
package/README.public.md
CHANGED
|
@@ -1,7 +1,639 @@
|
|
|
1
|
-
# @rljson/
|
|
1
|
+
# @rljson/io
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Low-level interface for reading and writing RLJSON data. This package provides a unified abstraction layer for working with RLJSON databases, supporting in-memory storage, remote connections, and multi-source data aggregation.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Quick Start](#quick-start)
|
|
9
|
+
- [Core Concepts](#core-concepts)
|
|
10
|
+
- [API Overview](#api-overview)
|
|
11
|
+
- [Implementations](#implementations)
|
|
12
|
+
- [Usage Examples](#usage-examples)
|
|
13
|
+
- [Testing Utilities](#testing-utilities)
|
|
14
|
+
- [TypeScript Support](#typescript-support)
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @rljson/io
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @rljson/io
|
|
22
|
+
# or
|
|
23
|
+
yarn add @rljson/io
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { IoMem } from '@rljson/io';
|
|
30
|
+
|
|
31
|
+
// Create an in-memory database
|
|
32
|
+
const io = new IoMem();
|
|
33
|
+
await io.init();
|
|
34
|
+
|
|
35
|
+
// Create table schema
|
|
36
|
+
await io.createOrExtendTable({
|
|
37
|
+
tableCfg: {
|
|
38
|
+
key: 'users',
|
|
39
|
+
type: 'components',
|
|
40
|
+
columns: [
|
|
41
|
+
{ key: '_hash', type: 'string', titleShort: 'Hash', titleLong: 'Hash' },
|
|
42
|
+
{ key: 'id', type: 'number', titleShort: 'ID', titleLong: 'User ID' },
|
|
43
|
+
{ key: 'name', type: 'string', titleShort: 'Name', titleLong: 'Name' }
|
|
44
|
+
],
|
|
45
|
+
isHead: false,
|
|
46
|
+
isRoot: false,
|
|
47
|
+
isShared: true
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Write data
|
|
52
|
+
await io.write({
|
|
53
|
+
data: {
|
|
54
|
+
users: {
|
|
55
|
+
_type: 'components',
|
|
56
|
+
_data: [
|
|
57
|
+
{ id: 1, name: 'Alice' },
|
|
58
|
+
{ id: 2, name: 'Bob' }
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Query data
|
|
65
|
+
const result = await io.readRows({
|
|
66
|
+
table: 'users',
|
|
67
|
+
where: { id: 1 }
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Core Concepts
|
|
72
|
+
|
|
73
|
+
### Io Interface
|
|
74
|
+
|
|
75
|
+
The `Io` interface is the core abstraction that defines a standard set of operations for working with RLJSON data:
|
|
76
|
+
|
|
77
|
+
- **Lifecycle Management**: `init()`, `close()`, `isReady()`
|
|
78
|
+
- **Data Operations**: `write()`, `readRows()`, `dump()`
|
|
79
|
+
- **Schema Management**: `createOrExtendTable()`, `tableExists()`, `rawTableCfgs()`
|
|
80
|
+
- **Metadata**: `contentType()`, `rowCount()`, `lastUpdate()`
|
|
81
|
+
|
|
82
|
+
All implementations (in-memory, remote, multi-source) conform to this interface.
|
|
83
|
+
|
|
84
|
+
### RLJSON Format
|
|
85
|
+
|
|
86
|
+
RLJSON (Relational JSON) is a structured data format that combines JSON with relational database concepts:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
{
|
|
90
|
+
tableName: {
|
|
91
|
+
_type: 'components', // Content type identifier
|
|
92
|
+
_data: [...rows] // Array of data objects
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## API Overview
|
|
98
|
+
|
|
99
|
+
### Lifecycle
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
// Initialize the Io instance
|
|
103
|
+
await io.init();
|
|
104
|
+
|
|
105
|
+
// Check if ready
|
|
106
|
+
await io.isReady();
|
|
107
|
+
|
|
108
|
+
// Check if open
|
|
109
|
+
if (io.isOpen) {
|
|
110
|
+
// Perform operations
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Close when done
|
|
114
|
+
await io.close();
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Writing Data
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
await io.write({
|
|
121
|
+
data: {
|
|
122
|
+
products: {
|
|
123
|
+
_type: 'components',
|
|
124
|
+
_data: [
|
|
125
|
+
{ sku: 'ABC123', name: 'Widget', price: 29.99 },
|
|
126
|
+
{ sku: 'XYZ789', name: 'Gadget', price: 49.99 }
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Reading Data
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
// Query with conditions
|
|
137
|
+
const users = await io.readRows({
|
|
138
|
+
table: 'users',
|
|
139
|
+
where: { active: true, role: 'admin' }
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Get row count
|
|
143
|
+
const count = await io.rowCount('users');
|
|
144
|
+
|
|
145
|
+
// Check if table exists
|
|
146
|
+
const exists = await io.tableExists('users');
|
|
147
|
+
|
|
148
|
+
// Get last update timestamp
|
|
149
|
+
const timestamp = await io.lastUpdate('users');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Dumping Data
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
// Dump entire database
|
|
156
|
+
const allData = await io.dump();
|
|
157
|
+
|
|
158
|
+
// Dump specific table
|
|
159
|
+
const tableData = await io.dumpTable({ table: 'users' });
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Schema Management
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Create or extend a table
|
|
166
|
+
await io.createOrExtendTable({
|
|
167
|
+
tableCfg: {
|
|
168
|
+
key: 'orders',
|
|
169
|
+
type: 'components',
|
|
170
|
+
columns: [
|
|
171
|
+
{ key: '_hash', type: 'string', titleShort: 'Hash', titleLong: 'Hash' },
|
|
172
|
+
{ key: 'orderId', type: 'number', titleShort: 'Order ID', titleLong: 'Order ID' },
|
|
173
|
+
{ key: 'customerId', type: 'number', titleShort: 'Customer', titleLong: 'Customer ID' },
|
|
174
|
+
{ key: 'total', type: 'number', titleShort: 'Total', titleLong: 'Total Amount' },
|
|
175
|
+
{ key: 'status', type: 'string', titleShort: 'Status', titleLong: 'Order Status' }
|
|
176
|
+
],
|
|
177
|
+
isHead: false,
|
|
178
|
+
isRoot: false,
|
|
179
|
+
isShared: true
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Get table configurations
|
|
184
|
+
const configs = await io.rawTableCfgs();
|
|
185
|
+
|
|
186
|
+
// Get content type
|
|
187
|
+
const contentType = await io.contentType({ table: 'orders' });
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Implementations
|
|
191
|
+
|
|
192
|
+
### IoMem - In-Memory Storage
|
|
193
|
+
|
|
194
|
+
Fast, synchronous in-memory database implementation. Perfect for testing, caching, or small datasets.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { IoMem } from '@rljson/io';
|
|
198
|
+
|
|
199
|
+
const io = new IoMem();
|
|
200
|
+
await io.init();
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Use Cases:**
|
|
204
|
+
|
|
205
|
+
- Unit testing
|
|
206
|
+
- Temporary data storage
|
|
207
|
+
- Fast prototyping
|
|
208
|
+
- Client-side caching
|
|
209
|
+
|
|
210
|
+
### IoPeer - Remote Connection
|
|
211
|
+
|
|
212
|
+
Connect to a remote RLJSON database over a socket connection (Socket.IO compatible).
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
import { IoPeer } from '@rljson/io';
|
|
216
|
+
import { io as socketClient } from 'socket.io-client';
|
|
217
|
+
|
|
218
|
+
const socket = socketClient('http://localhost:3000');
|
|
219
|
+
const io = new IoPeer(socket);
|
|
220
|
+
await io.init();
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Use Cases:**
|
|
224
|
+
|
|
225
|
+
- Distributed applications
|
|
226
|
+
- Client-server architectures
|
|
227
|
+
- Real-time data synchronization
|
|
228
|
+
- Microservices communication
|
|
229
|
+
|
|
230
|
+
### IoMulti - Multi-Source Aggregation
|
|
231
|
+
|
|
232
|
+
Combine multiple Io instances with priority-based cascading. Supports read/write splitting and hot-swap caching.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import { IoMulti, IoMem, IoPeer } from '@rljson/io';
|
|
236
|
+
|
|
237
|
+
const cache = new IoMem();
|
|
238
|
+
await cache.init();
|
|
239
|
+
|
|
240
|
+
const remote = new IoPeer(socket);
|
|
241
|
+
await remote.init();
|
|
242
|
+
|
|
243
|
+
const io = new IoMulti([
|
|
244
|
+
{ io: cache, priority: 1, read: true, write: true, dump: false },
|
|
245
|
+
{ io: remote, priority: 2, read: true, write: true, dump: true }
|
|
246
|
+
]);
|
|
247
|
+
await io.init();
|
|
248
|
+
|
|
249
|
+
// Reads cascade: cache first (priority 1), then remote (priority 2)
|
|
250
|
+
// Writes go to both cache and remote
|
|
251
|
+
// Cache is automatically updated with remote data (hot-swapping)
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Use Cases:**
|
|
255
|
+
|
|
256
|
+
- Performance optimization with caching layers
|
|
257
|
+
- Multi-tier data storage
|
|
258
|
+
- Fallback mechanisms
|
|
259
|
+
- Distributed data aggregation
|
|
260
|
+
|
|
261
|
+
**Key Features:**
|
|
262
|
+
|
|
263
|
+
- **Priority-based cascading**: Higher priority sources are queried first
|
|
264
|
+
- **Hot-swap caching**: Successful reads are written back to cache layers
|
|
265
|
+
- **Flexible capabilities**: Each source can be read-only, write-only, or both
|
|
266
|
+
- **Automatic table merging**: Results from multiple sources are merged intelligently
|
|
267
|
+
|
|
268
|
+
### IoPeerBridge - Server-Side Handler
|
|
269
|
+
|
|
270
|
+
Bridge between Socket events and Io operations. Used on the server to handle client requests.
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
import { IoPeerBridge, IoMem } from '@rljson/io';
|
|
274
|
+
import { Server } from 'socket.io';
|
|
275
|
+
|
|
276
|
+
const io = new Server(3000);
|
|
277
|
+
const db = new IoMem();
|
|
278
|
+
await db.init();
|
|
279
|
+
|
|
280
|
+
io.on('connection', (socket) => {
|
|
281
|
+
const bridge = new IoPeerBridge(socket, db);
|
|
282
|
+
bridge.start();
|
|
283
|
+
|
|
284
|
+
socket.on('disconnect', () => {
|
|
285
|
+
bridge.stop();
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Usage Examples
|
|
291
|
+
|
|
292
|
+
### Example 1: Simple In-Memory Database
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
import { IoMem } from '@rljson/io';
|
|
296
|
+
|
|
297
|
+
async function simpleExample() {
|
|
298
|
+
const io = new IoMem();
|
|
299
|
+
await io.init();
|
|
300
|
+
|
|
301
|
+
// Create a table
|
|
302
|
+
await io.createOrExtendTable({
|
|
303
|
+
tableCfg: {
|
|
304
|
+
key: 'tasks',
|
|
305
|
+
type: 'components',
|
|
306
|
+
columns: [
|
|
307
|
+
{ key: '_hash', type: 'string', titleShort: 'Hash', titleLong: 'Hash' },
|
|
308
|
+
{ key: 'id', type: 'number', titleShort: 'ID', titleLong: 'Task ID' },
|
|
309
|
+
{ key: 'title', type: 'string', titleShort: 'Title', titleLong: 'Task Title' },
|
|
310
|
+
{ key: 'completed', type: 'boolean', titleShort: 'Done', titleLong: 'Completed' }
|
|
311
|
+
],
|
|
312
|
+
isHead: false,
|
|
313
|
+
isRoot: false,
|
|
314
|
+
isShared: true
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Insert data
|
|
319
|
+
await io.write({
|
|
320
|
+
data: {
|
|
321
|
+
tasks: {
|
|
322
|
+
_type: 'components',
|
|
323
|
+
_data: [
|
|
324
|
+
{ id: 1, title: 'Learn RLJSON', completed: true },
|
|
325
|
+
{ id: 2, title: 'Build app', completed: false }
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// Query incomplete tasks
|
|
332
|
+
const incompleteTasks = await io.readRows({
|
|
333
|
+
table: 'tasks',
|
|
334
|
+
where: { completed: false }
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
console.log(incompleteTasks);
|
|
338
|
+
// { tasks: { _type: 'components', _data: [{ id: 2, title: 'Build app', completed: false }] } }
|
|
339
|
+
|
|
340
|
+
await io.close();
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Example 2: Client-Server Architecture
|
|
345
|
+
|
|
346
|
+
**Server:**
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { IoMem, IoPeerBridge } from '@rljson/io';
|
|
350
|
+
import { Server } from 'socket.io';
|
|
351
|
+
|
|
352
|
+
const ioServer = new Server(3000, {
|
|
353
|
+
cors: { origin: '*' }
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const db = new IoMem();
|
|
357
|
+
await db.init();
|
|
358
|
+
|
|
359
|
+
// Create table schema
|
|
360
|
+
await db.createOrExtendTable({
|
|
361
|
+
tableCfg: {
|
|
362
|
+
key: 'products',
|
|
363
|
+
type: 'components',
|
|
364
|
+
columns: [
|
|
365
|
+
{ key: '_hash', type: 'string', titleShort: 'Hash', titleLong: 'Hash' },
|
|
366
|
+
{ key: 'id', type: 'number', titleShort: 'ID', titleLong: 'Product ID' },
|
|
367
|
+
{ key: 'name', type: 'string', titleShort: 'Name', titleLong: 'Product Name' },
|
|
368
|
+
{ key: 'price', type: 'number', titleShort: 'Price', titleLong: 'Price' }
|
|
369
|
+
],
|
|
370
|
+
isHead: false,
|
|
371
|
+
isRoot: false,
|
|
372
|
+
isShared: true
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Pre-populate with data
|
|
377
|
+
await db.write({
|
|
378
|
+
data: {
|
|
379
|
+
products: {
|
|
380
|
+
_type: 'components',
|
|
381
|
+
_data: [{ id: 1, name: 'Widget', price: 10 }]
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
ioServer.on('connection', (socket) => {
|
|
387
|
+
const bridge = new IoPeerBridge(socket, db);
|
|
388
|
+
bridge.start();
|
|
389
|
+
|
|
390
|
+
socket.on('disconnect', () => bridge.stop());
|
|
391
|
+
});
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
**Client:**
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
import { IoPeer } from '@rljson/io';
|
|
398
|
+
import { io as socketClient } from 'socket.io-client';
|
|
399
|
+
|
|
400
|
+
const socket = socketClient('http://localhost:3000');
|
|
401
|
+
const io = new IoPeer(socket);
|
|
402
|
+
await io.init();
|
|
403
|
+
|
|
404
|
+
// Query remote database
|
|
405
|
+
const products = await io.readRows({
|
|
406
|
+
table: 'products',
|
|
407
|
+
where: {}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
console.log(products);
|
|
411
|
+
await io.close();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Example 3: Multi-Tier with Cache
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
import { IoMulti, IoMem, IoPeer } from '@rljson/io';
|
|
418
|
+
import { io as socketClient } from 'socket.io-client';
|
|
419
|
+
|
|
420
|
+
// Local cache
|
|
421
|
+
const cache = new IoMem();
|
|
422
|
+
await cache.init();
|
|
423
|
+
|
|
424
|
+
// Remote database
|
|
425
|
+
const socket = socketClient('http://localhost:3000');
|
|
426
|
+
const remote = new IoPeer(socket);
|
|
427
|
+
await remote.init();
|
|
428
|
+
|
|
429
|
+
// Create table schema in both cache and remote
|
|
430
|
+
const tableCfg = {
|
|
431
|
+
key: 'users',
|
|
432
|
+
type: 'components',
|
|
433
|
+
columns: [
|
|
434
|
+
{ key: '_hash', type: 'string', titleShort: 'Hash', titleLong: 'Hash' },
|
|
435
|
+
{ key: 'id', type: 'number', titleShort: 'ID', titleLong: 'User ID' },
|
|
436
|
+
{ key: 'name', type: 'string', titleShort: 'Name', titleLong: 'Name' }
|
|
437
|
+
],
|
|
438
|
+
isHead: false,
|
|
439
|
+
isRoot: false,
|
|
440
|
+
isShared: true
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
await cache.createOrExtendTable({ tableCfg });
|
|
444
|
+
await remote.createOrExtendTable({ tableCfg });
|
|
445
|
+
|
|
446
|
+
// Combined multi-tier Io
|
|
447
|
+
const io = new IoMulti([
|
|
448
|
+
{
|
|
449
|
+
io: cache,
|
|
450
|
+
priority: 1, // Check cache first
|
|
451
|
+
read: true,
|
|
452
|
+
write: true, // Write to cache
|
|
453
|
+
dump: false
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
io: remote,
|
|
457
|
+
priority: 2, // Fallback to remote
|
|
458
|
+
read: true,
|
|
459
|
+
write: true, // Also write to remote
|
|
460
|
+
dump: true // Remote is source of truth for dumps
|
|
461
|
+
}
|
|
462
|
+
]);
|
|
463
|
+
await io.init();
|
|
464
|
+
|
|
465
|
+
// First read hits remote, caches result
|
|
466
|
+
const data1 = await io.readRows({
|
|
467
|
+
table: 'users',
|
|
468
|
+
where: { id: 1 }
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
// Second read hits cache (faster!)
|
|
472
|
+
const data2 = await io.readRows({
|
|
473
|
+
table: 'users',
|
|
474
|
+
where: { id: 1 }
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
// Writes go to both cache and remote
|
|
478
|
+
await io.write({
|
|
479
|
+
data: {
|
|
480
|
+
users: {
|
|
481
|
+
_type: 'components',
|
|
482
|
+
_data: [{ id: 2, name: 'Charlie' }]
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
await io.close();
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Testing Utilities
|
|
491
|
+
|
|
492
|
+
### SocketMock
|
|
493
|
+
|
|
494
|
+
Mock socket for testing without real network connections.
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
import { SocketMock } from '@rljson/io';
|
|
498
|
+
|
|
499
|
+
const socket = new SocketMock();
|
|
500
|
+
socket.on('test', (data) => console.log(data));
|
|
501
|
+
socket.emit('test', 'hello');
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
### DirectionalSocketMock
|
|
505
|
+
|
|
506
|
+
Bidirectional socket pair for client-server testing.
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
import { createSocketPair } from '@rljson/io';
|
|
510
|
+
|
|
511
|
+
const [clientSocket, serverSocket] = createSocketPair();
|
|
512
|
+
|
|
513
|
+
// Server listens
|
|
514
|
+
serverSocket.on('request', (data, callback) => {
|
|
515
|
+
callback({ result: 'success' });
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
// Client sends
|
|
519
|
+
clientSocket.emit('request', { query: 'data' }, (response) => {
|
|
520
|
+
console.log(response); // { result: 'success' }
|
|
521
|
+
});
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### PeerSocketMock
|
|
525
|
+
|
|
526
|
+
Mock socket pair for testing IoPeer/IoPeerBridge interactions.
|
|
527
|
+
|
|
528
|
+
```typescript
|
|
529
|
+
import { PeerSocketMock, IoPeer, IoPeerBridge, IoMem } from '@rljson/io';
|
|
530
|
+
|
|
531
|
+
const [clientSocket, serverSocket] = PeerSocketMock.createPeerSocketPair();
|
|
532
|
+
|
|
533
|
+
const serverDb = new IoMem();
|
|
534
|
+
await serverDb.init();
|
|
535
|
+
|
|
536
|
+
const bridge = new IoPeerBridge(serverSocket, serverDb);
|
|
537
|
+
bridge.start();
|
|
538
|
+
|
|
539
|
+
const clientIo = new IoPeer(clientSocket);
|
|
540
|
+
await clientIo.init();
|
|
541
|
+
|
|
542
|
+
// Client can now interact with server
|
|
543
|
+
const data = await clientIo.dump();
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### IoTestSetup
|
|
547
|
+
|
|
548
|
+
Standard test setup interface for creating test fixtures.
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
import { IoTestSetup } from '@rljson/io';
|
|
552
|
+
|
|
553
|
+
class MyTestSetup implements IoTestSetup {
|
|
554
|
+
constructor(public io: Io) {}
|
|
555
|
+
|
|
556
|
+
async before() {
|
|
557
|
+
await this.io.init();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async after() {
|
|
561
|
+
await this.io.close();
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## TypeScript Support
|
|
567
|
+
|
|
568
|
+
Full TypeScript support with comprehensive type definitions:
|
|
569
|
+
|
|
570
|
+
```typescript
|
|
571
|
+
import {
|
|
572
|
+
Io,
|
|
573
|
+
IoMultiIo,
|
|
574
|
+
Socket
|
|
575
|
+
} from '@rljson/io';
|
|
576
|
+
|
|
577
|
+
// All interfaces are fully typed
|
|
578
|
+
const ios: IoMultiIo[] = [
|
|
579
|
+
{
|
|
580
|
+
io: myIo,
|
|
581
|
+
priority: 1,
|
|
582
|
+
read: true,
|
|
583
|
+
write: true,
|
|
584
|
+
dump: false
|
|
585
|
+
}
|
|
586
|
+
];
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
## Advanced Features
|
|
590
|
+
|
|
591
|
+
### Database Name Mapping
|
|
592
|
+
|
|
593
|
+
Map table names between different representations:
|
|
594
|
+
|
|
595
|
+
```typescript
|
|
596
|
+
import { IoDbNameMapping } from '@rljson/io';
|
|
597
|
+
|
|
598
|
+
const mapping = new IoDbNameMapping(underlyingIo, {
|
|
599
|
+
'user_accounts': 'userAccounts',
|
|
600
|
+
'order_items': 'orderItems'
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
// Access with either name
|
|
604
|
+
await mapping.readRows({ table: 'userAccounts', where: {} });
|
|
605
|
+
await mapping.readRows({ table: 'user_accounts', where: {} });
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
### IoTools
|
|
609
|
+
|
|
610
|
+
Utility functions for working with Io instances:
|
|
611
|
+
|
|
612
|
+
```typescript
|
|
613
|
+
import { IoTools } from '@rljson/io';
|
|
614
|
+
|
|
615
|
+
// Validate table configurations
|
|
616
|
+
const isValid = IoTools.validateTableCfg(tableCfg);
|
|
617
|
+
|
|
618
|
+
// Merge RLJSON data
|
|
619
|
+
const merged = IoTools.mergeRljson(data1, data2);
|
|
620
|
+
|
|
621
|
+
// Extract type information
|
|
622
|
+
const types = IoTools.extractTypes(rljsonData);
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
## API Reference
|
|
626
|
+
|
|
627
|
+
For detailed API documentation, see the TypeScript definitions or visit the [API docs](https://github.com/rljson/io).
|
|
4
628
|
|
|
5
629
|
## Example
|
|
6
630
|
|
|
7
|
-
[src/example.ts](src/example.ts)
|
|
631
|
+
See [src/example.ts](src/example.ts) for more examples.
|
|
632
|
+
|
|
633
|
+
## Contributing
|
|
634
|
+
|
|
635
|
+
See [README.contributors.md](README.contributors.md) for development guidelines.
|
|
636
|
+
|
|
637
|
+
## License
|
|
638
|
+
|
|
639
|
+
MIT © [Rljson](https://github.com/rljson)
|