Skip to content

Commit fbc5747

Browse files
authored
Merge pull request #9 from r-el/feature/unique-fields-and-enhancements
feature/unique fields and enhancements
2 parents 99e1494 + 7790e1f commit fbc5747

File tree

9 files changed

+627
-217
lines changed

9 files changed

+627
-217
lines changed

CHANGELOG.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.1.0] - 2025-07-07
9+
10+
### Added
11+
- **Unique Fields Support** - Prevent duplicate values in specified fields
12+
- Configure unique fields via `uniqueFields` option
13+
- Automatic validation on create and update operations
14+
- Clear error messages for duplicate field values
15+
- **Auto-ID Toggle** - Control automatic ID assignment
16+
- Enable/disable auto-ID with `autoId` option
17+
- Default behavior remains unchanged (auto-ID enabled)
18+
- **deleteAll Method** - Remove all items from the database
19+
- Simple `deleteAll(callback)` method
20+
- Thread-safe operation through existing queue system
21+
- **createCrud Convenience Function** - Quick CRUD instance creation
22+
- Simplified API: `createCrud(filePath, options)`
23+
- Exported as named export for easy access
24+
- **Automatic Directory Creation** - Create directories if they don't exist
25+
- Automatically creates parent directories for file paths
26+
- No need to manually create directories before using the library
27+
28+
### Enhanced
29+
- **Test Suite Reorganization** - Improved test structure
30+
- Split tests into logical files by functionality
31+
- `test-basic.js` - Basic functionality and convenience features
32+
- `test-config-options.js` - Configuration options (uniqueFields, autoId)
33+
- `test-delete.js` - Delete operations including deleteAll
34+
- Total test count increased to 37 tests
35+
- **Configuration Options** - Enhanced constructor options
36+
- `uniqueFields: string[]` - Array of field names that must be unique
37+
- `autoId: boolean` - Enable/disable automatic ID assignment
38+
- Backward compatible with existing code
39+
40+
### Changed
41+
- Package description updated to reflect new features
42+
- Test scripts updated for reorganized test structure
43+
44+
### Technical Details
45+
- All new features maintain backward compatibility
46+
- Thread-safe operations through existing queue system
47+
- Comprehensive error handling for all new features
48+
- Zero breaking changes to existing API
49+
850
## [1.0.0] - 2025-07-07
951

1052
### Added
@@ -55,3 +97,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5597
- Batch operations (createMany, updateMany, deleteMany)
5698
- File locking for multi-process safety
5799
- Enhanced documentation and examples
100+
101+
---
102+
103+
[1.1.0]: https://github.com/arielweizman/json-file-crud/compare/v1.0.0...v1.1.0
104+
[1.0.0]: https://github.com/arielweizman/json-file-crud/releases/tag/v1.0.0

README.md

Lines changed: 103 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ A simple, robust, and thread-safe CRUD library for managing JSON objects in file
66

77
- **Simple API** - Easy to use CRUD operations
88
- **Thread-safe** - Sequential operations with automatic queuing
9-
- **Auto-ID assignment** - Automatic ID generation for new items
10-
- **Configurable ID field** - Use any field name as the primary key
11-
- **Comprehensive error handling** - Detailed error messages and validation
9+
- **Auto-ID assignment** - Automatic ID generation for new items (configurable)
10+
- **Unique Fields** - Prevent duplicate values in specified fields ✨ *New in v1.1*
11+
- **Concurrent Operations** - Thread-safe operations with automatic queuing
12+
- **Custom ID Fields** - Use any field name as the primary key (default: 'id')
13+
- **Directory Creation** - Automatically creates directories if they don't exist ✨ *New in v1.1*
14+
- **Convenience Functions** - Helper functions for quick setup ✨ *New in v1.1*
15+
- **Error Handling** - Comprehensive error handling and detailed error messages
1216
- **Zero dependencies** - Built with only Node.js built-in modules
1317
- **ESM support** - Full ES modules support
1418

@@ -21,10 +25,20 @@ npm install json-file-crud
2125
## Quick Start
2226

