Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] - 2025-07-07

### Added
- **Unique Fields Support** - Prevent duplicate values in specified fields
- Configure unique fields via `uniqueFields` option
- Automatic validation on create and update operations
- Clear error messages for duplicate field values
- **Auto-ID Toggle** - Control automatic ID assignment
- Enable/disable auto-ID with `autoId` option
- Default behavior remains unchanged (auto-ID enabled)
- **deleteAll Method** - Remove all items from the database
- Simple `deleteAll(callback)` method
- Thread-safe operation through existing queue system
- **createCrud Convenience Function** - Quick CRUD instance creation
- Simplified API: `createCrud(filePath, options)`
- Exported as named export for easy access
- **Automatic Directory Creation** - Create directories if they don't exist
- Automatically creates parent directories for file paths
- No need to manually create directories before using the library

### Enhanced
- **Test Suite Reorganization** - Improved test structure
- Split tests into logical files by functionality
- `test-basic.js` - Basic functionality and convenience features
- `test-config-options.js` - Configuration options (uniqueFields, autoId)
- `test-delete.js` - Delete operations including deleteAll
- Total test count increased to 37 tests
- **Configuration Options** - Enhanced constructor options
- `uniqueFields: string[]` - Array of field names that must be unique
- `autoId: boolean` - Enable/disable automatic ID assignment
- Backward compatible with existing code

### Changed
- Package description updated to reflect new features
- Test scripts updated for reorganized test structure

### Technical Details
- All new features maintain backward compatibility
- Thread-safe operations through existing queue system
- Comprehensive error handling for all new features
- Zero breaking changes to existing API

## [1.0.0] - 2025-07-07

### Added
Expand Down Expand Up @@ -55,3 +97,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Batch operations (createMany, updateMany, deleteMany)
- File locking for multi-process safety
- Enhanced documentation and examples

---

[1.1.0]: https://github.com/arielweizman/json-file-crud/compare/v1.0.0...v1.1.0
[1.0.0]: https://github.com/arielweizman/json-file-crud/releases/tag/v1.0.0
149 changes: 103 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ A simple, robust, and thread-safe CRUD library for managing JSON objects in file

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

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

```javascript
import JsonFileCRUD from 'json-file-crud';
import JsonFileCRUD, { createCrud } from 'json-file-crud';

// Standard usage
const db = new JsonFileCRUD('./data.json');

// Quick setup with convenience function
const db2 = createCrud('./users.json');

// Advanced configuration with unique fields
const userDb = new JsonFileCRUD('./users.json', {
uniqueFields: ['email', 'username'],
autoId: true
});

// Create a new item
db.create({ name: 'John', age: 30 }, (err, result) => {
if (err) {
Expand Down Expand Up @@ -67,16 +81,41 @@ db.delete(1, (err, deletedItem) => {

Creates a new JsonFileCRUD instance.

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

```javascript
// Default ID field
// Default settings
const db = new JsonFileCRUD('./data.json');

// Custom ID field
const products = new JsonFileCRUD('./products.json', { idField: 'productId' });

// Unique fields validation
const users = new JsonFileCRUD('./users.json', {
uniqueFields: ['email', 'username']
});

// Disable auto-ID
const manualDb = new JsonFileCRUD('./manual.json', { autoId: false });

// Deep directory path (automatically created)
const deepDb = new JsonFileCRUD('./data/nested/deep/file.json');
```

### Convenience Functions

#### `createCrud(filePath, options)`

Quick way to create a JsonFileCRUD instance.

```javascript
import { createCrud } from 'json-file-crud';

const db = createCrud('./data.json', { uniqueFields: ['email'] });
```

### CRUD Operations
Expand Down Expand Up @@ -165,6 +204,19 @@ db.delete(1, (err, deleted) => {
});
```

#### `deleteAll(callback)`

Deletes all items from the database.

- `callback` (function): `(error) => {}`

```javascript
db.deleteAll((err) => {
if (err) throw err;
console.log('All items deleted');
});
```

#### `count(callback)`

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

## Advanced Features

### Auto-ID Assignment
### Unique Fields

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

