mongolite-ts 0.4.0 → 0.6.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 CHANGED
@@ -16,6 +16,49 @@ A MongoDB-like client that uses SQLite as its underlying persistent store. Writt
16
16
  * Written in TypeScript with strong typing.
17
17
  * 100% test coverage (aiming for).
18
18
  * **Interactive Query Debugger** - Debug complex queries with `npx mongolite-debug`
19
+ * **JSON Safety & Data Integrity** - Comprehensive protection against malformed JSON and data corruption
20
+ * **Change Streams** - Real-time change tracking similar to MongoDB's `changeStream = collection.watch()`
21
+
22
+ ## JSON Safety & Data Integrity
23
+
24
+ MongoLite includes robust safeguards to prevent and handle malformed JSON data that could cause application failures or data corruption:
25
+
26
+ ### Document Validation
27
+ - **Pre-storage validation**: Automatically validates documents before insertion to prevent storing invalid data
28
+ - **Type safety**: Rejects non-JSON-serializable data (functions, symbols, BigInt, RegExp, circular references)
29
+ - **Round-trip verification**: Ensures all data can be safely stored and retrieved
30
+
31
+ ### Malformed JSON Recovery
32
+ - **Graceful degradation**: Handles corrupted JSON data without crashing your application
33
+ - **Automatic recovery**: Attempts to fix common JSON corruption issues (escaped quotes, backslashes)
34
+ - **Fallback objects**: Returns special marker objects for unrecoverable data with debugging information
35
+ - **Error logging**: Detailed logging for debugging and monitoring data integrity issues
36
+
37
+ ### Example Usage
38
+
39
+ ```typescript
40
+ // Document validation prevents invalid data
41
+ try {
42
+ await collection.insertOne({
43
+ name: 'user',
44
+ invalidFunction: () => 'not allowed' // This will be rejected
45
+ });
46
+ } catch (error) {
47
+ console.log('Validation error:', error.message);
48
+ // "Cannot insert document: Document validation failed: Functions are not allowed in documents"
49
+ }
50
+
51
+ // Corrupted data recovery
52
+ const doc = await collection.findOne({ _id: 'some-id' });
53
+ if (doc && '__mongoLiteCorrupted' in doc) {
54
+ console.log('Found corrupted document');
55
+ console.log('Original data:', doc.__originalData);
56
+ console.log('Error details:', doc.__error);
57
+ // Handle corruption appropriately
58
+ }
59
+ ```
60
+
61
+ For detailed information about JSON safety features, see [JSON_SAFETY.md](./docs/JSON_SAFETY.md).
19
62
 
20
63
  ## Installation
21
64
 