2327
```javascript
24-
import JsonFileCRUD from 'json-file-crud';
28+
import JsonFileCRUD, { createCrud } from 'json-file-crud';
2529

30+
// Standard usage
2631
const db = new JsonFileCRUD('./data.json');
2732

33+
// Quick setup with convenience function
34+
const db2 = createCrud('./users.json');
35+
36+
// Advanced configuration with unique fields
37+
const userDb = new JsonFileCRUD('./users.json', {
38+
uniqueFields: ['email', 'username'],
39+
autoId: true
40+
});
41+
2842
// Create a new item
2943
db.create({ name: 'John', age: 30 }, (err, result) => {
3044
if (err) {
@@ -67,16 +81,41 @@ db.delete(1, (err, deletedItem) => {
6781

6882
Creates a new JsonFileCRUD instance.
6983

70-
- `filePath` (string): Path to the JSON file
84+
- `filePath` (string): Path to the JSON file (directories will be created if they don't exist)
7185
- `options` (object, optional):
7286
- `idField` (string): Name of the ID field (default: 'id')
87+
- `uniqueFields` (array): Array of field names that must be unique (default: [])
88+
- `autoId` (boolean): Enable automatic ID assignment (default: true)
7389

7490
```javascript
75-
// Default ID field
91+
// Default settings
7692
const db = new JsonFileCRUD('./data.json');
7793

7894
// Custom ID field
7995
const products = new JsonFileCRUD('./products.json', { idField: 'productId' });
96+
97+
// Unique fields validation
98+
const users = new JsonFileCRUD('./users.json', {
99+
uniqueFields: ['email', 'username']
100+
});
101+
102+
// Disable auto-ID
103+
const manualDb = new JsonFileCRUD('./manual.json', { autoId: false });
104+
105+
// Deep directory path (automatically created)
106+
const deepDb = new JsonFileCRUD('./data/nested/deep/file.json');
107+
```
108+
109+
### Convenience Functions
110+
111+
#### `createCrud(filePath, options)`
112+
113+
Quick way to create a JsonFileCRUD instance.
114+
115+
```javascript
116+
import { createCrud } from 'json-file-crud';
117+
118+
const db = createCrud('./data.json', { uniqueFields: ['email'] });
80119
```
81120

82121
### CRUD Operations
@@ -165,6 +204,19 @@ db.delete(1, (err, deleted) => {
165204
});
166205
```
167206

207+
#### `deleteAll(callback)`
208+
209+
Deletes all items from the database.
210+
211+
- `callback` (function): `(error) => {}`
212+
213+
```javascript
214+
db.deleteAll((err) => {
215+
if (err) throw err;
216+
console.log('All items deleted');
217+
});
218+
```
219+
168220
#### `count(callback)`
169221

