nodejs-json-db 0.0.1 โ†’ 0.0.3

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,256 @@ 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
+ * Get collection metadata and cache safely (throws if not initialized)
717
+ */
718
+ private getCollectionData;
719
+ /**
720
+ * Initialize a collection - loads index only, not documents
721
+ */
722
+ initCollection(collectionName: string): Promise<void>;
723
+ /**
724
+ * Save index file for fast loading
725
+ */
726
+ private saveIndex;
727
+ /**
728
+ * Get document count without loading documents
729
+ */
730
+ getCount(collectionName: string): number;
731
+ /**
732
+ * Check if document exists without loading it
733
+ */
734
+ hasDocument(collectionName: string, docId: string): boolean;
735
+ /**
736
+ * Get all document IDs without loading documents
737
+ */
738
+ getDocumentIds(collectionName: string): string[];
739
+ /**
740
+ * Get a single document by ID - uses cache or loads from disk
741
+ */
742
+ getDocument<T extends Document>(collectionName: string, docId: string): Promise<T | null>;
743
+ /**
744
+ * Load document from disk (internal)
745
+ */
746
+ private loadDocumentFromDisk;
747
+ /**
748
+ * Get multiple documents by IDs (batch load)
749
+ */
750
+ getDocuments<T extends Document>(collectionName: string, docIds: string[]): Promise<T[]>;
751
+ /**
752
+ * Load multiple documents from disk
753
+ */
754
+ private loadDocumentsFromDisk;
755
+ /**
756
+ * Get all documents (full load - use sparingly for large collections)
757
+ */
758
+ getAllDocuments<T extends Document>(collectionName: string): Promise<T[]>;
759
+ /**
760
+ * Insert a document
761
+ */
762
+ insertDocument<T extends Document>(collectionName: string, doc: T): Promise<void>;
763
+ /**
764
+ * Insert multiple documents
765
+ */
766
+ insertDocuments<T extends Document>(collectionName: string, docs: T[]): Promise<void>;
767
+ /**
768
+ * Update a document
769
+ */
770
+ updateDocument<T extends Document>(collectionName: string, doc: T): Promise<void>;
771
+ /**
772
+ * Delete a document
773
+ */
774
+ deleteDocument(collectionName: string, docId: string): Promise<void>;
775
+ /**
776
+ * Delete multiple documents
777
+ */
778
+ deleteDocuments(collectionName: string, docIds: string[]): Promise<void>;
779
+ /**
780
+ * Clear all documents from a collection
781
+ */
782
+ clearCollection(collectionName: string): Promise<void>;
783
+ /**
784
+ * Persist collection to disk
785
+ */
786
+ private persistCollection;
787
+ /**
788
+ * Build document array from cache and disk
789
+ */
790
+ private buildDocumentArray;
791
+ /**
792
+ * Delete a collection
793
+ */
794
+ deleteCollection(collectionName: string): Promise<void>;
795
+ /**
796
+ * Check if collection exists
797
+ */
798
+ exists(collectionName: string): Promise<boolean>;
799
+ /**
800
+ * List all collections
801
+ */
802
+ list(): Promise<string[]>;
803
+ /**
804
+ * Get cache statistics
805
+ */
806
+ getStats(): {
807
+ collections: number;
808
+ cachedDocuments: number;
809
+ cacheSize: number;
810
+ };
811
+ /**
812
+ * Clear cache for a collection
813
+ */
814
+ clearCache(collectionName?: string): void;
815
+ /**
816
+ * Flush pending writes
817
+ */
818
+ flush(): Promise<void>;
819
+ /**
820
+ * Get data directory path
821
+ */
822
+ getDataDir(): string;
823
+ }
824
+
825
+ /**
826
+ * LazyCollection - Memory-efficient collection using lazy loading storage
827
+ *
828
+ * Unlike standard Collection which loads all documents:
829
+ * - Only document IDs are kept in memory
830
+ * - Documents are loaded on-demand with LRU caching
831
+ * - Queries that scan all documents still need to load from disk
832
+ */
833
+ declare class LazyCollection<T extends Document> {
834
+ private readonly name;
835
+ private readonly storage;
836
+ private readonly queryEngine;
837
+ private readonly idGenerator;
838
+ private readonly schema?;
839
+ constructor(name: string, storage: LazyStorage, options?: {
840
+ idGenerator?: () => string;
841
+ schema?: SchemaValidator$1<T>;
842
+ });
843
+ /**
844
+ * Validate a document against the schema (if defined)
845
+ */
846
+ private validate;
847
+ /**
848
+ * Insert a single document
849
+ */
850
+ insert(doc: Omit<T, '_id'> & {
851
+ _id?: string;
852
+ }): Promise<T>;
853
+ /**
854
+ * Insert without duplicate check (faster)
855
+ */
856
+ insertFast(doc: Omit<T, '_id'> & {
857
+ _id?: string;
858
+ }): Promise<T>;
859
+ /**
860
+ * Insert multiple documents
861
+ */
862
+ insertMany(docs: (Omit<T, '_id'> & {
863
+ _id?: string;
864
+ })[]): Promise<T[]>;
865
+ /**
866
+ * Find documents matching a query
867
+ * Note: This loads documents from disk for filtering
868
+ */
869
+ find(query?: Query<T>, options?: FindOptions<T>): Promise<T[]>;
870
+ /**
871
+ * Find a single document matching a query
872
+ */
873
+ findOne(query: Query<T>): Promise<T | null>;
874
+ /**
875
+ * Find a document by ID - optimized, uses cache
876
+ */
877
+ findById(id: string): Promise<T | null>;
878
+ /**
879
+ * Count documents matching a query
880
+ */
881
+ count(query?: Query<T>): Promise<number>;
882
+ /**
883
+ * Update documents matching a query
884
+ */
885
+ update(query: Query<T>, update: UpdateOperators<T> | Partial<T>): Promise<number>;
886
+ /**
887
+ * Update a single document matching a query
888
+ */
889
+ updateOne(query: Query<T>, update: UpdateOperators<T> | Partial<T>): Promise<T | null>;
890
+ /**
891
+ * Update a document by ID - optimized, uses cache
892
+ */
893
+ updateById(id: string, update: UpdateOperators<T> | Partial<T>): Promise<T | null>;
894
+ /**
895
+ * Delete documents matching a query
896
+ */
897
+ delete(query: Query<T>): Promise<number>;
898
+ /**
899
+ * Delete a single document matching a query
900
+ */
901
+ deleteOne(query: Query<T>): Promise<T | null>;
902
+ /**
903
+ * Delete a document by ID - optimized
904
+ */
905
+ deleteById(id: string): Promise<T | null>;
906
+ /**
907
+ * Get all documents
908
+ */
909
+ getAll(): Promise<T[]>;
910
+ /**
911
+ * Clear all documents
912
+ */
913
+ clear(): Promise<void>;
914
+ /**
915
+ * Drop the collection
916
+ */
917
+ drop(): Promise<void>;
918
+ /**
919
+ * Flush pending writes
920
+ */
921
+ flush(): Promise<void>;
922
+ /**
923
+ * Get collection name
924
+ */
925
+ getName(): string;
926
+ /**
927
+ * Apply update operators to a document
928
+ */
929
+ private applyUpdate;
930
+ /**
931
+ * Sort documents
932
+ */
933
+ private sortDocuments;
934
+ }
935
+
936
+ /**
937
+ * Collection type union for all modes
655
938
  */
