dart_db 0.1.0 copy "dart_db: ^0.1.0" to clipboard
dart_db: ^0.1.0 copied to clipboard

High-performance embedded key-value database for pure Dart backend applications. Built on LMDB with Rust FFI for persistence.

DartDB #

pub package License: MIT

A high-performance embedded key-value database for pure Dart backend applications. Built on LMDB with Rust FFI for maximum performance and data persistence.

πŸš€ Features #

  • Embedded Database: No external database server required
  • High Performance: Built on LMDB (Lightning Memory-Mapped Database)
  • Persistent Storage: Data survives application restarts
  • Redis-like API: Familiar interface for key-value operations
  • Pure Dart: Designed specifically for Dart backend applications
  • Cross Platform: Works on Linux, macOS, and Windows
  • ACID Transactions: Full transaction support
  • Memory Efficient: Memory-mapped files for optimal performance
  • Rust FFI: Native performance through Rust integration

🎯 Use Cases #

Perfect for backend applications that need:

  • Caching Layer: Fast in-memory cache with persistence
  • Session Storage: User session data with reliability
  • Configuration Storage: Application settings and metadata
  • Queue Management: Job queues and task scheduling
  • Metrics Collection: Performance metrics and analytics
  • Embedded Analytics: Local data processing and aggregation

πŸ“¦ Installation #

Add this to your pubspec.yaml:

dependencies:
  dart_db: ^0.1.0

Then run:

dart pub get

πŸ”§ Quick Start #

import 'package:dart_db/dart_db.dart';

void main() async {
  // Initialize the database
  final db = await DartDB.open('my_database');
  
  // Store data
  await db.set('user:1', {'name': 'John', 'email': 'john@example.com'});
  await db.set('counter', 42);
  
  // Retrieve data
  final user = await db.get('user:1');
  final counter = await db.get<int>('counter');
  
  print('User: $user');
  print('Counter: $counter');
  
  // Check if key exists
  final exists = await db.exists('user:1');
  print('User exists: $exists');
  
  // Delete data
  await db.delete('counter');
  
  // Close the database
  await db.close();
}

πŸ“– API Reference #

Database Operations #

Opening a Database

// Open with default options
final db = await DartDB.open('database_name');

// Open with custom options
final db = await DartDB.open(
  'database_name',
  options: DatabaseOptions(
    maxSize: 1024 * 1024 * 100, // 100MB
    readOnly: false,
    createIfNotExists: true,
  ),
);

Basic Operations

// Set a value
await db.set('key', 'value');
await db.set('user:123', {'name': 'Alice', 'age': 30});

// Get a value
final value = await db.get('key');
final user = await db.get<Map>('user:123');

// Get with default value
final count = await db.get('count', defaultValue: 0);

// Check if key exists
final exists = await db.exists('key');

// Delete a key
await db.delete('key');

// Get all keys
final keys = await db.keys();

// Get keys with pattern
final userKeys = await db.keys(pattern: 'user:*');

Batch Operations

// Set multiple values at once
await db.setMultiple({
  'key1': 'value1',
  'key2': 'value2',
  'key3': 'value3',
});

// Get multiple values at once
final values = await db.getMultiple(['key1', 'key2', 'key3']);

// Delete multiple keys
await db.deleteMultiple(['key1', 'key2', 'key3']);

Advanced Operations

// Increment a numeric value
await db.increment('counter', by: 5);

// Decrement a numeric value
await db.decrement('counter', by: 2);

// Set with expiration (TTL)
await db.setWithTTL('session:abc', sessionData, Duration(hours: 2));

// Get database statistics
final stats = await db.stats();
print('Total keys: ${stats.keyCount}');
print('Database size: ${stats.sizeBytes}');

Transactions

// Execute operations in a transaction
await db.transaction((txn) async {
  await txn.set('account:1', 100);
  await txn.set('account:2', 200);
  final total = await txn.get<int>('account:1') + await txn.get<int>('account:2');
  await txn.set('total', total);
});

