Skip to content

Modern, feature-rich JSON database module for Node.js with encryption, compression, transactions, MongoDB-like collections, query builder, TTL, events, schema validation, and plugin system.

License

Notifications You must be signed in to change notification settings

devRaikou/datara

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ—„οΈ Datara v2.0

Modern, feature-rich and secure JSON database module for Node.js.

License: MIT Node.js Version

✨ Features

Core Features

  • πŸš€ Simple & User-Friendly: Minimalist API for quick start
  • πŸ’Ύ Auto Save: Automatically saves on every operation (configurable)
  • πŸ”— Dot Notation: Easy access to nested objects (user.settings.theme)
  • πŸ“ TypeScript Support: Full TypeScript definitions included
  • 🎯 Zero Dependencies: No external dependencies required
  • ⚑ Lightweight: Minimal file size

New in v2.0

  • πŸ” AES-256 Encryption: Secure your database with password encryption
  • πŸ“¦ Gzip Compression: Reduce file size with compression
  • πŸ’Ό Transactions: Begin, commit, and rollback operations
  • πŸ” Query Builder: SQL-like queries on arrays
  • πŸ“ Collection API: MongoDB-like document collections
  • ⏰ TTL Support: Auto-expiring keys
  • πŸ‘€ Watch/Observe: Listen to data changes
  • πŸ“‘ Event Emitter: React to database events
  • βœ… Schema Validation: Validate data before saving
  • πŸ’Ύ Backup/Restore: Automatic backups with restore capability
  • πŸ”Œ Plugin System: Extend functionality with plugins
  • ⚑ Async/Await: Promise-based async operations
  • πŸ“¦ ESM Support: ES Modules support

πŸ“¦ Installation

npm install datara

or

yarn add datara

πŸš€ Quick Start

const Datara = require('datara');

// Create a database
const db = new Datara('./mydb.json');

// Save data
db.set('name', 'Datara');
db.set('version', '2.0.0');

// Read data
console.log(db.get('name')); // 'Datara'

// Nested objects
db.set('user.name', 'devraikou');
db.set('user.settings.theme', 'dark');
console.log(db.get('user')); // { name: 'devraikou', settings: { theme: 'dark' } }

// Clean up when done
db.close();

πŸ“– Documentation

Initialization

const Datara = require('datara');

// Basic usage
const db = new Datara('./database.json');

// With options
const db = new Datara('./database.json', {
  autoSave: true,          // Auto-save on every operation (default: true)
  pretty: true,            // Pretty print JSON (default: true)
  indentSize: 2,           // Indentation size (default: 2)
  encryption: 'secret',    // Encryption password (default: null)
  compression: true,       // Enable gzip compression (default: false)
  backupInterval: 3600000, // Auto-backup interval in ms (default: null)
  maxBackups: 5,           // Max backup files to keep (default: 5)
  timestamps: true,        // Add timestamps to objects (default: false)
  schema: {                // Schema validation rules (default: null)
    username: { type: 'string', required: true }
  }
});

Basic Operations

set(key, value)

Save data to the database.

db.set('username', 'devraikou');
db.set('score', 100);
db.set('active', true);

// Nested objects with dot notation
db.set('user.profile.name', 'Ali');
db.set('settings.theme.color', 'dark');

get(key, defaultValue)

Read data from the database.

const username = db.get('username'); // 'devraikou'
const score = db.get('score'); // 100

// With default value
const lang = db.get('language', 'en'); // 'en' (if not exists)

// Get all data
const allData = db.get(); // Entire database

has(key)

Check if a key exists.

db.has('username'); // true
db.has('nonexistent'); // false

delete(key)

Delete a key.

db.delete('username'); // true
db.delete('nonexistent'); // false

update(key, callback)

Update a value using a callback function.

db.set('counter', 10);
db.update('counter', val => val * 2); // 20

rename(oldKey, newKey)

Rename a key.

db.set('oldName', 'value');
db.rename('oldName', 'newName');

clone(sourceKey, destKey)

Clone a value to a new key.

db.set('original', { data: 'test' });
db.clone('original', 'copy');

type(key)

Get the type of a value.

db.type('name');     // 'string'
db.type('count');    // 'number'
db.type('items');    // 'array'
db.type('user');     // 'object'
db.type('missing');  // 'undefined'

merge(key, data)

Deep merge data into an existing object.

db.set('config', { a: 1, b: 2 });
db.merge('config', { b: 3, c: 4 });
// Result: { a: 1, b: 3, c: 4 }

Array Operations

// Initialize array
db.set('items', []);

// Push - Add to end
db.push('items', 'first');
db.push('items', 'second');

// Pop - Remove from end
db.pop('items'); // Returns 'second'

