@push.rocks/smartmongo 2.2.0 → 4.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/index.js +3 -3
- package/dist_ts/tsmdb/engine/AggregationEngine.js +189 -0
- package/dist_ts/{congodb → tsmdb}/engine/IndexEngine.d.ts +23 -3
- package/dist_ts/tsmdb/engine/IndexEngine.js +678 -0
- package/dist_ts/tsmdb/engine/QueryEngine.js +271 -0
- package/dist_ts/tsmdb/engine/QueryPlanner.d.ts +64 -0
- package/dist_ts/tsmdb/engine/QueryPlanner.js +308 -0
- package/dist_ts/tsmdb/engine/SessionEngine.d.ts +117 -0
- package/dist_ts/tsmdb/engine/SessionEngine.js +232 -0
- package/dist_ts/{congodb → tsmdb}/engine/TransactionEngine.d.ts +1 -1
- package/dist_ts/tsmdb/engine/TransactionEngine.js +287 -0
- package/dist_ts/tsmdb/engine/UpdateEngine.js +461 -0
- package/dist_ts/{congodb/errors/CongoErrors.d.ts → tsmdb/errors/TsmdbErrors.d.ts} +16 -16
- package/dist_ts/tsmdb/errors/TsmdbErrors.js +155 -0
- package/dist_ts/{congodb → tsmdb}/index.d.ts +11 -4
- package/dist_ts/tsmdb/index.js +31 -0
- package/dist_ts/tsmdb/server/CommandRouter.d.ts +87 -0
- package/dist_ts/tsmdb/server/CommandRouter.js +222 -0
- package/dist_ts/{congodb/server/CongoServer.d.ts → tsmdb/server/TsmdbServer.d.ts} +6 -6
- package/dist_ts/tsmdb/server/TsmdbServer.js +229 -0
- package/dist_ts/{congodb → tsmdb}/server/WireProtocol.d.ts +1 -1
- package/dist_ts/tsmdb/server/WireProtocol.js +298 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/AdminHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/AdminHandler.js +668 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/AggregateHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/AggregateHandler.js +277 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/DeleteHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/DeleteHandler.js +95 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/FindHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/FindHandler.js +291 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.d.ts +1 -1
- package/dist_ts/{congodb → tsmdb}/server/handlers/HelloHandler.js +2 -2
- package/dist_ts/{congodb → tsmdb}/server/handlers/IndexHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/IndexHandler.js +183 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/InsertHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/InsertHandler.js +79 -0
- package/dist_ts/{congodb → tsmdb}/server/handlers/UpdateHandler.d.ts +1 -1
- package/dist_ts/tsmdb/server/handlers/UpdateHandler.js +296 -0
- package/dist_ts/tsmdb/server/handlers/index.js +10 -0
- package/dist_ts/{congodb → tsmdb}/server/index.d.ts +2 -2
- package/dist_ts/tsmdb/server/index.js +7 -0
- package/dist_ts/{congodb → tsmdb}/storage/FileStorageAdapter.d.ts +27 -3
- package/dist_ts/tsmdb/storage/FileStorageAdapter.js +465 -0
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.d.ts +7 -2
- package/dist_ts/{congodb → tsmdb}/storage/IStorageAdapter.js +1 -1
- package/dist_ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.d.ts +3 -2
- package/dist_ts/tsmdb/storage/MemoryStorageAdapter.js +378 -0
- package/dist_ts/{congodb → tsmdb}/storage/OpLog.d.ts +1 -1
- package/dist_ts/tsmdb/storage/OpLog.js +221 -0
- package/dist_ts/tsmdb/storage/WAL.d.ts +117 -0
- package/dist_ts/tsmdb/storage/WAL.js +286 -0
- package/dist_ts/tsmdb/tsmdb.plugins.js +14 -0
- package/dist_ts/{congodb → tsmdb}/types/interfaces.d.ts +3 -3
- package/dist_ts/{congodb → tsmdb}/types/interfaces.js +1 -1
- package/dist_ts/tsmdb/utils/checksum.d.ts +30 -0
- package/dist_ts/tsmdb/utils/checksum.js +77 -0
- package/dist_ts/tsmdb/utils/index.d.ts +1 -0
- package/dist_ts/tsmdb/utils/index.js +2 -0
- package/package.json +1 -1
- package/readme.hints.md +7 -12
- package/readme.md +25 -25
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +2 -2
- package/ts/{congodb → tsmdb}/engine/AggregationEngine.ts +1 -1
- package/ts/tsmdb/engine/IndexEngine.ts +798 -0
- package/ts/{congodb → tsmdb}/engine/QueryEngine.ts +1 -1
- package/ts/tsmdb/engine/QueryPlanner.ts +393 -0
- package/ts/tsmdb/engine/SessionEngine.ts +292 -0
- package/ts/{congodb → tsmdb}/engine/TransactionEngine.ts +12 -12
- package/ts/{congodb → tsmdb}/engine/UpdateEngine.ts +1 -1
- package/ts/{congodb/errors/CongoErrors.ts → tsmdb/errors/TsmdbErrors.ts} +34 -34
- package/ts/{congodb → tsmdb}/index.ts +16 -7
- package/ts/{congodb → tsmdb}/server/CommandRouter.ts +114 -5
- package/ts/{congodb/server/CongoServer.ts → tsmdb/server/TsmdbServer.ts} +11 -8
- package/ts/{congodb → tsmdb}/server/WireProtocol.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/AdminHandler.ts +116 -11
- package/ts/{congodb → tsmdb}/server/handlers/AggregateHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/DeleteHandler.ts +18 -3
- package/ts/{congodb → tsmdb}/server/handlers/FindHandler.ts +43 -14
- package/ts/{congodb → tsmdb}/server/handlers/HelloHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/IndexHandler.ts +1 -1
- package/ts/{congodb → tsmdb}/server/handlers/InsertHandler.ts +7 -1
- package/ts/{congodb → tsmdb}/server/handlers/UpdateHandler.ts +34 -5
- package/ts/{congodb → tsmdb}/server/index.ts +2 -2
- package/ts/{congodb → tsmdb}/storage/FileStorageAdapter.ts +90 -7
- package/ts/{congodb → tsmdb}/storage/IStorageAdapter.ts +8 -2
- package/ts/{congodb → tsmdb}/storage/MemoryStorageAdapter.ts +14 -2
- package/ts/{congodb → tsmdb}/storage/OpLog.ts +1 -1
- package/ts/tsmdb/storage/WAL.ts +375 -0
- package/ts/{congodb → tsmdb}/types/interfaces.ts +3 -3
- package/ts/tsmdb/utils/checksum.ts +88 -0
- package/ts/tsmdb/utils/index.ts +1 -0
- package/dist_ts/congodb/congodb.plugins.js +0 -14
- package/dist_ts/congodb/engine/AggregationEngine.js +0 -189
- package/dist_ts/congodb/engine/IndexEngine.js +0 -376
- package/dist_ts/congodb/engine/QueryEngine.js +0 -271
- package/dist_ts/congodb/engine/TransactionEngine.js +0 -287
- package/dist_ts/congodb/engine/UpdateEngine.js +0 -461
- package/dist_ts/congodb/errors/CongoErrors.js +0 -155
- package/dist_ts/congodb/index.js +0 -26
- package/dist_ts/congodb/server/CommandRouter.d.ts +0 -51
- package/dist_ts/congodb/server/CommandRouter.js +0 -132
- package/dist_ts/congodb/server/CongoServer.js +0 -227
- package/dist_ts/congodb/server/WireProtocol.js +0 -298
- package/dist_ts/congodb/server/handlers/AdminHandler.js +0 -568
- package/dist_ts/congodb/server/handlers/AggregateHandler.js +0 -277
- package/dist_ts/congodb/server/handlers/DeleteHandler.js +0 -83
- package/dist_ts/congodb/server/handlers/FindHandler.js +0 -261
- package/dist_ts/congodb/server/handlers/IndexHandler.js +0 -183
- package/dist_ts/congodb/server/handlers/InsertHandler.js +0 -76
- package/dist_ts/congodb/server/handlers/UpdateHandler.js +0 -270
- package/dist_ts/congodb/server/handlers/index.js +0 -10
- package/dist_ts/congodb/server/index.js +0 -7
- package/dist_ts/congodb/storage/FileStorageAdapter.js +0 -396
- package/dist_ts/congodb/storage/MemoryStorageAdapter.js +0 -367
- package/dist_ts/congodb/storage/OpLog.js +0 -221
- package/ts/congodb/engine/IndexEngine.ts +0 -479
- /package/dist_ts/{congodb → tsmdb}/engine/AggregationEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/engine/QueryEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/engine/UpdateEngine.d.ts +0 -0
- /package/dist_ts/{congodb → tsmdb}/server/handlers/index.d.ts +0 -0
- /package/dist_ts/{congodb/congodb.plugins.d.ts → tsmdb/tsmdb.plugins.d.ts} +0 -0
- /package/ts/{congodb → tsmdb}/server/handlers/index.ts +0 -0
- /package/ts/{congodb/congodb.plugins.ts → tsmdb/tsmdb.plugins.ts} +0 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import type { IStoredDocument } from '../types/interfaces.js';
|
|
2
|
+
/**
|
|
3
|
+
* WAL entry operation types
|
|
4
|
+
*/
|
|
5
|
+
export type TWalOperation = 'insert' | 'update' | 'delete' | 'checkpoint' | 'begin' | 'commit' | 'abort';
|
|
6
|
+
/**
|
|
7
|
+
* WAL entry structure
|
|
8
|
+
*/
|
|
9
|
+
export interface IWalEntry {
|
|
10
|
+
/** Log Sequence Number - monotonically increasing */
|
|
11
|
+
lsn: number;
|
|
12
|
+
/** Timestamp of the operation */
|
|
13
|
+
timestamp: number;
|
|
14
|
+
/** Operation type */
|
|
15
|
+
operation: TWalOperation;
|
|
16
|
+
/** Database name */
|
|
17
|
+
dbName: string;
|
|
18
|
+
/** Collection name */
|
|
19
|
+
collName: string;
|
|
20
|
+
/** Document ID (hex string) */
|
|
21
|
+
documentId: string;
|
|
22
|
+
/** Document data (BSON serialized, base64 encoded) */
|
|
23
|
+
data?: string;
|
|
24
|
+
/** Previous document data for updates (for rollback) */
|
|
25
|
+
previousData?: string;
|
|
26
|
+
/** Transaction ID if part of a transaction */
|
|
27
|
+
txnId?: string;
|
|
28
|
+
/** CRC32 checksum of the entry (excluding this field) */
|
|
29
|
+
checksum: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Write-Ahead Log (WAL) for durability and crash recovery
|
|
33
|
+
*
|
|
34
|
+
* The WAL ensures durability by writing operations to a log file before
|
|
35
|
+
* they are applied to the main storage. On crash recovery, uncommitted
|
|
36
|
+
* operations can be replayed to restore the database to a consistent state.
|
|
37
|
+
*/
|
|
38
|
+
export declare class WAL {
|
|
39
|
+
private walPath;
|
|
40
|
+
private currentLsn;
|
|
41
|
+
private lastCheckpointLsn;
|
|
42
|
+
private entries;
|
|
43
|
+
private isInitialized;
|
|
44
|
+
private fs;
|
|
45
|
+
private uncommittedTxns;
|
|
46
|
+
private checkpointInterval;
|
|
47
|
+
constructor(walPath: string, options?: {
|
|
48
|
+
checkpointInterval?: number;
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Initialize the WAL, loading existing entries and recovering if needed
|
|
52
|
+
*/
|
|
53
|
+
initialize(): Promise<{
|
|
54
|
+
recoveredEntries: IWalEntry[];
|
|
55
|
+
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Log an insert operation
|
|
58
|
+
*/
|
|
59
|
+
logInsert(dbName: string, collName: string, doc: IStoredDocument, txnId?: string): Promise<number>;
|
|
60
|
+
/**
|
|
61
|
+
* Log an update operation
|
|
62
|
+
*/
|
|
63
|
+
logUpdate(dbName: string, collName: string, oldDoc: IStoredDocument, newDoc: IStoredDocument, txnId?: string): Promise<number>;
|
|
64
|
+
/**
|
|
65
|
+
* Log a delete operation
|
|
66
|
+
*/
|
|
67
|
+
logDelete(dbName: string, collName: string, doc: IStoredDocument, txnId?: string): Promise<number>;
|
|
68
|
+
/**
|
|
69
|
+
* Log transaction begin
|
|
70
|
+
*/
|
|
71
|
+
logBeginTransaction(txnId: string): Promise<number>;
|
|
72
|
+
/**
|
|
73
|
+
* Log transaction commit
|
|
74
|
+
*/
|
|
75
|
+
logCommitTransaction(txnId: string): Promise<number>;
|
|
76
|
+
/**
|
|
77
|
+
* Log transaction abort
|
|
78
|
+
*/
|
|
79
|
+
logAbortTransaction(txnId: string): Promise<number>;
|
|
80
|
+
/**
|
|
81
|
+
* Get entries to roll back for an aborted transaction
|
|
82
|
+
*/
|
|
83
|
+
getTransactionEntries(txnId: string): IWalEntry[];
|
|
84
|
+
/**
|
|
85
|
+
* Create a checkpoint - marks a consistent point in the log
|
|
86
|
+
*/
|
|
87
|
+
checkpoint(): Promise<number>;
|
|
88
|
+
/**
|
|
89
|
+
* Truncate the WAL file, removing entries before the last checkpoint
|
|
90
|
+
*/
|
|
91
|
+
private truncate;
|
|
92
|
+
/**
|
|
93
|
+
* Get current LSN
|
|
94
|
+
*/
|
|
95
|
+
getCurrentLsn(): number;
|
|
96
|
+
/**
|
|
97
|
+
* Get entries after a specific LSN (for recovery)
|
|
98
|
+
*/
|
|
99
|
+
getEntriesAfter(lsn: number): IWalEntry[];
|
|
100
|
+
/**
|
|
101
|
+
* Close the WAL
|
|
102
|
+
*/
|
|
103
|
+
close(): Promise<void>;
|
|
104
|
+
private appendEntry;
|
|
105
|
+
private serializeDocument;
|
|
106
|
+
private deserializeDocument;
|
|
107
|
+
private calculateChecksum;
|
|
108
|
+
private verifyChecksum;
|
|
109
|
+
/**
|
|
110
|
+
* Recover document from WAL entry
|
|
111
|
+
*/
|
|
112
|
+
recoverDocument(entry: IWalEntry): IStoredDocument | null;
|
|
113
|
+
/**
|
|
114
|
+
* Recover previous document state from WAL entry (for rollback)
|
|
115
|
+
*/
|
|
116
|
+
recoverPreviousDocument(entry: IWalEntry): IStoredDocument | null;
|
|
117
|
+
}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import * as plugins from '../tsmdb.plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Write-Ahead Log (WAL) for durability and crash recovery
|
|
4
|
+
*
|
|
5
|
+
* The WAL ensures durability by writing operations to a log file before
|
|
6
|
+
* they are applied to the main storage. On crash recovery, uncommitted
|
|
7
|
+
* operations can be replayed to restore the database to a consistent state.
|
|
8
|
+
*/
|
|
9
|
+
export class WAL {
|
|
10
|
+
walPath;
|
|
11
|
+
currentLsn = 0;
|
|
12
|
+
lastCheckpointLsn = 0;
|
|
13
|
+
entries = [];
|
|
14
|
+
isInitialized = false;
|
|
15
|
+
fs = new plugins.smartfs.SmartFs(new plugins.smartfs.SmartFsProviderNode());
|
|
16
|
+
// In-memory uncommitted entries per transaction
|
|
17
|
+
uncommittedTxns = new Map();
|
|
18
|
+
// Checkpoint interval (number of entries between checkpoints)
|
|
19
|
+
checkpointInterval = 1000;
|
|
20
|
+
constructor(walPath, options) {
|
|
21
|
+
this.walPath = walPath;
|
|
22
|
+
if (options?.checkpointInterval) {
|
|
23
|
+
this.checkpointInterval = options.checkpointInterval;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the WAL, loading existing entries and recovering if needed
|
|
28
|
+
*/
|
|
29
|
+
async initialize() {
|
|
30
|
+
if (this.isInitialized) {
|
|
31
|
+
return { recoveredEntries: [] };
|
|
32
|
+
}
|
|
33
|
+
// Ensure WAL directory exists
|
|
34
|
+
const walDir = this.walPath.substring(0, this.walPath.lastIndexOf('/'));
|
|
35
|
+
if (walDir) {
|
|
36
|
+
await this.fs.directory(walDir).recursive().create();
|
|
37
|
+
}
|
|
38
|
+
// Try to load existing WAL
|
|
39
|
+
const exists = await this.fs.file(this.walPath).exists();
|
|
40
|
+
if (exists) {
|
|
41
|
+
const content = await this.fs.file(this.walPath).encoding('utf8').read();
|
|
42
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
43
|
+
for (const line of lines) {
|
|
44
|
+
try {
|
|
45
|
+
const entry = JSON.parse(line);
|
|
46
|
+
// Verify checksum
|
|
47
|
+
if (this.verifyChecksum(entry)) {
|
|
48
|
+
this.entries.push(entry);
|
|
49
|
+
if (entry.lsn > this.currentLsn) {
|
|
50
|
+
this.currentLsn = entry.lsn;
|
|
51
|
+
}
|
|
52
|
+
if (entry.operation === 'checkpoint') {
|
|
53
|
+
this.lastCheckpointLsn = entry.lsn;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Skip corrupted entries
|
|
59
|
+
console.warn('Skipping corrupted WAL entry');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
this.isInitialized = true;
|
|
64
|
+
// Return entries after last checkpoint that need recovery
|
|
65
|
+
const recoveredEntries = this.entries.filter(e => e.lsn > this.lastCheckpointLsn &&
|
|
66
|
+
(e.operation === 'insert' || e.operation === 'update' || e.operation === 'delete'));
|
|
67
|
+
return { recoveredEntries };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Log an insert operation
|
|
71
|
+
*/
|
|
72
|
+
async logInsert(dbName, collName, doc, txnId) {
|
|
73
|
+
return this.appendEntry({
|
|
74
|
+
operation: 'insert',
|
|
75
|
+
dbName,
|
|
76
|
+
collName,
|
|
77
|
+
documentId: doc._id.toHexString(),
|
|
78
|
+
data: this.serializeDocument(doc),
|
|
79
|
+
txnId,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Log an update operation
|
|
84
|
+
*/
|
|
85
|
+
async logUpdate(dbName, collName, oldDoc, newDoc, txnId) {
|
|
86
|
+
return this.appendEntry({
|
|
87
|
+
operation: 'update',
|
|
88
|
+
dbName,
|
|
89
|
+
collName,
|
|
90
|
+
documentId: oldDoc._id.toHexString(),
|
|
91
|
+
data: this.serializeDocument(newDoc),
|
|
92
|
+
previousData: this.serializeDocument(oldDoc),
|
|
93
|
+
txnId,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Log a delete operation
|
|
98
|
+
*/
|
|
99
|
+
async logDelete(dbName, collName, doc, txnId) {
|
|
100
|
+
return this.appendEntry({
|
|
101
|
+
operation: 'delete',
|
|
102
|
+
dbName,
|
|
103
|
+
collName,
|
|
104
|
+
documentId: doc._id.toHexString(),
|
|
105
|
+
previousData: this.serializeDocument(doc),
|
|
106
|
+
txnId,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Log transaction begin
|
|
111
|
+
*/
|
|
112
|
+
async logBeginTransaction(txnId) {
|
|
113
|
+
this.uncommittedTxns.set(txnId, []);
|
|
114
|
+
return this.appendEntry({
|
|
115
|
+
operation: 'begin',
|
|
116
|
+
dbName: '',
|
|
117
|
+
collName: '',
|
|
118
|
+
documentId: '',
|
|
119
|
+
txnId,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Log transaction commit
|
|
124
|
+
*/
|
|
125
|
+
async logCommitTransaction(txnId) {
|
|
126
|
+
this.uncommittedTxns.delete(txnId);
|
|
127
|
+
return this.appendEntry({
|
|
128
|
+
operation: 'commit',
|
|
129
|
+
dbName: '',
|
|
130
|
+
collName: '',
|
|
131
|
+
documentId: '',
|
|
132
|
+
txnId,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Log transaction abort
|
|
137
|
+
*/
|
|
138
|
+
async logAbortTransaction(txnId) {
|
|
139
|
+
this.uncommittedTxns.delete(txnId);
|
|
140
|
+
return this.appendEntry({
|
|
141
|
+
operation: 'abort',
|
|
142
|
+
dbName: '',
|
|
143
|
+
collName: '',
|
|
144
|
+
documentId: '',
|
|
145
|
+
txnId,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get entries to roll back for an aborted transaction
|
|
150
|
+
*/
|
|
151
|
+
getTransactionEntries(txnId) {
|
|
152
|
+
return this.entries.filter(e => e.txnId === txnId);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Create a checkpoint - marks a consistent point in the log
|
|
156
|
+
*/
|
|
157
|
+
async checkpoint() {
|
|
158
|
+
const lsn = await this.appendEntry({
|
|
159
|
+
operation: 'checkpoint',
|
|
160
|
+
dbName: '',
|
|
161
|
+
collName: '',
|
|
162
|
+
documentId: '',
|
|
163
|
+
});
|
|
164
|
+
this.lastCheckpointLsn = lsn;
|
|
165
|
+
// Truncate old entries (keep only entries after checkpoint)
|
|
166
|
+
await this.truncate();
|
|
167
|
+
return lsn;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Truncate the WAL file, removing entries before the last checkpoint
|
|
171
|
+
*/
|
|
172
|
+
async truncate() {
|
|
173
|
+
// Keep entries after last checkpoint
|
|
174
|
+
const newEntries = this.entries.filter(e => e.lsn >= this.lastCheckpointLsn);
|
|
175
|
+
this.entries = newEntries;
|
|
176
|
+
// Rewrite the WAL file
|
|
177
|
+
const lines = this.entries.map(e => JSON.stringify(e)).join('\n');
|
|
178
|
+
await this.fs.file(this.walPath).encoding('utf8').write(lines);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get current LSN
|
|
182
|
+
*/
|
|
183
|
+
getCurrentLsn() {
|
|
184
|
+
return this.currentLsn;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Get entries after a specific LSN (for recovery)
|
|
188
|
+
*/
|
|
189
|
+
getEntriesAfter(lsn) {
|
|
190
|
+
return this.entries.filter(e => e.lsn > lsn);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Close the WAL
|
|
194
|
+
*/
|
|
195
|
+
async close() {
|
|
196
|
+
if (this.isInitialized) {
|
|
197
|
+
// Final checkpoint before close
|
|
198
|
+
await this.checkpoint();
|
|
199
|
+
}
|
|
200
|
+
this.isInitialized = false;
|
|
201
|
+
}
|
|
202
|
+
// ============================================================================
|
|
203
|
+
// Private Methods
|
|
204
|
+
// ============================================================================
|
|
205
|
+
async appendEntry(partial) {
|
|
206
|
+
await this.initialize();
|
|
207
|
+
this.currentLsn++;
|
|
208
|
+
const entry = {
|
|
209
|
+
...partial,
|
|
210
|
+
lsn: this.currentLsn,
|
|
211
|
+
timestamp: Date.now(),
|
|
212
|
+
checksum: 0, // Will be calculated
|
|
213
|
+
};
|
|
214
|
+
// Calculate checksum
|
|
215
|
+
entry.checksum = this.calculateChecksum(entry);
|
|
216
|
+
// Track in transaction if applicable
|
|
217
|
+
if (partial.txnId && this.uncommittedTxns.has(partial.txnId)) {
|
|
218
|
+
this.uncommittedTxns.get(partial.txnId).push(entry);
|
|
219
|
+
}
|
|
220
|
+
// Add to in-memory log
|
|
221
|
+
this.entries.push(entry);
|
|
222
|
+
// Append to file (append mode for durability)
|
|
223
|
+
await this.fs.file(this.walPath).encoding('utf8').append(JSON.stringify(entry) + '\n');
|
|
224
|
+
// Check if we need a checkpoint
|
|
225
|
+
if (this.entries.length - this.lastCheckpointLsn >= this.checkpointInterval) {
|
|
226
|
+
await this.checkpoint();
|
|
227
|
+
}
|
|
228
|
+
return entry.lsn;
|
|
229
|
+
}
|
|
230
|
+
serializeDocument(doc) {
|
|
231
|
+
// Serialize document to BSON and encode as base64
|
|
232
|
+
const bsonData = plugins.bson.serialize(doc);
|
|
233
|
+
return Buffer.from(bsonData).toString('base64');
|
|
234
|
+
}
|
|
235
|
+
deserializeDocument(data) {
|
|
236
|
+
// Decode base64 and deserialize from BSON
|
|
237
|
+
const buffer = Buffer.from(data, 'base64');
|
|
238
|
+
return plugins.bson.deserialize(buffer);
|
|
239
|
+
}
|
|
240
|
+
calculateChecksum(entry) {
|
|
241
|
+
// Simple CRC32-like checksum
|
|
242
|
+
const str = JSON.stringify({
|
|
243
|
+
lsn: entry.lsn,
|
|
244
|
+
timestamp: entry.timestamp,
|
|
245
|
+
operation: entry.operation,
|
|
246
|
+
dbName: entry.dbName,
|
|
247
|
+
collName: entry.collName,
|
|
248
|
+
documentId: entry.documentId,
|
|
249
|
+
data: entry.data,
|
|
250
|
+
previousData: entry.previousData,
|
|
251
|
+
txnId: entry.txnId,
|
|
252
|
+
});
|
|
253
|
+
let crc = 0xFFFFFFFF;
|
|
254
|
+
for (let i = 0; i < str.length; i++) {
|
|
255
|
+
crc ^= str.charCodeAt(i);
|
|
256
|
+
for (let j = 0; j < 8; j++) {
|
|
257
|
+
crc = (crc >>> 1) ^ (crc & 1 ? 0xEDB88320 : 0);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return (~crc) >>> 0;
|
|
261
|
+
}
|
|
262
|
+
verifyChecksum(entry) {
|
|
263
|
+
const savedChecksum = entry.checksum;
|
|
264
|
+
entry.checksum = 0;
|
|
265
|
+
const calculatedChecksum = this.calculateChecksum(entry);
|
|
266
|
+
entry.checksum = savedChecksum;
|
|
267
|
+
return calculatedChecksum === savedChecksum;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Recover document from WAL entry
|
|
271
|
+
*/
|
|
272
|
+
recoverDocument(entry) {
|
|
273
|
+
if (!entry.data)
|
|
274
|
+
return null;
|
|
275
|
+
return this.deserializeDocument(entry.data);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Recover previous document state from WAL entry (for rollback)
|
|
279
|
+
*/
|
|
280
|
+
recoverPreviousDocument(entry) {
|
|
281
|
+
if (!entry.previousData)
|
|
282
|
+
return null;
|
|
283
|
+
return this.deserializeDocument(entry.previousData);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiV0FMLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHMvdHNtZGIvc3RvcmFnZS9XQUwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxxQkFBcUIsQ0FBQztBQTJDL0M7Ozs7OztHQU1HO0FBQ0gsTUFBTSxPQUFPLEdBQUc7SUFDTixPQUFPLENBQVM7SUFDaEIsVUFBVSxHQUFXLENBQUMsQ0FBQztJQUN2QixpQkFBaUIsR0FBVyxDQUFDLENBQUM7SUFDOUIsT0FBTyxHQUFnQixFQUFFLENBQUM7SUFDMUIsYUFBYSxHQUFZLEtBQUssQ0FBQztJQUMvQixFQUFFLEdBQUcsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsbUJBQW1CLEVBQUUsQ0FBQyxDQUFDO0lBRXBGLGdEQUFnRDtJQUN4QyxlQUFlLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7SUFFOUQsOERBQThEO0lBQ3RELGtCQUFrQixHQUFXLElBQUksQ0FBQztJQUUxQyxZQUFZLE9BQWUsRUFBRSxPQUF5QztRQUNwRSxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxDQUFDO1lBQ2hDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsa0JBQWtCLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7WUFDdkIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLEVBQUUsRUFBRSxDQUFDO1FBQ2xDLENBQUM7UUFFRCw4QkFBOEI7UUFDOUIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEdBQUcs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
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// @push.rocks scope
|
|
2
|
+
import * as smartfs from '@push.rocks/smartfs';
|
|
3
|
+
import * as smartpath from '@push.rocks/smartpath';
|
|
4
|
+
import * as smartpromise from '@push.rocks/smartpromise';
|
|
5
|
+
import * as smartrx from '@push.rocks/smartrx';
|
|
6
|
+
export { smartfs, smartpath, smartpromise, smartrx };
|
|
7
|
+
// thirdparty
|
|
8
|
+
import * as bson from 'bson';
|
|
9
|
+
import * as mingo from 'mingo';
|
|
10
|
+
export { bson, mingo };
|
|
11
|
+
// Re-export commonly used mingo classes
|
|
12
|
+
export { Query } from 'mingo';
|
|
13
|
+
export { Aggregator } from 'mingo';
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHNtZGIucGx1Z2lucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL3RzbWRiL3RzbWRiLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0JBQW9CO0FBQ3BCLE9BQU8sS0FBSyxPQUFPLE1BQU0scUJBQXFCLENBQUM7QUFDL0MsT0FBTyxLQUFLLFNBQVMsTUFBTSx1QkFBdUIsQ0FBQztBQUNuRCxPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxPQUFPLE1BQU0scUJBQXFCLENBQUM7QUFFL0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBRXJELGFBQWE7QUFDYixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEtBQUssS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUUvQixPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDO0FBRXZCLHdDQUF3QztBQUN4QyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQzlCLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxPQUFPLENBQUMifQ==
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type * as plugins from '../
|
|
1
|
+
import type * as plugins from '../tsmdb.plugins.js';
|
|
2
2
|
export type Document = Record<string, any>;
|
|
3
3
|
export interface WithId<TSchema> {
|
|
4
4
|
_id: plugins.bson.ObjectId;
|
|
5
5
|
}
|
|
6
|
-
export interface
|
|
6
|
+
export interface ITsmdbClientOptions {
|
|
7
7
|
/** Storage adapter type: 'memory' or 'file' */
|
|
8
8
|
storageType?: 'memory' | 'file';
|
|
9
9
|
/** Path for file-based storage */
|
|
@@ -14,7 +14,7 @@ export interface ICongoClientOptions {
|
|
|
14
14
|
persistPath?: string;
|
|
15
15
|
}
|
|
16
16
|
export interface IParsedConnectionString {
|
|
17
|
-
protocol: '
|
|
17
|
+
protocol: 'tsmdb';
|
|
18
18
|
storageType: 'memory' | 'file';
|
|
19
19
|
options: {
|
|
20
20
|
persist?: string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export {};
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
2
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3RzL3RzbWRiL3R5cGVzL2ludGVyZmFjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiJ9
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRC32 checksum utilities for data integrity
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Calculate CRC32 checksum for a string
|
|
6
|
+
*/
|
|
7
|
+
export declare function calculateCRC32(data: string): number;
|
|
8
|
+
/**
|
|
9
|
+
* Calculate CRC32 checksum for a Buffer
|
|
10
|
+
*/
|
|
11
|
+
export declare function calculateCRC32Buffer(data: Buffer): number;
|
|
12
|
+
/**
|
|
13
|
+
* Calculate checksum for a document (serialized as JSON)
|
|
14
|
+
*/
|
|
15
|
+
export declare function calculateDocumentChecksum(doc: Record<string, any>): number;
|
|
16
|
+
/**
|
|
17
|
+
* Add checksum to a document
|
|
18
|
+
*/
|
|
19
|
+
export declare function addChecksum<T extends Record<string, any>>(doc: T): T & {
|
|
20
|
+
_checksum: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Verify checksum of a document
|
|
24
|
+
* Returns true if checksum is valid or if document has no checksum
|
|
25
|
+
*/
|
|
26
|
+
export declare function verifyChecksum(doc: Record<string, any>): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Remove checksum from a document
|
|
29
|
+
*/
|
|
30
|
+
export declare function removeChecksum<T extends Record<string, any>>(doc: T): Omit<T, '_checksum'>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CRC32 checksum utilities for data integrity
|
|
3
|
+
*/
|
|
4
|
+
// CRC32 lookup table
|
|
5
|
+
const CRC32_TABLE = [];
|
|
6
|
+
// Initialize the CRC32 table
|
|
7
|
+
function initCRC32Table() {
|
|
8
|
+
if (CRC32_TABLE.length > 0)
|
|
9
|
+
return;
|
|
10
|
+
for (let i = 0; i < 256; i++) {
|
|
11
|
+
let crc = i;
|
|
12
|
+
for (let j = 0; j < 8; j++) {
|
|
13
|
+
crc = (crc & 1) ? (0xEDB88320 ^ (crc >>> 1)) : (crc >>> 1);
|
|
14
|
+
}
|
|
15
|
+
CRC32_TABLE[i] = crc >>> 0;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Calculate CRC32 checksum for a string
|
|
20
|
+
*/
|
|
21
|
+
export function calculateCRC32(data) {
|
|
22
|
+
initCRC32Table();
|
|
23
|
+
let crc = 0xFFFFFFFF;
|
|
24
|
+
for (let i = 0; i < data.length; i++) {
|
|
25
|
+
const byte = data.charCodeAt(i) & 0xFF;
|
|
26
|
+
crc = CRC32_TABLE[(crc ^ byte) & 0xFF] ^ (crc >>> 8);
|
|
27
|
+
}
|
|
28
|
+
return (~crc) >>> 0;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Calculate CRC32 checksum for a Buffer
|
|
32
|
+
*/
|
|
33
|
+
export function calculateCRC32Buffer(data) {
|
|
34
|
+
initCRC32Table();
|
|
35
|
+
let crc = 0xFFFFFFFF;
|
|
36
|
+
for (let i = 0; i < data.length; i++) {
|
|
37
|
+
crc = CRC32_TABLE[(crc ^ data[i]) & 0xFF] ^ (crc >>> 8);
|
|
38
|
+
}
|
|
39
|
+
return (~crc) >>> 0;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Calculate checksum for a document (serialized as JSON)
|
|
43
|
+
*/
|
|
44
|
+
export function calculateDocumentChecksum(doc) {
|
|
45
|
+
// Exclude _checksum field from calculation
|
|
46
|
+
const { _checksum, ...docWithoutChecksum } = doc;
|
|
47
|
+
const json = JSON.stringify(docWithoutChecksum);
|
|
48
|
+
return calculateCRC32(json);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Add checksum to a document
|
|
52
|
+
*/
|
|
53
|
+
export function addChecksum(doc) {
|
|
54
|
+
const checksum = calculateDocumentChecksum(doc);
|
|
55
|
+
return { ...doc, _checksum: checksum };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Verify checksum of a document
|
|
59
|
+
* Returns true if checksum is valid or if document has no checksum
|
|
60
|
+
*/
|
|
61
|
+
export function verifyChecksum(doc) {
|
|
62
|
+
if (!('_checksum' in doc)) {
|
|
63
|
+
// No checksum to verify
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
const storedChecksum = doc._checksum;
|
|
67
|
+
const calculatedChecksum = calculateDocumentChecksum(doc);
|
|
68
|
+
return storedChecksum === calculatedChecksum;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Remove checksum from a document
|
|
72
|
+
*/
|
|
73
|
+
export function removeChecksum(doc) {
|
|
74
|
+
const { _checksum, ...docWithoutChecksum } = doc;
|
|
75
|
+
return docWithoutChecksum;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hlY2tzdW0uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy90c21kYi91dGlscy9jaGVja3N1bS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILHFCQUFxQjtBQUNyQixNQUFNLFdBQVcsR0FBYSxFQUFFLENBQUM7QUFFakMsNkJBQTZCO0FBQzdCLFNBQVMsY0FBYztJQUNyQixJQUFJLFdBQVcsQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLE9BQU87SUFFbkMsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQzdCLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNaLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUMzQixHQUFHLEdBQUcsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQzdELENBQUM7UUFDRCxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxLQUFLLENBQUMsQ0FBQztJQUM3QixDQUFDO0FBQ0gsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxJQUFZO0lBQ3pDLGNBQWMsRUFBRSxDQUFDO0lBRWpCLElBQUksR0FBRyxHQUFHLFVBQVUsQ0FBQztJQUNyQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ3JDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO1FBQ3ZDLEdBQUcsR0FBRyxXQUFXLENBQUMsQ0FBQyxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUNELE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUN0QixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsb0JBQW9CLENBQUMsSUFBWTtJQUMvQyxjQUFjLEVBQUUsQ0FBQztJQUVqQixJQUFJLEdBQUcsR0FBRyxVQUFVLENBQUM7SUFDckIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNyQyxHQUFHLEdBQUcsV0FBVyxDQUFDLENBQUMsR0FBRyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQzFELENBQUM7SUFDRCxPQUFPLENBQUMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDdEIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLHlCQUF5QixDQUFDLEdBQXdCO0lBQ2hFLDJDQUEyQztJQUMzQyxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsa0JBQWtCLEVBQUUsR0FBRyxHQUFHLENBQUM7SUFDakQsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0lBQ2hELE9BQU8sY0FBYyxDQUFDLElBQUksQ0FBQyxDQUFDO0FBQzlCLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQWdDLEdBQU07SUFDL0QsTUFBTSxRQUFRLEdBQUcseUJBQXlCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEQsT0FBTyxFQUFFLEdBQUcsR0FBRyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBQztBQUN6QyxDQUFDO0FBRUQ7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxHQUF3QjtJQUNyRCxJQUFJLENBQUMsQ0FBQyxXQUFXLElBQUksR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUMxQix3QkFBd0I7UUFDeEIsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsTUFBTSxjQUFjLEdBQUcsR0FBRyxDQUFDLFNBQVMsQ0FBQztJQUNyQyxNQUFNLGtCQUFrQixHQUFHLHlCQUF5QixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRTFELE9BQU8sY0FBYyxLQUFLLGtCQUFrQixDQUFDO0FBQy9DLENBQUM7QUFFRDs7R0FFRztBQUNILE1BQU0sVUFBVSxjQUFjLENBQWdDLEdBQU07SUFDbEUsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLGtCQUFrQixFQUFFLEdBQUcsR0FBRyxDQUFDO0lBQ2pELE9BQU8sa0JBQTBDLENBQUM7QUFDcEQsQ0FBQyJ9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './checksum.js';
|
package/package.json
CHANGED
package/readme.hints.md
CHANGED
|
@@ -9,21 +9,21 @@
|
|
|
9
9
|
- **Why:** Deno wraps CommonJS exports in a `default` property, so default imports are required
|
|
10
10
|
- Fixed in version 2.0.13 (changed from `import * as mongoPlugin`)
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## TsmDB - MongoDB Wire Protocol Server
|
|
13
13
|
|
|
14
14
|
### Architecture
|
|
15
|
-
|
|
15
|
+
TsmDB implements the MongoDB binary wire protocol (OP_MSG, OP_QUERY) allowing official MongoDB drivers to connect directly.
|
|
16
16
|
|
|
17
17
|
```
|
|
18
|
-
Official MongoClient → TCP (wire protocol) →
|
|
18
|
+
Official MongoClient → TCP (wire protocol) → TsmdbServer → Engines → Storage
|
|
19
19
|
(mongodb npm) OP_MSG/BSON (port)
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
### Module Structure
|
|
23
23
|
```
|
|
24
|
-
ts/
|
|
24
|
+
ts/tsmdb/
|
|
25
25
|
├── server/ # Wire protocol server
|
|
26
|
-
│ ├──
|
|
26
|
+
│ ├── TsmdbServer.ts # TCP server, connection handling
|
|
27
27
|
│ ├── WireProtocol.ts # OP_MSG/OP_QUERY parsing & encoding
|
|
28
28
|
│ ├── CommandRouter.ts # Route commands to handlers
|
|
29
29
|
│ └── handlers/ # Command implementations
|
|
@@ -53,11 +53,11 @@ ts/congodb/
|
|
|
53
53
|
|
|
54
54
|
### Usage Example
|
|
55
55
|
```typescript
|
|
56
|
-
import {
|
|
56
|
+
import { TsmdbServer } from '@push.rocks/smartmongo/tsmdb';
|
|
57
57
|
import { MongoClient } from 'mongodb';
|
|
58
58
|
|
|
59
59
|
// Start server
|
|
60
|
-
const server = new
|
|
60
|
+
const server = new TsmdbServer({ port: 27117 });
|
|
61
61
|
await server.start();
|
|
62
62
|
|
|
63
63
|
// Connect with official MongoDB driver
|
|
@@ -82,8 +82,3 @@ await server.stop();
|
|
|
82
82
|
- **Aggregation**: aggregate, count, distinct
|
|
83
83
|
- **Indexes**: createIndexes, dropIndexes, listIndexes
|
|
84
84
|
- **Admin**: ping, listDatabases, listCollections, drop, dropDatabase, create, serverStatus, buildInfo
|
|
85
|
-
|
|
86
|
-
### Notes
|
|
87
|
-
- The old CongoClient/CongoDb/CongoCollection classes have been removed
|
|
88
|
-
- Use the official `mongodb` npm package's MongoClient instead
|
|
89
|
-
- Server supports MongoDB wire protocol versions 0-21 (MongoDB 3.6 through 7.0 compatible)
|