```javascript
db.create({ name: 'John' }, (err, result) => {
// result: { name: 'John', id: 1 }
const userDb = new JsonFileCRUD('./users.json', {
uniqueFields: ['email', 'username']
});

db.create({ name: 'Jane' }, (err, result) => {
// result: { name: 'Jane', id: 2 }
// This will fail if email already exists
userDb.create({
name: 'John',
email: 'john@example.com'
}, (err, user) => {
// err.message: "Item with email 'john@example.com' already exists"
});
```

### Concurrent Operations
### Auto-ID Control

All write operations are automatically queued to prevent race conditions:
Disable automatic ID assignment:

```javascript
// These will be executed sequentially, not simultaneously
db.create({ name: 'User 1' }, callback1);
db.create({ name: 'User 2' }, callback2);
db.update(1, { active: true }, callback3);
const db = new JsonFileCRUD('./data.json', { autoId: false });

// No ID will be auto-generated
db.create({ name: 'Test' }, (err, item) => {
// item: { name: 'Test' } (no id field)
});
```

### Custom ID Fields
### Directory Creation

You can use any field name as the primary key:
Automatically creates directories for deep paths:

```javascript
const products = new JsonFileCRUD('./products.json', { idField: 'productId' });

products.create({ name: 'Laptop', price: 999 }, (err, product) => {
// product: { name: 'Laptop', price: 999, productId: 1 }
});
// This will create ./data/users/ directories if they don't exist
const db = new JsonFileCRUD('./data/users/profiles.json');
```

### Error Handling
## Examples

For comprehensive examples, see the [examples](./examples/) directory:

- **[Basic Usage](./examples/basic-usage.js)** - Simple CRUD operations
- **[Advanced Features](./examples/advanced-usage.js)** - Concurrent operations, filtering, custom ID fields
- **[User Management](./examples/user-management.js)** - Real-world application with unique fields validation

JsonFileCRUD provides detailed error messages for common scenarios:
### Quick Examples

```javascript
// Validation errors
db.create(null, (err) => {
// err.message: "Item must be an object"
// Basic usage with unique fields
import JsonFileCRUD, { createCrud } from 'json-file-crud';

const userDb = createCrud('./users.json', {
uniqueFields: ['email', 'username']
});

// Not found errors
db.findById(999, (err) => {
// err.message: "Item with id 999 not found"
// Delete all users
userDb.deleteAll((err) => {
console.log('All users deleted');
});

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

## Examples

For comprehensive examples, see the [examples](./examples/) directory:

- **[Basic Usage](./examples/basic-usage.js)** - Simple CRUD operations
- **[Advanced Features](./examples/advanced-usage.js)** - Concurrent operations, filtering, custom ID fields
- **[User Management](./examples/user-management.js)** - Real-world application example

To run examples:

```bash
cd examples
node basic-usage.js
npm run examples
# or individually:
node examples/basic-usage.js
```

## TypeScript Support
Expand Down
5 changes: 4 additions & 1 deletion lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const OPERATION_TYPES = {
CREATE: 'create',
UPDATE: 'update',
DELETE: 'delete',
DELETE_ALL: 'deleteAll',
WRITE_ALL: 'writeAll'
};

Expand All @@ -20,5 +21,7 @@ export const ERROR_MESSAGES = {
};

export const DEFAULT_CONFIG = {
ID_FIELD: 'id'
ID_FIELD: 'id',
AUTO_ID: true,
UNIQUE_FIELDS: []
};
15 changes: 12 additions & 3 deletions lib/file-operations.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/**
* File operations utilities for JsonFileCRUD
* @version 1.0.0
* @version 1.1.0
*/

import fs from 'fs';
import path from 'path';
import { ERROR_MESSAGES } from './constants.js';

/**
Expand Down Expand Up @@ -38,6 +39,14 @@ export function readAllFromFile(filePath, callback) {
* @param {Function} callback - Called with (error)
*/
export function writeItemsToFile(filePath, items, callback) {
const content = JSON.stringify(items, null, 2);
fs.writeFile(filePath, content, callback);
// Ensure directory exists
const dir = path.dirname(filePath);
fs.mkdir(dir, { recursive: true }, (mkdirErr) => {
if (mkdirErr) {
return callback(mkdirErr);
}

const content = JSON.stringify(items, null, 2);
fs.writeFile(filePath, content, callback);
});
}
Loading