// Read-only transaction
final result = await db.readTransaction((txn) async {
  final user1 = await txn.get('user:1');
  final user2 = await txn.get('user:2');
  return [user1, user2];
});

Data Types Support #

DartDB supports all JSON-serializable Dart types:

// Primitives
await db.set('string', 'Hello World');
await db.set('number', 42);
await db.set('double', 3.14159);
await db.set('boolean', true);

// Collections
await db.set('list', [1, 2, 3, 4, 5]);
await db.set('map', {'key': 'value', 'number': 123});

// Complex objects (must be JSON-serializable)
await db.set('user', {
  'id': 123,
  'name': 'Alice',
  'preferences': {
    'theme': 'dark',
    'notifications': true,
  },
  'tags': ['admin', 'premium'],
});

⚑ Performance #

DartDB is built on LMDB, one of the fastest embedded databases available:

  • Read Performance: Up to 1M+ reads per second
  • Write Performance: Up to 100K+ writes per second
  • Memory Efficient: Uses memory-mapped files
  • Crash Safe: ACID transactions ensure data integrity
  • Concurrent Access: Multiple readers, single writer

Benchmarks #

Operation    | Operations/sec | Latency (avg)
-------------|----------------|-------------
GET          | 1,200,000      | 0.8ΞΌs
SET          | 150,000        | 6.7ΞΌs
DELETE       | 180,000        | 5.6ΞΌs
BATCH SET    | 300,000        | 3.3ΞΌs
TRANSACTION  | 80,000         | 12.5ΞΌs

πŸ”§ Configuration #

Database Options #

final options = DatabaseOptions(
  // Maximum database size (default: 100MB)
  maxSize: 1024 * 1024 * 500, // 500MB
  
  // Open database in read-only mode
  readOnly: false,
  
  // Create database if it doesn't exist
  createIfNotExists: true,
  
  // Number of readers allowed
  maxReaders: 126,
  
  // Sync mode for durability
  syncMode: SyncMode.full, // full, lazy, none
  
  // Compression settings
  compression: CompressionOptions(
    enabled: true,
    algorithm: CompressionAlgorithm.lz4,
    level: 1,
  ),
);

final db = await DartDB.open('database', options: options);

Environment Variables #

# Default database directory
export DART_DB_PATH=/var/lib/dart_db

# Default maximum size
export DART_DB_MAX_SIZE=104857600

# Log level
export DART_DB_LOG_LEVEL=info

πŸ—οΈ Architecture #

DartDB uses a layered architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Dart API      β”‚  ← High-level Dart interface
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   FFI Bridge    β”‚  ← Dart ↔ Rust communication
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Rust Core     β”‚  ← Core database logic
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   LMDB Engine   β”‚  ← Lightning Memory-Mapped DB
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Components #

  • Dart API: High-level, type-safe interface for Dart applications
  • FFI Bridge: Efficient communication layer between Dart and Rust
  • Rust Core: Core database operations, serialization, and error handling
  • LMDB Engine: Battle-tested, high-performance storage engine

πŸ“š Examples #

Web API Cache #

import 'package:dart_db/dart_db.dart';

class ApiCache {
  late DartDB _db;
  
  Future<void> init() async {
    _db = await DartDB.open('api_cache');
  }
  
  Future<Map<String, dynamic>?> getCachedResponse(String endpoint) async {
    return await _db.get<Map<String, dynamic>>(endpoint);
  }
  
  Future<void> cacheResponse(
    String endpoint, 
    Map<String, dynamic> response,
    {Duration? ttl}
  ) async {
    if (ttl != null) {
      await _db.setWithTTL(endpoint, response, ttl);
    } else {
      await _db.set(endpoint, response);
    }
  }
}

Session Store #

import 'package:dart_db/dart_db.dart';

class SessionStore {
  late DartDB _db;
  
  Future<void> init() async {
    _db = await DartDB.open('sessions');
  }
  
  Future<void> createSession(String sessionId, Map<String, dynamic> data) async {
    await _db.setWithTTL(
      'session:$sessionId',
      {
        ...data,
        'created': DateTime.now().toIso8601String(),
        'lastAccessed': DateTime.now().toIso8601String(),
      },
      Duration(hours: 24),
    );
  }
  