170222
Returns the total number of items.
@@ -197,77 +249,82 @@ db.writeAll(newData, (err) => {
197249

198250
## Advanced Features
199251

200-
### Auto-ID Assignment
252+
### Unique Fields
201253

202-
When creating items without an ID, JsonFileCRUD automatically assigns the next available numeric ID:
254+
Prevent duplicate values in specified fields:
203255

204256
```javascript
205-
db.create({ name: 'John' }, (err, result) => {
206-
// result: { name: 'John', id: 1 }
257+
const userDb = new JsonFileCRUD('./users.json', {
258+
uniqueFields: ['email', 'username']
207259
});
208260

209-
db.create({ name: 'Jane' }, (err, result) => {
210-
// result: { name: 'Jane', id: 2 }
261+
// This will fail if email already exists
262+
userDb.create({
263+
name: 'John',
264+
email: 'john@example.com'
265+
}, (err, user) => {
266+
// err.message: "Item with email 'john@example.com' already exists"
211267
});
212268
```
213269

214-
### Concurrent Operations
270+
### Auto-ID Control
215271

216-
All write operations are automatically queued to prevent race conditions:
272+
Disable automatic ID assignment:
217273

218274
```javascript
219-
// These will be executed sequentially, not simultaneously
220-
db.create({ name: 'User 1' }, callback1);
221-
db.create({ name: 'User 2' }, callback2);
222-
db.update(1, { active: true }, callback3);
275+
const db = new JsonFileCRUD('./data.json', { autoId: false });
276+
277+
// No ID will be auto-generated
278+
db.create({ name: 'Test' }, (err, item) => {
279+
// item: { name: 'Test' } (no id field)
280+
});
223281
```
224282

225-
### Custom ID Fields
283+
### Directory Creation
226284

227-
You can use any field name as the primary key:
285+
Automatically creates directories for deep paths:
228286

229287
```javascript
230-
const products = new JsonFileCRUD('./products.json', { idField: 'productId' });
231-
232-
products.create({ name: 'Laptop', price: 999 }, (err, product) => {
233-
// product: { name: 'Laptop', price: 999, productId: 1 }
234-
});
288+
// This will create ./data/users/ directories if they don't exist
289+
const db = new JsonFileCRUD('./data/users/profiles.json');
235290
```
236291

237-
### Error Handling
292+
## Examples
293+
294+
For comprehensive examples, see the [examples](./examples/) directory:
295+
296+
- **[Basic Usage](./examples/basic-usage.js)** - Simple CRUD operations
297+
- **[Advanced Features](./examples/advanced-usage.js)** - Concurrent operations, filtering, custom ID fields
298+
- **[User Management](./examples/user-management.js)** - Real-world application with unique fields validation
238299

239-
JsonFileCRUD provides detailed error messages for common scenarios:
300+
### Quick Examples
240301

241302
```javascript
242-
// Validation errors
243-
db.create(null, (err) => {
244-
// err.message: "Item must be an object"
303+
// Basic usage with unique fields
304+
import JsonFileCRUD, { createCrud } from 'json-file-crud';
305+
306+
const userDb = createCrud('./users.json', {
307+
uniqueFields: ['email', 'username']
245308
});
246309

247-
// Not found errors
248-
db.findById(999, (err) => {
249-
// err.message: "Item with id 999 not found"
310+
// Delete all users
311+
userDb.deleteAll((err) => {
312+
console.log('All users deleted');
250313
});
251314

252-
// Duplicate ID errors
253-
db.create({ id: 1, name: 'Duplicate' }, (err) => {
254-
// err.message: "Item with id 1 already exists"
315+
// Example with auto-ID disabled
316+
const manualDb = new JsonFileCRUD('./manual.json', { autoId: false });
317+
manualDb.create({ name: 'Test' }, (err, item) => {
318+
// item: { name: 'Test' } (no auto-generated ID)
255319
});
256320
```
257321

258-
## Examples
259-
260-
For comprehensive examples, see the [examples](./examples/) directory:
261-
262-
- **[Basic Usage](./examples/basic-usage.js)** - Simple CRUD operations
263-
- **[Advanced Features](./examples/advanced-usage.js)** - Concurrent operations, filtering, custom ID fields
264-
- **[User Management](./examples/user-management.js)** - Real-world application example
265-
266322
To run examples:
267323

268324
```bash
269-
cd examples
270-
node basic-usage.js
325+
npm run examples
326+
# or individually:
327+
node examples/basic-usage.js
271328
```
272329

273330
## TypeScript Support

lib/constants.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const OPERATION_TYPES = {
77
CREATE: 'create',
88
UPDATE: 'update',
99
DELETE: 'delete',
10+
DELETE_ALL: 'deleteAll',
1011
WRITE_ALL: 'writeAll'
1112
};
1213

@@ -20,5 +21,7 @@ export const ERROR_MESSAGES = {
2021
};
2122

2223
export const DEFAULT_CONFIG = {
23-
ID_FIELD: 'id'
24+
ID_FIELD: 'id',
25+
AUTO_ID: true,
26+
UNIQUE_FIELDS: []
2427
};

lib/file-operations.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/**
22
* File operations utilities for JsonFileCRUD
3-
* @version 1.0.0
3+
* @version 1.1.0
44
*/
55

66
import fs from 'fs';
7+
import path from 'path';
78
import { ERROR_MESSAGES } from './constants.js';
89

910
/**
@@ -38,6 +39,14 @@ export function readAllFromFile(filePath, callback) {
3839
* @param {Function} callback - Called with (error)
3940
*/
4041
export function writeItemsToFile(filePath, items, callback) {
41-
const content = JSON.stringify(items, null, 2);
42-
fs.writeFile(filePath, content, callback);
42+
// Ensure directory exists
43+
const dir = path.dirname(filePath);
44+
fs.mkdir(dir, { recursive: true }, (mkdirErr) => {
45+
if (mkdirErr) {
46+
return callback(mkdirErr);
47+
}
48+
49+
const content = JSON.stringify(items, null, 2);
50+
fs.writeFile(filePath, content, callback);
51+
});
4352
}

0 commit comments

Comments
 (0)