// Shift - Remove from start
db.shift('items'); // Returns 'first'

// Unshift - Add to start
db.unshift('items', 'new first');

// Splice - Remove/replace elements
db.splice('items', 1, 2, 'replacement');

// Filter
const evens = db.filter('numbers', n => n % 2 === 0);

// Find
const user = db.find('users', u => u.id === 1);

// FindIndex
const index = db.findIndex('users', u => u.id === 1);

// Map
const names = db.map('users', u => u.name);

// Some - At least one matches
db.some('numbers', n => n > 10); // true/false

// Every - All match
db.every('numbers', n => n > 0); // true/false

// Reduce
const sum = db.reduce('numbers', (acc, n) => acc + n, 0);

// IndexOf
db.indexOf('items', 'value'); // Returns index or -1

// Includes
db.includes('items', 'value'); // true/false

// Sort
db.sort('numbers'); // Ascending
db.sort('numbers', (a, b) => b - a); // Descending

// Reverse
db.reverse('items');

// Flat - Flatten nested arrays
db.flat('nested', 2); // depth = 2

// Unique - Remove duplicates
db.unique('items');

// Pull - Remove specific value
db.pull('items', 'value');

Math Operations

db.set('score', 100);

// Increment/Decrement
db.increment('score');        // 101
db.increment('score', 5);     // 106
db.decrement('score', 3);     // 103

// Add/Subtract
db.add('score', 50);          // 153
db.subtract('score', 30);     // 123

// Multiply/Divide
db.multiply('score', 2);      // 246
db.divide('score', 3);        // 82

// Modulo
db.modulo('score', 10);       // 2

// Power
db.power('score', 2);         // 4

// Custom math operation
db.math('score', n => Math.sqrt(n)); // 2

Query Builder

db.set('users', [
  { name: 'Alice', age: 25, active: true },
  { name: 'Bob', age: 30, active: false },
  { name: 'Charlie', age: 35, active: true }
]);

// Simple query
const results = db.query('users')
  .where('age', '>', 25)
  .where('active', '==', true)
  .get();

// With ordering and limit
const top2 = db.query('users')
  .orderBy('age', 'desc')
  .limit(2)
  .get();

// Skip for pagination
const page2 = db.query('users')
  .skip(10)
  .limit(10)
  .get();

// Get first result
const first = db.query('users')
  .where('active', '==', true)
  .first();

// Count results
const count = db.query('users')
  .where('age', '>=', 30)
  .count();

// Available operators:
// '==' | '===' | '!=' | '!==' | '>' | '>=' | '<' | '<='
// 'includes' | 'startsWith' | 'endsWith' | 'in' | 'notIn' | 'regex'

Collection API (MongoDB-like)

// Get or create a collection
const users = db.collection('users');

// Insert documents
const user = users.insert({ name: 'John', email: '[email protected]' });
// Returns: { _id: 'uuid', name: 'John', email: '...', _createdAt: '...', _updatedAt: '...' }

// Insert many
users.insertMany([
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 30 }
]);

// Find by ID
const found = users.findById('uuid');

// Find one by query
const alice = users.findOne({ name: 'Alice' });

// Find many with query operators
const adults = users.findMany({ age: { $gte: 18 } });

// Available operators:
// $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $regex, $exists

// Update by ID
users.updateById('uuid', { age: 26 });

// Update one by query
users.updateOne({ name: 'Alice' }, { age: 27 });

// Update many
users.updateMany({ active: false }, { status: 'inactive' });

// Delete by ID
users.deleteById('uuid');

// Delete one by query
users.deleteOne({ name: 'Bob' });

// Delete many
const deletedCount = users.deleteMany({ active: false });

// Count
const count = users.count({ active: true });

// Drop collection
users.drop();

TTL (Time-To-Live)

// Set with TTL (expires in 5 seconds)
db.setWithTTL('session', { userId: 123 }, 5000);

// Check remaining TTL
const ttl = db.getTTL('session'); // milliseconds or null

// Make persistent (remove TTL)
db.persist('session');

// Listen to expiration
db.on('expire', (key) => {
  console.log(`Key "${key}" expired`);
});

Watch/Observer

// Watch for changes
const unwatch = db.watch('user.settings', (newValue, oldValue, key) => {
  console.log(`${key} changed from`, oldValue, 'to', newValue);
});

// Make changes
db.set('user.settings.theme', 'dark'); // Triggers watcher

// Stop watching
unwatch();

// Or unwatch all callbacks for a key
db.unwatch('user.settings');

Transactions

db.set('balance', 100);

// Begin transaction
db.beginTransaction();

try {
  db.set('balance', db.get('balance') - 50);
  db.set('transferred', 50);
  
  // Commit changes
  db.commit();
} catch (error) {
  // Rollback on error
  db.rollback();
}