@@ -113,6 +156,154 @@ async function main() {
113
156
  main();
114
157
  ```
115
158
 
159
+ ## Change Streams
160
+
161
+ MongoLite supports real-time change tracking through change streams, similar to MongoDB's `collection.watch()` feature. Change streams allow you to monitor and react to data changes (inserts, updates, deletes) in real-time.
162
+
163
+ ### Basic Usage
164
+
165
+ ```typescript
166
+ import { MongoLite } from 'mongolite-ts';
167
+
168
+ const client = new MongoLite('./mydatabase.sqlite');
169
+ const collection = client.collection('users');
170
+
171
+ // Create a change stream
172
+ const changeStream = collection.watch({
173
+ fullDocument: 'updateLookup', // Include full document on updates
174
+ fullDocumentBeforeChange: 'whenAvailable' // Include document before change
175
+ });
176
+
177
+ // Listen for changes
178
+ changeStream.on('change', (change) => {
179
+ console.log('Change detected:', {
180
+ operation: change.operationType, // 'insert', 'update', 'delete'
181
+ documentId: change.documentKey._id,
182
+ collection: change.ns.coll,
183
+ timestamp: change.clusterTime
184
+ });
185
+
186
+ if (change.fullDocument) {
187
+ console.log('New document state:', change.fullDocument);
188
+ }
189
+
190
+ if (change.updateDescription) {
191
+ console.log('Updated fields:', change.updateDescription.updatedFields);
192
+ console.log('Removed fields:', change.updateDescription.removedFields);
193
+ }
194
+ });
195
+
196
+ // Handle errors
197
+ changeStream.on('error', (error) => {
198
+ console.error('Change stream error:', error);
199
+ });
200
+
201
+ // Perform operations - changes will be captured
202
+ await collection.insertOne({ name: 'Alice', age: 30 });
203
+ await collection.updateOne({ name: 'Alice' }, { $set: { age: 31 } });
204
+ await collection.deleteOne({ name: 'Alice' });
205
+
206
+ // Close the change stream when done
207
+ changeStream.close();
208
+ ```
209
+
210
+ ### Async Iteration
211
+
212
+ Change streams support async iteration for a more declarative approach:
213
+
214
+ ```typescript
215
+ const changeStream = collection.watch();
216
+
217
+ // Use async iteration
218
+ for await (const change of changeStream) {
219
+ console.log('Change detected:', change.operationType);
220
+
221
+ // Process the change...
222
+
223
+ // Break after processing some changes
224
+ if (someCondition) {
225
+ changeStream.close();
226
+ break;
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### Change Stream Options
232
+
233
+ ```typescript
234
+ interface ChangeStreamOptions {
235
+ // Filter to apply to change events
236
+ filter?: Filter<ChangeStreamDocument>;
237
+
238
+ // Whether to include the full document in insert and update operations
239
+ fullDocument?: 'default' | 'updateLookup' | 'whenAvailable' | 'required';
240
+
241
+ // Whether to include the full document before the change
242
+ fullDocumentBeforeChange?: 'off' | 'whenAvailable' | 'required';
243
+
244
+ // Maximum number of events to buffer
245
+ maxBufferSize?: number;
246
+ }
247
+
248
+ // Example with options
249
+ const changeStream = collection.watch({
250
+ fullDocument: 'updateLookup',
251
+ fullDocumentBeforeChange: 'whenAvailable',
252
+ maxBufferSize: 500
253
+ });
254
+ ```
255
+
256
+ ### Change Document Structure
257
+
258
+ Each change event contains detailed information about the operation:
259
+
260
+ ```typescript
261
+ interface ChangeStreamDocument {
262
+ _id: string; // Unique change event ID
263
+ operationType: 'insert' | 'update' | 'delete' | 'replace';
264
+ clusterTime?: Date; // Timestamp of the change
265
+ fullDocument?: T; // Full document (based on options)
266
+ fullDocumentBeforeChange?: T; // Document before change (based on options)
267
+ documentKey: { _id: string }; // ID of the affected document
268
+ ns: { // Namespace information
269
+ db: string; // Database name
270
+ coll: string; // Collection name
271
+ };
272
+ updateDescription?: { // Update details (for update operations)
273
+ updatedFields: Record<string, unknown>;
274
+ removedFields: string[];
275
+ };
276
+ }
277
+ ```
278
+
279
+ ### Implementation Details
280
+
281
+ - **SQLite Triggers**: Uses SQLite triggers to capture changes automatically
282
+ - **Change Log Table**: Stores change events in a dedicated `__mongolite_changes__` table
283
+ - **Polling**: Efficiently polls for new changes every 100ms
284
+ - **Cleanup**: Automatically cleans up triggers when change streams are closed
285
+ - **Error Handling**: Robust error handling for database operations and malformed data
286
+
287
+ ### Best Practices
288
+
289
+ 1. **Close Change Streams**: Always close change streams when done to free resources
290
+ 2. **Error Handling**: Implement proper error handling for change stream events
291
+ 3. **Buffer Management**: Consider the `maxBufferSize` option for high-volume scenarios
292
+ 4. **Cleanup**: Call `changeStream.cleanup()` to remove triggers if needed
293
+
294
+ ```typescript
295
+ // Proper cleanup
296
+ try {
297
+ const changeStream = collection.watch();
298
+
299
+ // ... use change stream
300
+
301
+ } finally {
302
+ changeStream.close();
303
+ await changeStream.cleanup(); // Remove triggers if needed
304
+ }
305
+ ```
306
+
116
307
  ## Query Debugger
117
308
 
118
309
  MongoLite includes an interactive query debugger to help you debug complex queries and understand how MongoDB-style filters are converted to SQL.
@@ -214,6 +405,38 @@ Deletes a single document matching the filter.
214
405
  * `filter`: The selection criteria for the deletion.
215
406
  * Returns `DeleteResult`: `{ acknowledged: boolean; deletedCount: number; }`.
216
407
 
408
+ #### `watch(options?: ChangeStreamOptions<T>): ChangeStream<T>`
409
+
410
+ Opens a change stream to watch for changes on this collection. Returns a ChangeStream that emits events when documents are inserted, updated, or deleted.
411
+
412
+ * `options`: Optional configuration for the change stream
413
+ * `fullDocument`: Controls when to include the full document ('default', 'updateLookup', 'whenAvailable', 'required')
414
+ * `fullDocumentBeforeChange`: Controls when to include the document before change ('off', 'whenAvailable', 'required')
415
+ * `maxBufferSize`: Maximum number of events to buffer (default: 1000)
416
+ * Returns a `ChangeStream` instance that extends EventEmitter and supports async iteration.
417
+
418
+ ```typescript
419
+ // Basic change stream
420
+ const changeStream = collection.watch();
421
+ changeStream.on('change', (change) => {
422
+ console.log('Change detected:', change);
423
+ });
424
+
425
+ // With options
426
+ const changeStream = collection.watch({
427
+ fullDocument: 'updateLookup',
428
+ fullDocumentBeforeChange: 'whenAvailable'
429
+ });
430
+
431
+ // Async iteration
432
+ for await (const change of changeStream) {
433
+ console.log('Change:', change.operationType);
434
+ }
435
+
436
+ // Always close when done
437
+ changeStream.close();
438
+ ```
439
+
217
440
 
218
441
  ### `FindCursor<T>`
219
442
 
@@ -71,7 +71,7 @@ async function main() {
71
71
  'database.db',
72
72
  'database.sqlite',
73
73
  'app.db',
74
- 'app.sqlite'
74
+ 'app.sqlite',
75
75
  ];
76
76
  // Check if any common database files exist
77
77
  const { existsSync } = await import('fs');
@@ -108,7 +108,7 @@ async function main() {
108
108
  process.exit(1);
109
109
  }
110
110
  }
111
- main().catch(error => {
111
+ main().catch((error) => {
112
112
  console.error('Unexpected error:', error);
113
113
  process.exit(1);
114
114
  });
@@ -1 +1 @@
1
- {"version":3,"file":"mongolite-debug.js","sourceRoot":"","sources":["../../src/bin/mongolite-debug.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mongolite-debug.js","sourceRoot":"","sources":["../../src/bin/mongolite-debug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,114 @@
1
+ import { EventEmitter } from 'events';
2
+ import { SQLiteDB } from './db.js';
3
+ import { DocumentWithId, Filter } from './types.js';
4
+ export type ChangeOperationType = 'insert' | 'update' | 'delete' | 'replace';
5
+ export interface ChangeStreamDocument<T extends DocumentWithId = DocumentWithId> {
6
+ _id: string;
7
+ operationType: ChangeOperationType;
8
+ clusterTime?: Date;
9
+ fullDocument?: T;
10
+ fullDocumentBeforeChange?: T;
11
+ documentKey: {
12
+ _id: string;
13
+ };
14
+ ns: {
15
+ db: string;
16
+ coll: string;
17
+ };
18
+ updateDescription?: {
19
+ updatedFields: Record<string, unknown>;
20
+ removedFields: string[];
21
+ };
22
+ }
23
+ export interface ChangeStreamOptions<T extends DocumentWithId = DocumentWithId> {
24
+ /**
25
+ * Filter to apply to change events
26
+ */
27
+ filter?: Filter<ChangeStreamDocument<T>>;
28
+ /**
29
+ * Whether to include the full document in insert and update operations
30
+ */
31
+ fullDocument?: 'default' | 'updateLookup' | 'whenAvailable' | 'required';
32
+ /**
33
+ * Whether to include the full document before the change for update operations
34
+ */
35
+ fullDocumentBeforeChange?: 'off' | 'whenAvailable' | 'required';
36
+ /**
37
+ * Resume token for resuming change streams (not implemented in this version)
38
+ */
39
+ resumeAfter?: string;
40
+ /**
41
+ * Maximum number of events to buffer
42
+ */
43
+ maxBufferSize?: number;
44
+ }
45
+ export declare class ChangeStream<T extends DocumentWithId = DocumentWithId> extends EventEmitter {
46
+ private readonly db;
47
+ private readonly collectionName;
48
+ private readonly options;
49
+ private closed;
50
+ private pollInterval;
51
+ private lastProcessedId;
52
+ private buffer;
53
+ private readonly maxBufferSize;
54
+ constructor(db: SQLiteDB, collectionName: string, options?: ChangeStreamOptions<T>);
55
+ /**
56
+ * Sets up the change tracking infrastructure
57
+ */
58
+ private setupChangeTracking;
59
+ /**
60
+ * Creates the change log table if it doesn't exist
61
+ */
62
+ private ensureChangeLogTable;
63
+ /**
64
+ * Sets up triggers for tracking changes on the collection
65
+ */
66
+ private setupTriggers;
67
+ /**
68
+ * Starts polling for new changes
69
+ */
70
+ private startPolling;
71
+ /**
72
+ * Polls for new changes from the change log
73
+ */
74
+ private pollForChanges;
75
+ /**
76
+ * Transforms a raw change event from the database into a ChangeStreamDocument
77
+ */
78
+ private transformChangeEvent;
79
+ /**
80
+ * Computes the update description by comparing before and after documents
81
+ */
82
+ private computeUpdateDescription;
83
+ /**
84
+ * Determines if the full document should be included
85
+ */
86
+ private shouldIncludeFullDocument;
87
+ /**
88
+ * Determines if the full document before change should be included
89
+ */
90
+ private shouldIncludeFullDocumentBefore;
91
+ /**
92
+ * Checks if a change document passes the filter
93
+ */
94
+ private passesFilter;
95
+ /**
96
+ * Returns an async iterator for the change stream
97
+ */
98
+ [Symbol.asyncIterator](): AsyncIterableIterator<ChangeStreamDocument<T>>;
99
+ /**
100
+ * Closes the change stream
101
+ */
102
+ close(): void;
103
+ /**
104
+ * Returns the next change document
105
+ */
106
+ next(): Promise<{
107
+ value: ChangeStreamDocument<T>;
108
+ done: boolean;
109
+ }>;
110
+ /**
111
+ * Cleanup triggers when the change stream is destroyed
112
+ */
113
+ cleanup(): Promise<void>;
114
+ }