@rljson/io 0.0.69 → 0.0.71
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 +25 -10
- package/README.public.md +5 -0
- package/dist/README.architecture.md +25 -10
- package/dist/README.public.md +5 -0
- package/dist/io-mem.d.ts +78 -1
- package/dist/io-multi.d.ts +17 -0
- package/dist/io-peer.d.ts +15 -0
- package/dist/io.d.ts +11 -0
- package/dist/io.js +389 -23
- package/dist/io.js.map +1 -1
- package/package.json +1 -1
package/README.architecture.md
CHANGED
|
@@ -18,7 +18,7 @@ found in the LICENSE file in the root of this package.
|
|
|
18
18
|
|
|
19
19
|
The central abstraction that defines all database operations:
|
|
20
20
|
|
|
21
|
-
```
|
|
21
|
+
```text
|
|
22
22
|
┌─────────────────────────────────────────────┐
|
|
23
23
|
│ Io Interface │
|
|
24
24
|
├─────────────────────────────────────────────┤
|
|
@@ -42,7 +42,7 @@ The central abstraction that defines all database operations:
|
|
|
42
42
|
|
|
43
43
|
In-memory implementation using JavaScript objects.
|
|
44
44
|
|
|
45
|
-
```
|
|
45
|
+
```text
|
|
46
46
|
┌─────────────────────┐
|
|
47
47
|
│ IoMem │
|
|
48
48
|
├─────────────────────┤
|
|
@@ -61,6 +61,21 @@ In-memory implementation using JavaScript objects.
|
|
|
61
61
|
- Uses `@rljson/hash` for data hashing and identity
|
|
62
62
|
- `IsReady` pattern for initialization tracking
|
|
63
63
|
|
|
64
|
+
**Performance internals** (no observable API change):
|
|
65
|
+
|
|
66
|
+
- Rows are indexed per table by content hash — write dedup is O(1) and
|
|
67
|
+
`readRows` with a string `_hash` in the where clause resolves through
|
|
68
|
+
the index instead of scanning the table
|
|
69
|
+
- Table data is kept hash-sorted incrementally (binary-searched insert)
|
|
70
|
+
instead of re-sorting the whole table per write
|
|
71
|
+
- Table and global hashes are updated lazily: writes mark tables dirty,
|
|
72
|
+
hashes are recomputed before they become observable (`dump`,
|
|
73
|
+
`dumpTable`, `createOrExtendTable`, re-`init`) — deterministic hashes
|
|
74
|
+
make the refreshed state identical to eager updates
|
|
75
|
+
- The latest table configuration and column keys are cached per table
|
|
76
|
+
(updated on create/extend), so validation does not re-scan all
|
|
77
|
+
configurations per read/write
|
|
78
|
+
|
|
64
79
|
**Data Structure:**
|
|
65
80
|
|
|
66
81
|
```typescript
|
|
@@ -76,7 +91,7 @@ _mem = {
|
|
|
76
91
|
|
|
77
92
|
Remote database connection over sockets (Socket.IO compatible).
|
|
78
93
|
|
|
79
|
-
```
|
|
94
|
+
```text
|
|
80
95
|
┌──────────────┐ Socket ┌──────────────┐
|
|
81
96
|
│ IoPeer │◄───────────────────────►│ IoPeerBridge │
|
|
82
97
|
│ (Client) │ Events/Acks │ (Server) │
|
|
@@ -107,7 +122,7 @@ Remote database connection over sockets (Socket.IO compatible).
|
|
|
107
122
|
|
|
108
123
|
Server-side handler that bridges socket events to Io operations.
|
|
109
124
|
|
|
110
|
-
```
|
|
125
|
+
```text
|
|
111
126
|
┌─────────────────────────────────────┐
|
|
112
127
|
│ IoPeerBridge │
|
|
113
128
|
├─────────────────────────────────────┤
|
|
@@ -132,7 +147,7 @@ Server-side handler that bridges socket events to Io operations.
|
|
|
132
147
|
|
|
133
148
|
Aggregates multiple Io instances with priority-based cascading.
|
|
134
149
|
|
|
135
|
-
```
|
|
150
|
+
```text
|
|
136
151
|
┌────────────────────────────────────────────┐
|
|
137
152
|
│ IoMulti │
|
|
138
153
|
├────────────────────────────────────────────┤
|
|
@@ -182,7 +197,7 @@ IoMultiIo {
|
|
|
182
197
|
|
|
183
198
|
Provides name mapping between different table name formats.
|
|
184
199
|
|
|
185
|
-
```
|
|
200
|
+
```text
|
|
186
201
|
┌──────────────────────────────────────┐
|
|
187
202
|
│ IoDbNameMapping │
|
|
188
203
|
├──────────────────────────────────────┤
|
|
@@ -202,7 +217,7 @@ Provides name mapping between different table name formats.
|
|
|
202
217
|
|
|
203
218
|
Server implementation that combines Socket.IO with Io backends.
|
|
204
219
|
|
|
205
|
-
```
|
|
220
|
+
```text
|
|
206
221
|
┌─────────────────────────────────────┐
|
|
207
222
|
│ IoServer │
|
|
208
223
|
├─────────────────────────────────────┤
|
|
@@ -230,7 +245,7 @@ Server implementation that combines Socket.IO with Io backends.
|
|
|
230
245
|
|
|
231
246
|
### Write Operation
|
|
232
247
|
|
|
233
|
-
```
|
|
248
|
+
```text
|
|
234
249
|
Client Code
|
|
235
250
|
│
|
|
236
251
|
▼
|
|
@@ -248,7 +263,7 @@ io.write(data)
|
|
|
248
263
|
|
|
249
264
|
### Read Operation (IoMulti Cascade)
|
|
250
265
|
|
|
251
|
-
```
|
|
266
|
+
```text
|
|
252
267
|
io.readRows({table: 'users', where: {id: 1}})
|
|
253
268
|
│
|
|
254
269
|
▼
|
|
@@ -293,7 +308,7 @@ return rljson; // Only after loop completes
|
|
|
293
308
|
|
|
294
309
|
### Event-Based Protocol
|
|
295
310
|
|
|
296
|
-
```
|
|
311
|
+
```text
|
|
297
312
|
Client (IoPeer) Server (IoPeerBridge)
|
|
298
313
|
│ │
|
|
299
314
|
├─── emit('readRows', request) ────►│
|
package/README.public.md
CHANGED
|
@@ -78,6 +78,11 @@ The `Io` interface is the core abstraction that defines a standard set of operat
|
|
|
78
78
|
- **Data Operations**: `write()`, `readRows()`, `dump()`
|
|
79
79
|
- **Schema Management**: `createOrExtendTable()`, `tableExists()`, `rawTableCfgs()`
|
|
80
80
|
- **Metadata**: `contentType()`, `rowCount()`, `lastUpdate()`
|
|
81
|
+
- **Optional Batch Reads**: `readRowsByHashes()` — answers many content
|
|
82
|
+
hash lookups in one request. Implementations may omit it; callers must
|
|
83
|
+
fall back to `readRows()` then. `IoMem`, `IoMulti` (per-hash cascade
|
|
84
|
+
across its members) and `IoPeer`/`IoServer` (one socket round trip,
|
|
85
|
+
with automatic per-hash fallback against older remotes) support it.
|
|
81
86
|
|
|
82
87
|
All implementations (in-memory, remote, multi-source) conform to this interface.
|
|
83
88
|
|
|
@@ -18,7 +18,7 @@ found in the LICENSE file in the root of this package.
|
|
|
18
18
|
|
|
19
19
|
The central abstraction that defines all database operations:
|
|
20
20
|
|
|
21
|
-
```
|
|
21
|
+
```text
|
|
22
22
|
┌─────────────────────────────────────────────┐
|
|
23
23
|
│ Io Interface │
|
|
24
24
|
├─────────────────────────────────────────────┤
|
|
@@ -42,7 +42,7 @@ The central abstraction that defines all database operations:
|
|
|
42
42
|
|
|
43
43
|
In-memory implementation using JavaScript objects.
|
|
44
44
|
|
|
45
|
-
```
|
|
45
|
+
```text
|
|
46
46
|
┌─────────────────────┐
|
|
47
47
|
│ IoMem │
|
|
48
48
|
├─────────────────────┤
|
|
@@ -61,6 +61,21 @@ In-memory implementation using JavaScript objects.
|
|
|
61
61
|
- Uses `@rljson/hash` for data hashing and identity
|
|
62
62
|
- `IsReady` pattern for initialization tracking
|
|
63
63
|
|
|
64
|
+
**Performance internals** (no observable API change):
|
|
65
|
+
|
|
66
|
+
- Rows are indexed per table by content hash — write dedup is O(1) and
|
|
67
|
+
`readRows` with a string `_hash` in the where clause resolves through
|
|
68
|
+
the index instead of scanning the table
|
|
69
|
+
- Table data is kept hash-sorted incrementally (binary-searched insert)
|
|
70
|
+
instead of re-sorting the whole table per write
|
|
71
|
+
- Table and global hashes are updated lazily: writes mark tables dirty,
|
|
72
|
+
hashes are recomputed before they become observable (`dump`,
|
|
73
|
+
`dumpTable`, `createOrExtendTable`, re-`init`) — deterministic hashes
|
|
74
|
+
make the refreshed state identical to eager updates
|
|
75
|
+
- The latest table configuration and column keys are cached per table
|
|
76
|
+
(updated on create/extend), so validation does not re-scan all
|
|
77
|
+
configurations per read/write
|
|
78
|
+
|
|
64
79
|
**Data Structure:**
|
|
65
80
|
|
|
66
81
|
```typescript
|
|
@@ -76,7 +91,7 @@ _mem = {
|
|
|
76
91
|
|
|
77
92
|
Remote database connection over sockets (Socket.IO compatible).
|
|
78
93
|
|
|
79
|
-
```
|
|
94
|
+
```text
|
|
80
95
|
┌──────────────┐ Socket ┌──────────────┐
|
|
81
96
|
│ IoPeer │◄───────────────────────►│ IoPeerBridge │
|
|
82
97
|
│ (Client) │ Events/Acks │ (Server) │
|
|
@@ -107,7 +122,7 @@ Remote database connection over sockets (Socket.IO compatible).
|
|
|
107
122
|
|
|
108
123
|
Server-side handler that bridges socket events to Io operations.
|
|
109
124
|
|
|
110
|
-
```
|
|
125
|
+
```text
|
|
111
126
|
┌─────────────────────────────────────┐
|
|
112
127
|
│ IoPeerBridge │
|
|
113
128
|
├─────────────────────────────────────┤
|
|
@@ -132,7 +147,7 @@ Server-side handler that bridges socket events to Io operations.
|
|
|
132
147
|
|
|
133
148
|
Aggregates multiple Io instances with priority-based cascading.
|
|
134
149
|
|
|
135
|
-
```
|
|
150
|
+
```text
|
|
136
151
|
┌────────────────────────────────────────────┐
|
|
137
152
|
│ IoMulti │
|
|
138
153
|
├────────────────────────────────────────────┤
|
|
@@ -182,7 +197,7 @@ IoMultiIo {
|
|
|
182
197
|
|
|
183
198
|
Provides name mapping between different table name formats.
|
|
184
199
|
|
|
185
|
-
```
|
|
200
|
+
```text
|
|
186
201
|
┌──────────────────────────────────────┐
|
|
187
202
|
│ IoDbNameMapping │
|
|
188
203
|
├──────────────────────────────────────┤
|
|
@@ -202,7 +217,7 @@ Provides name mapping between different table name formats.
|
|
|
202
217
|
|
|
203
218
|
Server implementation that combines Socket.IO with Io backends.
|
|
204
219
|
|
|
205
|
-
```
|
|
220
|
+
```text
|
|
206
221
|
┌─────────────────────────────────────┐
|
|
207
222
|
│ IoServer │
|
|
208
223
|
├─────────────────────────────────────┤
|
|
@@ -230,7 +245,7 @@ Server implementation that combines Socket.IO with Io backends.
|
|
|
230
245
|
|
|
231
246
|
### Write Operation
|
|
232
247
|
|
|
233
|
-
```
|
|
248
|
+
```text
|
|
234
249
|
Client Code
|
|
235
250
|
│
|
|
236
251
|
▼
|
|
@@ -248,7 +263,7 @@ io.write(data)
|
|
|
248
263
|
|
|
249
264
|
### Read Operation (IoMulti Cascade)
|
|
250
265
|
|
|
251
|
-
```
|
|
266
|
+
```text
|
|
252
267
|
io.readRows({table: 'users', where: {id: 1}})
|
|
253
268
|
│
|
|
254
269
|
▼
|
|
@@ -293,7 +308,7 @@ return rljson; // Only after loop completes
|
|
|
293
308
|
|
|
294
309
|
### Event-Based Protocol
|
|
295
310
|
|
|
296
|
-
```
|
|
311
|
+
```text
|
|
297
312
|
Client (IoPeer) Server (IoPeerBridge)
|
|
298
313
|
│ │
|
|
299
314
|
├─── emit('readRows', request) ────►│
|
package/dist/README.public.md
CHANGED
|
@@ -78,6 +78,11 @@ The `Io` interface is the core abstraction that defines a standard set of operat
|
|
|
78
78
|
- **Data Operations**: `write()`, `readRows()`, `dump()`
|
|
79
79
|
- **Schema Management**: `createOrExtendTable()`, `tableExists()`, `rawTableCfgs()`
|
|
80
80
|
- **Metadata**: `contentType()`, `rowCount()`, `lastUpdate()`
|
|
81
|
+
- **Optional Batch Reads**: `readRowsByHashes()` — answers many content
|
|
82
|
+
hash lookups in one request. Implementations may omit it; callers must
|
|
83
|
+
fall back to `readRows()` then. `IoMem`, `IoMulti` (per-hash cascade
|
|
84
|
+
across its members) and `IoPeer`/`IoServer` (one socket round trip,
|
|
85
|
+
with automatic per-hash fallback against older remotes) support it.
|
|
81
86
|
|
|
82
87
|
All implementations (in-memory, remote, multi-source) conform to this interface.
|
|
83
88
|
|
package/dist/io-mem.d.ts
CHANGED
|
@@ -23,6 +23,10 @@ export declare class IoMem implements Io {
|
|
|
23
23
|
[column: string]: JsonValue;
|
|
24
24
|
};
|
|
25
25
|
}): Promise<Rljson>;
|
|
26
|
+
readRowsByHashes(request: {
|
|
27
|
+
table: string;
|
|
28
|
+
hashes: string[];
|
|
29
|
+
}): Promise<Rljson>;
|
|
26
30
|
rowCount(table: string): Promise<number>;
|
|
27
31
|
write(request: {
|
|
28
32
|
data: Rljson;
|
|
@@ -36,6 +40,79 @@ export declare class IoMem implements Io {
|
|
|
36
40
|
private _isReady;
|
|
37
41
|
private _isOpen;
|
|
38
42
|
private _mem;
|
|
43
|
+
/**
|
|
44
|
+
* Latest table configuration per table (the one with the most
|
|
45
|
+
* columns). Kept in sync by _createTable/_extendTable so that reads
|
|
46
|
+
* and writes need no repeated scan over all configurations.
|
|
47
|
+
*/
|
|
48
|
+
private readonly _latestCfgs;
|
|
49
|
+
/** Column key sets per table, derived from _latestCfgs */
|
|
50
|
+
private readonly _columnKeys;
|
|
51
|
+
/**
|
|
52
|
+
* Per-table index of rows by content hash. Rows are only ever added,
|
|
53
|
+
* never removed, so the index cannot go stale.
|
|
54
|
+
*/
|
|
55
|
+
private readonly _rowIndex;
|
|
56
|
+
/**
|
|
57
|
+
* Tables whose table hash (and thus the global hash) is outdated
|
|
58
|
+
* after writes. Hashes are refreshed lazily before they become
|
|
59
|
+
* observable (dump, dumpTable, create/extend) instead of after every
|
|
60
|
+
* single write — row hashes themselves are always up to date.
|
|
61
|
+
*/
|
|
62
|
+
private readonly _dirtyTableHashes;
|
|
63
|
+
/**
|
|
64
|
+
* Recomputes the hashes of all dirty tables and the global hash.
|
|
65
|
+
* Produces exactly the state an eager per-write update would have
|
|
66
|
+
* produced (hashes are deterministic over the same data).
|
|
67
|
+
*/
|
|
68
|
+
private _refreshHashes;
|
|
69
|
+
/**
|
|
70
|
+
* Returns the row index of a table, building it lazily from the
|
|
71
|
+
* table data on first access.
|
|
72
|
+
* @param table - The table to index
|
|
73
|
+
*/
|
|
74
|
+
private _rowIndexFor;
|
|
75
|
+
/**
|
|
76
|
+
* Inserts a row into hash-sorted table data at its sorted position —
|
|
77
|
+
* preserves the order sortTableDataAndUpdateHash establishes without
|
|
78
|
+
* a full re-sort.
|
|
79
|
+
* @param data - The hash-sorted table data
|
|
80
|
+
* @param row - The row to insert
|
|
81
|
+
*/
|
|
82
|
+
private static _insertSortedByHash;
|
|
83
|
+
/**
|
|
84
|
+
* The row filter predicate of readRows. Extracted so that the indexed
|
|
85
|
+
* fast path and the full scan share identical semantics.
|
|
86
|
+
* @param row - The row to check
|
|
87
|
+
* @param where - The where clause
|
|
88
|
+
*/
|
|
89
|
+
private static _rowMatchesWhere;
|
|
90
|
+
/**
|
|
91
|
+
* Returns the latest table configuration, filling the cache lazily
|
|
92
|
+
* from IoTools (which picks the config with the most columns).
|
|
93
|
+
* @param table - The table to get the configuration for
|
|
94
|
+
*/
|
|
95
|
+
private _latestCfg;
|
|
96
|
+
/**
|
|
97
|
+
* Updates the cached latest configuration of a table
|
|
98
|
+
* @param cfg - The new latest configuration
|
|
99
|
+
*/
|
|
100
|
+
private _setLatestCfg;
|
|
101
|
+
/**
|
|
102
|
+
* Throws when one of the given columns does not exist in the table.
|
|
103
|
+
* Mirrors IoTools.throwWhenColumnDoesNotExist but uses the cached
|
|
104
|
+
* configuration.
|
|
105
|
+
* @param table - The table to check
|
|
106
|
+
* @param columns - The columns to check
|
|
107
|
+
*/
|
|
108
|
+
private _throwWhenColumnDoesNotExist;
|
|
109
|
+
/**
|
|
110
|
+
* Throws when the data does not match the table configurations.
|
|
111
|
+
* Mirrors IoTools.throwWhenTableDataDoesNotMatchCfg but uses the
|
|
112
|
+
* cached configurations.
|
|
113
|
+
* @param data - The data to validate
|
|
114
|
+
*/
|
|
115
|
+
private _throwWhenTableDataDoesNotMatchCfg;
|
|
39
116
|
private _init;
|
|
40
117
|
private _initTableCfgs;
|
|
41
118
|
private _updateGlobalHash;
|
|
@@ -48,5 +125,5 @@ export declare class IoMem implements Io {
|
|
|
48
125
|
private _contentType;
|
|
49
126
|
private _write;
|
|
50
127
|
private _readRows;
|
|
51
|
-
_removeNullValues(rljson: Rljson):
|
|
128
|
+
_removeNullValues(rljson: Rljson): boolean;
|
|
52
129
|
}
|
package/dist/io-multi.d.ts
CHANGED
|
@@ -112,6 +112,23 @@ export declare class IoMulti implements Io {
|
|
|
112
112
|
* @returns A promise that resolves to the row count of the table.
|
|
113
113
|
*/
|
|
114
114
|
rowCount(table: string): Promise<number>;
|
|
115
|
+
/**
|
|
116
|
+
* Batch read with PER-HASH cascade: every hash not found in a
|
|
117
|
+
* higher-priority readable is looked up in the next one. Readables
|
|
118
|
+
* without readRowsByHashes are queried per hash via readRows.
|
|
119
|
+
* @param request - The table and the row hashes to read
|
|
120
|
+
*/
|
|
121
|
+
readRowsByHashes(request: {
|
|
122
|
+
table: string;
|
|
123
|
+
hashes: string[];
|
|
124
|
+
}): Promise<Rljson>;
|
|
125
|
+
/**
|
|
126
|
+
* Per-hash fallback for readables without readRowsByHashes.
|
|
127
|
+
* @param io - The readable io
|
|
128
|
+
* @param table - The table to read from
|
|
129
|
+
* @param hashes - The row hashes to read
|
|
130
|
+
*/
|
|
131
|
+
private static _readHashesViaReadRows;
|
|
115
132
|
/**
|
|
116
133
|
* Gets the list of underlying readable Io instances, sorted by priority.
|
|
117
134
|
*/
|
package/dist/io-peer.d.ts
CHANGED
|
@@ -88,6 +88,21 @@ export declare class IoPeer implements Io {
|
|
|
88
88
|
[column: string]: JsonValue | null;
|
|
89
89
|
};
|
|
90
90
|
}): Promise<Rljson>;
|
|
91
|
+
/**
|
|
92
|
+
* True once the remote side signalled that it does not support batch
|
|
93
|
+
* reads — all further batch reads then use per-hash readRows.
|
|
94
|
+
*/
|
|
95
|
+
private _batchReadsUnsupported;
|
|
96
|
+
/**
|
|
97
|
+
* Batch read over the socket. Falls back to per-hash readRows when
|
|
98
|
+
* the remote side does not support it (older server) and remembers
|
|
99
|
+
* the capability for subsequent calls.
|
|
100
|
+
* @param request - The table and the row hashes to read
|
|
101
|
+
*/
|
|
102
|
+
readRowsByHashes(request: {
|
|
103
|
+
table: string;
|
|
104
|
+
hashes: string[];
|
|
105
|
+
}): Promise<Rljson>;
|
|
91
106
|
/**
|
|
92
107
|
* Retrieves the number of rows in a specific table.
|
|
93
108
|
* @param table The name of the table to count rows in.
|
package/dist/io.d.ts
CHANGED
|
@@ -50,6 +50,17 @@ export interface Io {
|
|
|
50
50
|
[column: string]: JsonValue | null;
|
|
51
51
|
};
|
|
52
52
|
}): Promise<Rljson>;
|
|
53
|
+
/**
|
|
54
|
+
* Optional batch read: returns the rows matching the given content
|
|
55
|
+
* hashes in one request. Hashes without a matching row are simply
|
|
56
|
+
* absent from the result. Implementations answering many hash lookups
|
|
57
|
+
* in one round trip should provide this; callers MUST fall back to
|
|
58
|
+
* readRows when the method is not implemented.
|
|
59
|
+
*/
|
|
60
|
+
readRowsByHashes?(request: {
|
|
61
|
+
table: string;
|
|
62
|
+
hashes: string[];
|
|
63
|
+
}): Promise<Rljson>;
|
|
53
64
|
/** Returns the number of rows in the given table */
|
|
54
65
|
rowCount(table: string): Promise<number>;
|
|
55
66
|
}
|