@objectql/driver-fs 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,38 @@
1
+ # Changelog
2
+
3
+ All notable changes to the @objectql/driver-fs package will be documented in this file.
4
+
5
+ ## [0.1.1] - 2024-01-16
6
+
7
+ ### Added
8
+ - `initialData` configuration option to pre-populate data on initialization
9
+ - `clear(objectName)` method to clear all data for a specific object
10
+ - `clearAll()` method to clear all data from all objects
11
+ - `invalidateCache(objectName)` method to force cache reload
12
+ - `getCacheSize()` method to get the number of cached objects
13
+ - Chinese documentation (README.zh-CN.md)
14
+ - Better error handling for invalid JSON files
15
+ - Support for empty JSON files
16
+
17
+ ### Improved
18
+ - Enhanced JSON parse error messages with more detailed information
19
+ - Better documentation with examples for all new features
20
+ - Added 7 new test cases (total: 36 tests)
21
+ - TypeScript configuration for proper workspace resolution
22
+
23
+ ## [0.1.0] - 2024-01-16
24
+
25
+ ### Added
26
+ - Initial release of FileSystem Driver for ObjectQL
27
+ - One JSON file per table/object type
28
+ - Atomic write operations with temp file + rename strategy
29
+ - Automatic backup files (`.bak`) on write
30
+ - Full query support (filters, sorting, pagination, field projection)
31
+ - Support for all standard Driver interface methods:
32
+ - find, findOne, create, update, delete
33
+ - count, distinct
34
+ - createMany, updateMany, deleteMany
35
+ - Pretty-printed JSON for human readability
36
+ - Zero external dependencies (only @objectql/types)
37
+ - Comprehensive test suite with 30+ test cases
38
+ - Complete documentation and examples
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ObjectQL Contributors (https://github.com/objectql)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,426 @@
1
+ # @objectql/driver-fs
2
+
3
+ File System Driver for ObjectQL - JSON file-based persistent storage with one file per table.
4
+
5
+ > **中文文档**: [README.zh-CN.md](./README.zh-CN.md)
6
+
7
+ ## Features
8
+
9
+ ✅ **Persistent Storage** - Data survives process restarts
10
+ ✅ **One File Per Table** - Each object type stored in a separate JSON file (e.g., `users.json`, `projects.json`)
11
+ ✅ **Human-Readable** - Pretty-printed JSON for easy inspection and debugging
12
+ ✅ **Atomic Writes** - Temp file + rename strategy prevents corruption
13
+ ✅ **Backup Support** - Automatic backup files (`.bak`) on write
14
+ ✅ **Full Query Support** - Filters, sorting, pagination, field projection
15
+ ✅ **Zero Database Setup** - No external dependencies or database installation required
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @objectql/driver-fs
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ import { ObjectQL } from '@objectql/core';
27
+ import { FileSystemDriver } from '@objectql/driver-fs';
28
+
29
+ // 1. Initialize Driver
30
+ const driver = new FileSystemDriver({
31
+ dataDir: './data' // Directory where JSON files will be stored
32
+ });
33
+
34
+ // 2. Initialize ObjectQL
35
+ const app = new ObjectQL({
36
+ datasources: {
37
+ default: driver
38
+ }
39
+ });
40
+
41
+ // 3. Define Objects
42
+ app.registerObject({
43
+ name: 'users',
44
+ fields: {
45
+ name: { type: 'text', required: true },
46
+ email: { type: 'email' },
47
+ age: { type: 'number' }
48
+ }
49
+ });
50
+
51
+ await app.init();
52
+
53
+ // 4. Use the API
54
+ const ctx = app.createContext({ isSystem: true });
55
+ const users = ctx.object('users');
56
+
57
+ // Create
58
+ await users.create({ name: 'Alice', email: 'alice@example.com', age: 30 });
59
+
60
+ // Find
61
+ const allUsers = await users.find({});
62
+ console.log(allUsers);
63
+
64
+ // Query with filters
65
+ const youngUsers = await users.find({
66
+ filters: [['age', '<', 25]]
67
+ });
68
+ ```
69
+
70
+ ## Configuration
71
+
72
+ ```typescript
73
+ interface FileSystemDriverConfig {
74
+ /** Directory path where JSON files will be stored */
75
+ dataDir: string;
76
+
77
+ /** Enable pretty-print JSON for readability (default: true) */
78
+ prettyPrint?: boolean;
79
+
80
+ /** Enable backup files on write (default: true) */
81
+ enableBackup?: boolean;
82
+
83
+ /** Enable strict mode (throw on missing objects) (default: false) */
84
+ strictMode?: boolean;
85
+
86
+ /** Initial data to populate the store (optional) */
87
+ initialData?: Record<string, any[]>;
88
+ }
89
+ ```
90
+
91
+ ### Example with Options
92
+
93
+ ```typescript
94
+ const driver = new FileSystemDriver({
95
+ dataDir: './data',
96
+ prettyPrint: true, // Human-readable JSON
97
+ enableBackup: true, // Create .bak files
98
+ strictMode: false, // Graceful handling of missing records
99
+ initialData: { // Pre-populate with initial data
100
+ users: [
101
+ { id: 'admin', name: 'Admin User', role: 'admin' }
102
+ ]
103
+ }
104
+ });
105
+ ```
106
+
107
+ ## File Storage Format
108
+
109
+ Each object type is stored in a separate JSON file:
110
+
111
+ ```
112
+ ./data/
113
+ ├── users.json
114
+ ├── users.json.bak (backup)
115
+ ├── projects.json
116
+ ├── projects.json.bak
117
+ └── tasks.json
118
+ ```
119
+
120
+ ### File Content Example (`users.json`)
121
+
122
+ ```json
123
+ [
124
+ {
125
+ "id": "users-1234567890-1",
126
+ "name": "Alice",
127
+ "email": "alice@example.com",
128
+ "age": 30,
129
+ "created_at": "2024-01-15T10:30:00.000Z",
130
+ "updated_at": "2024-01-15T10:30:00.000Z"
131
+ },
132
+ {
133
+ "id": "users-1234567891-2",
134
+ "name": "Bob",
135
+ "email": "bob@example.com",
136
+ "age": 25,
137
+ "created_at": "2024-01-15T11:00:00.000Z",
138
+ "updated_at": "2024-01-15T11:00:00.000Z"
139
+ }
140
+ ]
141
+ ```
142
+
143
+ ## API Examples
144
+
145
+ ### CRUD Operations
146
+
147
+ ```typescript
148
+ const ctx = app.createContext({ isSystem: true });
149
+ const products = ctx.object('products');
150
+
151
+ // Create
152
+ const product = await products.create({
153
+ name: 'Laptop',
154
+ price: 1000,
155
+ category: 'electronics'
156
+ });
157
+
158
+ // Find One by ID
159
+ const found = await products.findOne(product.id);
160
+
161
+ // Update
162
+ await products.update(product.id, { price: 950 });
163
+
164
+ // Delete
165
+ await products.delete(product.id);
166
+ ```
167
+
168
+ ### Querying
169
+
170
+ ```typescript
171
+ // Filter
172
+ const electronics = await products.find({
173
+ filters: [['category', '=', 'electronics']]
174
+ });
175
+
176
+ // Multiple filters with OR
177
+ const results = await products.find({
178
+ filters: [
179
+ ['price', '<', 500],
180
+ 'or',
181
+ ['category', '=', 'sale']
182
+ ]
183
+ });
184
+
185
+ // Sorting
186
+ const sorted = await products.find({
187
+ sort: [['price', 'desc']]
188
+ });
189
+
190
+ // Pagination
191
+ const page1 = await products.find({
192
+ limit: 10,
193
+ skip: 0
194
+ });
195
+
196
+ // Field Projection
197
+ const names = await products.find({
198
+ fields: ['name', 'price']
199
+ });
200
+ ```
201
+
202
+ ### Bulk Operations
203
+
204
+ ```typescript
205
+ // Create Many
206
+ await products.createMany([
207
+ { name: 'Item 1', price: 10 },
208
+ { name: 'Item 2', price: 20 },
209
+ { name: 'Item 3', price: 30 }
210
+ ]);
211
+
212
+ // Update Many
213
+ await products.updateMany(
214
+ [['category', '=', 'electronics']], // filters
215
+ { onSale: true } // update data
216
+ );
217
+
218
+ // Delete Many
219
+ await products.deleteMany([
220
+ ['price', '<', 10]
221
+ ]);
222
+
223
+ // Count
224
+ const count = await products.count({
225
+ filters: [['category', '=', 'electronics']]
226
+ });
227
+
228
+ // Distinct Values
229
+ const categories = await products.distinct('category');
230
+ ```
231
+
232
+ ## Supported Query Operators
233
+
234
+ - **Equality**: `=`, `==`, `!=`, `<>`
235
+ - **Comparison**: `>`, `>=`, `<`, `<=`
236
+ - **Membership**: `in`, `nin` (not in)
237
+ - **String Matching**: `like`, `contains`, `startswith`, `endswith`
238
+ - **Range**: `between`
239
+
240
+ ## Use Cases
241
+
242
+ ### ✅ Ideal For
243
+
244
+ - **Small to Medium Datasets** (< 10k records per object)
245
+ - **Development and Prototyping** with persistent data
246
+ - **Configuration Storage** (settings, metadata)
247
+ - **Embedded Applications** (Electron, Tauri)
248
+ - **Scenarios without Database** (no DB setup required)
249
+ - **Human-Inspectable Data** (easy to debug and modify)
250
+
251
+ ### ❌ Not Recommended For
252
+
253
+ - **Large Datasets** (> 10k records per object)
254
+ - **High-Concurrency Writes** (multiple processes writing simultaneously)
255
+ - **Production High-Traffic Apps** (use SQL/MongoDB drivers instead)
256
+ - **Complex Transactions** (use SQL driver with transaction support)
257
+
258
+ ## Performance Characteristics
259
+
260
+ - **Read Performance**: O(n) for filtered queries, fast for simple lookups
261
+ - **Write Performance**: O(n) - entire file is rewritten on each update
262
+ - **Storage Format**: Human-readable JSON (larger than binary formats)
263
+ - **Concurrency**: Single-process safe, multi-process requires external locking
264
+
265
+ ## Data Safety
266
+
267
+ ### Atomic Writes
268
+
269
+ The driver uses a temp file + rename strategy to prevent corruption:
270
+
271
+ 1. Write new data to `{file}.tmp`
272
+ 2. Rename `{file}.tmp` → `{file}` (atomic operation)
273
+ 3. If the process crashes during write, the original file remains intact
274
+
275
+ ### Backup Files
276
+
277
+ When `enableBackup: true`, the driver creates `.bak` files:
278
+
279
+ ```
280
+ users.json ← Current data
281
+ users.json.bak ← Previous version
282
+ ```
283
+
284
+ To restore from backup:
285
+
286
+ ```bash
287
+ cp data/users.json.bak data/users.json
288
+ ```
289
+
290
+ ## Advanced Usage
291
+
292
+ ### Custom ID Generation
293
+
294
+ ```typescript
295
+ // Use your own ID
296
+ await products.create({
297
+ id: 'PROD-001',
298
+ name: 'Custom Product'
299
+ });
300
+
301
+ // Or use _id (MongoDB-style)
302
+ await products.create({
303
+ _id: '507f1f77bcf86cd799439011',
304
+ name: 'Mongo-Style Product'
305
+ });
306
+ ```
307
+
308
+ ### Loading Initial Data
309
+
310
+ **Method 1: Provide in configuration**
311
+
312
+ ```typescript
313
+ const driver = new FileSystemDriver({
314
+ dataDir: './data',
315
+ initialData: {
316
+ users: [
317
+ { id: 'admin-001', name: 'Admin User', role: 'admin' }
318
+ ],
319
+ settings: [
320
+ { key: 'theme', value: 'dark' }
321
+ ]
322
+ }
323
+ });
324
+ ```
325
+
326
+ **Method 2: Pre-create JSON files**
327
+
328
+ You can pre-populate JSON files:
329
+
330
+ ```json
331
+ // ./data/users.json
332
+ [
333
+ {
334
+ "id": "admin-001",
335
+ "name": "Admin User",
336
+ "email": "admin@example.com",
337
+ "role": "admin",
338
+ "created_at": "2024-01-01T00:00:00.000Z",
339
+ "updated_at": "2024-01-01T00:00:00.000Z"
340
+ }
341
+ ]
342
+ ```
343
+
344
+ The driver will load this data on startup.
345
+
346
+ ### Multiple Data Directories
347
+
348
+ ```typescript
349
+ // Development
350
+ const devDriver = new FileSystemDriver({
351
+ dataDir: './data/dev'
352
+ });
353
+
354
+ // Testing
355
+ const testDriver = new FileSystemDriver({
356
+ dataDir: './data/test'
357
+ });
358
+ ```
359
+
360
+ ### Utility Methods
361
+
362
+ ```typescript
363
+ // Clear all data for a specific object
364
+ await driver.clear('users');
365
+
366
+ // Clear all data for all objects
367
+ await driver.clearAll();
368
+
369
+ // Invalidate cache for an object
370
+ driver.invalidateCache('users');
371
+
372
+ // Get cache size
373
+ const size = driver.getCacheSize();
374
+ ```
375
+
376
+ ## Comparison with Other Drivers
377
+
378
+ | Feature | FileSystem | Memory | SQL | MongoDB |
379
+ |---------|-----------|--------|-----|---------|
380
+ | Persistence | ✅ Yes | ❌ No | ✅ Yes | ✅ Yes |
381
+ | Setup Required | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
382
+ | Human-Readable | ✅ Yes | ❌ No | ❌ No | ⚠️ Partial |
383
+ | Performance (Large Data) | ⚠️ Slow | ✅ Fast | ✅ Fast | ✅ Fast |
384
+ | Transactions | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
385
+ | Best For | Dev/Config | Testing | Production | Production |
386
+
387
+ ## Troubleshooting
388
+
389
+ ### File Corruption
390
+
391
+ If a JSON file becomes corrupted, restore from backup:
392
+
393
+ ```bash
394
+ cp data/users.json.bak data/users.json
395
+ ```
396
+
397
+ ### Permission Issues
398
+
399
+ Ensure the process has read/write permissions:
400
+
401
+ ```bash
402
+ chmod 755 ./data
403
+ ```
404
+
405
+ ### Large Files
406
+
407
+ If files become too large (> 1MB), consider:
408
+
409
+ 1. Splitting data into multiple object types
410
+ 2. Using SQL/MongoDB drivers for production
411
+ 3. Implementing data archiving strategy
412
+
413
+ ## License
414
+
415
+ MIT
416
+
417
+ ## Contributing
418
+
419
+ Contributions are welcome! Please open an issue or PR on GitHub.
420
+
421
+ ## Related Packages
422
+
423
+ - [@objectql/core](https://www.npmjs.com/package/@objectql/core) - Core ObjectQL engine
424
+ - [@objectql/driver-sql](https://www.npmjs.com/package/@objectql/driver-sql) - SQL driver (PostgreSQL, MySQL, SQLite)
425
+ - [@objectql/driver-mongo](https://www.npmjs.com/package/@objectql/driver-mongo) - MongoDB driver
426
+ - [@objectql/driver-memory](https://www.npmjs.com/package/@objectql/driver-memory) - In-memory driver