656
- type AnyCollection<T extends Document> = Collection<T> | HighConcurrencyCollection<T>;
939
+ type AnyCollection<T extends Document> = Collection<T> | HighConcurrencyCollection<T> | LazyCollection<T>;
657
940
  /**
658
941
  * Stats returned by getStats() in high-concurrency mode
659
942
  */
@@ -665,16 +948,19 @@ interface HighConcurrencyStats {
665
948
  /**
666
949
  * JsonDB - A lightweight JSON-based database for Node.js and Electron
667
950
  *
668
- * Supports two modes:
951
+ * Supports three modes:
669
952
  * - Standard mode: Single-file storage per collection (default)
670
953
  * - High-concurrency mode: Partitioned storage with write batching (opt-in)
954
+ * - Lazy loading mode: Memory-efficient with document-level LRU caching (opt-in)
671
955
  */
672
956
  declare class JsonDB {
673
957
  private readonly options;
674
958
  private readonly storage;
675
959
  private readonly hcStorage;
960
+ private readonly lazyStorage;
676
961
  private readonly collections;
677
962
  private readonly isHighConcurrency;
963
+ private readonly isLazyLoading;
678
964
  private connected;
679
965
  /**
680
966
  * Create a new JsonDB instance
@@ -682,13 +968,17 @@ declare class JsonDB {
682
968
  */
683
969
  constructor(options: JsonDBOptions);
684
970
  /**
685
- * Get the standard storage (throws if in HC mode)
971
+ * Get the standard storage (throws if in HC or lazy mode)
686
972
  */
687
973
  private getStorage;
688
974
  /**
689
- * Get the high-concurrency storage (throws if in standard mode)
975
+ * Get the high-concurrency storage (throws if in standard or lazy mode)
690
976
  */
691
977
  private getHCStorage;
978
+ /**
979
+ * Get the lazy storage (throws if in standard or HC mode)
980
+ */
981
+ private getLazyStorage;
692
982
  /**
693
983
  * Connect to the database (initialize storage)
694
984
  */
@@ -698,10 +988,10 @@ declare class JsonDB {
698
988
  */
699
989
  close(): Promise<void>;
700
990
  /**
701
- * Get or create a collection
702
- * @param name Collection name
703
- * @param options Collection options (including optional Zod schema)
704
- */
991
+ * Get or create a collection
992
+ * @param name Collection name
993
+ * @param options Collection options (including optional Zod schema)
994
+ */
705
995
  collection<T extends Document>(name: string, options?: {
706
996
  schema?: {
707
997
  safeParse(data: unknown): {
@@ -1049,4 +1339,4 @@ declare function generateId(_length?: number): string;
1049
1339
  */
1050
1340
  declare function isValidId(id: unknown): id is string;
1051
1341
 
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 };
1342
+ export { type AnyCollection, Collection, type CollectionData, CollectionError, type CollectionOptions, type ComparisonOperators, type Document, DocumentNotFoundError, DuplicateKeyError, type FindOptions, HighConcurrencyCollection, type HighConcurrencyOptions, HighConcurrencyStorage, JsonDB, JsonDBError, type JsonDBOptions, LazyCollection, 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 z=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 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 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 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 _=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);if(e!==void 0)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=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();}}getCollectionData(t){let e=this.collections.get(t),i=this.documentCache.get(t);if(!e||!i)throw new f(`Collection "${t}" is not initialized`,new Error("Not initialized"));return {meta:e,cache:i}}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,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 C(this.cacheSize));let{cache:a}=this.getCollectionData(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{cache:s}=this.getCollectionData(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{cache:i}=this.getCollectionData(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),{cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:i,cache:s}=this.getCollectionData(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);let{cache:r}=this.getCollectionData(t);r.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 Q=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"},J=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 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 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 Q(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=J;exports.JsonDBError=D;exports.LazyCollection=Q;exports.PartitionManager=A;exports.StorageError=f;exports.ValidationError=w;exports.WorkerPool=E;exports.WriteQueue=$;exports.generateId=P;exports.isValidId=B;exports.parallelLimit=W;
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 M=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 J(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(!J(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 L(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 L(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 L(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);if(e!==void 0)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 j=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();}}getCollectionData(t){let e=this.collections.get(t),i=this.documentCache.get(t);if(!e||!i)throw new f(`Collection "${t}" is not initialized`,new Error("Not initialized"));return {meta:e,cache:i}}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,z)=>{r.set(u._id,{id:u._id,offset:z});});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{cache:a}=this.getCollectionData(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{cache:s}=this.getCollectionData(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{cache:i}=this.getCollectionData(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),{cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:s,cache:n}=this.getCollectionData(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{meta:i,cache:s}=this.getCollectionData(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);let{cache:r}=this.getCollectionData(t);r.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 F=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"},H=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 j(this.options)):(this.storage=new M(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 F(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,H as JsonDB,P as JsonDBError,F as LazyCollection,E as PartitionManager,f as StorageError,T as ValidationError,I as WorkerPool,A as WriteQueue,v as generateId,U as isValidId,L as parallelLimit};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodejs-json-db",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A production-ready, lightweight JSON-based database for Node.js and Electron applications",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -24,7 +24,8 @@
24
24
  "format": "prettier --write \"src/**/*.ts\"",
25
25
  "typecheck": "tsc --noEmit",
26
26
  "prepublishOnly": "npm run build && npm run test",
27
- "benchmark": "tsx examples/benchmark.ts"
27
+ "benchmark": "tsx examples/benchmark.ts",
28
+ "prepare": "husky"
28
29
  },
29
30
  "files": [
30
31
  "dist",
@@ -66,6 +67,8 @@
66
67
  "@vitest/coverage-v8": "^4.0.16",
67
68
  "eslint": "^9.18.0",
68
69
  "globals": "^15.14.0",
70
+ "husky": "^9.1.7",
71
+ "lint-staged": "^16.2.7",
69
72
  "prettier": "^3.4.2",
70
73
  "tsup": "^8.5.1",
71
74
  "tsx": "^4.21.0",
@@ -84,5 +87,11 @@
84
87
  "zod": {
85
88
  "optional": true
86
89
  }
90
+ },
91
+ "lint-staged": {
92
+ "*.ts": [
93
+ "eslint --fix",
94
+ "prettier --write"
95
+ ]
87
96
  }
88
97
  }