nodejs-json-db 0.0.1 โ†’ 0.0.2

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
@@ -4,19 +4,21 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- A production-ready, lightweight JSON-based database for Node.js and Electron applications. Zero external database dependencies, fully typed, with a MongoDB-like query API and optional high-concurrency mode.
7
+ A production-ready, lightweight JSON-based database for Node.js and Electron applications. Zero external database dependencies, fully typed, with a MongoDB-like query API. Supports three storage modes: Standard, High-Concurrency, and Lazy Loading.
8
8
 
9
9
  ## โœจ Features
10
10
 
11
11
  - ๐Ÿš€ **Zero Dependencies** - No external database server required
12
12
  - ๐Ÿ“ฆ **Dual Module Support** - Works with both ESM and CommonJS
13
13
  - ๐Ÿ”’ **Type-Safe** - Full TypeScript support with generics
14
- - ๐Ÿ” **MongoDB-like Queries** - Familiar query operators (`$eq`, `$gt`, `$in`, `$regex`, etc.)
14
+ - ๐Ÿ” **MongoDB-like Queries** - Rich query operators (`$eq`, `$gt`, `$in`, `$regex`, `$all`, `$elemMatch`, etc.)
15
+ - ๐ŸŽฏ **Field Projection** - Select which fields to return in queries
15
16
  - โšก **High Performance** - Memory caching with atomic file writes
16
17
  - ๐Ÿ”„ **High-Concurrency Mode** - Partitioned storage with write batching for massive throughput
18
+ - ๐Ÿ’พ **Lazy Loading Mode** - Memory-efficient storage for huge datasets with LRU caching
17
19
  - โœ… **Schema Validation** - Optional Zod integration for document validation
18
20
  - ๐Ÿ–ฅ๏ธ **Electron Ready** - Perfect for desktop applications
19
- - ๐Ÿงช **Well Tested** - 107 tests with comprehensive coverage
21
+ - ๐Ÿงช **Well Tested** - 141 tests with comprehensive coverage
20
22
 
21
23
  ## ๐Ÿ“ฆ Installation
22
24
 
@@ -29,6 +31,7 @@ yarn add nodejs-json-db
29
31
  ```
30
32
 
31
33
  For schema validation (optional):
34
+
32
35
  ```bash
33
36
  npm install zod
34
37
  ```
@@ -75,21 +78,22 @@ Performance tested with documents up to 1 million records:
75
78
 
76
79
  ### Write Performance (insertMany)
77
80
 
78
- | Documents | Standard Mode | High-Concurrency Mode |
79
- |-----------|---------------|----------------------|
80
- | 100,000 | 390K docs/sec (56 MB/s) | 355K docs/sec (51 MB/s) |
81
- | 500,000 | 382K docs/sec (55 MB/s) | **423K docs/sec (61 MB/s)** โœ… |
82
- | 1,000,000 | 392K docs/sec (56 MB/s) | **392K docs/sec (56 MB/s)** |
81
+ | Documents | Standard Mode | High-Concurrency Mode |
82
+ | --------- | ----------------------- | ------------------------------ |
83
+ | 100,000 | 390K docs/sec (56 MB/s) | 355K docs/sec (51 MB/s) |
84
+ | 500,000 | 382K docs/sec (55 MB/s) | **423K docs/sec (61 MB/s)** โœ… |
85
+ | 1,000,000 | 392K docs/sec (56 MB/s) | **392K docs/sec (56 MB/s)** |
83
86
 
84
87
  ### Read Performance (find)
85
88
 
86
- | Documents | Standard Mode | High-Concurrency Mode |
87
- |-----------|---------------|----------------------|
88
- | 1,000 | 648K docs/sec (93 MB/s) | **803K docs/sec (115 MB/s)** โœ… |
89
- | 10,000 | 1.5M docs/sec (218 MB/s) | **2.2M docs/sec (309 MB/s)** โœ… |
90
- | 100,000+ | **2.8M+ docs/sec** | 2.0M docs/sec |
89
+ | Documents | Standard Mode | High-Concurrency Mode |
90
+ | --------- | ------------------------ | ------------------------------- |
91
+ | 1,000 | 648K docs/sec (93 MB/s) | **803K docs/sec (115 MB/s)** โœ… |
92
+ | 10,000 | 1.5M docs/sec (218 MB/s) | **2.2M docs/sec (309 MB/s)** โœ… |
93
+ | 100,000+ | **2.8M+ docs/sec** | 2.0M docs/sec |
91
94
 
92
95
  Run benchmarks yourself:
96
+
93
97
  ```bash
94
98
  npx tsx examples/benchmark.ts
95
99
  ```
@@ -103,10 +107,10 @@ const db = new JsonDB({
103
107
  dataDir: './data',
104
108
  highConcurrency: {
105
109
  enabled: true,
106
- partitions: 16, // Data shards (default: 16)
107
- batchSize: 1000, // Writes before auto-flush (default: 1000)
108
- flushInterval: 100, // Max ms before flush (default: 100)
109
- maxConcurrentIO: 4, // Parallel I/O operations (default: 4)
110
+ partitions: 16, // Data shards (default: 16)
111
+ batchSize: 1000, // Writes before auto-flush (default: 1000)
112
+ flushInterval: 100, // Max ms before flush (default: 100)
113
+ maxConcurrentIO: 4, // Parallel I/O operations (default: 4)
110
114
  },
111
115
  });
112
116
 
@@ -127,12 +131,57 @@ await db.close();
127
131
 
128
132
  ### When to Use High-Concurrency Mode
129
133
 
130
- | Use Case | Recommended Mode |
131
- |----------|-----------------|
132
- | Desktop apps, small datasets | Standard |
133
- | Web servers with concurrent requests | High-Concurrency |
134
- | Bulk data import | Either (both fast) |
135
- | Real-time applications | High-Concurrency |
134
+ | Use Case | Recommended Mode |
135
+ | ------------------------------------ | ------------------ |
136
+ | Desktop apps, small datasets | Standard |
137
+ | Web servers with concurrent requests | High-Concurrency |
138
+ | Bulk data import | Either (both fast) |
139
+ | Real-time applications | High-Concurrency |
140
+
141
+ ## ๐Ÿ’พ Lazy Loading Mode
142
+
143
+ For applications with huge datasets that don't fit in memory, enable lazy loading mode:
144
+
145
+ ```typescript
146
+ const db = new JsonDB({
147
+ dataDir: './data',
148
+ lazyLoading: {
149
+ enabled: true,
150
+ cacheSize: 1000, // Max documents in memory (default: 1000)
151
+ chunkSize: 10000, // Future: documents per chunk file
152
+ },
153
+ });
154
+
155
+ await db.connect();
156
+ const users = db.collection('users');
157
+
158
+ // Documents are loaded on-demand with LRU caching
159
+ const user = await users.findById('some-id'); // Efficient - uses cache
160
+ const count = await users.count(); // Efficient - uses index only
161
+
162
+ // Queries still work but load documents from disk
163
+ const results = await users.find({ age: { $gt: 25 } });
164
+
165
+ await db.close();
166
+ ```
167
+
168
+ ### How It Works
169
+
170
+ - **Index in memory**: Only document IDs are kept in memory
171
+ - **LRU cache**: Frequently accessed documents are cached (up to `cacheSize`)
172
+ - **On-demand loading**: Full documents are loaded from disk when needed
173
+ - **ID-based optimization**: `findById()` and `count()` are optimized
174
+
175
+ ### When to Use Lazy Loading Mode
176
+
177
+ | Use Case | Recommended Mode |
178
+ | ------------------------------ | ---------------- |
179
+ | Small datasets (< 10K docs) | Standard |
180
+ | Medium datasets | Standard or Lazy |
181
+ | Huge datasets (> 100K docs) | Lazy Loading |
182
+ | Memory-constrained environment | Lazy Loading |
183
+ | Frequent full queries | Standard |
184
+ | ID-based access patterns | Lazy Loading |
136
185
 
137
186
  ## โœ… Schema Validation (Zod)
138
187
 
@@ -174,14 +223,15 @@ try {
174
223
 
175
224
  ### JsonDB Options
176
225
 
177
- | Option | Type | Default | Description |
178
- |--------|------|---------|-------------|
179
- | `dataDir` | `string` | **required** | Path to store JSON files |
180
- | `autoSave` | `boolean` | `true` | Auto-save after writes |
181
- | `saveDebounce` | `number` | `0` | Debounce time (ms) for saves |
182
- | `prettyPrint` | `boolean` | `true` | Format JSON files |
183
- | `fileExtension` | `string` | `.json` | Custom file extension |
184
- | `highConcurrency` | `object` | `undefined` | Enable high-concurrency mode |
226
+ | Option | Type | Default | Description |
227
+ | ----------------- | --------- | ------------ | ------------------------------------------ |
228
+ | `dataDir` | `string` | **required** | Path to store JSON files |
229
+ | `autoSave` | `boolean` | `true` | Auto-save after writes |
230
+ | `saveDebounce` | `number` | `0` | Debounce time (ms) for saves |
231
+ | `prettyPrint` | `boolean` | `true` | Format JSON files |
232
+ | `fileExtension` | `string` | `.json` | Custom file extension |
233
+ | `highConcurrency` | `object` | `undefined` | Enable high-concurrency mode |
234
+ | `lazyLoading` | `object` | `undefined` | Enable lazy loading mode for huge datasets |
185
235
 
186
236
  ### JsonDB Methods
187
237
 
@@ -234,21 +284,38 @@ collection.getName(); // Get collection name
234
284
 
235
285
  ### Comparison
236
286
 
237
- | Operator | Example |
238
- |----------|---------|
239
- | `$eq` | `{ age: { $eq: 25 } }` |
240
- | `$ne` | `{ status: { $ne: 'deleted' } }` |
241
- | `$gt` / `$gte` | `{ age: { $gte: 18 } }` |
242
- | `$lt` / `$lte` | `{ price: { $lt: 100 } }` |
287
+ | Operator | Example |
288
+ | -------------- | ------------------------------------- |
289
+ | `$eq` | `{ age: { $eq: 25 } }` |
290
+ | `$ne` | `{ status: { $ne: 'deleted' } }` |
291
+ | `$gt` / `$gte` | `{ age: { $gte: 18 } }` |
292
+ | `$lt` / `$lte` | `{ price: { $lt: 100 } }` |
243
293
  | `$in` / `$nin` | `{ role: { $in: ['admin', 'mod'] } }` |
244
294
 
245
295
  ### String
246
296
 
247
- | Operator | Example |
248
- |----------|---------|
249
- | `$regex` | `{ email: { $regex: /@gmail\.com$/ } }` |
250
- | `$startsWith` | `{ name: { $startsWith: 'John' } }` |
251
- | `$endsWith` | `{ email: { $endsWith: '.com' } }` |
297
+ | Operator | Example |
298
+ | ------------- | --------------------------------------- |
299
+ | `$regex` | `{ email: { $regex: /@gmail\.com$/ } }` |
300
+ | `$startsWith` | `{ name: { $startsWith: 'John' } }` |
301
+ | `$endsWith` | `{ email: { $endsWith: '.com' } }` |
302
+
303
+ ### Array
304
+
305
+ | Operator | Description | Example |
306
+ | ------------ | ------------------------- | ------------------------------------------------ |
307
+ | `$contains` | Array contains value | `{ tags: { $contains: 'admin' } }` |
308
+ | `$all` | Array contains all values | `{ tags: { $all: ['user', 'premium'] } }` |
309
+ | `$elemMatch` | Element matches sub-query | `{ items: { $elemMatch: { qty: { $gt: 5 } } } }` |
310
+ | `$size` | Array has exact length | `{ tags: { $size: 3 } }` |
311
+
312
+ ### Utility
313
+
314
+ | Operator | Description | Example |
315
+ | --------- | ---------------- | ------------------------------ |
316
+ | `$type` | Value type check | `{ age: { $type: 'number' } }` |
317
+ | `$mod` | Modulo operation | `{ qty: { $mod: [4, 0] } }` |
318
+ | `$exists` | Field exists | `{ email: { $exists: true } }` |
252
319
 
253
320
  ### Logical
254
321
 
@@ -263,23 +330,33 @@ collection.getName(); // Get collection name
263
330
  { $not: { status: 'deleted' } }
264
331
  ```
265
332
 
266
- ### Existence
333
+ ## ๐ŸŽฏ Projection
334
+
335
+ Select which fields to return in query results:
267
336
 
268
337
  ```typescript
269
- { email: { $exists: true } } // Field exists
270
- { deletedAt: { $exists: false } } // Field doesn't exist
338
+ // Include only specific fields (_id included by default)
339
+ await users.find({}, { projection: { name: 1, email: 1 } });
340
+
341
+ // Exclude specific fields
342
+ await users.find({}, { projection: { password: 0, secret: 0 } });
343
+
344
+ // Exclude _id
345
+ await users.find({}, { projection: { name: 1, _id: 0 } });
271
346
  ```
272
347
 
348
+ > **Note:** Cannot mix inclusion and exclusion (except for `_id`).
349
+
273
350
  ## ๐Ÿ“ Update Operators
274
351
 
275
- | Operator | Description | Example |
276
- |----------|-------------|---------|
277
- | `$set` | Set field | `{ $set: { name: 'New' } }` |
278
- | `$unset` | Remove field | `{ $unset: { temp: true } }` |
279
- | `$inc` | Increment | `{ $inc: { views: 1 } }` |
280
- | `$push` | Add to array | `{ $push: { tags: 'new' } }` |
281
- | `$pull` | Remove from array | `{ $pull: { tags: 'old' } }` |
282
- | `$addToSet` | Add unique | `{ $addToSet: { tags: 'unique' } }` |
352
+ | Operator | Description | Example |
353
+ | ----------- | ----------------- | ----------------------------------- |
354
+ | `$set` | Set field | `{ $set: { name: 'New' } }` |
355
+ | `$unset` | Remove field | `{ $unset: { temp: true } }` |
356
+ | `$inc` | Increment | `{ $inc: { views: 1 } }` |
357
+ | `$push` | Add to array | `{ $push: { tags: 'new' } }` |
358
+ | `$pull` | Remove from array | `{ $pull: { tags: 'old' } }` |
359
+ | `$addToSet` | Add unique | `{ $addToSet: { tags: 'unique' } }` |
283
360
 
284
361
  ## ๐Ÿ–ฅ๏ธ Electron Integration
285
362
 
@@ -298,6 +375,7 @@ await db.connect();
298
375
  ## ๐Ÿ“ Data Storage
299
376
 
300
377
  Standard mode stores one JSON file per collection:
378
+
301
379
  ```
302
380
  data/
303
381
  โ”œโ”€โ”€ users.json
@@ -306,6 +384,7 @@ data/
306
384
  ```
307
385
 
308
386
  High-concurrency mode partitions data:
387
+
309
388
  ```
310
389
  data/
311
390
  โ”œโ”€โ”€ users_p0.json
@@ -314,6 +393,16 @@ data/
314
393
  โ””โ”€โ”€ ...
315
394
  ```
316
395
 
396
+ Lazy loading mode uses index files for fast loading:
397
+
398
+ ```
399
+ data/
400
+ โ”œโ”€โ”€ users.json # Full document data
401
+ โ”œโ”€โ”€ users.index.json # ID index for fast access
402
+ โ”œโ”€โ”€ posts.json
403
+ โ””โ”€โ”€ posts.index.json
404
+ ```
405
+
317
406
  ## ๐Ÿงช Examples
318
407
 
