@matteuccimarco/slim-db
v0.1.0
Published
Embedded database with native SLIM storage - optimized for AI/LLM workloads
Maintainers
Readme
slim-db
SLIM-DB - Embedded document database with native SLIM storage. Part of the SLIM Protocol ecosystem.
Why SLIM-DB?
- Token-efficient storage: Uses SLIM format (40-50% smaller than JSON)
- Zero dependencies (except slim-protocol-core)
- MongoDB-like API: Familiar query and update operators
- Multiple index types: B-tree, Hash, Bitmap, Inverted
- Transactions: Snapshot isolation with rollback support
- TypeScript first: Full type safety
Installation
npm install slim-dbQuick Start
import { createDatabase } from 'slim-db';
// Create in-memory database
const db = createDatabase();
// Or with persistence
const db = createDatabase({ dataDir: './my-database' });
// Get a collection
const users = db.collection('users');
// Insert documents
users.insert({ name: 'Mario', age: 35, role: 'plumber' });
users.insertMany([
{ name: 'Luigi', age: 33, role: 'plumber' },
{ name: 'Peach', age: 30, role: 'princess' },
]);
// Find documents
const plumbers = await users.find({ role: 'plumber' }).toArray();
const mario = users.findOne({ name: 'Mario' });
// Update documents
users.updateOne({ name: 'Mario' }, { $set: { coins: 100 } });
users.updateMany({ role: 'plumber' }, { $inc: { coins: 10 } });
// Delete documents
users.deleteOne({ name: 'Bowser' });
// Save to disk (if using persistence)
db.save();Query Operators
Comparison
users.find({ age: { $gt: 30 } }); // Greater than
users.find({ age: { $gte: 30 } }); // Greater than or equal
users.find({ age: { $lt: 35 } }); // Less than
users.find({ age: { $lte: 35 } }); // Less than or equal
users.find({ age: { $ne: 30 } }); // Not equal
users.find({ name: { $in: ['Mario', 'Luigi'] } }); // In array
users.find({ name: { $nin: ['Bowser'] } }); // Not in arrayLogical
users.find({ $and: [{ age: { $gt: 30 } }, { role: 'plumber' }] });
users.find({ $or: [{ name: 'Mario' }, { name: 'Luigi' }] });
users.find({ age: { $not: { $lt: 30 } } });Element
users.find({ coins: { $exists: true } });
users.find({ role: { $type: 'string' } });String
users.find({ name: { $regex: '^Mar' } });
users.find({ name: { $startsWith: 'Mar' } });
users.find({ name: { $endsWith: 'io' } });Array
users.find({ items: { $contains: 'mushroom' } });Update Operators
// Set fields
users.updateOne({ name: 'Mario' }, { $set: { level: 1 } });
// Unset fields
users.updateOne({ name: 'Mario' }, { $unset: { tempBonus: true } });
// Increment numbers
users.updateOne({ name: 'Mario' }, { $inc: { coins: 10 } });
// Array operations
users.updateOne({ name: 'Mario' }, { $push: { items: 'star' } });
users.updateOne({ name: 'Mario' }, { $pull: { items: 'mushroom' } });
// Min/Max (keep smaller/larger value)
users.updateOne({ name: 'Mario' }, { $min: { score: 50 } });
users.updateOne({ name: 'Mario' }, { $max: { score: 100 } });
// Rename field
users.updateOne({ name: 'Mario' }, { $rename: { hp: 'health' } });Cursor Operations
const results = await users.find({ role: 'plumber' })
.sort({ age: -1 }) // Sort descending
.skip(10) // Skip first 10
.limit(5) // Limit to 5
.project(['name', 'age']) // Only these fields
.toArray();
// Iteration
await users.find().forEach(doc => console.log(doc));
const names = await users.find().map(doc => doc.name);
const count = await users.find({ active: true }).count();Indexes
// Create indexes
users.createIndex({ fields: ['email'], unique: true });
users.createIndex({ fields: ['age'], type: 'btree' });
users.createIndex({ fields: ['status'], type: 'bitmap' }); // Low cardinality
users.createIndex({ fields: ['tags'], type: 'inverted' }); // Arrays
// List indexes
const indexes = users.getIndexes();
// Drop index
users.dropIndex('email');Transactions
const tx = db.beginTransaction();
try {
tx.insert('users', { name: 'Toad', role: 'helper' });
tx.updateOne('users', { name: 'Mario' }, { $inc: { coins: -50 } });
tx.commit();
} catch (error) {
tx.rollback();
}
// Or use withTransaction helper
await db.withTransaction(async (tx) => {
// Operations here auto-commit on success, rollback on error
});SLIM Functions
SQL-style functions for querying SLIM data:
import { slimFunctions } from 'slim-db';
const doc = { _id: '1', user: { name: 'Mario', items: ['star', 'mushroom'] } };
slimFunctions.slim_get(doc, 'user.name'); // 'Mario'
slimFunctions.slim_num(doc, 'user.age'); // null (not a number)
slimFunctions.slim_str(doc, 'user.name'); // 'Mario'
slimFunctions.slim_arr(doc, 'user.items'); // ['star', 'mushroom']
slimFunctions.slim_len(doc, 'user.items'); // 2
slimFunctions.slim_exists(doc, 'user.coins'); // false
slimFunctions.slim_type(doc, 'user.items'); // 'array'
slimFunctions.slim_match(doc, { 'user.name': 'Mario' }); // truePersistence
// Create with file persistence
const db = createDatabase({ dataDir: './data' });
// Auto-save every 5 seconds
const db = createDatabase({
dataDir: './data',
autoSaveInterval: 5000
});
// Manual save
db.save();
// Check for unsaved changes
if (db.isDirty()) {
db.save();
}Export/Import
// Export entire database as SLIM
const slim = db.exportSLIM();
// Import into another database
const db2 = createDatabase();
db2.importSLIM(slim);
// Export single collection
const usersSlim = users.toSLIM();
const usersJson = users.toJSON();Collection Options
const users = db.collection('users', {
// Add createdAt/updatedAt timestamps
timestamps: true,
// Custom validation
validator: (doc) => {
if (!doc.email) return 'Email required';
return true;
},
// Auto-create indexes
indexes: [
{ fields: ['email'], unique: true },
{ fields: ['createdAt'] }
]
});API Reference
Database
createDatabase(options?: DatabaseOptions): SlimDB
interface DatabaseOptions {
dataDir?: string | null; // Directory for persistence
autoSaveInterval?: number; // Auto-save interval in ms
}
// Methods
db.collection(name, options?) // Get/create collection
db.listCollections() // List collection names
db.dropCollection(name) // Drop a collection
db.beginTransaction() // Start transaction
db.save() // Save to disk
db.stats() // Get statistics
db.exportSLIM() // Export as SLIM
db.importSLIM(slim) // Import from SLIMCollection
// CRUD
collection.insert(doc)
collection.insertMany(docs)
collection.find(filter?, options?)
collection.findOne(filter?)
collection.findById(id)
collection.updateOne(filter, update)
collection.updateMany(filter, update)
collection.updateById(id, update)
collection.replaceOne(filter, doc)
collection.deleteOne(filter)
collection.deleteMany(filter)
collection.deleteById(id)
// Utilities
collection.count(filter?)
collection.exists(filter)
collection.distinct(field, filter?)
// Indexes
collection.createIndex(spec)
collection.dropIndex(name)
collection.getIndexes()
// Export
collection.toSLIM()
collection.toJSON()
collection.stats()Test Coverage
- 103 tests passing
- Full coverage of CRUD, queries, updates, indexes, transactions
Requirements
- Node.js >= 18.0.0
- slim-protocol-core >= 0.1.0
Related Packages
- slim-protocol-core - Core SLIM serialization
License
MIT