// Check transaction state
db.inTransaction(); // true/false

Backup/Restore

// Create backup
const backupPath = db.backup();
// Or with custom path
const backupPath = db.backup('./backups/mydb-backup.json');

// List available backups
const backups = db.listBackups();
// ['./mydb.json.backup-2024-01-15T10-30-00-000Z', ...]

// Restore from backup
db.restore(backupPath);

Events

// Available events
db.on('set', (key, value, oldValue) => {});
db.on('delete', (key, oldValue) => {});
db.on('clear', (oldData) => {});
db.on('save', (data) => {});
db.on('reload', (data) => {});
db.on('import', (data, merge) => {});
db.on('expire', (key) => {});
db.on('backup', (path) => {});
db.on('restore', (path) => {});
db.on('close', () => {});
db.on('transactionBegin', () => {});
db.on('transactionCommit', () => {});
db.on('transactionRollback', () => {});

Encryption

// Create encrypted database
const db = new Datara('./secure.json', {
  encryption: 'my-secret-password'
});

// Data is automatically encrypted on save
db.set('secret', 'classified information');

// And decrypted on load
console.log(db.get('secret')); // 'classified information'

// File content is encrypted with AES-256-GCM

Compression

// Enable gzip compression
const db = new Datara('./compressed.json', {
  compression: true
});

// Data is automatically compressed/decompressed

Schema Validation

const db = new Datara('./validated.json', {
  schema: {
    username: {
      type: 'string',
      required: true,
      minLength: 3,
      maxLength: 20
    },
    age: {
      type: 'number',
      min: 0,
      max: 150
    },
    email: {
      type: 'string',
      pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    },
    role: {
      type: 'string',
      enum: ['admin', 'user', 'guest']
    },
    score: {
      type: 'number',
      custom: (value) => value >= 0 || 'Score must be positive'
    }
  }
});

// Valid data
db.set('username', 'john'); // OK
db.set('age', 25); // OK

// Invalid data throws ValidationError
db.set('username', 'ab'); // Error: minLength
db.set('age', 200); // Error: max

Plugin System

// Create a plugin
const timestampPlugin = {
  install(datara) {
    // Add new methods
    datara.setWithTimestamp = function(key, value) {
      return this.set(key, {
        value,
        createdAt: new Date().toISOString()
      });
    };
  }
};

// Use the plugin
db.use(timestampPlugin);

// Use new methods
db.setWithTimestamp('item', 'data');
// { value: 'data', createdAt: '2024-01-15T10:30:00.000Z' }

Async Operations

// Async set
await db.setAsync('key', 'value');

// Async get
const value = await db.getAsync('key');

// Async save
await db.saveAsync();

Utility Methods

// Get all keys
db.keys(); // ['key1', 'key2', ...]
db.keys('user'); // Keys starting with 'user'

// Get all values
db.values(); // [value1, value2, ...]

// Get all entries
db.entries(); // [['key1', value1], ['key2', value2], ...]

// Iterate
db.forEach((value, key) => {
  console.log(key, value);
});

// Size
db.size(); // Number of top-level keys

// Count array items
db.count('items'); // Array length
db.count('items', item => item.active); // Count with filter

// Clear all data
db.clear();

// Export database
const data = db.export();

// Import data
db.import(data);
db.import(data, true); // Merge with existing

// Reload from file
db.reload();

// Close database (cleanup)
db.close();

ESM Support

// ES Modules
import Datara from 'datara';

// Or import specific classes
import { Datara, DataraError, ValidationError } from 'datara';

Error Classes

const { 
  DataraError, 
  ValidationError, 
  EncryptionError, 
  TransactionError 
} = require('datara');

try {
  db.set('invalid', value);
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Validation failed:', error.key, error.value);
  } else if (error instanceof EncryptionError) {
    console.log('Encryption failed');
  }
}

πŸ”§ Configuration Options

Option Type Default Description
autoSave boolean true Automatically save after each operation
pretty boolean true Pretty print JSON with indentation
indentSize number 2 Indentation size for pretty print
encryption string null Password for AES-256-GCM encryption
compression boolean false Enable gzip compression
backupInterval number null Auto-backup interval in milliseconds
maxBackups number 5 Maximum backup files to keep
timestamps boolean false Add _createdAt/_updatedAt to objects
schema object null Schema validation rules

πŸ“„ License

MIT Β© devraikou

🀝 Contributing

Contributions, issues and feature requests are welcome!

⭐ Show your support

Give a ⭐️ if this project helped you!

About

Modern, feature-rich JSON database module for Node.js with encryption, compression, transactions, MongoDB-like collections, query builder, TTL, events, schema validation, and plugin system.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published