319
408
  ```bash
package/dist/index.d.ts CHANGED
@@ -22,6 +22,16 @@ interface ComparisonOperators<T> {
22
22
  $startsWith?: string;
23
23
  $endsWith?: string;
24
24
  $contains?: T extends unknown[] ? T[number] : never;
25
+ /** Array must contain all specified values */
26
+ $all?: T extends unknown[] ? T : never;
27
+ /** Array element must match the sub-query */
28
+ $elemMatch?: T extends unknown[] ? Record<string, unknown> : never;
29
+ /** Array must have exact length */
30
+ $size?: number;
31
+ /** Value must be of specified type: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'null' */
32
+ $type?: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'null' | 'undefined';
33
+ /** Modulo operation: [divisor, remainder] - matches if value % divisor === remainder */
34
+ $mod?: [number, number];
25
35
  }
26
36
  /**
27
37
  * Field-level query type
@@ -68,6 +78,16 @@ type SortOrder = 1 | -1 | 'asc' | 'desc';
68
78
  type Sort<T> = {
69
79
  [K in keyof T]?: SortOrder;
70
80
  };
81
+ /**
82
+ * Projection specification for field selection
83
+ * Use 1 to include fields, 0 to exclude fields
84
+ * Cannot mix inclusion and exclusion (except _id)
85
+ */
86
+ type Projection<T> = {
87
+ [K in keyof T]?: 0 | 1 | boolean;
88
+ } & {
89
+ _id?: 0 | 1 | boolean;
90
+ };
71
91
  /**
72
92
  * Options for find operations
73
93
  */
@@ -75,6 +95,8 @@ interface FindOptions<T> {
75
95
  sort?: Sort<T>;
76
96
  limit?: number;
77
97
  skip?: number;
98
+ /** Field projection - specify which fields to include/exclude */
99
+ projection?: Projection<T>;
78
100
  }
79
101
  /**
80
102
  * Collection configuration options
@@ -102,6 +124,17 @@ interface HighConcurrencyOptions {
102
124
  /** Whether to coalesce duplicate writes (default: true) */
103
125
  coalesceWrites?: boolean;
104
126
  }
127
+ /**
128
+ * Lazy loading mode options for memory-efficient storage
129
+ */
130
+ interface LazyLoadingOptions {
131
+ /** Enable lazy loading mode */
132
+ enabled: boolean;
133
+ /** Maximum documents to keep in memory cache (default: 1000) */
134
+ cacheSize?: number;
135
+ /** Documents per chunk file (default: 10000, 0 = no chunking) */
136
+ chunkSize?: number;
137
+ }
105
138
  /**
106
139
  * JsonDB configuration options
107
140
  */
@@ -118,6 +151,8 @@ interface JsonDBOptions {
118
151
  fileExtension?: string;
119
152
  /** High-concurrency mode options (opt-in) */
120
153
  highConcurrency?: HighConcurrencyOptions;
154
+ /** Lazy loading mode options for memory-efficient storage (opt-in) */
155
+ lazyLoading?: LazyLoadingOptions;
121
156
  }
122
157
  /**
123
158
  * Internal collection data structure
@@ -266,6 +301,7 @@ declare class Collection<T extends Document> {
266
301
  })[]): Promise<T[]>;
267
302
  /**
268
303
  * Find documents matching a query
304
+ * When projection is used, only specified fields are returned
269
305
  */
270
306
  find(query?: Query<T>, options?: FindOptions<T>): Promise<T[]>;
271
307
  /**
@@ -651,9 +687,252 @@ declare class HighConcurrencyCollection<T extends Document> {
651
687
  }
652
688
 
653
689
  /**
654
- * Collection type union for standard and high-concurrency modes
690
+ * LazyStorage - Memory-efficient storage adapter
691
+ *
692
+ * Instead of loading all documents into memory:
693
+ * - Keeps only document IDs (index) in memory
694
+ * - Uses LRU cache for frequently accessed documents
695
+ * - Loads full documents on-demand
696
+ * - Supports chunked storage for huge collections
697
+ */
698
+ declare class LazyStorage {
699
+ private readonly dataDir;
700
+ private readonly fileExtension;
701
+ private readonly prettyPrint;
702
+ private readonly cacheSize;
703
+ private readonly chunkSize;
704
+ /** Document cache per collection: Map<collectionName, LRUCache<docId, document>> */
705
+ private readonly documentCache;
706
+ /** Collection metadata: Map<collectionName, metadata> */
707
+ private readonly collections;
708
+ /** Locks for concurrent access */
709
+ private readonly locks;
710
+ constructor(options: JsonDBOptions);
711
+ private ensureDirectory;
712
+ private getFilePath;
713
+ private getIndexFilePath;
714
+ private acquireLock;
715
+ /**
716
+ * Initialize a collection - loads index only, not documents
717
+ */
718
+ initCollection(collectionName: string): Promise<void>;
719
+ /**
720
+ * Save index file for fast loading
721
+ */
722
+ private saveIndex;
723
+ /**
724
+ * Get document count without loading documents
725
+ */
726
+ getCount(collectionName: string): number;
727
+ /**
728
+ * Check if document exists without loading it
729
+ */
730
+ hasDocument(collectionName: string, docId: string): boolean;
731
+ /**
732
+ * Get all document IDs without loading documents
733
+ */
734
+ getDocumentIds(collectionName: string): string[];
735
+ /**
736
+ * Get a single document by ID - uses cache or loads from disk
737
+ */
738
+ getDocument<T extends Document>(collectionName: string, docId: string): Promise<T | null>;
739
+ /**
740
+ * Load document from disk (internal)
741
+ */
742
+ private loadDocumentFromDisk;
743
+ /**
744
+ * Get multiple documents by IDs (batch load)
745
+ */
746
+ getDocuments<T extends Document>(collectionName: string, docIds: string[]): Promise<T[]>;
747
+ /**
748
+ * Load multiple documents from disk
749
+ */
750
+ private loadDocumentsFromDisk;
751
+ /**
752
+ * Get all documents (full load - use sparingly for large collections)
753
+ */
754
+ getAllDocuments<T extends Document>(collectionName: string): Promise<T[]>;
755
+ /**
756
+ * Insert a document
757
+ */
758
+ insertDocument<T extends Document>(collectionName: string, doc: T): Promise<void>;
759
+ /**
760
+ * Insert multiple documents
761
+ */
762
+ insertDocuments<T extends Document>(collectionName: string, docs: T[]): Promise<void>;
763
+ /**
764
+ * Update a document
765
+ */
766
+ updateDocument<T extends Document>(collectionName: string, doc: T): Promise<void>;
767
+ /**
768
+ * Delete a document
769
+ */
770
+ deleteDocument(collectionName: string, docId: string): Promise<void>;
771
+ /**
772
+ * Delete multiple documents
773
+ */
774
+ deleteDocuments(collectionName: string, docIds: string[]): Promise<void>;
775
+ /**
776
+ * Clear all documents from a collection
777
+ */
778
+ clearCollection(collectionName: string): Promise<void>;
779
+ /**
780
+ * Persist collection to disk
781
+ */
782
+ private persistCollection;
783
+ /**
784
+ * Build document array from cache and disk
785
+ */
786
+ private buildDocumentArray;
787
+ /**
788
+ * Delete a collection
789
+ */
790
+ deleteCollection(collectionName: string): Promise<void>;
791
+ /**
792
+ * Check if collection exists
793
+ */
794
+ exists(collectionName: string): Promise<boolean>;
795
+ /**
796
+ * List all collections
797
+ */
798
+ list(): Promise<string[]>;
799
+ /**
800
+ * Get cache statistics
801
+ */
802
+ getStats(): {
803
+ collections: number;
804
+ cachedDocuments: number;
805
+ cacheSize: number;
806
+ };
807
+ /**
808
+ * Clear cache for a collection
809
+ */
810
+ clearCache(collectionName?: string): void;
811
+ /**
812
+ * Flush pending writes
813
+ */
814
+ flush(): Promise<void>;
815
+ /**
816
+ * Get data directory path
817
+ */
818
+ getDataDir(): string;
819
+ }
820
+
821
+ /**
822
+ * LazyCollection - Memory-efficient collection using lazy loading storage
823
+ *
824
+ * Unlike standard Collection which loads all documents:
825
+ * - Only document IDs are kept in memory
826
+ * - Documents are loaded on-demand with LRU caching
827
+ * - Queries that scan all documents still need to load from disk
828
+ */
829
+ declare class LazyCollection<T extends Document> {
830
+ private readonly name;
831
+ private readonly storage;
832
+ private readonly queryEngine;
833
+ private readonly idGenerator;
834
+ private readonly schema?;
835
+ constructor(name: string, storage: LazyStorage, options?: {
836
+ idGenerator?: () => string;
837
+ schema?: SchemaValidator$1<T>;
838
+ });
839
+ /**
840
+ * Validate a document against the schema (if defined)
841
+ */
842
+ private validate;
843
+ /**
844
+ * Insert a single document
845
+ */
846
+ insert(doc: Omit<T, '_id'> & {
847
+ _id?: string;
848
+ }): Promise<T>;
849
+ /**
850
+ * Insert without duplicate check (faster)
851
+ */
852
+ insertFast(doc: Omit<T, '_id'> & {
853
+ _id?: string;
854
+ }): Promise<T>;
855
+ /**
856
+ * Insert multiple documents
857
+ */
858
+ insertMany(docs: (Omit<T, '_id'> & {
859
+ _id?: string;
860
+ })[]): Promise<T[]>;
861
+ /**
862
+ * Find documents matching a query
863
+ * Note: This loads documents from disk for filtering
864
+ */
865
+ find(query?: Query<T>, options?: FindOptions<T>): Promise<T[]>;
866
+ /**
867
+ * Find a single document matching a query
868
+ */
869
+ findOne(query: Query<T>): Promise<T | null>;
870
+ /**
871
+ * Find a document by ID - optimized, uses cache
872
+ */
873
+ findById(id: string): Promise<T | null>;
874
+ /**
875
+ * Count documents matching a query
876
+ */
877
+ count(query?: Query<T>): Promise<number>;
878
+ /**
879
+ * Update documents matching a query
880
+ */
881
+ update(query: Query<T>, update: UpdateOperators<T> | Partial<T>): Promise<number>;
882
+ /**
883
+ * Update a single document matching a query
884
+ */
885
+ updateOne(query: Query<T>, update: UpdateOperators<T> | Partial<T>): Promise<T | null>;
886
+ /**
887
+ * Update a document by ID - optimized, uses cache
888
+ */
889
+ updateById(id: string, update: UpdateOperators<T> | Partial<T>): Promise<T | null>;
890
+ /**
891
+ * Delete documents matching a query
892
+ */
893
+ delete(query: Query<T>): Promise<number>;
894
+ /**
895
+ * Delete a single document matching a query
896
+ */
897
+ deleteOne(query: Query<T>): Promise<T | null>;
898
+ /**
899
+ * Delete a document by ID - optimized
900
+ */
901
+ deleteById(id: string): Promise<T | null>;
902
+ /**
903
+ * Get all documents
904
+ */
905
+ getAll(): Promise<T[]>;
906
+ /**
907
+ * Clear all documents
908
+ */
909
+ clear(): Promise<void>;
910
+ /**
911
+ * Drop the collection
912
+ */
913
+ drop(): Promise<void>;
914
+ /**
915
+ * Flush pending writes
916
+ */
917
+ flush(): Promise<void>;
918
+ /**
919
+ * Get collection name
920
+ */
921
+ getName(): string;
922
+ /**
923
+ * Apply update operators to a document
924
+ */
925
+ private applyUpdate;
926
+ /**
927
+ * Sort documents
928
+ */
929
+ private sortDocuments;
930
+ }
931
+
932
+ /**
933
+ * Collection type union for all modes
655
934
  */
656
- type AnyCollection<T extends Document> = Collection<T> | HighConcurrencyCollection<T>;
935
+ type AnyCollection<T extends Document> = Collection<T> | HighConcurrencyCollection<T> | LazyCollection<T>;
657
936
  /**
658
937
  * Stats returned by getStats() in high-concurrency mode
659
938
  */
@@ -665,16 +944,19 @@ interface HighConcurrencyStats {
665
944
  /**
666
945
  * JsonDB - A lightweight JSON-based database for Node.js and Electron
667
946
  *
668
- * Supports two modes:
947
+ * Supports three modes:
669
948
  * - Standard mode: Single-file storage per collection (default)
670
949
  * - High-concurrency mode: Partitioned storage with write batching (opt-in)
950
+ * - Lazy loading mode: Memory-efficient with document-level LRU caching (opt-in)
671
951
  */
672
952
  declare class JsonDB {
673
953
  private readonly options;
674
954
  private readonly storage;
675
955
  private readonly hcStorage;
956
+ private readonly lazyStorage;
676
957
  private readonly collections;
677
958
  private readonly isHighConcurrency;
959
+ private readonly isLazyLoading;
678
960
  private connected;
679
961
  /**
680
962
  * Create a new JsonDB instance
@@ -682,13 +964,17 @@ declare class JsonDB {
682
964
  */
683
965
  constructor(options: JsonDBOptions);
684
966
  /**
685
- * Get the standard storage (throws if in HC mode)
967
+ * Get the standard storage (throws if in HC or lazy mode)
686
968
  */
687
969
  private getStorage;
688
970
  /**
689
- * Get the high-concurrency storage (throws if in standard mode)
971
+ * Get the high-concurrency storage (throws if in standard or lazy mode)
690
972
  */
691
973
  private getHCStorage;
974
+ /**
975
+ * Get the lazy storage (throws if in standard or HC mode)
976
+ */
977
+ private getLazyStorage;
692
978
  /**
693
979
  * Connect to the database (initialize storage)
694
980
  */
@@ -698,10 +984,10 @@ declare class JsonDB {
698
984
  */
699
985
  close(): Promise<void>;
700
986
  /**
701
- * Get or create a collection
702
- * @param name Collection name
703
- * @param options Collection options (including optional Zod schema)
704
- */
987
+ * Get or create a collection
988
+ * @param name Collection name
989
+ * @param options Collection options (including optional Zod schema)
990
+ */
705
991
  collection<T extends Document>(name: string, options?: {
706
992
  schema?: {
707
993
  safeParse(data: unknown): {
@@ -1049,4 +1335,4 @@ declare function generateId(_length?: number): string;
1049
1335
  */
1050
1336
  declare function isValidId(id: unknown): id is string;
1051
1337
 
1052
- export { Collection, type CollectionData, CollectionError, type CollectionOptions, type ComparisonOperators, type Document, DocumentNotFoundError, DuplicateKeyError, type FindOptions, HighConcurrencyCollection, type HighConcurrencyOptions, HighConcurrencyStorage, JsonDB, JsonDBError, type JsonDBOptions, PartitionManager, type Query, type QueryField, type SchemaIssue, type SchemaValidator$1 as SchemaValidator, type Sort, type SortOrder, type StorageAdapter, StorageError, type UpdateOperators, ValidationError, WorkerPool, WriteQueue, generateId, isValidId, parallelLimit };
1338
+ export { Collection, type CollectionData, CollectionError, type CollectionOptions, type ComparisonOperators, type Document, DocumentNotFoundError, DuplicateKeyError, type FindOptions, HighConcurrencyCollection, type HighConcurrencyOptions, HighConcurrencyStorage, JsonDB, JsonDBError, type JsonDBOptions, PartitionManager, type Projection, type Query, type QueryField, type SchemaIssue, type SchemaValidator$1 as SchemaValidator, type Sort, type SortOrder, type StorageAdapter, StorageError, type UpdateOperators, ValidationError, WorkerPool, WriteQueue, generateId, isValidId, parallelLimit };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- 'use strict';var d=require('fs'),$=require('path'),bson=require('bson');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var d__namespace=/*#__PURE__*/_interopNamespace(d);var $__namespace=/*#__PURE__*/_interopNamespace($);var g=class extends Error{constructor(t){super(t),this.name="JsonDBError",Error.captureStackTrace?.(this,this.constructor);}},Q=class extends g{constructor(t,e){super(e?`Document with id "${e}" not found in collection "${t}"`:`Document not found in collection "${t}"`),this.name="DocumentNotFoundError";}},y=class extends g{constructor(t,e){super(`Duplicate key error: document with id "${e}" already exists in collection "${t}"`),this.name="DuplicateKeyError";}},w=class extends g{collectionName;issues;field;value;constructor(t,e,i,r){let n=e.map(s=>`${s.path.join(".")}: ${s.message}`).join("; ");super(`Validation failed for collection "${t}": ${n}`),this.name="ValidationError",this.collectionName=t,this.issues=e,this.field=i,this.value=r;}},f=class extends g{cause;constructor(t,e){super(t),this.name="StorageError",this.cause=e;}},P=class extends g{constructor(t){super(t),this.name="CollectionError";}};var b=class{dataDir;fileExtension;prettyPrint;cache=new Map;locks=new Map;constructor(t){this.dataDir=$__namespace.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.ensureDirectory();}ensureDirectory(){try{d__namespace.existsSync(this.dataDir)||d__namespace.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t){return $__namespace.join(this.dataDir,`${t}${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(r=>{e=r;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async read(t){if(this.cache.has(t))return this.cache.get(t);let e=this.getFilePath(t);try{if(!d__namespace.existsSync(e))return null;let i=await d__namespace.promises.readFile(e,"utf-8"),r=JSON.parse(i);return this.cache.set(t,r),r}catch(i){throw new f(`Failed to read collection "${t}"`,i)}}async write(t,e){let i=this.getFilePath(t),r=`${i}.tmp.${Date.now()}`,n=await this.acquireLock(t);try{e.updatedAt=new Date().toISOString();let s=this.prettyPrint?JSON.stringify(e,null,2):JSON.stringify(e);await d__namespace.promises.writeFile(r,s,"utf-8"),await d__namespace.promises.rename(r,i),this.cache.set(t,e);}catch(s){try{d__namespace.existsSync(r)&&await d__namespace.promises.unlink(r);}catch{}throw new f(`Failed to write collection "${t}"`,s)}finally{n();}}async exists(t){let e=this.getFilePath(t);return d__namespace.existsSync(e)}async delete(t){let e=this.getFilePath(t),i=await this.acquireLock(t);try{d__namespace.existsSync(e)&&await d__namespace.promises.unlink(e),this.cache.delete(t);}catch(r){throw new f(`Failed to delete collection "${t}"`,r)}finally{i();}}async list(){try{return (await d__namespace.promises.readdir(this.dataDir)).filter(e=>e.endsWith(this.fileExtension)).map(e=>e.slice(0,-this.fileExtension.length))}catch(t){throw new f("Failed to list collections",t)}}clearCache(t){t?this.cache.delete(t):this.cache.clear();}getDataDir(){return this.dataDir}};function v(a){return new bson.ObjectId().toHexString()}function H(a){return typeof a!="string"||a.length===0||a.length>64?false:a.length===24?bson.ObjectId.isValid(a):true}function l(a){if(a===null||typeof a!="object")return a;if(a instanceof Date)return new Date(a.getTime());if(a instanceof RegExp)return new RegExp(a.source,a.flags);if(Array.isArray(a))return a.map(e=>l(e));let t={};for(let e in a)Object.prototype.hasOwnProperty.call(a,e)&&(t[e]=l(a[e]));return t}function A(a,t){let e=t.split("."),i=a;for(let r of e){if(i==null||typeof i!="object")return;i=i[r];}return i}function W(a,t,e){let i=t.split("."),r=a;for(let n=0;n<i.length-1;n++){let s=i[n];(!(s in r)||typeof r[s]!="object"||r[s]===null)&&(r[s]={}),r=r[s];}r[i[i.length-1]]=e;}function q(a,t){let e=t.split("."),i=a;for(let n=0;n<e.length-1;n++){let s=e[n];if(!(s in i)||typeof i[s]!="object"||i[s]===null)return false;i=i[s];}let r=e[e.length-1];return r in i?(delete i[r],true):false}function _(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)&&!(a instanceof Date)&&!(a instanceof RegExp)}var T=class{filter(t,e){return !e||Object.keys(e).length===0?t:t.filter(i=>this.matches(i,e))}matches(t,e){if("$and"in e&&e.$and)return e.$and.every(i=>this.matches(t,i));if("$or"in e&&e.$or)return e.$or.some(i=>this.matches(t,i));if("$not"in e&&e.$not)return !this.matches(t,e.$not);for(let[i,r]of Object.entries(e)){if(i.startsWith("$"))continue;let n=A(t,i);if(!this.matchesCondition(n,r))return false}return true}matchesCondition(t,e){if(!_(e)||!this.hasOperators(e))return this.isEqual(t,e);let i=e;if("$eq"in i&&!this.isEqual(t,i.$eq)||"$ne"in i&&this.isEqual(t,i.$ne)||"$gt"in i&&!this.compareValues(t,i.$gt,">")||"$gte"in i&&!this.compareValues(t,i.$gte,">=")||"$lt"in i&&!this.compareValues(t,i.$lt,"<")||"$lte"in i&&!this.compareValues(t,i.$lte,"<=")||"$in"in i&&Array.isArray(i.$in)&&!i.$in.some(r=>this.isEqual(t,r))||"$nin"in i&&Array.isArray(i.$nin)&&i.$nin.some(r=>this.isEqual(t,r)))return false;if("$exists"in i){let r=t!=null;if(i.$exists!==r)return false}return !("$regex"in i&&(typeof t!="string"||!(i.$regex instanceof RegExp?i.$regex:new RegExp(i.$regex)).test(t))||"$startsWith"in i&&(typeof t!="string"||typeof i.$startsWith!="string"||!t.startsWith(i.$startsWith))||"$endsWith"in i&&(typeof t!="string"||typeof i.$endsWith!="string"||!t.endsWith(i.$endsWith))||"$contains"in i&&(!Array.isArray(t)||!t.some(r=>this.isEqual(r,i.$contains))))}hasOperators(t){return Object.keys(t).some(e=>e.startsWith("$"))}isEqual(t,e){if(t===e)return true;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return false;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?false:t.every((i,r)=>this.isEqual(i,e[r]));if(typeof t=="object"&&typeof e=="object"){let i=Object.keys(t),r=Object.keys(e);return i.length!==r.length?false:i.every(n=>this.isEqual(t[n],e[n]))}return false}compareValues(t,e,i){if(typeof t=="number"&&typeof e=="number")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(typeof t=="string"&&typeof e=="string")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(t instanceof Date&&e instanceof Date)switch(i){case ">":return t.getTime()>e.getTime();case ">=":return t.getTime()>=e.getTime();case "<":return t.getTime()<e.getTime();case "<=":return t.getTime()<=e.getTime()}return false}};var D=class{name;storage;queryEngine;autoSave;saveDebounce;idGenerator;schema;saveTimeout=null;pendingSave=null;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new T,this.autoSave=i.autoSave??true,this.saveDebounce=i.saveDebounce??0,this.idGenerator=i.idGenerator??v,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new w(this.name,e.error.issues);return e.data}async getData(){let t=await this.storage.read(this.name);if(!t){let e={name:this.name,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return await this.storage.write(this.name,e),e}return t}async save(t){if(this.autoSave){if(this.saveDebounce>0)return this.saveTimeout&&clearTimeout(this.saveTimeout),new Promise(e=>{this.saveTimeout=setTimeout(async()=>{await this.storage.write(this.name,t),this.saveTimeout=null,e();},this.saveDebounce);});await this.storage.write(this.name,t);}}async flush(){this.saveTimeout&&(clearTimeout(this.saveTimeout),this.saveTimeout=null),this.pendingSave&&await this.pendingSave;let t=await this.getData();await this.storage.write(this.name,t);}async insert(t){let e=await this.getData(),i=t._id||this.idGenerator();if(e.documents.some(s=>s._id===i))throw new y(this.name,i);let r={...l(t),_id:i},n=this.validate(r);return e.documents.push(n),await this.save(e),l(n)}async insertFast(t){let e=await this.getData(),i=t._id||this.idGenerator(),r={...l(t),_id:i},n=this.validate(r);return e.documents.push(n),await this.save(e),l(n)}async insertMany(t){if(t.length===0)return [];let e=await this.getData(),i=[],r=new Set(e.documents.map(n=>n._id));for(let n of t){let s=n._id||this.idGenerator();if(r.has(s))throw new y(this.name,s);r.add(s);let o={...l(n),_id:s},c=this.validate(o);e.documents.push(c),i.push(l(c));}return await this.save(e),i}async find(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);return e?.sort&&(r=this.sortDocuments(r,e.sort)),e?.skip&&e.skip>0&&(r=r.slice(e.skip)),e?.limit&&e.limit>0&&(r=r.slice(0,e.limit)),r.map(n=>l(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){return this.findOne({_id:t})}async count(t){let e=await this.getData();return this.queryEngine.filter(e.documents,t).length}async update(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);if(r.length===0)return 0;for(let n of r)this.applyUpdate(n,e);return await this.save(i),r.length}async updateOne(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);if(r.length===0)return null;let n=r[0];return this.applyUpdate(n,e),await this.save(i),l(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.getData(),i=e.documents.length;e.documents=e.documents.filter(n=>!this.queryEngine.matches(n,t));let r=i-e.documents.length;return r>0&&await this.save(e),r}async deleteOne(t){let e=await this.getData(),i=e.documents.findIndex(n=>this.queryEngine.matches(n,t));if(i===-1)return null;let[r]=e.documents.splice(i,1);return await this.save(e),l(r)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){let t=await this.getData();t.documents=[],await this.save(t);}async drop(){await this.storage.delete(this.name);}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let r=e;if(r.$set)for(let[n,s]of Object.entries(r.$set))n!=="_id"&&W(t,n,s);if(r.$unset)for(let n of Object.keys(r.$unset))n!=="_id"&&q(t,n);if(r.$inc)for(let[n,s]of Object.entries(r.$inc)){let o=t[n];typeof o=="number"&&typeof s=="number"&&(t[n]=o+s);}if(r.$push)for(let[n,s]of Object.entries(r.$push)){let o=t[n];Array.isArray(o)&&o.push(s);}if(r.$pull)for(let[n,s]of Object.entries(r.$pull)){let o=t[n];if(Array.isArray(o)){let c=o.findIndex(u=>JSON.stringify(u)===JSON.stringify(s));c!==-1&&o.splice(c,1);}}if(r.$addToSet)for(let[n,s]of Object.entries(r.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(u=>JSON.stringify(u)===JSON.stringify(s))||o.push(s));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((r,n)=>{for(let[s,o]of i){let c=r[s],u=n[s],h=0;if(c===u?h=0:c==null?h=1:u==null?h=-1:typeof c=="number"&&typeof u=="number"?h=c-u:typeof c=="string"&&typeof u=="string"?h=c.localeCompare(u):c instanceof Date&&u instanceof Date?h=c.getTime()-u.getTime():h=String(c).localeCompare(String(u)),h!==0)return h*(o===-1||o==="desc"?-1:1)}return 0})}};var C=class{batchSize;flushInterval;coalesceWrites;batchProcessor;queue=new Map;flushTimer=null;pendingFlush=null;totalQueued=0;isShuttingDown=false;constructor(t,e={}){this.batchSize=e.batchSize??1e3,this.flushInterval=e.flushInterval??100,this.coalesceWrites=e.coalesceWrites??true,this.batchProcessor=t;}async enqueue(t){if(this.isShuttingDown)throw new Error("WriteQueue is shutting down, no new writes accepted");return new Promise((e,i)=>{let r={operation:t,resolve:e,reject:i,timestamp:Date.now()},n=t.collectionName,s=this.queue.get(n);s||(s=[],this.queue.set(n,s)),!(this.coalesceWrites&&this.tryCoalesce(n,r))&&(s.push(r),this.totalQueued++,this.scheduleFlush(),this.totalQueued>=this.batchSize&&this.flush().catch(i));})}tryCoalesce(t,e){let i=this.queue.get(t);if(!i||i.length===0)return false;let r=e.operation;if(r.type==="update")for(let n=i.length-1;n>=0;n--){let s=i[n].operation;if(s.type==="update"&&s.documentId===r.documentId){s.changes={...s.changes,...r.changes};let o=i[n].resolve;return i[n].resolve=()=>{o(),e.resolve();},true}}if(r.type==="delete")for(let n=i.length-1;n>=0;n--){let s=i[n].operation;(s.type==="insert"&&s.document._id===r.documentId||s.type==="update"&&s.documentId===r.documentId)&&(i.splice(n,1),this.totalQueued--);}if(r.type==="clear"||r.type==="fullWrite"){for(let n of i)n.resolve();i.length=0,this.totalQueued-=i.length;}return false}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush().catch(t=>{console.error("WriteQueue flush error:",t);});},this.flushInterval));}async flush(){if(this.pendingFlush)return this.pendingFlush;if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.totalQueued===0)return;let t=this.queue;this.queue=new Map,this.totalQueued=0;let e=new Map;for(let[i,r]of t)e.set(i,r.map(n=>n.operation));this.pendingFlush=this.processBatch(t,e),await this.pendingFlush,this.pendingFlush=null;}async processBatch(t,e){try{await this.batchProcessor(e);for(let i of t.values())for(let r of i)r.resolve();}catch(i){for(let r of t.values())for(let n of r)n.reject(i);}}async shutdown(){this.isShuttingDown=true,await this.flush();}pending(){return this.totalQueued}isEmpty(){return this.totalQueued===0}isClosing(){return this.isShuttingDown}};var x=class{dataDir;partitionCount;prettyPrint;fileExtension;cache=new Map;locks=new Map;constructor(t,e={}){this.dataDir=$__namespace.resolve(t),this.partitionCount=e.partitionCount??16,this.prettyPrint=e.prettyPrint??true,this.fileExtension=e.fileExtension??".json",this.ensureDirectory();}ensureDirectory(){try{d__namespace.existsSync(this.dataDir)||d__namespace.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getPartitionIndex(t){let e=0;for(let i=0;i<t.length;i++){let r=t.charCodeAt(i);e=(e<<5)-e+r,e=e&e;}return Math.abs(e)%this.partitionCount}getPartitionFileName(t,e){return `${t}_p${e.toString().padStart(3,"0")}${this.fileExtension}`}getPartitionFilePath(t,e){return $__namespace.join(this.dataDir,this.getPartitionFileName(t,e))}getCacheKey(t,e){return `${t}:${e}`}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(r=>{e=r;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async readPartition(t,e){let i=this.getCacheKey(t,e);if(this.cache.has(i))return this.cache.get(i);let r=this.getPartitionFilePath(t,e);try{if(!d__namespace.existsSync(r))return null;let n=await d__namespace.promises.readFile(r,"utf-8"),s=JSON.parse(n);return this.cache.set(i,s),s}catch(n){throw new f(`Failed to read partition ${e} for collection "${t}"`,n)}}async writePartition(t,e,i){let r=this.getPartitionFilePath(t,e),n=`${r}.tmp.${Date.now()}`,s=this.getCacheKey(t,e),o=await this.acquireLock(s);try{i.updatedAt=new Date().toISOString();let c=this.prettyPrint?JSON.stringify(i,null,2):JSON.stringify(i);await d__namespace.promises.writeFile(n,c,"utf-8"),await d__namespace.promises.rename(n,r),this.cache.set(s,i);}catch(c){try{d__namespace.existsSync(n)&&await d__namespace.promises.unlink(n);}catch{}throw new f(`Failed to write partition ${e} for collection "${t}"`,c)}finally{o();}}async readAllPartitions(t){let e=new Map,i=[];for(let r=0;r<this.partitionCount;r++)i.push(this.readPartition(t,r).then(n=>{n&&e.set(r,n);}));return await Promise.all(i),e}async writePartitions(t,e){let i=[];for(let[r,n]of e)i.push(this.writePartition(t,r,n));await Promise.all(i);}async initializePartitions(t){let e=[];for(let i=0;i<this.partitionCount;i++)if(!d__namespace.existsSync(this.getPartitionFilePath(t,i))){let n={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};e.push(this.writePartition(t,i,n));}await Promise.all(e);}async getPartitionInfo(t){let e=await this.readAllPartitions(t),i=[];for(let r=0;r<this.partitionCount;r++){let n=e.get(r);i.push({name:this.getPartitionFileName(t,r),partitionIndex:r,documentCount:n?.documents.length??0});}return i}async getAllDocuments(t){let e=await this.readAllPartitions(t),i=[];for(let r of e.values())i.push(...r.documents);return i}async findById(t,e){let i=this.getPartitionIndex(e),r=await this.readPartition(t,i);return r?r.documents.find(n=>n._id===e)??null:null}async deleteCollection(t){let e=[];for(let i=0;i<this.partitionCount;i++){let r=this.getPartitionFilePath(t,i),n=this.getCacheKey(t,i);e.push((async()=>{let s=await this.acquireLock(n);try{d__namespace.existsSync(r)&&await d__namespace.promises.unlink(r),this.cache.delete(n);}finally{s();}})());}await Promise.all(e);}clearCache(t){if(t)for(let e=0;e<this.partitionCount;e++)this.cache.delete(this.getCacheKey(t,e));else this.cache.clear();}getPartitionCount(){return this.partitionCount}async listCollections(){try{let t=await d__namespace.promises.readdir(this.dataDir),e=new Set,i=new RegExp(`^(.+)_p\\d{3}\\${this.fileExtension}$`);for(let r of t){let n=r.match(i);n&&e.add(n[1]);}return Array.from(e)}catch(t){throw new f("Failed to list partitioned collections",t)}}};var S=class{maxConcurrent;maxQueueSize;queue=[];activeCount=0;completedCount=0;failedCount=0;isShuttingDown=false;constructor(t={}){this.maxConcurrent=t.maxConcurrent??4,this.maxQueueSize=t.maxQueueSize??1e4;}async submit(t,e=0){if(this.isShuttingDown)throw new Error("WorkerPool is shutting down, no new tasks accepted");if(this.queue.length>=this.maxQueueSize)throw new Error("WorkerPool queue is full, task rejected (backpressure)");return new Promise((i,r)=>{let n={task:t,resolve:i,reject:r,priority:e},s=false;for(let o=0;o<this.queue.length;o++)if(e>this.queue[o].priority){this.queue.splice(o,0,n),s=true;break}s||this.queue.push(n),this.processNext();})}async submitAll(t,e=0){let i=t.map(r=>this.submit(r,e));return Promise.all(i)}async*submitStream(t,e=0){let i=t.map(r=>this.submit(r,e));for(let r of i)yield await r;}processNext(){if(this.activeCount>=this.maxConcurrent||this.queue.length===0)return;let t=this.queue.shift();t&&(this.activeCount++,t.task().then(e=>{this.completedCount++,t.resolve(e);}).catch(e=>{this.failedCount++,t.reject(e);}).finally(()=>{this.activeCount--,this.processNext();}));}async drain(){return new Promise(t=>{let e=()=>{this.activeCount===0&&this.queue.length===0?t():setImmediate(e);};e();})}async shutdown(){this.isShuttingDown=true,await this.drain();}getStats(){return {activeWorkers:this.activeCount,queuedTasks:this.queue.length,completedTasks:this.completedCount,failedTasks:this.failedCount}}isIdle(){return this.activeCount===0&&this.queue.length===0}isClosing(){return this.isShuttingDown}queueSize(){return this.queue.length}activeWorkers(){return this.activeCount}};async function I(a,t,e){let i=[],r=0;async function n(){let o=r++;o>=a.length||(i[o]=await e(a[o],o),await n());}let s=Array(Math.min(t,a.length)).fill(null).map(()=>n());return await Promise.all(s),i}var R={partitions:16,batchSize:1e3,flushInterval:100,maxConcurrentIO:4,coalesceWrites:true},k=class{partitionManager;writeQueue;workerPool;options;constructor(t){let e=t.highConcurrency;this.options={...R,...e},this.partitionManager=new x(t.dataDir,{partitionCount:this.options.partitions,prettyPrint:t.prettyPrint??true,fileExtension:t.fileExtension??".json"}),this.workerPool=new S({maxConcurrent:this.options.maxConcurrentIO});let i=this.processBatch.bind(this);this.writeQueue=new C(i,{batchSize:this.options.batchSize,flushInterval:this.options.flushInterval,coalesceWrites:this.options.coalesceWrites});}async processBatch(t){let e=Array.from(t.entries());await I(e,this.options.maxConcurrentIO,async([i,r])=>{await this.processCollectionOperations(i,r);});}async processCollectionOperations(t,e){let i=new Map,r=n=>{let s=i.get(n);return s||(s=[],i.set(n,s)),s};for(let n of e)if(n.type==="fullWrite"||n.type==="clear")for(let s=0;s<this.partitionManager.getPartitionCount();s++)r(s).push(n);else if(n.type==="insert"){let s=this.partitionManager.getPartitionIndex(n.document._id);r(s).push(n);}else if(n.type==="update"||n.type==="delete"){let s=this.partitionManager.getPartitionIndex(n.documentId);r(s).push(n);}else if(n.type==="bulkInsert")for(let s of n.documents){let o=this.partitionManager.getPartitionIndex(s._id);r(o).push({type:"insert",collectionName:t,document:s});}else if(n.type==="bulkUpdate"||n.type==="bulkDelete")for(let s of n.documentIds){let o=this.partitionManager.getPartitionIndex(s);n.type==="bulkUpdate"?r(o).push({type:"update",collectionName:t,documentId:s,changes:n.changes}):r(o).push({type:"delete",collectionName:t,documentId:s});}await I(Array.from(i.entries()),this.options.maxConcurrentIO,async([n,s])=>{await this.processPartitionOperations(t,n,s);});}async processPartitionOperations(t,e,i){let r=await this.partitionManager.readPartition(t,e);r||(r={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});for(let n of i)switch(n.type){case "insert":r.documents.push(n.document);break;case "update":{let s=r.documents.findIndex(o=>o._id===n.documentId);s!==-1&&Object.assign(r.documents[s],n.changes);break}case "delete":{let s=r.documents.findIndex(o=>o._id===n.documentId);s!==-1&&r.documents.splice(s,1);break}case "clear":r.documents=[];break;case "fullWrite":{let s=n.data.documents.filter(o=>this.partitionManager.getPartitionIndex(o._id)===e);r.documents=s;break}}await this.partitionManager.writePartition(t,e,r);}async insert(t,e){await this.writeQueue.enqueue({type:"insert",collectionName:t,document:e});}async insertMany(t,e){await this.writeQueue.enqueue({type:"bulkInsert",collectionName:t,documents:e});}async update(t,e,i){await this.writeQueue.enqueue({type:"update",collectionName:t,documentId:e,changes:i});}async delete(t,e){await this.writeQueue.enqueue({type:"delete",collectionName:t,documentId:e});}async clear(t){await this.writeQueue.enqueue({type:"clear",collectionName:t});}async findById(t,e){return await this.writeQueue.flush(),this.partitionManager.findById(t,e)}async readAll(t){return await this.writeQueue.flush(),this.partitionManager.getAllDocuments(t)}async exists(t){return (await this.partitionManager.listCollections()).includes(t)}async initializeCollection(t){await this.partitionManager.initializePartitions(t);}async deleteCollection(t){await this.writeQueue.flush(),await this.partitionManager.deleteCollection(t);}async listCollections(){return this.partitionManager.listCollections()}async flush(){await this.writeQueue.flush();}async shutdown(){await this.writeQueue.shutdown(),await this.workerPool.shutdown();}pendingWrites(){return this.writeQueue.pending()}getStats(){return {pendingWrites:this.writeQueue.pending(),workerPool:this.workerPool.getStats(),partitions:this.options.partitions}}clearCache(t){this.partitionManager.clearCache(t);}};var O=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new T,this.idGenerator=i.idGenerator??v,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new w(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(await this.storage.findById(this.name,e))throw new y(this.name,e);let r={...l(t),_id:e},n=this.validate(r);return await this.storage.insert(this.name,n),n}async insertFast(t){let e=t._id||this.idGenerator(),i={...l(t),_id:e},r=this.validate(i);return await this.storage.insert(this.name,r),r}async insertMany(t){if(t.length===0)return [];let e=[],i=[];for(let r of t){let n=r._id||this.idGenerator(),s={...l(r),_id:n},o=this.validate(s);i.push(o),e.push(l(o));}return await this.storage.insertMany(this.name,i),e}async find(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);return e?.sort&&(r=this.sortDocuments(r,e.sort)),e?.skip&&e.skip>0&&(r=r.slice(e.skip)),e?.limit&&e.limit>0&&(r=r.slice(0,e.limit)),r.map(n=>l(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.findById(this.name,t);return e?l(e):null}async count(t){let e=await this.storage.readAll(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);if(r.length===0)return 0;for(let n of r){let s=this.getUpdateChanges(n,e);await this.storage.update(this.name,n._id,s);}return r.length}async updateOne(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);if(r.length===0)return null;let n=r[0],s=this.getUpdateChanges(n,e);return await this.storage.update(this.name,n._id,s),Object.assign(n,s),l(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;for(let r of i)await this.storage.delete(this.name,r._id);return i.length}async deleteOne(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let r=i[0];return await this.storage.delete(this.name,r._id),l(r)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){await this.storage.clear(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}getUpdateChanges(t,e){if(!Object.keys(e).some(s=>s.startsWith("$")))return e;let r=e,n={};if(r.$set)for(let[s,o]of Object.entries(r.$set))s!=="_id"&&(n[s]=o);if(r.$inc)for(let[s,o]of Object.entries(r.$inc)){let c=t[s];typeof c=="number"&&typeof o=="number"&&(n[s]=c+o);}if(r.$push)for(let[s,o]of Object.entries(r.$push)){let c=t[s];Array.isArray(c)&&(n[s]=[...c,o]);}if(r.$pull)for(let[s,o]of Object.entries(r.$pull)){let c=t[s];Array.isArray(c)&&(n[s]=c.filter(u=>JSON.stringify(u)!==JSON.stringify(o)));}if(r.$addToSet)for(let[s,o]of Object.entries(r.$addToSet)){let c=t[s];Array.isArray(c)&&(c.some(h=>JSON.stringify(h)===JSON.stringify(o))?n[s]=c:n[s]=[...c,o]);}return n}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((r,n)=>{for(let[s,o]of i){let c=r[s],u=n[s],h=0;if(c===u?h=0:c==null?h=1:u==null?h=-1:typeof c=="number"&&typeof u=="number"?h=c-u:typeof c=="string"&&typeof u=="string"?h=c.localeCompare(u):c instanceof Date&&u instanceof Date?h=c.getTime()-u.getTime():h=String(c).localeCompare(String(u)),h!==0)return h*(o===-1||o==="desc"?-1:1)}return 0})}};var V={autoSave:true,saveDebounce:0,prettyPrint:true,fileExtension:".json"},F=class{options;storage;hcStorage;collections=new Map;isHighConcurrency;connected=false;constructor(t){this.options={...V,...t},this.isHighConcurrency=t.highConcurrency?.enabled??false,this.isHighConcurrency?(this.storage=null,this.hcStorage=new k(this.options)):(this.storage=new b(this.options),this.hcStorage=null);}getStorage(){if(this.storage===null)throw new Error("Storage is not available in high-concurrency mode");return this.storage}getHCStorage(){if(this.hcStorage===null)throw new Error("HighConcurrencyStorage is not available in standard mode");return this.hcStorage}async connect(){if(!this.connected){if(this.isHighConcurrency){let t=await this.getHCStorage().listCollections();for(let e of t)this.getOrCreateCollection(e);}else {let t=await this.getStorage().list();for(let e of t)this.getOrCreateCollection(e);}this.connected=true;}}async close(){if(this.connected){for(let t of this.collections.values())await t.flush();this.isHighConcurrency&&this.hcStorage&&await this.hcStorage.shutdown(),this.collections.clear(),this.storage&&this.storage.clearCache(),this.hcStorage&&this.hcStorage.clearCache(),this.connected=false;}}collection(t,e){if(!t||typeof t!="string")throw new P("Collection name must be a non-empty string");if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(t))throw new P("Collection name must start with a letter or underscore and contain only letters, numbers, underscores, and hyphens");return this.getOrCreateCollection(t,e)}getOrCreateCollection(t,e){if(this.collections.has(t))return this.collections.get(t);if(this.isHighConcurrency){let i=new O(t,this.getHCStorage(),{schema:e?.schema});this.collections.set(t,i);}else {let i=new D(t,this.getStorage(),{autoSave:this.options.autoSave,saveDebounce:this.options.saveDebounce,schema:e?.schema});this.collections.set(t,i);}return this.collections.get(t)}async hasCollection(t){return this.isHighConcurrency?this.getHCStorage().exists(t):this.getStorage().exists(t)}async listCollections(){return this.isHighConcurrency?this.getHCStorage().listCollections():this.getStorage().list()}async dropCollection(t){let e=this.collections.get(t);e?(await e.drop(),this.collections.delete(t)):this.isHighConcurrency?await this.getHCStorage().deleteCollection(t):await this.getStorage().delete(t);}async drop(){if(this.isHighConcurrency){let t=this.getHCStorage(),e=await t.listCollections();for(let i of e)await t.deleteCollection(i);}else {let t=this.getStorage(),e=await t.list();for(let i of e)await t.delete(i);}this.collections.clear(),this.storage?.clearCache(),this.hcStorage?.clearCache();}getDataDir(){return this.isHighConcurrency?this.options.dataDir:this.getStorage().getDataDir()}isConnected(){return this.connected}isHighConcurrencyMode(){return this.isHighConcurrency}getStats(){return !this.isHighConcurrency||!this.hcStorage?null:this.hcStorage.getStats()}async flush(){for(let t of this.collections.values())await t.flush();}};exports.Collection=D;exports.CollectionError=P;exports.DocumentNotFoundError=Q;exports.DuplicateKeyError=y;exports.HighConcurrencyCollection=O;exports.HighConcurrencyStorage=k;exports.JsonDB=F;exports.JsonDBError=g;exports.PartitionManager=x;exports.StorageError=f;exports.ValidationError=w;exports.WorkerPool=S;exports.WriteQueue=C;exports.generateId=v;exports.isValidId=H;exports.parallelLimit=I;
1
+ 'use strict';var d=require('fs'),S=require('path'),bson=require('bson');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var d__namespace=/*#__PURE__*/_interopNamespace(d);var S__namespace=/*#__PURE__*/_interopNamespace(S);var D=class extends Error{constructor(t){super(t),this.name="JsonDBError",Error.captureStackTrace?.(this,this.constructor);}},j=class extends D{constructor(t,e){super(e?`Document with id "${e}" not found in collection "${t}"`:`Document not found in collection "${t}"`),this.name="DocumentNotFoundError";}},y=class extends D{constructor(t,e){super(`Duplicate key error: document with id "${e}" already exists in collection "${t}"`),this.name="DuplicateKeyError";}},w=class extends D{collectionName;issues;field;value;constructor(t,e,i,s){let n=e.map(r=>`${r.path.join(".")}: ${r.message}`).join("; ");super(`Validation failed for collection "${t}": ${n}`),this.name="ValidationError",this.collectionName=t,this.issues=e,this.field=i,this.value=s;}},f=class extends D{cause;constructor(t,e){super(t),this.name="StorageError",this.cause=e;}},v=class extends D{constructor(t){super(t),this.name="CollectionError";}};var F=class{dataDir;fileExtension;prettyPrint;cache=new Map;locks=new Map;constructor(t){this.dataDir=S__namespace.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.ensureDirectory();}ensureDirectory(){try{d__namespace.existsSync(this.dataDir)||d__namespace.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t){return S__namespace.join(this.dataDir,`${t}${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async read(t){if(this.cache.has(t))return this.cache.get(t);let e=this.getFilePath(t);try{if(!d__namespace.existsSync(e))return null;let i=await d__namespace.promises.readFile(e,"utf-8"),s=JSON.parse(i);return this.cache.set(t,s),s}catch(i){throw new f(`Failed to read collection "${t}"`,i)}}async write(t,e){let i=this.getFilePath(t),s=`${i}.tmp.${Date.now()}`,n=await this.acquireLock(t);try{e.updatedAt=new Date().toISOString();let r=this.prettyPrint?JSON.stringify(e,null,2):JSON.stringify(e);await d__namespace.promises.writeFile(s,r,"utf-8"),await d__namespace.promises.rename(s,i),this.cache.set(t,e);}catch(r){try{d__namespace.existsSync(s)&&await d__namespace.promises.unlink(s);}catch{}throw new f(`Failed to write collection "${t}"`,r)}finally{n();}}async exists(t){let e=this.getFilePath(t);return d__namespace.existsSync(e)}async delete(t){let e=this.getFilePath(t),i=await this.acquireLock(t);try{d__namespace.existsSync(e)&&await d__namespace.promises.unlink(e),this.cache.delete(t);}catch(s){throw new f(`Failed to delete collection "${t}"`,s)}finally{i();}}async list(){try{return (await d__namespace.promises.readdir(this.dataDir)).filter(e=>e.endsWith(this.fileExtension)).map(e=>e.slice(0,-this.fileExtension.length))}catch(t){throw new f("Failed to list collections",t)}}clearCache(t){t?this.cache.delete(t):this.cache.clear();}getDataDir(){return this.dataDir}};function P(c){return new bson.ObjectId().toHexString()}function B(c){return typeof c!="string"||c.length===0||c.length>64?false:c.length===24?bson.ObjectId.isValid(c):true}function h(c){if(c===null||typeof c!="object")return c;if(c instanceof Date)return new Date(c.getTime());if(c instanceof RegExp)return new RegExp(c.source,c.flags);if(Array.isArray(c))return c.map(e=>h(e));let t={};for(let e in c)Object.prototype.hasOwnProperty.call(c,e)&&(t[e]=h(c[e]));return t}function R(c,t){let e=t.split("."),i=c;for(let s of e){if(i==null||typeof i!="object")return;i=i[s];}return i}function x(c,t,e){let i=t.split("."),s=c;for(let n=0;n<i.length-1;n++){let r=i[n];(!(r in s)||typeof s[r]!="object"||s[r]===null)&&(s[r]={}),s=s[r];}s[i[i.length-1]]=e;}function k(c,t){let e=t.split("."),i=c;for(let n=0;n<e.length-1;n++){let r=e[n];if(!(r in i)||typeof i[r]!="object"||i[r]===null)return false;i=i[r];}let s=e[e.length-1];return s in i?(delete i[s],true):false}function V(c){return typeof c=="object"&&c!==null&&!Array.isArray(c)&&!(c instanceof Date)&&!(c instanceof RegExp)}function b(c,t){if(!t||Object.keys(t).length===0)return c;let e=Object.entries(t).filter(([a])=>a!=="_id"),i=t._id,s=e.some(([,a])=>a===1||a===true),n=e.some(([,a])=>a===0||a===false);if(s&&n)throw new Error("Cannot mix inclusion and exclusion in projection");let r=s,o={};if(r){i!==0&&i!==false&&"_id"in c&&(o._id=c._id);for(let[l,u]of e)(u===1||u===true)&&l in c&&(o[l]=c[l]);}else {let a=new Set(e.filter(([,u])=>u===0||u===false).map(([u])=>u));(i===0||i===false)&&a.add("_id");for(let u of Object.keys(c))a.has(u)||(o[u]=c[u]);}return o}var T=class{filter(t,e){return !e||Object.keys(e).length===0?t:t.filter(i=>this.matches(i,e))}matches(t,e){if("$and"in e&&e.$and)return e.$and.every(i=>this.matches(t,i));if("$or"in e&&e.$or)return e.$or.some(i=>this.matches(t,i));if("$not"in e&&e.$not)return !this.matches(t,e.$not);for(let[i,s]of Object.entries(e)){if(i.startsWith("$"))continue;let n=R(t,i);if(!this.matchesCondition(n,s))return false}return true}matchesCondition(t,e){if(!V(e)||!this.hasOperators(e))return this.isEqual(t,e);let i=e;if("$eq"in i&&!this.isEqual(t,i.$eq)||"$ne"in i&&this.isEqual(t,i.$ne)||"$gt"in i&&!this.compareValues(t,i.$gt,">")||"$gte"in i&&!this.compareValues(t,i.$gte,">=")||"$lt"in i&&!this.compareValues(t,i.$lt,"<")||"$lte"in i&&!this.compareValues(t,i.$lte,"<=")||"$in"in i&&Array.isArray(i.$in)&&!i.$in.some(s=>this.isEqual(t,s))||"$nin"in i&&Array.isArray(i.$nin)&&i.$nin.some(s=>this.isEqual(t,s)))return false;if("$exists"in i){let s=t!=null;if(i.$exists!==s)return false}if("$regex"in i&&(typeof t!="string"||!(i.$regex instanceof RegExp?i.$regex:new RegExp(i.$regex)).test(t))||"$startsWith"in i&&(typeof t!="string"||typeof i.$startsWith!="string"||!t.startsWith(i.$startsWith))||"$endsWith"in i&&(typeof t!="string"||typeof i.$endsWith!="string"||!t.endsWith(i.$endsWith))||"$contains"in i&&(!Array.isArray(t)||!t.some(s=>this.isEqual(s,i.$contains)))||"$all"in i&&Array.isArray(i.$all)&&(!Array.isArray(t)||!i.$all.every(s=>t.some(n=>this.isEqual(n,s)))))return false;if("$elemMatch"in i&&i.$elemMatch){if(!Array.isArray(t))return false;let s=i.$elemMatch;if(!t.some(r=>typeof r!="object"||r===null?false:Object.entries(s).every(([o,a])=>{let l=r[o];return this.matchesCondition(l,a)})))return false}if("$size"in i&&typeof i.$size=="number"&&(!Array.isArray(t)||t.length!==i.$size))return false;if("$type"in i&&i.$type){let s=i.$type,n;if(t===null?n="null":t===void 0?n="undefined":Array.isArray(t)?n="array":n=typeof t,n!==s)return false}if("$mod"in i&&Array.isArray(i.$mod)&&i.$mod.length===2){if(typeof t!="number")return false;let[s,n]=i.$mod;if(t%s!==n)return false}return true}hasOperators(t){return Object.keys(t).some(e=>e.startsWith("$"))}isEqual(t,e){if(t===e)return true;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return false;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?false:t.every((i,s)=>this.isEqual(i,e[s]));if(typeof t=="object"&&typeof e=="object"){let i=Object.keys(t),s=Object.keys(e);return i.length!==s.length?false:i.every(n=>this.isEqual(t[n],e[n]))}return false}compareValues(t,e,i){if(typeof t=="number"&&typeof e=="number")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(typeof t=="string"&&typeof e=="string")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(t instanceof Date&&e instanceof Date)switch(i){case ">":return t.getTime()>e.getTime();case ">=":return t.getTime()>=e.getTime();case "<":return t.getTime()<e.getTime();case "<=":return t.getTime()<=e.getTime()}return false}};var O=class{name;storage;queryEngine;autoSave;saveDebounce;idGenerator;schema;saveTimeout=null;pendingSave=null;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new T,this.autoSave=i.autoSave??true,this.saveDebounce=i.saveDebounce??0,this.idGenerator=i.idGenerator??P,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new w(this.name,e.error.issues);return e.data}async getData(){let t=await this.storage.read(this.name);if(!t){let e={name:this.name,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return await this.storage.write(this.name,e),e}return t}async save(t){if(this.autoSave){if(this.saveDebounce>0)return this.saveTimeout&&clearTimeout(this.saveTimeout),new Promise(e=>{this.saveTimeout=setTimeout(async()=>{await this.storage.write(this.name,t),this.saveTimeout=null,e();},this.saveDebounce);});await this.storage.write(this.name,t);}}async flush(){this.saveTimeout&&(clearTimeout(this.saveTimeout),this.saveTimeout=null),this.pendingSave&&await this.pendingSave;let t=await this.getData();await this.storage.write(this.name,t);}async insert(t){let e=await this.getData(),i=t._id||this.idGenerator();if(e.documents.some(r=>r._id===i))throw new y(this.name,i);let s={...h(t),_id:i},n=this.validate(s);return e.documents.push(n),await this.save(e),h(n)}async insertFast(t){let e=await this.getData(),i=t._id||this.idGenerator(),s={...h(t),_id:i},n=this.validate(s);return e.documents.push(n),await this.save(e),h(n)}async insertMany(t){if(t.length===0)return [];let e=await this.getData(),i=[],s=new Set(e.documents.map(n=>n._id));for(let n of t){let r=n._id||this.idGenerator();if(s.has(r))throw new y(this.name,r);s.add(r);let o={...h(n),_id:r},a=this.validate(o);e.documents.push(a),i.push(h(a));}return await this.save(e),i}async find(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),e?.projection?s.map(n=>b(h(n),e.projection)):s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){return this.findOne({_id:t})}async count(t){let e=await this.getData();return this.queryEngine.filter(e.documents,t).length}async update(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);if(s.length===0)return 0;for(let n of s)this.applyUpdate(n,e);return await this.save(i),s.length}async updateOne(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);if(s.length===0)return null;let n=s[0];return this.applyUpdate(n,e),await this.save(i),h(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.getData(),i=e.documents.length;e.documents=e.documents.filter(n=>!this.queryEngine.matches(n,t));let s=i-e.documents.length;return s>0&&await this.save(e),s}async deleteOne(t){let e=await this.getData(),i=e.documents.findIndex(n=>this.queryEngine.matches(n,t));if(i===-1)return null;let[s]=e.documents.splice(i,1);return await this.save(e),h(s)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){let t=await this.getData();t.documents=[],await this.save(t);}async drop(){await this.storage.delete(this.name);}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let s=e;if(s.$set)for(let[n,r]of Object.entries(s.$set))n!=="_id"&&x(t,n,r);if(s.$unset)for(let n of Object.keys(s.$unset))n!=="_id"&&k(t,n);if(s.$inc)for(let[n,r]of Object.entries(s.$inc)){let o=t[n];typeof o=="number"&&typeof r=="number"&&(t[n]=o+r);}if(s.$push)for(let[n,r]of Object.entries(s.$push)){let o=t[n];Array.isArray(o)&&o.push(r);}if(s.$pull)for(let[n,r]of Object.entries(s.$pull)){let o=t[n];if(Array.isArray(o)){let a=o.findIndex(l=>JSON.stringify(l)===JSON.stringify(r));a!==-1&&o.splice(a,1);}}if(s.$addToSet)for(let[n,r]of Object.entries(s.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(l=>JSON.stringify(l)===JSON.stringify(r))||o.push(r));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var $=class{batchSize;flushInterval;coalesceWrites;batchProcessor;queue=new Map;flushTimer=null;pendingFlush=null;totalQueued=0;isShuttingDown=false;constructor(t,e={}){this.batchSize=e.batchSize??1e3,this.flushInterval=e.flushInterval??100,this.coalesceWrites=e.coalesceWrites??true,this.batchProcessor=t;}async enqueue(t){if(this.isShuttingDown)throw new Error("WriteQueue is shutting down, no new writes accepted");return new Promise((e,i)=>{let s={operation:t,resolve:e,reject:i,timestamp:Date.now()},n=t.collectionName,r=this.queue.get(n);r||(r=[],this.queue.set(n,r)),!(this.coalesceWrites&&this.tryCoalesce(n,s))&&(r.push(s),this.totalQueued++,this.scheduleFlush(),this.totalQueued>=this.batchSize&&this.flush().catch(i));})}tryCoalesce(t,e){let i=this.queue.get(t);if(!i||i.length===0)return false;let s=e.operation;if(s.type==="update")for(let n=i.length-1;n>=0;n--){let r=i[n].operation;if(r.type==="update"&&r.documentId===s.documentId){r.changes={...r.changes,...s.changes};let o=i[n].resolve;return i[n].resolve=()=>{o(),e.resolve();},true}}if(s.type==="delete")for(let n=i.length-1;n>=0;n--){let r=i[n].operation;(r.type==="insert"&&r.document._id===s.documentId||r.type==="update"&&r.documentId===s.documentId)&&(i.splice(n,1),this.totalQueued--);}if(s.type==="clear"||s.type==="fullWrite"){for(let n of i)n.resolve();i.length=0,this.totalQueued-=i.length;}return false}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush().catch(t=>{console.error("WriteQueue flush error:",t);});},this.flushInterval));}async flush(){if(this.pendingFlush)return this.pendingFlush;if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.totalQueued===0)return;let t=this.queue;this.queue=new Map,this.totalQueued=0;let e=new Map;for(let[i,s]of t)e.set(i,s.map(n=>n.operation));this.pendingFlush=this.processBatch(t,e),await this.pendingFlush,this.pendingFlush=null;}async processBatch(t,e){try{await this.batchProcessor(e);for(let i of t.values())for(let s of i)s.resolve();}catch(i){for(let s of t.values())for(let n of s)n.reject(i);}}async shutdown(){this.isShuttingDown=true,await this.flush();}pending(){return this.totalQueued}isEmpty(){return this.totalQueued===0}isClosing(){return this.isShuttingDown}};var A=class{dataDir;partitionCount;prettyPrint;fileExtension;cache=new Map;locks=new Map;constructor(t,e={}){this.dataDir=S__namespace.resolve(t),this.partitionCount=e.partitionCount??16,this.prettyPrint=e.prettyPrint??true,this.fileExtension=e.fileExtension??".json",this.ensureDirectory();}ensureDirectory(){try{d__namespace.existsSync(this.dataDir)||d__namespace.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getPartitionIndex(t){let e=0;for(let i=0;i<t.length;i++){let s=t.charCodeAt(i);e=(e<<5)-e+s,e=e&e;}return Math.abs(e)%this.partitionCount}getPartitionFileName(t,e){return `${t}_p${e.toString().padStart(3,"0")}${this.fileExtension}`}getPartitionFilePath(t,e){return S__namespace.join(this.dataDir,this.getPartitionFileName(t,e))}getCacheKey(t,e){return `${t}:${e}`}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async readPartition(t,e){let i=this.getCacheKey(t,e);if(this.cache.has(i))return this.cache.get(i);let s=this.getPartitionFilePath(t,e);try{if(!d__namespace.existsSync(s))return null;let n=await d__namespace.promises.readFile(s,"utf-8"),r=JSON.parse(n);return this.cache.set(i,r),r}catch(n){throw new f(`Failed to read partition ${e} for collection "${t}"`,n)}}async writePartition(t,e,i){let s=this.getPartitionFilePath(t,e),n=`${s}.tmp.${Date.now()}`,r=this.getCacheKey(t,e),o=await this.acquireLock(r);try{i.updatedAt=new Date().toISOString();let a=this.prettyPrint?JSON.stringify(i,null,2):JSON.stringify(i);await d__namespace.promises.writeFile(n,a,"utf-8"),await d__namespace.promises.rename(n,s),this.cache.set(r,i);}catch(a){try{d__namespace.existsSync(n)&&await d__namespace.promises.unlink(n);}catch{}throw new f(`Failed to write partition ${e} for collection "${t}"`,a)}finally{o();}}async readAllPartitions(t){let e=new Map,i=[];for(let s=0;s<this.partitionCount;s++)i.push(this.readPartition(t,s).then(n=>{n&&e.set(s,n);}));return await Promise.all(i),e}async writePartitions(t,e){let i=[];for(let[s,n]of e)i.push(this.writePartition(t,s,n));await Promise.all(i);}async initializePartitions(t){let e=[];for(let i=0;i<this.partitionCount;i++)if(!d__namespace.existsSync(this.getPartitionFilePath(t,i))){let n={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};e.push(this.writePartition(t,i,n));}await Promise.all(e);}async getPartitionInfo(t){let e=await this.readAllPartitions(t),i=[];for(let s=0;s<this.partitionCount;s++){let n=e.get(s);i.push({name:this.getPartitionFileName(t,s),partitionIndex:s,documentCount:n?.documents.length??0});}return i}async getAllDocuments(t){let e=await this.readAllPartitions(t),i=[];for(let s of e.values())i.push(...s.documents);return i}async findById(t,e){let i=this.getPartitionIndex(e),s=await this.readPartition(t,i);return s?s.documents.find(n=>n._id===e)??null:null}async deleteCollection(t){let e=[];for(let i=0;i<this.partitionCount;i++){let s=this.getPartitionFilePath(t,i),n=this.getCacheKey(t,i);e.push((async()=>{let r=await this.acquireLock(n);try{d__namespace.existsSync(s)&&await d__namespace.promises.unlink(s),this.cache.delete(n);}finally{r();}})());}await Promise.all(e);}clearCache(t){if(t)for(let e=0;e<this.partitionCount;e++)this.cache.delete(this.getCacheKey(t,e));else this.cache.clear();}getPartitionCount(){return this.partitionCount}async listCollections(){try{let t=await d__namespace.promises.readdir(this.dataDir),e=new Set,i=new RegExp(`^(.+)_p\\d{3}\\${this.fileExtension}$`);for(let s of t){let n=s.match(i);n&&e.add(n[1]);}return Array.from(e)}catch(t){throw new f("Failed to list partitioned collections",t)}}};var E=class{maxConcurrent;maxQueueSize;queue=[];activeCount=0;completedCount=0;failedCount=0;isShuttingDown=false;constructor(t={}){this.maxConcurrent=t.maxConcurrent??4,this.maxQueueSize=t.maxQueueSize??1e4;}async submit(t,e=0){if(this.isShuttingDown)throw new Error("WorkerPool is shutting down, no new tasks accepted");if(this.queue.length>=this.maxQueueSize)throw new Error("WorkerPool queue is full, task rejected (backpressure)");return new Promise((i,s)=>{let n={task:t,resolve:i,reject:s,priority:e},r=false;for(let o=0;o<this.queue.length;o++)if(e>this.queue[o].priority){this.queue.splice(o,0,n),r=true;break}r||this.queue.push(n),this.processNext();})}async submitAll(t,e=0){let i=t.map(s=>this.submit(s,e));return Promise.all(i)}async*submitStream(t,e=0){let i=t.map(s=>this.submit(s,e));for(let s of i)yield await s;}processNext(){if(this.activeCount>=this.maxConcurrent||this.queue.length===0)return;let t=this.queue.shift();t&&(this.activeCount++,t.task().then(e=>{this.completedCount++,t.resolve(e);}).catch(e=>{this.failedCount++,t.reject(e);}).finally(()=>{this.activeCount--,this.processNext();}));}async drain(){return new Promise(t=>{let e=()=>{this.activeCount===0&&this.queue.length===0?t():setImmediate(e);};e();})}async shutdown(){this.isShuttingDown=true,await this.drain();}getStats(){return {activeWorkers:this.activeCount,queuedTasks:this.queue.length,completedTasks:this.completedCount,failedTasks:this.failedCount}}isIdle(){return this.activeCount===0&&this.queue.length===0}isClosing(){return this.isShuttingDown}queueSize(){return this.queue.length}activeWorkers(){return this.activeCount}};async function q(c,t,e){let i=[],s=0;async function n(){let o=s++;o>=c.length||(i[o]=await e(c[o],o),await n());}let r=Array(Math.min(t,c.length)).fill(null).map(()=>n());return await Promise.all(r),i}var U={partitions:16,batchSize:1e3,flushInterval:100,maxConcurrentIO:4,coalesceWrites:true},I=class{partitionManager;writeQueue;workerPool;options;constructor(t){let e=t.highConcurrency;this.options={...U,...e},this.partitionManager=new A(t.dataDir,{partitionCount:this.options.partitions,prettyPrint:t.prettyPrint??true,fileExtension:t.fileExtension??".json"}),this.workerPool=new E({maxConcurrent:this.options.maxConcurrentIO});let i=this.processBatch.bind(this);this.writeQueue=new $(i,{batchSize:this.options.batchSize,flushInterval:this.options.flushInterval,coalesceWrites:this.options.coalesceWrites});}async processBatch(t){let e=Array.from(t.entries());await q(e,this.options.maxConcurrentIO,async([i,s])=>{await this.processCollectionOperations(i,s);});}async processCollectionOperations(t,e){let i=new Map,s=n=>{let r=i.get(n);return r||(r=[],i.set(n,r)),r};for(let n of e)if(n.type==="fullWrite"||n.type==="clear")for(let r=0;r<this.partitionManager.getPartitionCount();r++)s(r).push(n);else if(n.type==="insert"){let r=this.partitionManager.getPartitionIndex(n.document._id);s(r).push(n);}else if(n.type==="update"||n.type==="delete"){let r=this.partitionManager.getPartitionIndex(n.documentId);s(r).push(n);}else if(n.type==="bulkInsert")for(let r of n.documents){let o=this.partitionManager.getPartitionIndex(r._id);s(o).push({type:"insert",collectionName:t,document:r});}else if(n.type==="bulkUpdate"||n.type==="bulkDelete")for(let r of n.documentIds){let o=this.partitionManager.getPartitionIndex(r);n.type==="bulkUpdate"?s(o).push({type:"update",collectionName:t,documentId:r,changes:n.changes}):s(o).push({type:"delete",collectionName:t,documentId:r});}await q(Array.from(i.entries()),this.options.maxConcurrentIO,async([n,r])=>{await this.processPartitionOperations(t,n,r);});}async processPartitionOperations(t,e,i){let s=await this.partitionManager.readPartition(t,e);s||(s={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});for(let n of i)switch(n.type){case "insert":s.documents.push(n.document);break;case "update":{let r=s.documents.findIndex(o=>o._id===n.documentId);r!==-1&&Object.assign(s.documents[r],n.changes);break}case "delete":{let r=s.documents.findIndex(o=>o._id===n.documentId);r!==-1&&s.documents.splice(r,1);break}case "clear":s.documents=[];break;case "fullWrite":{let r=n.data.documents.filter(o=>this.partitionManager.getPartitionIndex(o._id)===e);s.documents=r;break}}await this.partitionManager.writePartition(t,e,s);}async insert(t,e){await this.writeQueue.enqueue({type:"insert",collectionName:t,document:e});}async insertMany(t,e){await this.writeQueue.enqueue({type:"bulkInsert",collectionName:t,documents:e});}async update(t,e,i){await this.writeQueue.enqueue({type:"update",collectionName:t,documentId:e,changes:i});}async delete(t,e){await this.writeQueue.enqueue({type:"delete",collectionName:t,documentId:e});}async clear(t){await this.writeQueue.enqueue({type:"clear",collectionName:t});}async findById(t,e){return await this.writeQueue.flush(),this.partitionManager.findById(t,e)}async readAll(t){return await this.writeQueue.flush(),this.partitionManager.getAllDocuments(t)}async exists(t){return (await this.partitionManager.listCollections()).includes(t)}async initializeCollection(t){await this.partitionManager.initializePartitions(t);}async deleteCollection(t){await this.writeQueue.flush(),await this.partitionManager.deleteCollection(t);}async listCollections(){return this.partitionManager.listCollections()}async flush(){await this.writeQueue.flush();}async shutdown(){await this.writeQueue.shutdown(),await this.workerPool.shutdown();}pendingWrites(){return this.writeQueue.pending()}getStats(){return {pendingWrites:this.writeQueue.pending(),workerPool:this.workerPool.getStats(),partitions:this.options.partitions}}clearCache(t){this.partitionManager.clearCache(t);}};var _=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new T,this.idGenerator=i.idGenerator??P,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new w(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(await this.storage.findById(this.name,e))throw new y(this.name,e);let s={...h(t),_id:e},n=this.validate(s);return await this.storage.insert(this.name,n),n}async insertFast(t){let e=t._id||this.idGenerator(),i={...h(t),_id:e},s=this.validate(i);return await this.storage.insert(this.name,s),s}async insertMany(t){if(t.length===0)return [];let e=[],i=[];for(let s of t){let n=s._id||this.idGenerator(),r={...h(s),_id:n},o=this.validate(r);i.push(o),e.push(h(o));}return await this.storage.insertMany(this.name,i),e}async find(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.findById(this.name,t);return e?h(e):null}async count(t){let e=await this.storage.readAll(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return 0;for(let n of s){let r=this.getUpdateChanges(n,e);await this.storage.update(this.name,n._id,r);}return s.length}async updateOne(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return null;let n=s[0],r=this.getUpdateChanges(n,e);return await this.storage.update(this.name,n._id,r),Object.assign(n,r),h(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;for(let s of i)await this.storage.delete(this.name,s._id);return i.length}async deleteOne(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let s=i[0];return await this.storage.delete(this.name,s._id),h(s)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){await this.storage.clear(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}getUpdateChanges(t,e){if(!Object.keys(e).some(r=>r.startsWith("$")))return e;let s=e,n={};if(s.$set)for(let[r,o]of Object.entries(s.$set))r!=="_id"&&(n[r]=o);if(s.$inc)for(let[r,o]of Object.entries(s.$inc)){let a=t[r];typeof a=="number"&&typeof o=="number"&&(n[r]=a+o);}if(s.$push)for(let[r,o]of Object.entries(s.$push)){let a=t[r];Array.isArray(a)&&(n[r]=[...a,o]);}if(s.$pull)for(let[r,o]of Object.entries(s.$pull)){let a=t[r];Array.isArray(a)&&(n[r]=a.filter(l=>JSON.stringify(l)!==JSON.stringify(o)));}if(s.$addToSet)for(let[r,o]of Object.entries(s.$addToSet)){let a=t[r];Array.isArray(a)&&(a.some(u=>JSON.stringify(u)===JSON.stringify(o))?n[r]=a:n[r]=[...a,o]);}return n}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var C=class{capacity;cache;constructor(t){this.capacity=t,this.cache=new Map;}get(t){if(!this.cache.has(t))return;let e=this.cache.get(t);return this.cache.delete(t),this.cache.set(t,e),e}set(t,e){if(this.cache.has(t))this.cache.delete(t);else if(this.cache.size>=this.capacity){let i=this.cache.keys().next().value;i!==void 0&&this.cache.delete(i);}this.cache.set(t,e);}has(t){return this.cache.has(t)}delete(t){return this.cache.delete(t)}clear(){this.cache.clear();}get size(){return this.cache.size}keys(){return this.cache.keys()}values(){return this.cache.values()}entries(){return this.cache.entries()}forEach(t){this.cache.forEach(t);}};var W=class{dataDir;fileExtension;prettyPrint;cacheSize;chunkSize;documentCache;collections;locks;constructor(t){this.dataDir=S__namespace.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.cacheSize=t.lazyLoading?.cacheSize??1e3,this.chunkSize=t.lazyLoading?.chunkSize??1e4,this.documentCache=new Map,this.collections=new Map,this.locks=new Map,this.ensureDirectory();}ensureDirectory(){try{d__namespace.existsSync(this.dataDir)||d__namespace.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t,e){return e!==void 0&&this.chunkSize>0?S__namespace.join(this.dataDir,`${t}_chunk${e}${this.fileExtension}`):S__namespace.join(this.dataDir,`${t}${this.fileExtension}`)}getIndexFilePath(t){return S__namespace.join(this.dataDir,`${t}.index${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async initCollection(t){if(this.collections.has(t))return;let e=this.getFilePath(t),i=this.getIndexFilePath(t);if(d__namespace.existsSync(i))try{let s=await d__namespace.promises.readFile(i,"utf-8"),n=JSON.parse(s),r={name:t,createdAt:n.createdAt,updatedAt:n.updatedAt,index:new Map(n.ids.map((o,a)=>[o,{id:o,offset:a}])),count:n.ids.length,dirty:!1};this.collections.set(t,r),this.documentCache.set(t,new C(this.cacheSize));return}catch{}if(d__namespace.existsSync(e))try{let s=await d__namespace.promises.readFile(e,"utf-8"),n=JSON.parse(s),r=new Map;n.documents.forEach((u,Q)=>{r.set(u._id,{id:u._id,offset:Q});});let o={name:t,createdAt:n.createdAt,updatedAt:n.updatedAt,index:r,count:n.documents.length,dirty:!1};this.collections.set(t,o),this.documentCache.set(t,new C(this.cacheSize));let a=this.documentCache.get(t),l=Math.min(n.documents.length,this.cacheSize);for(let u=0;u<l;u++)a.set(n.documents[u]._id,n.documents[u]);await this.saveIndex(t);}catch(s){throw new f(`Failed to initialize collection "${t}"`,s)}else {let s={name:t,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString(),index:new Map,count:0,dirty:false};this.collections.set(t,s),this.documentCache.set(t,new C(this.cacheSize));}}async saveIndex(t){let e=this.collections.get(t);if(!e)return;let i=this.getIndexFilePath(t),s={name:t,createdAt:e.createdAt,updatedAt:e.updatedAt,ids:Array.from(e.index.keys())},n=this.prettyPrint?JSON.stringify(s,null,2):JSON.stringify(s);await d__namespace.promises.writeFile(i,n,"utf-8");}getCount(t){return this.collections.get(t)?.count??0}hasDocument(t,e){return this.collections.get(t)?.index.has(e)??false}getDocumentIds(t){let e=this.collections.get(t);return e?Array.from(e.index.keys()):[]}async getDocument(t,e){await this.initCollection(t);let i=this.collections.get(t);if(!i||!i.index.has(e))return null;let s=this.documentCache.get(t),n=s.get(e);if(n)return n;let r=await this.loadDocumentFromDisk(t,e);return r&&s.set(e,r),r}async loadDocumentFromDisk(t,e){let i=this.getFilePath(t);try{let s=await d__namespace.promises.readFile(i,"utf-8");return JSON.parse(s).documents.find(r=>r._id===e)??null}catch{return null}}async getDocuments(t,e){await this.initCollection(t);let i=this.documentCache.get(t),s=[],n=[];for(let r of e){let o=i.get(r);o?s.push(o):n.push(r);}if(n.length>0){let r=await this.loadDocumentsFromDisk(t,n);for(let o of r)i.set(o._id,o),s.push(o);}return s}async loadDocumentsFromDisk(t,e){let i=this.getFilePath(t),s=new Set(e);try{let n=await d__namespace.promises.readFile(i,"utf-8");return JSON.parse(n).documents.filter(o=>s.has(o._id))}catch{return []}}async getAllDocuments(t){await this.initCollection(t);let e=this.getFilePath(t);try{if(!d__namespace.existsSync(e))return [];let i=await d__namespace.promises.readFile(e,"utf-8"),s=JSON.parse(i),n=this.documentCache.get(t);for(let r of s.documents)n.set(r._id,r);return s.documents}catch{return []}}async insertDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);s.index.set(e._id,{id:e._id,offset:s.count}),s.count++,s.updatedAt=new Date().toISOString(),s.dirty=!0,n.set(e._id,e),await this.persistCollection(t);}finally{i();}}async insertDocuments(t,e){if(e.length===0)return;await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);for(let r of e)s.index.set(r._id,{id:r._id,offset:s.count}),s.count++,n.set(r._id,r);s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async updateDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);if(!s.index.has(e._id))return;n.set(e._id,e),s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async deleteDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);if(!s.index.has(e))return;s.index.delete(e),s.count--,n.delete(e),s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async deleteDocuments(t,e){if(e.length===0)return;await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);for(let r of e)s.index.has(r)&&(s.index.delete(r),s.count--,n.delete(r));s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async clearCollection(t){await this.initCollection(t);let e=await this.acquireLock(t);try{let i=this.collections.get(t),s=this.documentCache.get(t);i.index.clear(),i.count=0,s.clear(),i.updatedAt=new Date().toISOString(),i.dirty=!0,await this.persistCollection(t);}finally{e();}}async persistCollection(t){let e=this.collections.get(t);if(!e)return;let i=this.getFilePath(t),s=`${i}.tmp.${Date.now()}`;try{let n=await this.buildDocumentArray(t),r={name:t,documents:n,createdAt:e.createdAt,updatedAt:e.updatedAt},o=this.prettyPrint?JSON.stringify(r,null,2):JSON.stringify(r);await d__namespace.promises.writeFile(s,o,"utf-8"),await d__namespace.promises.rename(s,i),await this.saveIndex(t),e.dirty=!1;}catch(n){try{d__namespace.existsSync(s)&&await d__namespace.promises.unlink(s);}catch{}throw new f(`Failed to persist collection "${t}"`,n)}}async buildDocumentArray(t){let e=this.collections.get(t);if(!e||e.count===0)return [];let i=this.getFilePath(t),s=[];try{if(d__namespace.existsSync(i)){let a=await d__namespace.promises.readFile(i,"utf-8");s=JSON.parse(a).documents;}}catch{}let n=new Map;for(let a of s)n.set(a._id,a);this.documentCache.get(t).forEach((a,l)=>{n.set(l,a);});let o=[];for(let a of e.index.keys()){let l=n.get(a);l&&o.push(l);}return o}async deleteCollection(t){let e=await this.acquireLock(t);try{this.collections.delete(t),this.documentCache.delete(t);let i=this.getFilePath(t),s=this.getIndexFilePath(t);d__namespace.existsSync(i)&&await d__namespace.promises.unlink(i),d__namespace.existsSync(s)&&await d__namespace.promises.unlink(s);}finally{e();}}async exists(t){if(this.collections.has(t))return true;let e=this.getFilePath(t);return d__namespace.existsSync(e)}async list(){try{let t=await d__namespace.promises.readdir(this.dataDir),e=new Set;for(let i of t)i.includes(".index")||i.includes("_chunk")||i.endsWith(this.fileExtension)&&e.add(i.slice(0,-this.fileExtension.length));return Array.from(e)}catch{return []}}getStats(){let t=0;for(let e of this.documentCache.values())t+=e.size;return {collections:this.collections.size,cachedDocuments:t,cacheSize:this.cacheSize}}clearCache(t){if(t)this.documentCache.get(t)?.clear();else for(let e of this.documentCache.values())e.clear();}async flush(){for(let[t,e]of this.collections.entries())e.dirty&&await this.persistCollection(t);}getDataDir(){return this.dataDir}};var L=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new T,this.idGenerator=i.idGenerator??P,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new w(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(this.storage.hasDocument(this.name,e))throw new y(this.name,e);let i={...h(t),_id:e},s=this.validate(i);return await this.storage.insertDocument(this.name,s),h(s)}async insertFast(t){let e=t._id||this.idGenerator(),i={...h(t),_id:e},s=this.validate(i);return await this.storage.insertDocument(this.name,s),h(s)}async insertMany(t){if(t.length===0)return [];let e=new Set(this.storage.getDocumentIds(this.name)),i=[];for(let s of t){let n=s._id||this.idGenerator();if(e.has(n))throw new y(this.name,n);e.add(n);let r={...h(s),_id:n},o=this.validate(r);i.push(o);}return await this.storage.insertDocuments(this.name,i),i.map(s=>h(s))}async find(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),e?.projection?s.map(n=>b(h(n),e.projection)):s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.getDocument(this.name,t);return e?h(e):null}async count(t){if(!t||Object.keys(t).length===0)return this.storage.getCount(this.name);let e=await this.storage.getAllDocuments(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return 0;for(let n of s)this.applyUpdate(n,e),await this.storage.updateDocument(this.name,n);return s.length}async updateOne(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return null;let n=s[0];return this.applyUpdate(n,e),await this.storage.updateDocument(this.name,n),h(n)}async updateById(t,e){let i=await this.storage.getDocument(this.name,t);return i?(this.applyUpdate(i,e),await this.storage.updateDocument(this.name,i),h(i)):null}async delete(t){let e=await this.storage.getAllDocuments(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;let s=i.map(n=>n._id);return await this.storage.deleteDocuments(this.name,s),i.length}async deleteOne(t){let e=await this.storage.getAllDocuments(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let s=i[0];return await this.storage.deleteDocument(this.name,s._id),h(s)}async deleteById(t){let e=await this.storage.getDocument(this.name,t);return e?(await this.storage.deleteDocument(this.name,t),h(e)):null}async getAll(){return this.find()}async clear(){await this.storage.clearCollection(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let s=e;if(s.$set)for(let[n,r]of Object.entries(s.$set))n!=="_id"&&x(t,n,r);if(s.$unset)for(let n of Object.keys(s.$unset))n!=="_id"&&k(t,n);if(s.$inc)for(let[n,r]of Object.entries(s.$inc)){let o=t[n];typeof o=="number"&&typeof r=="number"&&(t[n]=o+r);}if(s.$push)for(let[n,r]of Object.entries(s.$push)){let o=t[n];Array.isArray(o)&&o.push(r);}if(s.$pull)for(let[n,r]of Object.entries(s.$pull)){let o=t[n];if(Array.isArray(o)){let a=o.findIndex(l=>JSON.stringify(l)===JSON.stringify(r));a!==-1&&o.splice(a,1);}}if(s.$addToSet)for(let[n,r]of Object.entries(s.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(l=>JSON.stringify(l)===JSON.stringify(r))||o.push(r));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var K={autoSave:true,saveDebounce:0,prettyPrint:true,fileExtension:".json"},H=class{options;storage;hcStorage;lazyStorage;collections=new Map;isHighConcurrency;isLazyLoading;connected=false;constructor(t){if(this.options={...K,...t},this.isHighConcurrency=t.highConcurrency?.enabled??false,this.isLazyLoading=t.lazyLoading?.enabled??false,this.isHighConcurrency&&this.isLazyLoading)throw new Error("Cannot enable both highConcurrency and lazyLoading modes simultaneously");this.isHighConcurrency?(this.storage=null,this.hcStorage=new I(this.options),this.lazyStorage=null):this.isLazyLoading?(this.storage=null,this.hcStorage=null,this.lazyStorage=new W(this.options)):(this.storage=new F(this.options),this.hcStorage=null,this.lazyStorage=null);}getStorage(){if(this.storage===null)throw new Error("Storage is not available in high-concurrency or lazy loading mode");return this.storage}getHCStorage(){if(this.hcStorage===null)throw new Error("HighConcurrencyStorage is not available in standard or lazy loading mode");return this.hcStorage}getLazyStorage(){if(this.lazyStorage===null)throw new Error("LazyStorage is not available in standard or high-concurrency mode");return this.lazyStorage}async connect(){if(!this.connected){if(this.isHighConcurrency){let t=await this.getHCStorage().listCollections();for(let e of t)this.getOrCreateCollection(e);}else if(this.isLazyLoading){let t=await this.getLazyStorage().list();for(let e of t)this.getOrCreateCollection(e);}else {let t=await this.getStorage().list();for(let e of t)this.getOrCreateCollection(e);}this.connected=true;}}async close(){if(this.connected){for(let t of this.collections.values())await t.flush();this.isHighConcurrency&&this.hcStorage&&await this.hcStorage.shutdown(),this.collections.clear(),this.storage&&this.storage.clearCache(),this.hcStorage&&this.hcStorage.clearCache(),this.lazyStorage&&this.lazyStorage.clearCache(),this.connected=false;}}collection(t,e){if(!t||typeof t!="string")throw new v("Collection name must be a non-empty string");if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(t))throw new v("Collection name must start with a letter or underscore and contain only letters, numbers, underscores, and hyphens");return this.getOrCreateCollection(t,e)}getOrCreateCollection(t,e){if(this.collections.has(t))return this.collections.get(t);if(this.isHighConcurrency){let i=new _(t,this.getHCStorage(),{schema:e?.schema});this.collections.set(t,i);}else if(this.isLazyLoading){let i=new L(t,this.getLazyStorage(),{schema:e?.schema});this.collections.set(t,i);}else {let i=new O(t,this.getStorage(),{autoSave:this.options.autoSave,saveDebounce:this.options.saveDebounce,schema:e?.schema});this.collections.set(t,i);}return this.collections.get(t)}async hasCollection(t){return this.isHighConcurrency?this.getHCStorage().exists(t):this.getStorage().exists(t)}async listCollections(){return this.isHighConcurrency?this.getHCStorage().listCollections():this.getStorage().list()}async dropCollection(t){let e=this.collections.get(t);e?(await e.drop(),this.collections.delete(t)):this.isHighConcurrency?await this.getHCStorage().deleteCollection(t):await this.getStorage().delete(t);}async drop(){if(this.isHighConcurrency){let t=this.getHCStorage(),e=await t.listCollections();for(let i of e)await t.deleteCollection(i);}else {let t=this.getStorage(),e=await t.list();for(let i of e)await t.delete(i);}this.collections.clear(),this.storage?.clearCache(),this.hcStorage?.clearCache();}getDataDir(){return this.isHighConcurrency?this.options.dataDir:this.getStorage().getDataDir()}isConnected(){return this.connected}isHighConcurrencyMode(){return this.isHighConcurrency}getStats(){return !this.isHighConcurrency||!this.hcStorage?null:this.hcStorage.getStats()}async flush(){for(let t of this.collections.values())await t.flush();}};exports.Collection=O;exports.CollectionError=v;exports.DocumentNotFoundError=j;exports.DuplicateKeyError=y;exports.HighConcurrencyCollection=_;exports.HighConcurrencyStorage=I;exports.JsonDB=H;exports.JsonDBError=D;exports.PartitionManager=A;exports.StorageError=f;exports.ValidationError=w;exports.WorkerPool=E;exports.WriteQueue=$;exports.generateId=P;exports.isValidId=B;exports.parallelLimit=q;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import*as d from'fs';import*as E from'path';import {ObjectId}from'bson';var y=class extends Error{constructor(t){super(t),this.name="JsonDBError",Error.captureStackTrace?.(this,this.constructor);}},A=class extends y{constructor(t,e){super(e?`Document with id "${e}" not found in collection "${t}"`:`Document not found in collection "${t}"`),this.name="DocumentNotFoundError";}},w=class extends y{constructor(t,e){super(`Duplicate key error: document with id "${e}" already exists in collection "${t}"`),this.name="DuplicateKeyError";}},T=class extends y{collectionName;issues;field;value;constructor(t,e,i,r){let n=e.map(s=>`${s.path.join(".")}: ${s.message}`).join("; ");super(`Validation failed for collection "${t}": ${n}`),this.name="ValidationError",this.collectionName=t,this.issues=e,this.field=i,this.value=r;}},f=class extends y{cause;constructor(t,e){super(t),this.name="StorageError",this.cause=e;}},v=class extends y{constructor(t){super(t),this.name="CollectionError";}};var $=class{dataDir;fileExtension;prettyPrint;cache=new Map;locks=new Map;constructor(t){this.dataDir=E.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.ensureDirectory();}ensureDirectory(){try{d.existsSync(this.dataDir)||d.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t){return E.join(this.dataDir,`${t}${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(r=>{e=r;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async read(t){if(this.cache.has(t))return this.cache.get(t);let e=this.getFilePath(t);try{if(!d.existsSync(e))return null;let i=await d.promises.readFile(e,"utf-8"),r=JSON.parse(i);return this.cache.set(t,r),r}catch(i){throw new f(`Failed to read collection "${t}"`,i)}}async write(t,e){let i=this.getFilePath(t),r=`${i}.tmp.${Date.now()}`,n=await this.acquireLock(t);try{e.updatedAt=new Date().toISOString();let s=this.prettyPrint?JSON.stringify(e,null,2):JSON.stringify(e);await d.promises.writeFile(r,s,"utf-8"),await d.promises.rename(r,i),this.cache.set(t,e);}catch(s){try{d.existsSync(r)&&await d.promises.unlink(r);}catch{}throw new f(`Failed to write collection "${t}"`,s)}finally{n();}}async exists(t){let e=this.getFilePath(t);return d.existsSync(e)}async delete(t){let e=this.getFilePath(t),i=await this.acquireLock(t);try{d.existsSync(e)&&await d.promises.unlink(e),this.cache.delete(t);}catch(r){throw new f(`Failed to delete collection "${t}"`,r)}finally{i();}}async list(){try{return (await d.promises.readdir(this.dataDir)).filter(e=>e.endsWith(this.fileExtension)).map(e=>e.slice(0,-this.fileExtension.length))}catch(t){throw new f("Failed to list collections",t)}}clearCache(t){t?this.cache.delete(t):this.cache.clear();}getDataDir(){return this.dataDir}};function D(a){return new ObjectId().toHexString()}function j(a){return typeof a!="string"||a.length===0||a.length>64?false:a.length===24?ObjectId.isValid(a):true}function l(a){if(a===null||typeof a!="object")return a;if(a instanceof Date)return new Date(a.getTime());if(a instanceof RegExp)return new RegExp(a.source,a.flags);if(Array.isArray(a))return a.map(e=>l(e));let t={};for(let e in a)Object.prototype.hasOwnProperty.call(a,e)&&(t[e]=l(a[e]));return t}function W(a,t){let e=t.split("."),i=a;for(let r of e){if(i==null||typeof i!="object")return;i=i[r];}return i}function q(a,t,e){let i=t.split("."),r=a;for(let n=0;n<i.length-1;n++){let s=i[n];(!(s in r)||typeof r[s]!="object"||r[s]===null)&&(r[s]={}),r=r[s];}r[i[i.length-1]]=e;}function _(a,t){let e=t.split("."),i=a;for(let n=0;n<e.length-1;n++){let s=e[n];if(!(s in i)||typeof i[s]!="object"||i[s]===null)return false;i=i[s];}let r=e[e.length-1];return r in i?(delete i[r],true):false}function F(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)&&!(a instanceof Date)&&!(a instanceof RegExp)}var P=class{filter(t,e){return !e||Object.keys(e).length===0?t:t.filter(i=>this.matches(i,e))}matches(t,e){if("$and"in e&&e.$and)return e.$and.every(i=>this.matches(t,i));if("$or"in e&&e.$or)return e.$or.some(i=>this.matches(t,i));if("$not"in e&&e.$not)return !this.matches(t,e.$not);for(let[i,r]of Object.entries(e)){if(i.startsWith("$"))continue;let n=W(t,i);if(!this.matchesCondition(n,r))return false}return true}matchesCondition(t,e){if(!F(e)||!this.hasOperators(e))return this.isEqual(t,e);let i=e;if("$eq"in i&&!this.isEqual(t,i.$eq)||"$ne"in i&&this.isEqual(t,i.$ne)||"$gt"in i&&!this.compareValues(t,i.$gt,">")||"$gte"in i&&!this.compareValues(t,i.$gte,">=")||"$lt"in i&&!this.compareValues(t,i.$lt,"<")||"$lte"in i&&!this.compareValues(t,i.$lte,"<=")||"$in"in i&&Array.isArray(i.$in)&&!i.$in.some(r=>this.isEqual(t,r))||"$nin"in i&&Array.isArray(i.$nin)&&i.$nin.some(r=>this.isEqual(t,r)))return false;if("$exists"in i){let r=t!=null;if(i.$exists!==r)return false}return !("$regex"in i&&(typeof t!="string"||!(i.$regex instanceof RegExp?i.$regex:new RegExp(i.$regex)).test(t))||"$startsWith"in i&&(typeof t!="string"||typeof i.$startsWith!="string"||!t.startsWith(i.$startsWith))||"$endsWith"in i&&(typeof t!="string"||typeof i.$endsWith!="string"||!t.endsWith(i.$endsWith))||"$contains"in i&&(!Array.isArray(t)||!t.some(r=>this.isEqual(r,i.$contains))))}hasOperators(t){return Object.keys(t).some(e=>e.startsWith("$"))}isEqual(t,e){if(t===e)return true;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return false;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?false:t.every((i,r)=>this.isEqual(i,e[r]));if(typeof t=="object"&&typeof e=="object"){let i=Object.keys(t),r=Object.keys(e);return i.length!==r.length?false:i.every(n=>this.isEqual(t[n],e[n]))}return false}compareValues(t,e,i){if(typeof t=="number"&&typeof e=="number")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(typeof t=="string"&&typeof e=="string")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(t instanceof Date&&e instanceof Date)switch(i){case ">":return t.getTime()>e.getTime();case ">=":return t.getTime()>=e.getTime();case "<":return t.getTime()<e.getTime();case "<=":return t.getTime()<=e.getTime()}return false}};var C=class{name;storage;queryEngine;autoSave;saveDebounce;idGenerator;schema;saveTimeout=null;pendingSave=null;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new P,this.autoSave=i.autoSave??true,this.saveDebounce=i.saveDebounce??0,this.idGenerator=i.idGenerator??D,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new T(this.name,e.error.issues);return e.data}async getData(){let t=await this.storage.read(this.name);if(!t){let e={name:this.name,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return await this.storage.write(this.name,e),e}return t}async save(t){if(this.autoSave){if(this.saveDebounce>0)return this.saveTimeout&&clearTimeout(this.saveTimeout),new Promise(e=>{this.saveTimeout=setTimeout(async()=>{await this.storage.write(this.name,t),this.saveTimeout=null,e();},this.saveDebounce);});await this.storage.write(this.name,t);}}async flush(){this.saveTimeout&&(clearTimeout(this.saveTimeout),this.saveTimeout=null),this.pendingSave&&await this.pendingSave;let t=await this.getData();await this.storage.write(this.name,t);}async insert(t){let e=await this.getData(),i=t._id||this.idGenerator();if(e.documents.some(s=>s._id===i))throw new w(this.name,i);let r={...l(t),_id:i},n=this.validate(r);return e.documents.push(n),await this.save(e),l(n)}async insertFast(t){let e=await this.getData(),i=t._id||this.idGenerator(),r={...l(t),_id:i},n=this.validate(r);return e.documents.push(n),await this.save(e),l(n)}async insertMany(t){if(t.length===0)return [];let e=await this.getData(),i=[],r=new Set(e.documents.map(n=>n._id));for(let n of t){let s=n._id||this.idGenerator();if(r.has(s))throw new w(this.name,s);r.add(s);let o={...l(n),_id:s},c=this.validate(o);e.documents.push(c),i.push(l(c));}return await this.save(e),i}async find(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);return e?.sort&&(r=this.sortDocuments(r,e.sort)),e?.skip&&e.skip>0&&(r=r.slice(e.skip)),e?.limit&&e.limit>0&&(r=r.slice(0,e.limit)),r.map(n=>l(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){return this.findOne({_id:t})}async count(t){let e=await this.getData();return this.queryEngine.filter(e.documents,t).length}async update(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);if(r.length===0)return 0;for(let n of r)this.applyUpdate(n,e);return await this.save(i),r.length}async updateOne(t,e){let i=await this.getData(),r=this.queryEngine.filter(i.documents,t);if(r.length===0)return null;let n=r[0];return this.applyUpdate(n,e),await this.save(i),l(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.getData(),i=e.documents.length;e.documents=e.documents.filter(n=>!this.queryEngine.matches(n,t));let r=i-e.documents.length;return r>0&&await this.save(e),r}async deleteOne(t){let e=await this.getData(),i=e.documents.findIndex(n=>this.queryEngine.matches(n,t));if(i===-1)return null;let[r]=e.documents.splice(i,1);return await this.save(e),l(r)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){let t=await this.getData();t.documents=[],await this.save(t);}async drop(){await this.storage.delete(this.name);}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let r=e;if(r.$set)for(let[n,s]of Object.entries(r.$set))n!=="_id"&&q(t,n,s);if(r.$unset)for(let n of Object.keys(r.$unset))n!=="_id"&&_(t,n);if(r.$inc)for(let[n,s]of Object.entries(r.$inc)){let o=t[n];typeof o=="number"&&typeof s=="number"&&(t[n]=o+s);}if(r.$push)for(let[n,s]of Object.entries(r.$push)){let o=t[n];Array.isArray(o)&&o.push(s);}if(r.$pull)for(let[n,s]of Object.entries(r.$pull)){let o=t[n];if(Array.isArray(o)){let c=o.findIndex(u=>JSON.stringify(u)===JSON.stringify(s));c!==-1&&o.splice(c,1);}}if(r.$addToSet)for(let[n,s]of Object.entries(r.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(u=>JSON.stringify(u)===JSON.stringify(s))||o.push(s));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((r,n)=>{for(let[s,o]of i){let c=r[s],u=n[s],h=0;if(c===u?h=0:c==null?h=1:u==null?h=-1:typeof c=="number"&&typeof u=="number"?h=c-u:typeof c=="string"&&typeof u=="string"?h=c.localeCompare(u):c instanceof Date&&u instanceof Date?h=c.getTime()-u.getTime():h=String(c).localeCompare(String(u)),h!==0)return h*(o===-1||o==="desc"?-1:1)}return 0})}};var x=class{batchSize;flushInterval;coalesceWrites;batchProcessor;queue=new Map;flushTimer=null;pendingFlush=null;totalQueued=0;isShuttingDown=false;constructor(t,e={}){this.batchSize=e.batchSize??1e3,this.flushInterval=e.flushInterval??100,this.coalesceWrites=e.coalesceWrites??true,this.batchProcessor=t;}async enqueue(t){if(this.isShuttingDown)throw new Error("WriteQueue is shutting down, no new writes accepted");return new Promise((e,i)=>{let r={operation:t,resolve:e,reject:i,timestamp:Date.now()},n=t.collectionName,s=this.queue.get(n);s||(s=[],this.queue.set(n,s)),!(this.coalesceWrites&&this.tryCoalesce(n,r))&&(s.push(r),this.totalQueued++,this.scheduleFlush(),this.totalQueued>=this.batchSize&&this.flush().catch(i));})}tryCoalesce(t,e){let i=this.queue.get(t);if(!i||i.length===0)return false;let r=e.operation;if(r.type==="update")for(let n=i.length-1;n>=0;n--){let s=i[n].operation;if(s.type==="update"&&s.documentId===r.documentId){s.changes={...s.changes,...r.changes};let o=i[n].resolve;return i[n].resolve=()=>{o(),e.resolve();},true}}if(r.type==="delete")for(let n=i.length-1;n>=0;n--){let s=i[n].operation;(s.type==="insert"&&s.document._id===r.documentId||s.type==="update"&&s.documentId===r.documentId)&&(i.splice(n,1),this.totalQueued--);}if(r.type==="clear"||r.type==="fullWrite"){for(let n of i)n.resolve();i.length=0,this.totalQueued-=i.length;}return false}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush().catch(t=>{console.error("WriteQueue flush error:",t);});},this.flushInterval));}async flush(){if(this.pendingFlush)return this.pendingFlush;if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.totalQueued===0)return;let t=this.queue;this.queue=new Map,this.totalQueued=0;let e=new Map;for(let[i,r]of t)e.set(i,r.map(n=>n.operation));this.pendingFlush=this.processBatch(t,e),await this.pendingFlush,this.pendingFlush=null;}async processBatch(t,e){try{await this.batchProcessor(e);for(let i of t.values())for(let r of i)r.resolve();}catch(i){for(let r of t.values())for(let n of r)n.reject(i);}}async shutdown(){this.isShuttingDown=true,await this.flush();}pending(){return this.totalQueued}isEmpty(){return this.totalQueued===0}isClosing(){return this.isShuttingDown}};var S=class{dataDir;partitionCount;prettyPrint;fileExtension;cache=new Map;locks=new Map;constructor(t,e={}){this.dataDir=E.resolve(t),this.partitionCount=e.partitionCount??16,this.prettyPrint=e.prettyPrint??true,this.fileExtension=e.fileExtension??".json",this.ensureDirectory();}ensureDirectory(){try{d.existsSync(this.dataDir)||d.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getPartitionIndex(t){let e=0;for(let i=0;i<t.length;i++){let r=t.charCodeAt(i);e=(e<<5)-e+r,e=e&e;}return Math.abs(e)%this.partitionCount}getPartitionFileName(t,e){return `${t}_p${e.toString().padStart(3,"0")}${this.fileExtension}`}getPartitionFilePath(t,e){return E.join(this.dataDir,this.getPartitionFileName(t,e))}getCacheKey(t,e){return `${t}:${e}`}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(r=>{e=r;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async readPartition(t,e){let i=this.getCacheKey(t,e);if(this.cache.has(i))return this.cache.get(i);let r=this.getPartitionFilePath(t,e);try{if(!d.existsSync(r))return null;let n=await d.promises.readFile(r,"utf-8"),s=JSON.parse(n);return this.cache.set(i,s),s}catch(n){throw new f(`Failed to read partition ${e} for collection "${t}"`,n)}}async writePartition(t,e,i){let r=this.getPartitionFilePath(t,e),n=`${r}.tmp.${Date.now()}`,s=this.getCacheKey(t,e),o=await this.acquireLock(s);try{i.updatedAt=new Date().toISOString();let c=this.prettyPrint?JSON.stringify(i,null,2):JSON.stringify(i);await d.promises.writeFile(n,c,"utf-8"),await d.promises.rename(n,r),this.cache.set(s,i);}catch(c){try{d.existsSync(n)&&await d.promises.unlink(n);}catch{}throw new f(`Failed to write partition ${e} for collection "${t}"`,c)}finally{o();}}async readAllPartitions(t){let e=new Map,i=[];for(let r=0;r<this.partitionCount;r++)i.push(this.readPartition(t,r).then(n=>{n&&e.set(r,n);}));return await Promise.all(i),e}async writePartitions(t,e){let i=[];for(let[r,n]of e)i.push(this.writePartition(t,r,n));await Promise.all(i);}async initializePartitions(t){let e=[];for(let i=0;i<this.partitionCount;i++)if(!d.existsSync(this.getPartitionFilePath(t,i))){let n={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};e.push(this.writePartition(t,i,n));}await Promise.all(e);}async getPartitionInfo(t){let e=await this.readAllPartitions(t),i=[];for(let r=0;r<this.partitionCount;r++){let n=e.get(r);i.push({name:this.getPartitionFileName(t,r),partitionIndex:r,documentCount:n?.documents.length??0});}return i}async getAllDocuments(t){let e=await this.readAllPartitions(t),i=[];for(let r of e.values())i.push(...r.documents);return i}async findById(t,e){let i=this.getPartitionIndex(e),r=await this.readPartition(t,i);return r?r.documents.find(n=>n._id===e)??null:null}async deleteCollection(t){let e=[];for(let i=0;i<this.partitionCount;i++){let r=this.getPartitionFilePath(t,i),n=this.getCacheKey(t,i);e.push((async()=>{let s=await this.acquireLock(n);try{d.existsSync(r)&&await d.promises.unlink(r),this.cache.delete(n);}finally{s();}})());}await Promise.all(e);}clearCache(t){if(t)for(let e=0;e<this.partitionCount;e++)this.cache.delete(this.getCacheKey(t,e));else this.cache.clear();}getPartitionCount(){return this.partitionCount}async listCollections(){try{let t=await d.promises.readdir(this.dataDir),e=new Set,i=new RegExp(`^(.+)_p\\d{3}\\${this.fileExtension}$`);for(let r of t){let n=r.match(i);n&&e.add(n[1]);}return Array.from(e)}catch(t){throw new f("Failed to list partitioned collections",t)}}};var k=class{maxConcurrent;maxQueueSize;queue=[];activeCount=0;completedCount=0;failedCount=0;isShuttingDown=false;constructor(t={}){this.maxConcurrent=t.maxConcurrent??4,this.maxQueueSize=t.maxQueueSize??1e4;}async submit(t,e=0){if(this.isShuttingDown)throw new Error("WorkerPool is shutting down, no new tasks accepted");if(this.queue.length>=this.maxQueueSize)throw new Error("WorkerPool queue is full, task rejected (backpressure)");return new Promise((i,r)=>{let n={task:t,resolve:i,reject:r,priority:e},s=false;for(let o=0;o<this.queue.length;o++)if(e>this.queue[o].priority){this.queue.splice(o,0,n),s=true;break}s||this.queue.push(n),this.processNext();})}async submitAll(t,e=0){let i=t.map(r=>this.submit(r,e));return Promise.all(i)}async*submitStream(t,e=0){let i=t.map(r=>this.submit(r,e));for(let r of i)yield await r;}processNext(){if(this.activeCount>=this.maxConcurrent||this.queue.length===0)return;let t=this.queue.shift();t&&(this.activeCount++,t.task().then(e=>{this.completedCount++,t.resolve(e);}).catch(e=>{this.failedCount++,t.reject(e);}).finally(()=>{this.activeCount--,this.processNext();}));}async drain(){return new Promise(t=>{let e=()=>{this.activeCount===0&&this.queue.length===0?t():setImmediate(e);};e();})}async shutdown(){this.isShuttingDown=true,await this.drain();}getStats(){return {activeWorkers:this.activeCount,queuedTasks:this.queue.length,completedTasks:this.completedCount,failedTasks:this.failedCount}}isIdle(){return this.activeCount===0&&this.queue.length===0}isClosing(){return this.isShuttingDown}queueSize(){return this.queue.length}activeWorkers(){return this.activeCount}};async function Q(a,t,e){let i=[],r=0;async function n(){let o=r++;o>=a.length||(i[o]=await e(a[o],o),await n());}let s=Array(Math.min(t,a.length)).fill(null).map(()=>n());return await Promise.all(s),i}var V={partitions:16,batchSize:1e3,flushInterval:100,maxConcurrentIO:4,coalesceWrites:true},O=class{partitionManager;writeQueue;workerPool;options;constructor(t){let e=t.highConcurrency;this.options={...V,...e},this.partitionManager=new S(t.dataDir,{partitionCount:this.options.partitions,prettyPrint:t.prettyPrint??true,fileExtension:t.fileExtension??".json"}),this.workerPool=new k({maxConcurrent:this.options.maxConcurrentIO});let i=this.processBatch.bind(this);this.writeQueue=new x(i,{batchSize:this.options.batchSize,flushInterval:this.options.flushInterval,coalesceWrites:this.options.coalesceWrites});}async processBatch(t){let e=Array.from(t.entries());await Q(e,this.options.maxConcurrentIO,async([i,r])=>{await this.processCollectionOperations(i,r);});}async processCollectionOperations(t,e){let i=new Map,r=n=>{let s=i.get(n);return s||(s=[],i.set(n,s)),s};for(let n of e)if(n.type==="fullWrite"||n.type==="clear")for(let s=0;s<this.partitionManager.getPartitionCount();s++)r(s).push(n);else if(n.type==="insert"){let s=this.partitionManager.getPartitionIndex(n.document._id);r(s).push(n);}else if(n.type==="update"||n.type==="delete"){let s=this.partitionManager.getPartitionIndex(n.documentId);r(s).push(n);}else if(n.type==="bulkInsert")for(let s of n.documents){let o=this.partitionManager.getPartitionIndex(s._id);r(o).push({type:"insert",collectionName:t,document:s});}else if(n.type==="bulkUpdate"||n.type==="bulkDelete")for(let s of n.documentIds){let o=this.partitionManager.getPartitionIndex(s);n.type==="bulkUpdate"?r(o).push({type:"update",collectionName:t,documentId:s,changes:n.changes}):r(o).push({type:"delete",collectionName:t,documentId:s});}await Q(Array.from(i.entries()),this.options.maxConcurrentIO,async([n,s])=>{await this.processPartitionOperations(t,n,s);});}async processPartitionOperations(t,e,i){let r=await this.partitionManager.readPartition(t,e);r||(r={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});for(let n of i)switch(n.type){case "insert":r.documents.push(n.document);break;case "update":{let s=r.documents.findIndex(o=>o._id===n.documentId);s!==-1&&Object.assign(r.documents[s],n.changes);break}case "delete":{let s=r.documents.findIndex(o=>o._id===n.documentId);s!==-1&&r.documents.splice(s,1);break}case "clear":r.documents=[];break;case "fullWrite":{let s=n.data.documents.filter(o=>this.partitionManager.getPartitionIndex(o._id)===e);r.documents=s;break}}await this.partitionManager.writePartition(t,e,r);}async insert(t,e){await this.writeQueue.enqueue({type:"insert",collectionName:t,document:e});}async insertMany(t,e){await this.writeQueue.enqueue({type:"bulkInsert",collectionName:t,documents:e});}async update(t,e,i){await this.writeQueue.enqueue({type:"update",collectionName:t,documentId:e,changes:i});}async delete(t,e){await this.writeQueue.enqueue({type:"delete",collectionName:t,documentId:e});}async clear(t){await this.writeQueue.enqueue({type:"clear",collectionName:t});}async findById(t,e){return await this.writeQueue.flush(),this.partitionManager.findById(t,e)}async readAll(t){return await this.writeQueue.flush(),this.partitionManager.getAllDocuments(t)}async exists(t){return (await this.partitionManager.listCollections()).includes(t)}async initializeCollection(t){await this.partitionManager.initializePartitions(t);}async deleteCollection(t){await this.writeQueue.flush(),await this.partitionManager.deleteCollection(t);}async listCollections(){return this.partitionManager.listCollections()}async flush(){await this.writeQueue.flush();}async shutdown(){await this.writeQueue.shutdown(),await this.workerPool.shutdown();}pendingWrites(){return this.writeQueue.pending()}getStats(){return {pendingWrites:this.writeQueue.pending(),workerPool:this.workerPool.getStats(),partitions:this.options.partitions}}clearCache(t){this.partitionManager.clearCache(t);}};var b=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new P,this.idGenerator=i.idGenerator??D,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new T(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(await this.storage.findById(this.name,e))throw new w(this.name,e);let r={...l(t),_id:e},n=this.validate(r);return await this.storage.insert(this.name,n),n}async insertFast(t){let e=t._id||this.idGenerator(),i={...l(t),_id:e},r=this.validate(i);return await this.storage.insert(this.name,r),r}async insertMany(t){if(t.length===0)return [];let e=[],i=[];for(let r of t){let n=r._id||this.idGenerator(),s={...l(r),_id:n},o=this.validate(s);i.push(o),e.push(l(o));}return await this.storage.insertMany(this.name,i),e}async find(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);return e?.sort&&(r=this.sortDocuments(r,e.sort)),e?.skip&&e.skip>0&&(r=r.slice(e.skip)),e?.limit&&e.limit>0&&(r=r.slice(0,e.limit)),r.map(n=>l(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.findById(this.name,t);return e?l(e):null}async count(t){let e=await this.storage.readAll(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);if(r.length===0)return 0;for(let n of r){let s=this.getUpdateChanges(n,e);await this.storage.update(this.name,n._id,s);}return r.length}async updateOne(t,e){let i=await this.storage.readAll(this.name),r=this.queryEngine.filter(i,t);if(r.length===0)return null;let n=r[0],s=this.getUpdateChanges(n,e);return await this.storage.update(this.name,n._id,s),Object.assign(n,s),l(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;for(let r of i)await this.storage.delete(this.name,r._id);return i.length}async deleteOne(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let r=i[0];return await this.storage.delete(this.name,r._id),l(r)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){await this.storage.clear(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}getUpdateChanges(t,e){if(!Object.keys(e).some(s=>s.startsWith("$")))return e;let r=e,n={};if(r.$set)for(let[s,o]of Object.entries(r.$set))s!=="_id"&&(n[s]=o);if(r.$inc)for(let[s,o]of Object.entries(r.$inc)){let c=t[s];typeof c=="number"&&typeof o=="number"&&(n[s]=c+o);}if(r.$push)for(let[s,o]of Object.entries(r.$push)){let c=t[s];Array.isArray(c)&&(n[s]=[...c,o]);}if(r.$pull)for(let[s,o]of Object.entries(r.$pull)){let c=t[s];Array.isArray(c)&&(n[s]=c.filter(u=>JSON.stringify(u)!==JSON.stringify(o)));}if(r.$addToSet)for(let[s,o]of Object.entries(r.$addToSet)){let c=t[s];Array.isArray(c)&&(c.some(h=>JSON.stringify(h)===JSON.stringify(o))?n[s]=c:n[s]=[...c,o]);}return n}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((r,n)=>{for(let[s,o]of i){let c=r[s],u=n[s],h=0;if(c===u?h=0:c==null?h=1:u==null?h=-1:typeof c=="number"&&typeof u=="number"?h=c-u:typeof c=="string"&&typeof u=="string"?h=c.localeCompare(u):c instanceof Date&&u instanceof Date?h=c.getTime()-u.getTime():h=String(c).localeCompare(String(u)),h!==0)return h*(o===-1||o==="desc"?-1:1)}return 0})}};var B={autoSave:true,saveDebounce:0,prettyPrint:true,fileExtension:".json"},M=class{options;storage;hcStorage;collections=new Map;isHighConcurrency;connected=false;constructor(t){this.options={...B,...t},this.isHighConcurrency=t.highConcurrency?.enabled??false,this.isHighConcurrency?(this.storage=null,this.hcStorage=new O(this.options)):(this.storage=new $(this.options),this.hcStorage=null);}getStorage(){if(this.storage===null)throw new Error("Storage is not available in high-concurrency mode");return this.storage}getHCStorage(){if(this.hcStorage===null)throw new Error("HighConcurrencyStorage is not available in standard mode");return this.hcStorage}async connect(){if(!this.connected){if(this.isHighConcurrency){let t=await this.getHCStorage().listCollections();for(let e of t)this.getOrCreateCollection(e);}else {let t=await this.getStorage().list();for(let e of t)this.getOrCreateCollection(e);}this.connected=true;}}async close(){if(this.connected){for(let t of this.collections.values())await t.flush();this.isHighConcurrency&&this.hcStorage&&await this.hcStorage.shutdown(),this.collections.clear(),this.storage&&this.storage.clearCache(),this.hcStorage&&this.hcStorage.clearCache(),this.connected=false;}}collection(t,e){if(!t||typeof t!="string")throw new v("Collection name must be a non-empty string");if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(t))throw new v("Collection name must start with a letter or underscore and contain only letters, numbers, underscores, and hyphens");return this.getOrCreateCollection(t,e)}getOrCreateCollection(t,e){if(this.collections.has(t))return this.collections.get(t);if(this.isHighConcurrency){let i=new b(t,this.getHCStorage(),{schema:e?.schema});this.collections.set(t,i);}else {let i=new C(t,this.getStorage(),{autoSave:this.options.autoSave,saveDebounce:this.options.saveDebounce,schema:e?.schema});this.collections.set(t,i);}return this.collections.get(t)}async hasCollection(t){return this.isHighConcurrency?this.getHCStorage().exists(t):this.getStorage().exists(t)}async listCollections(){return this.isHighConcurrency?this.getHCStorage().listCollections():this.getStorage().list()}async dropCollection(t){let e=this.collections.get(t);e?(await e.drop(),this.collections.delete(t)):this.isHighConcurrency?await this.getHCStorage().deleteCollection(t):await this.getStorage().delete(t);}async drop(){if(this.isHighConcurrency){let t=this.getHCStorage(),e=await t.listCollections();for(let i of e)await t.deleteCollection(i);}else {let t=this.getStorage(),e=await t.list();for(let i of e)await t.delete(i);}this.collections.clear(),this.storage?.clearCache(),this.hcStorage?.clearCache();}getDataDir(){return this.isHighConcurrency?this.options.dataDir:this.getStorage().getDataDir()}isConnected(){return this.connected}isHighConcurrencyMode(){return this.isHighConcurrency}getStats(){return !this.isHighConcurrency||!this.hcStorage?null:this.hcStorage.getStats()}async flush(){for(let t of this.collections.values())await t.flush();}};export{C as Collection,v as CollectionError,A as DocumentNotFoundError,w as DuplicateKeyError,b as HighConcurrencyCollection,O as HighConcurrencyStorage,M as JsonDB,y as JsonDBError,S as PartitionManager,f as StorageError,T as ValidationError,k as WorkerPool,x as WriteQueue,D as generateId,j as isValidId,Q as parallelLimit};
1
+ import*as d from'fs';import*as x from'path';import {ObjectId}from'bson';var P=class extends Error{constructor(t){super(t),this.name="JsonDBError",Error.captureStackTrace?.(this,this.constructor);}},R=class extends P{constructor(t,e){super(e?`Document with id "${e}" not found in collection "${t}"`:`Document not found in collection "${t}"`),this.name="DocumentNotFoundError";}},w=class extends P{constructor(t,e){super(`Duplicate key error: document with id "${e}" already exists in collection "${t}"`),this.name="DuplicateKeyError";}},T=class extends P{collectionName;issues;field;value;constructor(t,e,i,s){let n=e.map(r=>`${r.path.join(".")}: ${r.message}`).join("; ");super(`Validation failed for collection "${t}": ${n}`),this.name="ValidationError",this.collectionName=t,this.issues=e,this.field=i,this.value=s;}},f=class extends P{cause;constructor(t,e){super(t),this.name="StorageError",this.cause=e;}},C=class extends P{constructor(t){super(t),this.name="CollectionError";}};var z=class{dataDir;fileExtension;prettyPrint;cache=new Map;locks=new Map;constructor(t){this.dataDir=x.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.ensureDirectory();}ensureDirectory(){try{d.existsSync(this.dataDir)||d.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t){return x.join(this.dataDir,`${t}${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async read(t){if(this.cache.has(t))return this.cache.get(t);let e=this.getFilePath(t);try{if(!d.existsSync(e))return null;let i=await d.promises.readFile(e,"utf-8"),s=JSON.parse(i);return this.cache.set(t,s),s}catch(i){throw new f(`Failed to read collection "${t}"`,i)}}async write(t,e){let i=this.getFilePath(t),s=`${i}.tmp.${Date.now()}`,n=await this.acquireLock(t);try{e.updatedAt=new Date().toISOString();let r=this.prettyPrint?JSON.stringify(e,null,2):JSON.stringify(e);await d.promises.writeFile(s,r,"utf-8"),await d.promises.rename(s,i),this.cache.set(t,e);}catch(r){try{d.existsSync(s)&&await d.promises.unlink(s);}catch{}throw new f(`Failed to write collection "${t}"`,r)}finally{n();}}async exists(t){let e=this.getFilePath(t);return d.existsSync(e)}async delete(t){let e=this.getFilePath(t),i=await this.acquireLock(t);try{d.existsSync(e)&&await d.promises.unlink(e),this.cache.delete(t);}catch(s){throw new f(`Failed to delete collection "${t}"`,s)}finally{i();}}async list(){try{return (await d.promises.readdir(this.dataDir)).filter(e=>e.endsWith(this.fileExtension)).map(e=>e.slice(0,-this.fileExtension.length))}catch(t){throw new f("Failed to list collections",t)}}clearCache(t){t?this.cache.delete(t):this.cache.clear();}getDataDir(){return this.dataDir}};function v(c){return new ObjectId().toHexString()}function U(c){return typeof c!="string"||c.length===0||c.length>64?false:c.length===24?ObjectId.isValid(c):true}function h(c){if(c===null||typeof c!="object")return c;if(c instanceof Date)return new Date(c.getTime());if(c instanceof RegExp)return new RegExp(c.source,c.flags);if(Array.isArray(c))return c.map(e=>h(e));let t={};for(let e in c)Object.prototype.hasOwnProperty.call(c,e)&&(t[e]=h(c[e]));return t}function V(c,t){let e=t.split("."),i=c;for(let s of e){if(i==null||typeof i!="object")return;i=i[s];}return i}function k(c,t,e){let i=t.split("."),s=c;for(let n=0;n<i.length-1;n++){let r=i[n];(!(r in s)||typeof s[r]!="object"||s[r]===null)&&(s[r]={}),s=s[r];}s[i[i.length-1]]=e;}function b(c,t){let e=t.split("."),i=c;for(let n=0;n<e.length-1;n++){let r=e[n];if(!(r in i)||typeof i[r]!="object"||i[r]===null)return false;i=i[r];}let s=e[e.length-1];return s in i?(delete i[s],true):false}function H(c){return typeof c=="object"&&c!==null&&!Array.isArray(c)&&!(c instanceof Date)&&!(c instanceof RegExp)}function O(c,t){if(!t||Object.keys(t).length===0)return c;let e=Object.entries(t).filter(([a])=>a!=="_id"),i=t._id,s=e.some(([,a])=>a===1||a===true),n=e.some(([,a])=>a===0||a===false);if(s&&n)throw new Error("Cannot mix inclusion and exclusion in projection");let r=s,o={};if(r){i!==0&&i!==false&&"_id"in c&&(o._id=c._id);for(let[l,u]of e)(u===1||u===true)&&l in c&&(o[l]=c[l]);}else {let a=new Set(e.filter(([,u])=>u===0||u===false).map(([u])=>u));(i===0||i===false)&&a.add("_id");for(let u of Object.keys(c))a.has(u)||(o[u]=c[u]);}return o}var D=class{filter(t,e){return !e||Object.keys(e).length===0?t:t.filter(i=>this.matches(i,e))}matches(t,e){if("$and"in e&&e.$and)return e.$and.every(i=>this.matches(t,i));if("$or"in e&&e.$or)return e.$or.some(i=>this.matches(t,i));if("$not"in e&&e.$not)return !this.matches(t,e.$not);for(let[i,s]of Object.entries(e)){if(i.startsWith("$"))continue;let n=V(t,i);if(!this.matchesCondition(n,s))return false}return true}matchesCondition(t,e){if(!H(e)||!this.hasOperators(e))return this.isEqual(t,e);let i=e;if("$eq"in i&&!this.isEqual(t,i.$eq)||"$ne"in i&&this.isEqual(t,i.$ne)||"$gt"in i&&!this.compareValues(t,i.$gt,">")||"$gte"in i&&!this.compareValues(t,i.$gte,">=")||"$lt"in i&&!this.compareValues(t,i.$lt,"<")||"$lte"in i&&!this.compareValues(t,i.$lte,"<=")||"$in"in i&&Array.isArray(i.$in)&&!i.$in.some(s=>this.isEqual(t,s))||"$nin"in i&&Array.isArray(i.$nin)&&i.$nin.some(s=>this.isEqual(t,s)))return false;if("$exists"in i){let s=t!=null;if(i.$exists!==s)return false}if("$regex"in i&&(typeof t!="string"||!(i.$regex instanceof RegExp?i.$regex:new RegExp(i.$regex)).test(t))||"$startsWith"in i&&(typeof t!="string"||typeof i.$startsWith!="string"||!t.startsWith(i.$startsWith))||"$endsWith"in i&&(typeof t!="string"||typeof i.$endsWith!="string"||!t.endsWith(i.$endsWith))||"$contains"in i&&(!Array.isArray(t)||!t.some(s=>this.isEqual(s,i.$contains)))||"$all"in i&&Array.isArray(i.$all)&&(!Array.isArray(t)||!i.$all.every(s=>t.some(n=>this.isEqual(n,s)))))return false;if("$elemMatch"in i&&i.$elemMatch){if(!Array.isArray(t))return false;let s=i.$elemMatch;if(!t.some(r=>typeof r!="object"||r===null?false:Object.entries(s).every(([o,a])=>{let l=r[o];return this.matchesCondition(l,a)})))return false}if("$size"in i&&typeof i.$size=="number"&&(!Array.isArray(t)||t.length!==i.$size))return false;if("$type"in i&&i.$type){let s=i.$type,n;if(t===null?n="null":t===void 0?n="undefined":Array.isArray(t)?n="array":n=typeof t,n!==s)return false}if("$mod"in i&&Array.isArray(i.$mod)&&i.$mod.length===2){if(typeof t!="number")return false;let[s,n]=i.$mod;if(t%s!==n)return false}return true}hasOperators(t){return Object.keys(t).some(e=>e.startsWith("$"))}isEqual(t,e){if(t===e)return true;if(t===null||e===null||t===void 0||e===void 0)return t===e;if(typeof t!=typeof e)return false;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(Array.isArray(t)&&Array.isArray(e))return t.length!==e.length?false:t.every((i,s)=>this.isEqual(i,e[s]));if(typeof t=="object"&&typeof e=="object"){let i=Object.keys(t),s=Object.keys(e);return i.length!==s.length?false:i.every(n=>this.isEqual(t[n],e[n]))}return false}compareValues(t,e,i){if(typeof t=="number"&&typeof e=="number")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(typeof t=="string"&&typeof e=="string")switch(i){case ">":return t>e;case ">=":return t>=e;case "<":return t<e;case "<=":return t<=e}if(t instanceof Date&&e instanceof Date)switch(i){case ">":return t.getTime()>e.getTime();case ">=":return t.getTime()>=e.getTime();case "<":return t.getTime()<e.getTime();case "<=":return t.getTime()<=e.getTime()}return false}};var $=class{name;storage;queryEngine;autoSave;saveDebounce;idGenerator;schema;saveTimeout=null;pendingSave=null;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new D,this.autoSave=i.autoSave??true,this.saveDebounce=i.saveDebounce??0,this.idGenerator=i.idGenerator??v,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new T(this.name,e.error.issues);return e.data}async getData(){let t=await this.storage.read(this.name);if(!t){let e={name:this.name,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};return await this.storage.write(this.name,e),e}return t}async save(t){if(this.autoSave){if(this.saveDebounce>0)return this.saveTimeout&&clearTimeout(this.saveTimeout),new Promise(e=>{this.saveTimeout=setTimeout(async()=>{await this.storage.write(this.name,t),this.saveTimeout=null,e();},this.saveDebounce);});await this.storage.write(this.name,t);}}async flush(){this.saveTimeout&&(clearTimeout(this.saveTimeout),this.saveTimeout=null),this.pendingSave&&await this.pendingSave;let t=await this.getData();await this.storage.write(this.name,t);}async insert(t){let e=await this.getData(),i=t._id||this.idGenerator();if(e.documents.some(r=>r._id===i))throw new w(this.name,i);let s={...h(t),_id:i},n=this.validate(s);return e.documents.push(n),await this.save(e),h(n)}async insertFast(t){let e=await this.getData(),i=t._id||this.idGenerator(),s={...h(t),_id:i},n=this.validate(s);return e.documents.push(n),await this.save(e),h(n)}async insertMany(t){if(t.length===0)return [];let e=await this.getData(),i=[],s=new Set(e.documents.map(n=>n._id));for(let n of t){let r=n._id||this.idGenerator();if(s.has(r))throw new w(this.name,r);s.add(r);let o={...h(n),_id:r},a=this.validate(o);e.documents.push(a),i.push(h(a));}return await this.save(e),i}async find(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),e?.projection?s.map(n=>O(h(n),e.projection)):s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){return this.findOne({_id:t})}async count(t){let e=await this.getData();return this.queryEngine.filter(e.documents,t).length}async update(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);if(s.length===0)return 0;for(let n of s)this.applyUpdate(n,e);return await this.save(i),s.length}async updateOne(t,e){let i=await this.getData(),s=this.queryEngine.filter(i.documents,t);if(s.length===0)return null;let n=s[0];return this.applyUpdate(n,e),await this.save(i),h(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.getData(),i=e.documents.length;e.documents=e.documents.filter(n=>!this.queryEngine.matches(n,t));let s=i-e.documents.length;return s>0&&await this.save(e),s}async deleteOne(t){let e=await this.getData(),i=e.documents.findIndex(n=>this.queryEngine.matches(n,t));if(i===-1)return null;let[s]=e.documents.splice(i,1);return await this.save(e),h(s)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){let t=await this.getData();t.documents=[],await this.save(t);}async drop(){await this.storage.delete(this.name);}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let s=e;if(s.$set)for(let[n,r]of Object.entries(s.$set))n!=="_id"&&k(t,n,r);if(s.$unset)for(let n of Object.keys(s.$unset))n!=="_id"&&b(t,n);if(s.$inc)for(let[n,r]of Object.entries(s.$inc)){let o=t[n];typeof o=="number"&&typeof r=="number"&&(t[n]=o+r);}if(s.$push)for(let[n,r]of Object.entries(s.$push)){let o=t[n];Array.isArray(o)&&o.push(r);}if(s.$pull)for(let[n,r]of Object.entries(s.$pull)){let o=t[n];if(Array.isArray(o)){let a=o.findIndex(l=>JSON.stringify(l)===JSON.stringify(r));a!==-1&&o.splice(a,1);}}if(s.$addToSet)for(let[n,r]of Object.entries(s.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(l=>JSON.stringify(l)===JSON.stringify(r))||o.push(r));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var A=class{batchSize;flushInterval;coalesceWrites;batchProcessor;queue=new Map;flushTimer=null;pendingFlush=null;totalQueued=0;isShuttingDown=false;constructor(t,e={}){this.batchSize=e.batchSize??1e3,this.flushInterval=e.flushInterval??100,this.coalesceWrites=e.coalesceWrites??true,this.batchProcessor=t;}async enqueue(t){if(this.isShuttingDown)throw new Error("WriteQueue is shutting down, no new writes accepted");return new Promise((e,i)=>{let s={operation:t,resolve:e,reject:i,timestamp:Date.now()},n=t.collectionName,r=this.queue.get(n);r||(r=[],this.queue.set(n,r)),!(this.coalesceWrites&&this.tryCoalesce(n,s))&&(r.push(s),this.totalQueued++,this.scheduleFlush(),this.totalQueued>=this.batchSize&&this.flush().catch(i));})}tryCoalesce(t,e){let i=this.queue.get(t);if(!i||i.length===0)return false;let s=e.operation;if(s.type==="update")for(let n=i.length-1;n>=0;n--){let r=i[n].operation;if(r.type==="update"&&r.documentId===s.documentId){r.changes={...r.changes,...s.changes};let o=i[n].resolve;return i[n].resolve=()=>{o(),e.resolve();},true}}if(s.type==="delete")for(let n=i.length-1;n>=0;n--){let r=i[n].operation;(r.type==="insert"&&r.document._id===s.documentId||r.type==="update"&&r.documentId===s.documentId)&&(i.splice(n,1),this.totalQueued--);}if(s.type==="clear"||s.type==="fullWrite"){for(let n of i)n.resolve();i.length=0,this.totalQueued-=i.length;}return false}scheduleFlush(){this.flushTimer===null&&(this.flushTimer=setTimeout(()=>{this.flushTimer=null,this.flush().catch(t=>{console.error("WriteQueue flush error:",t);});},this.flushInterval));}async flush(){if(this.pendingFlush)return this.pendingFlush;if(this.flushTimer!==null&&(clearTimeout(this.flushTimer),this.flushTimer=null),this.totalQueued===0)return;let t=this.queue;this.queue=new Map,this.totalQueued=0;let e=new Map;for(let[i,s]of t)e.set(i,s.map(n=>n.operation));this.pendingFlush=this.processBatch(t,e),await this.pendingFlush,this.pendingFlush=null;}async processBatch(t,e){try{await this.batchProcessor(e);for(let i of t.values())for(let s of i)s.resolve();}catch(i){for(let s of t.values())for(let n of s)n.reject(i);}}async shutdown(){this.isShuttingDown=true,await this.flush();}pending(){return this.totalQueued}isEmpty(){return this.totalQueued===0}isClosing(){return this.isShuttingDown}};var E=class{dataDir;partitionCount;prettyPrint;fileExtension;cache=new Map;locks=new Map;constructor(t,e={}){this.dataDir=x.resolve(t),this.partitionCount=e.partitionCount??16,this.prettyPrint=e.prettyPrint??true,this.fileExtension=e.fileExtension??".json",this.ensureDirectory();}ensureDirectory(){try{d.existsSync(this.dataDir)||d.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getPartitionIndex(t){let e=0;for(let i=0;i<t.length;i++){let s=t.charCodeAt(i);e=(e<<5)-e+s,e=e&e;}return Math.abs(e)%this.partitionCount}getPartitionFileName(t,e){return `${t}_p${e.toString().padStart(3,"0")}${this.fileExtension}`}getPartitionFilePath(t,e){return x.join(this.dataDir,this.getPartitionFileName(t,e))}getCacheKey(t,e){return `${t}:${e}`}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async readPartition(t,e){let i=this.getCacheKey(t,e);if(this.cache.has(i))return this.cache.get(i);let s=this.getPartitionFilePath(t,e);try{if(!d.existsSync(s))return null;let n=await d.promises.readFile(s,"utf-8"),r=JSON.parse(n);return this.cache.set(i,r),r}catch(n){throw new f(`Failed to read partition ${e} for collection "${t}"`,n)}}async writePartition(t,e,i){let s=this.getPartitionFilePath(t,e),n=`${s}.tmp.${Date.now()}`,r=this.getCacheKey(t,e),o=await this.acquireLock(r);try{i.updatedAt=new Date().toISOString();let a=this.prettyPrint?JSON.stringify(i,null,2):JSON.stringify(i);await d.promises.writeFile(n,a,"utf-8"),await d.promises.rename(n,s),this.cache.set(r,i);}catch(a){try{d.existsSync(n)&&await d.promises.unlink(n);}catch{}throw new f(`Failed to write partition ${e} for collection "${t}"`,a)}finally{o();}}async readAllPartitions(t){let e=new Map,i=[];for(let s=0;s<this.partitionCount;s++)i.push(this.readPartition(t,s).then(n=>{n&&e.set(s,n);}));return await Promise.all(i),e}async writePartitions(t,e){let i=[];for(let[s,n]of e)i.push(this.writePartition(t,s,n));await Promise.all(i);}async initializePartitions(t){let e=[];for(let i=0;i<this.partitionCount;i++)if(!d.existsSync(this.getPartitionFilePath(t,i))){let n={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()};e.push(this.writePartition(t,i,n));}await Promise.all(e);}async getPartitionInfo(t){let e=await this.readAllPartitions(t),i=[];for(let s=0;s<this.partitionCount;s++){let n=e.get(s);i.push({name:this.getPartitionFileName(t,s),partitionIndex:s,documentCount:n?.documents.length??0});}return i}async getAllDocuments(t){let e=await this.readAllPartitions(t),i=[];for(let s of e.values())i.push(...s.documents);return i}async findById(t,e){let i=this.getPartitionIndex(e),s=await this.readPartition(t,i);return s?s.documents.find(n=>n._id===e)??null:null}async deleteCollection(t){let e=[];for(let i=0;i<this.partitionCount;i++){let s=this.getPartitionFilePath(t,i),n=this.getCacheKey(t,i);e.push((async()=>{let r=await this.acquireLock(n);try{d.existsSync(s)&&await d.promises.unlink(s),this.cache.delete(n);}finally{r();}})());}await Promise.all(e);}clearCache(t){if(t)for(let e=0;e<this.partitionCount;e++)this.cache.delete(this.getCacheKey(t,e));else this.cache.clear();}getPartitionCount(){return this.partitionCount}async listCollections(){try{let t=await d.promises.readdir(this.dataDir),e=new Set,i=new RegExp(`^(.+)_p\\d{3}\\${this.fileExtension}$`);for(let s of t){let n=s.match(i);n&&e.add(n[1]);}return Array.from(e)}catch(t){throw new f("Failed to list partitioned collections",t)}}};var I=class{maxConcurrent;maxQueueSize;queue=[];activeCount=0;completedCount=0;failedCount=0;isShuttingDown=false;constructor(t={}){this.maxConcurrent=t.maxConcurrent??4,this.maxQueueSize=t.maxQueueSize??1e4;}async submit(t,e=0){if(this.isShuttingDown)throw new Error("WorkerPool is shutting down, no new tasks accepted");if(this.queue.length>=this.maxQueueSize)throw new Error("WorkerPool queue is full, task rejected (backpressure)");return new Promise((i,s)=>{let n={task:t,resolve:i,reject:s,priority:e},r=false;for(let o=0;o<this.queue.length;o++)if(e>this.queue[o].priority){this.queue.splice(o,0,n),r=true;break}r||this.queue.push(n),this.processNext();})}async submitAll(t,e=0){let i=t.map(s=>this.submit(s,e));return Promise.all(i)}async*submitStream(t,e=0){let i=t.map(s=>this.submit(s,e));for(let s of i)yield await s;}processNext(){if(this.activeCount>=this.maxConcurrent||this.queue.length===0)return;let t=this.queue.shift();t&&(this.activeCount++,t.task().then(e=>{this.completedCount++,t.resolve(e);}).catch(e=>{this.failedCount++,t.reject(e);}).finally(()=>{this.activeCount--,this.processNext();}));}async drain(){return new Promise(t=>{let e=()=>{this.activeCount===0&&this.queue.length===0?t():setImmediate(e);};e();})}async shutdown(){this.isShuttingDown=true,await this.drain();}getStats(){return {activeWorkers:this.activeCount,queuedTasks:this.queue.length,completedTasks:this.completedCount,failedTasks:this.failedCount}}isIdle(){return this.activeCount===0&&this.queue.length===0}isClosing(){return this.isShuttingDown}queueSize(){return this.queue.length}activeWorkers(){return this.activeCount}};async function W(c,t,e){let i=[],s=0;async function n(){let o=s++;o>=c.length||(i[o]=await e(c[o],o),await n());}let r=Array(Math.min(t,c.length)).fill(null).map(()=>n());return await Promise.all(r),i}var K={partitions:16,batchSize:1e3,flushInterval:100,maxConcurrentIO:4,coalesceWrites:true},_=class{partitionManager;writeQueue;workerPool;options;constructor(t){let e=t.highConcurrency;this.options={...K,...e},this.partitionManager=new E(t.dataDir,{partitionCount:this.options.partitions,prettyPrint:t.prettyPrint??true,fileExtension:t.fileExtension??".json"}),this.workerPool=new I({maxConcurrent:this.options.maxConcurrentIO});let i=this.processBatch.bind(this);this.writeQueue=new A(i,{batchSize:this.options.batchSize,flushInterval:this.options.flushInterval,coalesceWrites:this.options.coalesceWrites});}async processBatch(t){let e=Array.from(t.entries());await W(e,this.options.maxConcurrentIO,async([i,s])=>{await this.processCollectionOperations(i,s);});}async processCollectionOperations(t,e){let i=new Map,s=n=>{let r=i.get(n);return r||(r=[],i.set(n,r)),r};for(let n of e)if(n.type==="fullWrite"||n.type==="clear")for(let r=0;r<this.partitionManager.getPartitionCount();r++)s(r).push(n);else if(n.type==="insert"){let r=this.partitionManager.getPartitionIndex(n.document._id);s(r).push(n);}else if(n.type==="update"||n.type==="delete"){let r=this.partitionManager.getPartitionIndex(n.documentId);s(r).push(n);}else if(n.type==="bulkInsert")for(let r of n.documents){let o=this.partitionManager.getPartitionIndex(r._id);s(o).push({type:"insert",collectionName:t,document:r});}else if(n.type==="bulkUpdate"||n.type==="bulkDelete")for(let r of n.documentIds){let o=this.partitionManager.getPartitionIndex(r);n.type==="bulkUpdate"?s(o).push({type:"update",collectionName:t,documentId:r,changes:n.changes}):s(o).push({type:"delete",collectionName:t,documentId:r});}await W(Array.from(i.entries()),this.options.maxConcurrentIO,async([n,r])=>{await this.processPartitionOperations(t,n,r);});}async processPartitionOperations(t,e,i){let s=await this.partitionManager.readPartition(t,e);s||(s={name:t,documents:[],createdAt:new Date().toISOString(),updatedAt:new Date().toISOString()});for(let n of i)switch(n.type){case "insert":s.documents.push(n.document);break;case "update":{let r=s.documents.findIndex(o=>o._id===n.documentId);r!==-1&&Object.assign(s.documents[r],n.changes);break}case "delete":{let r=s.documents.findIndex(o=>o._id===n.documentId);r!==-1&&s.documents.splice(r,1);break}case "clear":s.documents=[];break;case "fullWrite":{let r=n.data.documents.filter(o=>this.partitionManager.getPartitionIndex(o._id)===e);s.documents=r;break}}await this.partitionManager.writePartition(t,e,s);}async insert(t,e){await this.writeQueue.enqueue({type:"insert",collectionName:t,document:e});}async insertMany(t,e){await this.writeQueue.enqueue({type:"bulkInsert",collectionName:t,documents:e});}async update(t,e,i){await this.writeQueue.enqueue({type:"update",collectionName:t,documentId:e,changes:i});}async delete(t,e){await this.writeQueue.enqueue({type:"delete",collectionName:t,documentId:e});}async clear(t){await this.writeQueue.enqueue({type:"clear",collectionName:t});}async findById(t,e){return await this.writeQueue.flush(),this.partitionManager.findById(t,e)}async readAll(t){return await this.writeQueue.flush(),this.partitionManager.getAllDocuments(t)}async exists(t){return (await this.partitionManager.listCollections()).includes(t)}async initializeCollection(t){await this.partitionManager.initializePartitions(t);}async deleteCollection(t){await this.writeQueue.flush(),await this.partitionManager.deleteCollection(t);}async listCollections(){return this.partitionManager.listCollections()}async flush(){await this.writeQueue.flush();}async shutdown(){await this.writeQueue.shutdown(),await this.workerPool.shutdown();}pendingWrites(){return this.writeQueue.pending()}getStats(){return {pendingWrites:this.writeQueue.pending(),workerPool:this.workerPool.getStats(),partitions:this.options.partitions}}clearCache(t){this.partitionManager.clearCache(t);}};var Q=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new D,this.idGenerator=i.idGenerator??v,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new T(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(await this.storage.findById(this.name,e))throw new w(this.name,e);let s={...h(t),_id:e},n=this.validate(s);return await this.storage.insert(this.name,n),n}async insertFast(t){let e=t._id||this.idGenerator(),i={...h(t),_id:e},s=this.validate(i);return await this.storage.insert(this.name,s),s}async insertMany(t){if(t.length===0)return [];let e=[],i=[];for(let s of t){let n=s._id||this.idGenerator(),r={...h(s),_id:n},o=this.validate(r);i.push(o),e.push(h(o));}return await this.storage.insertMany(this.name,i),e}async find(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.findById(this.name,t);return e?h(e):null}async count(t){let e=await this.storage.readAll(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return 0;for(let n of s){let r=this.getUpdateChanges(n,e);await this.storage.update(this.name,n._id,r);}return s.length}async updateOne(t,e){let i=await this.storage.readAll(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return null;let n=s[0],r=this.getUpdateChanges(n,e);return await this.storage.update(this.name,n._id,r),Object.assign(n,r),h(n)}async updateById(t,e){return this.updateOne({_id:t},e)}async delete(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;for(let s of i)await this.storage.delete(this.name,s._id);return i.length}async deleteOne(t){let e=await this.storage.readAll(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let s=i[0];return await this.storage.delete(this.name,s._id),h(s)}async deleteById(t){return this.deleteOne({_id:t})}async getAll(){return this.find()}async clear(){await this.storage.clear(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}getUpdateChanges(t,e){if(!Object.keys(e).some(r=>r.startsWith("$")))return e;let s=e,n={};if(s.$set)for(let[r,o]of Object.entries(s.$set))r!=="_id"&&(n[r]=o);if(s.$inc)for(let[r,o]of Object.entries(s.$inc)){let a=t[r];typeof a=="number"&&typeof o=="number"&&(n[r]=a+o);}if(s.$push)for(let[r,o]of Object.entries(s.$push)){let a=t[r];Array.isArray(a)&&(n[r]=[...a,o]);}if(s.$pull)for(let[r,o]of Object.entries(s.$pull)){let a=t[r];Array.isArray(a)&&(n[r]=a.filter(l=>JSON.stringify(l)!==JSON.stringify(o)));}if(s.$addToSet)for(let[r,o]of Object.entries(s.$addToSet)){let a=t[r];Array.isArray(a)&&(a.some(u=>JSON.stringify(u)===JSON.stringify(o))?n[r]=a:n[r]=[...a,o]);}return n}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var S=class{capacity;cache;constructor(t){this.capacity=t,this.cache=new Map;}get(t){if(!this.cache.has(t))return;let e=this.cache.get(t);return this.cache.delete(t),this.cache.set(t,e),e}set(t,e){if(this.cache.has(t))this.cache.delete(t);else if(this.cache.size>=this.capacity){let i=this.cache.keys().next().value;i!==void 0&&this.cache.delete(i);}this.cache.set(t,e);}has(t){return this.cache.has(t)}delete(t){return this.cache.delete(t)}clear(){this.cache.clear();}get size(){return this.cache.size}keys(){return this.cache.keys()}values(){return this.cache.values()}entries(){return this.cache.entries()}forEach(t){this.cache.forEach(t);}};var L=class{dataDir;fileExtension;prettyPrint;cacheSize;chunkSize;documentCache;collections;locks;constructor(t){this.dataDir=x.resolve(t.dataDir),this.fileExtension=t.fileExtension||".json",this.prettyPrint=t.prettyPrint??true,this.cacheSize=t.lazyLoading?.cacheSize??1e3,this.chunkSize=t.lazyLoading?.chunkSize??1e4,this.documentCache=new Map,this.collections=new Map,this.locks=new Map,this.ensureDirectory();}ensureDirectory(){try{d.existsSync(this.dataDir)||d.mkdirSync(this.dataDir,{recursive:!0});}catch(t){throw new f(`Failed to create data directory: ${this.dataDir}`,t)}}getFilePath(t,e){return e!==void 0&&this.chunkSize>0?x.join(this.dataDir,`${t}_chunk${e}${this.fileExtension}`):x.join(this.dataDir,`${t}${this.fileExtension}`)}getIndexFilePath(t){return x.join(this.dataDir,`${t}.index${this.fileExtension}`)}async acquireLock(t){for(;this.locks.has(t);)await this.locks.get(t);let e=()=>{},i=new Promise(s=>{e=s;});return this.locks.set(t,i),()=>{this.locks.delete(t),e();}}async initCollection(t){if(this.collections.has(t))return;let e=this.getFilePath(t),i=this.getIndexFilePath(t);if(d.existsSync(i))try{let s=await d.promises.readFile(i,"utf-8"),n=JSON.parse(s),r={name:t,createdAt:n.createdAt,updatedAt:n.updatedAt,index:new Map(n.ids.map((o,a)=>[o,{id:o,offset:a}])),count:n.ids.length,dirty:!1};this.collections.set(t,r),this.documentCache.set(t,new S(this.cacheSize));return}catch{}if(d.existsSync(e))try{let s=await d.promises.readFile(e,"utf-8"),n=JSON.parse(s),r=new Map;n.documents.forEach((u,F)=>{r.set(u._id,{id:u._id,offset:F});});let o={name:t,createdAt:n.createdAt,updatedAt:n.updatedAt,index:r,count:n.documents.length,dirty:!1};this.collections.set(t,o),this.documentCache.set(t,new S(this.cacheSize));let a=this.documentCache.get(t),l=Math.min(n.documents.length,this.cacheSize);for(let u=0;u<l;u++)a.set(n.documents[u]._id,n.documents[u]);await this.saveIndex(t);}catch(s){throw new f(`Failed to initialize collection "${t}"`,s)}else {let s={name:t,createdAt:new Date().toISOString(),updatedAt:new Date().toISOString(),index:new Map,count:0,dirty:false};this.collections.set(t,s),this.documentCache.set(t,new S(this.cacheSize));}}async saveIndex(t){let e=this.collections.get(t);if(!e)return;let i=this.getIndexFilePath(t),s={name:t,createdAt:e.createdAt,updatedAt:e.updatedAt,ids:Array.from(e.index.keys())},n=this.prettyPrint?JSON.stringify(s,null,2):JSON.stringify(s);await d.promises.writeFile(i,n,"utf-8");}getCount(t){return this.collections.get(t)?.count??0}hasDocument(t,e){return this.collections.get(t)?.index.has(e)??false}getDocumentIds(t){let e=this.collections.get(t);return e?Array.from(e.index.keys()):[]}async getDocument(t,e){await this.initCollection(t);let i=this.collections.get(t);if(!i||!i.index.has(e))return null;let s=this.documentCache.get(t),n=s.get(e);if(n)return n;let r=await this.loadDocumentFromDisk(t,e);return r&&s.set(e,r),r}async loadDocumentFromDisk(t,e){let i=this.getFilePath(t);try{let s=await d.promises.readFile(i,"utf-8");return JSON.parse(s).documents.find(r=>r._id===e)??null}catch{return null}}async getDocuments(t,e){await this.initCollection(t);let i=this.documentCache.get(t),s=[],n=[];for(let r of e){let o=i.get(r);o?s.push(o):n.push(r);}if(n.length>0){let r=await this.loadDocumentsFromDisk(t,n);for(let o of r)i.set(o._id,o),s.push(o);}return s}async loadDocumentsFromDisk(t,e){let i=this.getFilePath(t),s=new Set(e);try{let n=await d.promises.readFile(i,"utf-8");return JSON.parse(n).documents.filter(o=>s.has(o._id))}catch{return []}}async getAllDocuments(t){await this.initCollection(t);let e=this.getFilePath(t);try{if(!d.existsSync(e))return [];let i=await d.promises.readFile(e,"utf-8"),s=JSON.parse(i),n=this.documentCache.get(t);for(let r of s.documents)n.set(r._id,r);return s.documents}catch{return []}}async insertDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);s.index.set(e._id,{id:e._id,offset:s.count}),s.count++,s.updatedAt=new Date().toISOString(),s.dirty=!0,n.set(e._id,e),await this.persistCollection(t);}finally{i();}}async insertDocuments(t,e){if(e.length===0)return;await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);for(let r of e)s.index.set(r._id,{id:r._id,offset:s.count}),s.count++,n.set(r._id,r);s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async updateDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);if(!s.index.has(e._id))return;n.set(e._id,e),s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async deleteDocument(t,e){await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);if(!s.index.has(e))return;s.index.delete(e),s.count--,n.delete(e),s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async deleteDocuments(t,e){if(e.length===0)return;await this.initCollection(t);let i=await this.acquireLock(t);try{let s=this.collections.get(t),n=this.documentCache.get(t);for(let r of e)s.index.has(r)&&(s.index.delete(r),s.count--,n.delete(r));s.updatedAt=new Date().toISOString(),s.dirty=!0,await this.persistCollection(t);}finally{i();}}async clearCollection(t){await this.initCollection(t);let e=await this.acquireLock(t);try{let i=this.collections.get(t),s=this.documentCache.get(t);i.index.clear(),i.count=0,s.clear(),i.updatedAt=new Date().toISOString(),i.dirty=!0,await this.persistCollection(t);}finally{e();}}async persistCollection(t){let e=this.collections.get(t);if(!e)return;let i=this.getFilePath(t),s=`${i}.tmp.${Date.now()}`;try{let n=await this.buildDocumentArray(t),r={name:t,documents:n,createdAt:e.createdAt,updatedAt:e.updatedAt},o=this.prettyPrint?JSON.stringify(r,null,2):JSON.stringify(r);await d.promises.writeFile(s,o,"utf-8"),await d.promises.rename(s,i),await this.saveIndex(t),e.dirty=!1;}catch(n){try{d.existsSync(s)&&await d.promises.unlink(s);}catch{}throw new f(`Failed to persist collection "${t}"`,n)}}async buildDocumentArray(t){let e=this.collections.get(t);if(!e||e.count===0)return [];let i=this.getFilePath(t),s=[];try{if(d.existsSync(i)){let a=await d.promises.readFile(i,"utf-8");s=JSON.parse(a).documents;}}catch{}let n=new Map;for(let a of s)n.set(a._id,a);this.documentCache.get(t).forEach((a,l)=>{n.set(l,a);});let o=[];for(let a of e.index.keys()){let l=n.get(a);l&&o.push(l);}return o}async deleteCollection(t){let e=await this.acquireLock(t);try{this.collections.delete(t),this.documentCache.delete(t);let i=this.getFilePath(t),s=this.getIndexFilePath(t);d.existsSync(i)&&await d.promises.unlink(i),d.existsSync(s)&&await d.promises.unlink(s);}finally{e();}}async exists(t){if(this.collections.has(t))return true;let e=this.getFilePath(t);return d.existsSync(e)}async list(){try{let t=await d.promises.readdir(this.dataDir),e=new Set;for(let i of t)i.includes(".index")||i.includes("_chunk")||i.endsWith(this.fileExtension)&&e.add(i.slice(0,-this.fileExtension.length));return Array.from(e)}catch{return []}}getStats(){let t=0;for(let e of this.documentCache.values())t+=e.size;return {collections:this.collections.size,cachedDocuments:t,cacheSize:this.cacheSize}}clearCache(t){if(t)this.documentCache.get(t)?.clear();else for(let e of this.documentCache.values())e.clear();}async flush(){for(let[t,e]of this.collections.entries())e.dirty&&await this.persistCollection(t);}getDataDir(){return this.dataDir}};var j=class{name;storage;queryEngine;idGenerator;schema;constructor(t,e,i={}){this.name=t,this.storage=e,this.queryEngine=new D,this.idGenerator=i.idGenerator??v,this.schema=i.schema;}validate(t){if(!this.schema)return t;let e=this.schema.safeParse(t);if(!e.success)throw new T(this.name,e.error.issues);return e.data}async insert(t){let e=t._id||this.idGenerator();if(this.storage.hasDocument(this.name,e))throw new w(this.name,e);let i={...h(t),_id:e},s=this.validate(i);return await this.storage.insertDocument(this.name,s),h(s)}async insertFast(t){let e=t._id||this.idGenerator(),i={...h(t),_id:e},s=this.validate(i);return await this.storage.insertDocument(this.name,s),h(s)}async insertMany(t){if(t.length===0)return [];let e=new Set(this.storage.getDocumentIds(this.name)),i=[];for(let s of t){let n=s._id||this.idGenerator();if(e.has(n))throw new w(this.name,n);e.add(n);let r={...h(s),_id:n},o=this.validate(r);i.push(o);}return await this.storage.insertDocuments(this.name,i),i.map(s=>h(s))}async find(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);return e?.sort&&(s=this.sortDocuments(s,e.sort)),e?.skip&&e.skip>0&&(s=s.slice(e.skip)),e?.limit&&e.limit>0&&(s=s.slice(0,e.limit)),e?.projection?s.map(n=>O(h(n),e.projection)):s.map(n=>h(n))}async findOne(t){let e=await this.find(t,{limit:1});return e.length>0?e[0]:null}async findById(t){let e=await this.storage.getDocument(this.name,t);return e?h(e):null}async count(t){if(!t||Object.keys(t).length===0)return this.storage.getCount(this.name);let e=await this.storage.getAllDocuments(this.name);return this.queryEngine.filter(e,t).length}async update(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return 0;for(let n of s)this.applyUpdate(n,e),await this.storage.updateDocument(this.name,n);return s.length}async updateOne(t,e){let i=await this.storage.getAllDocuments(this.name),s=this.queryEngine.filter(i,t);if(s.length===0)return null;let n=s[0];return this.applyUpdate(n,e),await this.storage.updateDocument(this.name,n),h(n)}async updateById(t,e){let i=await this.storage.getDocument(this.name,t);return i?(this.applyUpdate(i,e),await this.storage.updateDocument(this.name,i),h(i)):null}async delete(t){let e=await this.storage.getAllDocuments(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return 0;let s=i.map(n=>n._id);return await this.storage.deleteDocuments(this.name,s),i.length}async deleteOne(t){let e=await this.storage.getAllDocuments(this.name),i=this.queryEngine.filter(e,t);if(i.length===0)return null;let s=i[0];return await this.storage.deleteDocument(this.name,s._id),h(s)}async deleteById(t){let e=await this.storage.getDocument(this.name,t);return e?(await this.storage.deleteDocument(this.name,t),h(e)):null}async getAll(){return this.find()}async clear(){await this.storage.clearCollection(this.name);}async drop(){await this.storage.deleteCollection(this.name);}async flush(){await this.storage.flush();}getName(){return this.name}applyUpdate(t,e){if(!Object.keys(e).some(n=>n.startsWith("$"))){Object.assign(t,e);return}let s=e;if(s.$set)for(let[n,r]of Object.entries(s.$set))n!=="_id"&&k(t,n,r);if(s.$unset)for(let n of Object.keys(s.$unset))n!=="_id"&&b(t,n);if(s.$inc)for(let[n,r]of Object.entries(s.$inc)){let o=t[n];typeof o=="number"&&typeof r=="number"&&(t[n]=o+r);}if(s.$push)for(let[n,r]of Object.entries(s.$push)){let o=t[n];Array.isArray(o)&&o.push(r);}if(s.$pull)for(let[n,r]of Object.entries(s.$pull)){let o=t[n];if(Array.isArray(o)){let a=o.findIndex(l=>JSON.stringify(l)===JSON.stringify(r));a!==-1&&o.splice(a,1);}}if(s.$addToSet)for(let[n,r]of Object.entries(s.$addToSet)){let o=t[n];Array.isArray(o)&&(o.some(l=>JSON.stringify(l)===JSON.stringify(r))||o.push(r));}}sortDocuments(t,e){let i=Object.entries(e);return [...t].sort((s,n)=>{for(let[r,o]of i){let a=s[r],l=n[r],u=0;if(a===l?u=0:a==null?u=1:l==null?u=-1:typeof a=="number"&&typeof l=="number"?u=a-l:typeof a=="string"&&typeof l=="string"?u=a.localeCompare(l):a instanceof Date&&l instanceof Date?u=a.getTime()-l.getTime():u=String(a).localeCompare(String(l)),u!==0)return u*(o===-1||o==="desc"?-1:1)}return 0})}};var G={autoSave:true,saveDebounce:0,prettyPrint:true,fileExtension:".json"},J=class{options;storage;hcStorage;lazyStorage;collections=new Map;isHighConcurrency;isLazyLoading;connected=false;constructor(t){if(this.options={...G,...t},this.isHighConcurrency=t.highConcurrency?.enabled??false,this.isLazyLoading=t.lazyLoading?.enabled??false,this.isHighConcurrency&&this.isLazyLoading)throw new Error("Cannot enable both highConcurrency and lazyLoading modes simultaneously");this.isHighConcurrency?(this.storage=null,this.hcStorage=new _(this.options),this.lazyStorage=null):this.isLazyLoading?(this.storage=null,this.hcStorage=null,this.lazyStorage=new L(this.options)):(this.storage=new z(this.options),this.hcStorage=null,this.lazyStorage=null);}getStorage(){if(this.storage===null)throw new Error("Storage is not available in high-concurrency or lazy loading mode");return this.storage}getHCStorage(){if(this.hcStorage===null)throw new Error("HighConcurrencyStorage is not available in standard or lazy loading mode");return this.hcStorage}getLazyStorage(){if(this.lazyStorage===null)throw new Error("LazyStorage is not available in standard or high-concurrency mode");return this.lazyStorage}async connect(){if(!this.connected){if(this.isHighConcurrency){let t=await this.getHCStorage().listCollections();for(let e of t)this.getOrCreateCollection(e);}else if(this.isLazyLoading){let t=await this.getLazyStorage().list();for(let e of t)this.getOrCreateCollection(e);}else {let t=await this.getStorage().list();for(let e of t)this.getOrCreateCollection(e);}this.connected=true;}}async close(){if(this.connected){for(let t of this.collections.values())await t.flush();this.isHighConcurrency&&this.hcStorage&&await this.hcStorage.shutdown(),this.collections.clear(),this.storage&&this.storage.clearCache(),this.hcStorage&&this.hcStorage.clearCache(),this.lazyStorage&&this.lazyStorage.clearCache(),this.connected=false;}}collection(t,e){if(!t||typeof t!="string")throw new C("Collection name must be a non-empty string");if(!/^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(t))throw new C("Collection name must start with a letter or underscore and contain only letters, numbers, underscores, and hyphens");return this.getOrCreateCollection(t,e)}getOrCreateCollection(t,e){if(this.collections.has(t))return this.collections.get(t);if(this.isHighConcurrency){let i=new Q(t,this.getHCStorage(),{schema:e?.schema});this.collections.set(t,i);}else if(this.isLazyLoading){let i=new j(t,this.getLazyStorage(),{schema:e?.schema});this.collections.set(t,i);}else {let i=new $(t,this.getStorage(),{autoSave:this.options.autoSave,saveDebounce:this.options.saveDebounce,schema:e?.schema});this.collections.set(t,i);}return this.collections.get(t)}async hasCollection(t){return this.isHighConcurrency?this.getHCStorage().exists(t):this.getStorage().exists(t)}async listCollections(){return this.isHighConcurrency?this.getHCStorage().listCollections():this.getStorage().list()}async dropCollection(t){let e=this.collections.get(t);e?(await e.drop(),this.collections.delete(t)):this.isHighConcurrency?await this.getHCStorage().deleteCollection(t):await this.getStorage().delete(t);}async drop(){if(this.isHighConcurrency){let t=this.getHCStorage(),e=await t.listCollections();for(let i of e)await t.deleteCollection(i);}else {let t=this.getStorage(),e=await t.list();for(let i of e)await t.delete(i);}this.collections.clear(),this.storage?.clearCache(),this.hcStorage?.clearCache();}getDataDir(){return this.isHighConcurrency?this.options.dataDir:this.getStorage().getDataDir()}isConnected(){return this.connected}isHighConcurrencyMode(){return this.isHighConcurrency}getStats(){return !this.isHighConcurrency||!this.hcStorage?null:this.hcStorage.getStats()}async flush(){for(let t of this.collections.values())await t.flush();}};export{$ as Collection,C as CollectionError,R as DocumentNotFoundError,w as DuplicateKeyError,Q as HighConcurrencyCollection,_ as HighConcurrencyStorage,J as JsonDB,P as JsonDBError,E as PartitionManager,f as StorageError,T as ValidationError,I as WorkerPool,A as WriteQueue,v as generateId,U as isValidId,W as parallelLimit};
package/package.json CHANGED
@@ -1,88 +1,97 @@
1
- {
2
- "name": "nodejs-json-db",
3
- "version": "0.0.1",
4
- "description": "A production-ready, lightweight JSON-based database for Node.js and Electron applications",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
- "module": "./dist/index.mjs",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "require": "./dist/index.js",
12
- "import": "./dist/index.mjs",
13
- "default": "./dist/index.js"
14
- }
15
- },
16
- "sideEffects": false,
17
- "scripts": {
18
- "build": "tsup",
19
- "test": "vitest run",
20
- "test:watch": "vitest",
21
- "test:coverage": "vitest run --coverage",
22
- "dev": "tsup --watch",
23
- "lint": "eslint src --ext .ts",
24
- "format": "prettier --write \"src/**/*.ts\"",
25
- "typecheck": "tsc --noEmit",
26
- "prepublishOnly": "npm run build && npm run test",
27
- "benchmark": "tsx examples/benchmark.ts"
28
- },
29
- "files": [
30
- "dist",
31
- "README.md",
32
- "LICENSE"
33
- ],
34
- "repository": {
35
- "type": "git",
36
- "url": "https://github.com/iqbal-rashed/nodejs-json-db.git"
37
- },
38
- "keywords": [
39
- "json",
40
- "database",
41
- "db",
42
- "nosql",
43
- "document",
44
- "storage",
45
- "electron",
46
- "nodejs",
47
- "typescript",
48
- "esm",
49
- "cjs",
50
- "lightweight",
51
- "file-based",
52
- "local-storage"
53
- ],
54
- "author": "Rashed Iqbal",
55
- "license": "MIT",
56
- "bugs": {
57
- "url": "https://github.com/iqbal-rashed/nodejs-json-db/issues"
58
- },
59
- "homepage": "https://github.com/iqbal-rashed/nodejs-json-db#readme",
60
- "engines": {
61
- "node": ">=18.0.0"
62
- },
63
- "devDependencies": {
64
- "@eslint/js": "^9.18.0",
65
- "@types/node": "^22.10.5",
66
- "@vitest/coverage-v8": "^4.0.16",
67
- "eslint": "^9.18.0",
68
- "globals": "^15.14.0",
69
- "prettier": "^3.4.2",
70
- "tsup": "^8.5.1",
71
- "tsx": "^4.21.0",
72
- "typescript": "^5.9.3",
73
- "typescript-eslint": "^8.19.1",
74
- "vitest": "^4.0.16",
75
- "zod": "^4.2.1"
76
- },
77
- "dependencies": {
78
- "bson": "^7.0.0"
79
- },
80
- "peerDependencies": {
81
- "zod": "^3.0.0 || ^4.0.0"
82
- },
83
- "peerDependenciesMeta": {
84
- "zod": {
85
- "optional": true
86
- }
87
- }
88
- }
1
+ {
2
+ "name": "nodejs-json-db",
3
+ "version": "0.0.2",
4
+ "description": "A production-ready, lightweight JSON-based database for Node.js and Electron applications",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "module": "./dist/index.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "require": "./dist/index.js",
12
+ "import": "./dist/index.mjs",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "sideEffects": false,
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "test:coverage": "vitest run --coverage",
22
+ "dev": "tsup --watch",
23
+ "lint": "eslint src --ext .ts",
24
+ "format": "prettier --write \"src/**/*.ts\"",
25
+ "typecheck": "tsc --noEmit",
26
+ "prepublishOnly": "npm run build && npm run test",
27
+ "benchmark": "tsx examples/benchmark.ts",
28
+ "prepare": "husky"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/iqbal-rashed/nodejs-json-db.git"
38
+ },
39
+ "keywords": [
40
+ "json",
41
+ "database",
42
+ "db",
43
+ "nosql",
44
+ "document",
45
+ "storage",
46
+ "electron",
47
+ "nodejs",
48
+ "typescript",
49
+ "esm",
50
+ "cjs",
51
+ "lightweight",
52
+ "file-based",
53
+ "local-storage"
54
+ ],
55
+ "author": "Rashed Iqbal",
56
+ "license": "MIT",
57
+ "bugs": {
58
+ "url": "https://github.com/iqbal-rashed/nodejs-json-db/issues"
59
+ },
60
+ "homepage": "https://github.com/iqbal-rashed/nodejs-json-db#readme",
61
+ "engines": {
62
+ "node": ">=18.0.0"
63
+ },
64
+ "devDependencies": {
65
+ "@eslint/js": "^9.18.0",
66
+ "@types/node": "^22.10.5",
67
+ "@vitest/coverage-v8": "^4.0.16",
68
+ "eslint": "^9.18.0",
69
+ "globals": "^15.14.0",
70
+ "husky": "^9.1.7",
71
+ "lint-staged": "^16.2.7",
72
+ "prettier": "^3.4.2",
73
+ "tsup": "^8.5.1",
74
+ "tsx": "^4.21.0",
75
+ "typescript": "^5.9.3",
76
+ "typescript-eslint": "^8.19.1",
77
+ "vitest": "^4.0.16",
78
+ "zod": "^4.2.1"
79
+ },
80
+ "dependencies": {
81
+ "bson": "^7.0.0"
82
+ },
83
+ "peerDependencies": {
84
+ "zod": "^3.0.0 || ^4.0.0"
85
+ },
86
+ "peerDependenciesMeta": {
87
+ "zod": {
88
+ "optional": true
89
+ }
90
+ },
91
+ "lint-staged": {
92
+ "*.ts": [
93
+ "eslint --fix",
94
+ "prettier --write"
95
+ ]
96
+ }
97
+ }