  Future<Map<String, dynamic>?> getSession(String sessionId) async {
    final session = await _db.get<Map<String, dynamic>>('session:$sessionId');
    if (session != null) {
      // Update last accessed time
      session['lastAccessed'] = DateTime.now().toIso8601String();
      await _db.setWithTTL('session:$sessionId', session, Duration(hours: 24));
    }
    return session;
  }
  
  Future<void> destroySession(String sessionId) async {
    await _db.delete('session:$sessionId');
  }
}

Configuration Manager #

import 'package:dart_db/dart_db.dart';

class ConfigManager {
  late DartDB _db;
  
  Future<void> init() async {
    _db = await DartDB.open('app_config');
  }
  
  Future<T?> getConfig<T>(String key, {T? defaultValue}) async {
    return await _db.get<T>(key, defaultValue: defaultValue);
  }
  
  Future<void> setConfig<T>(String key, T value) async {
    await _db.set(key, value);
  }
  
  Future<Map<String, dynamic>> getAllConfig() async {
    final keys = await _db.keys();
    final configs = <String, dynamic>{};
    
    for (final key in keys) {
      configs[key] = await _db.get(key);
    }
    
    return configs;
  }
}

πŸ§ͺ Testing #

import 'package:test/test.dart';
import 'package:dart_db/dart_db.dart';

void main() {
  group('DartDB Tests', () {
    late DartDB db;
    
    setUp(() async {
      // Use in-memory database for testing
      db = await DartDB.open(':memory:');
    });
    
    tearDown(() async {
      await db.close();
    });
    
    test('should store and retrieve values', () async {
      await db.set('test_key', 'test_value');
      final value = await db.get('test_key');
      expect(value, equals('test_value'));
    });
    
    test('should handle complex objects', () async {
      final complexObject = {
        'id': 123,
        'name': 'Test User',
        'preferences': ['dark_mode', 'notifications'],
      };
      
      await db.set('user', complexObject);
      final retrieved = await db.get<Map>('user');
      expect(retrieved, equals(complexObject));
    });
  });
}

πŸ” Troubleshooting #

Common Issues #

Database won't open

Error: Failed to open database
  • Check file permissions on the database directory
  • Ensure sufficient disk space
  • Verify the database path is valid

Out of memory errors

Error: Out of memory
  • Increase maxSize in DatabaseOptions
  • Check available system memory
  • Consider using compression

Performance issues

Slow read/write operations
  • Use batch operations for multiple keys
  • Enable compression for large values
  • Consider using transactions for related operations

Debug Mode #

Enable debug logging:

DartDB.setLogLevel(LogLevel.debug);

Memory Usage #

Monitor memory usage:

final stats = await db.stats();
print('Memory usage: ${stats.memoryUsage} bytes');
print('Disk usage: ${stats.diskUsage} bytes');

🀝 Contributing #

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Setup #

  1. Clone the repository
  2. Install Rust (for FFI compilation)
  3. Run dart pub get
  4. Run tests with dart test

Building #

# Build Rust FFI library
cargo build --release

# Run Dart tests
dart test

# Format code
dart format .

# Analyze code
dart analyze

πŸ“„ License #

This project is licensed under the MIT License - see the LICENSE file for details.

πŸ™ Acknowledgments #

  • LMDB - Lightning Memory-Mapped Database
  • Dart FFI - Foreign Function Interface
  • Rust - Systems programming language

Built with ❀️ for the Dart community by JhonaCode

1
likes
160
points
29
downloads

Publisher

verified publisherjhonacode.com

Weekly Downloads

High-performance embedded key-value database for pure Dart backend applications. Built on LMDB with Rust FFI for persistence.

Repository (GitHub)
View/report issues

Topics

#embedded #key-value #lmdb #backend #ffi

Documentation

API reference

Funding

Consider supporting this project:

github.com

License

MIT (license)

Dependencies

ffi

More

Packages that depend on dart_db