In-memory driver for ObjectQL - Fast MongoDB-like query engine powered by Mingo with DriverInterface v4.0 compliance
npm install @objectql/driver-memory> ✅ Production-Ready - A high-performance in-memory driver powered by Mingo for testing, development, and edge environments.
The Memory Driver is a production-ready implementation of the ObjectQL Driver interface that stores data in JavaScript Maps and uses Mingo (MongoDB query engine for in-memory objects) for query processing. It provides full MongoDB-like query support with high performance, making it ideal for scenarios where persistence is not required.
- ✅ MongoDB Query Engine - Powered by Mingo for MongoDB-compatible queries
- ✅ Full Query Support - Filters, sorting, pagination, field projection
- ✅ High Performance - No I/O overhead, all operations in-memory
- ✅ Bulk Operations - createMany, updateMany, deleteMany
- ✅ Thread-Safe - Safe for concurrent operations
- ✅ Strict Mode - Optional error throwing for missing records
- ✅ Initial Data - Pre-populate on initialization
- ✅ TypeScript - Full type safety and IntelliSense support
This driver is perfect for:
1. Unit Testing - No database setup required, instant cleanup
2. Development & Prototyping - Quick iteration without infrastructure
3. Edge Environments - Cloudflare Workers, Deno Deploy, Vercel Edge
4. Client-Side State - Browser-based applications
5. Temporary Caching - Short-lived data storage
6. CI/CD Pipelines - Fast tests without database dependencies
``bashUsing pnpm (recommended)
pnpm add @objectql/driver-memory
Or if you're using the ObjectQL monorepo:
`bash
pnpm add @objectql/driver-memory
`Basic Usage
`typescript
import { ObjectQL } from '@objectql/core';
import { MemoryDriver } from '@objectql/driver-memory';// Initialize the driver
const driver = new MemoryDriver();
// Create ObjectQL instance
const app = new ObjectQL({
datasources: { default: driver }
});
// Register your schema
app.registerObject({
name: 'users',
fields: {
name: { type: 'text', required: true },
email: { type: 'email', unique: true },
role: { type: 'select', options: ['admin', 'user'] }
}
});
await app.init();
// Use it!
const ctx = app.createContext({ isSystem: true });
const repo = ctx.object('users');
// Create
const user = await repo.create({
name: 'Alice',
email: 'alice@example.com',
role: 'admin'
});
// Find
const users = await repo.find({
filters: [['role', '=', 'user']]
});
// Update
await repo.update(user.id, { email: 'alice.new@example.com' });
// Delete
await repo.delete(user.id);
`Browser Usage
The Memory Driver works seamlessly in web browsers! Perfect for prototyping, client-side apps, and offline experiences.
$3
`html
ObjectQL in Browser
ObjectQL Browser Demo
`$3
See the examples in the repository for interactive demonstrations.
- 🎨 Beautiful UI with live CRUD operations
- 🖥️ Browser console debugging
- 📊 Real-time statistics
- ✨ Sample data generation
$3
- ✅ Chrome/Edge 90+
- ✅ Firefox 88+
- ✅ Safari 14+
- ✅ All modern browsers with ES6+ support
$3
| Feature | Browser | Node.js |
|---------|---------|---------|
| Performance | ⚡ Fast | ⚡ Fast |
| Persistence | ❌ Lost on refresh | ❌ Lost on process exit |
| Use Case | Prototyping, Client state | Testing, Dev, Edge |
| Data Limit | RAM (GB) | RAM (GB) |
For persistent browser storage, use the LocalStorage Driver.
Configuration Options
$3
`typescript
const driver = new MemoryDriver();
`$3
`typescript
const driver = new MemoryDriver({
initialData: {
users: [
{ id: '1', name: 'Alice', email: 'alice@example.com' },
{ id: '2', name: 'Bob', email: 'bob@example.com' }
],
posts: [
{ id: '1', title: 'Hello World', author_id: '1' }
]
}
});
`$3
`typescript
const driver = new MemoryDriver({
strictMode: true // Throws errors for missing records
});// This will throw an error instead of returning null
await driver.update('users', 'non-existent-id', { name: 'Test' });
// ObjectQLError: Record with id 'non-existent-id' not found in 'users'
`API Reference
$3
All methods implement the standard Driver interface from
@objectql/types:####
find(objectName, query, options)Find multiple records with optional filtering, sorting, and pagination.
`typescript
const users = await driver.find('users', {
filters: [
['role', '=', 'admin'],
'or',
['age', '>', 30]
],
sort: [['name', 'asc']],
skip: 0,
limit: 10,
fields: ['name', 'email']
});
`####
findOne(objectName, id, query, options)Find a single record by ID or query.
`typescript
// By ID
const user = await driver.findOne('users', 'user-123');// By query
const admin = await driver.findOne('users', null, {
filters: [['role', '=', 'admin']]
});
`####
create(objectName, data, options)Create a new record.
`typescript
const user = await driver.create('users', {
name: 'Alice',
email: 'alice@example.com'
});
// Returns: { id: 'users-1234567890-1', name: 'Alice', ... }
`####
update(objectName, id, data, options)Update an existing record.
`typescript
const updated = await driver.update('users', 'user-123', {
email: 'alice.new@example.com'
});
`####
delete(objectName, id, options)Delete a record.
`typescript
const deleted = await driver.delete('users', 'user-123');
// Returns: true if deleted, false if not found
`####
count(objectName, filters, options)Count records matching filters.
`typescript
const adminCount = await driver.count('users', [
['role', '=', 'admin']
]);
`$3
####
createMany(objectName, data, options)Create multiple records at once.
`typescript
const users = await driver.createMany('users', [
{ name: 'Alice' },
{ name: 'Bob' },
{ name: 'Charlie' }
]);
`####
updateMany(objectName, filters, data, options)Update all records matching filters.
`typescript
const result = await driver.updateMany(
'users',
[['role', '=', 'user']],
{ status: 'active' }
);
// Returns: { modifiedCount: 5 }
`####
deleteMany(objectName, filters, options)Delete all records matching filters.
`typescript
const result = await driver.deleteMany('users', [
['status', '=', 'inactive']
]);
// Returns: { deletedCount: 3 }
`$3
####
distinct(objectName, field, filters, options)Get unique values for a field.
`typescript
const roles = await driver.distinct('users', 'role');
// Returns: ['admin', 'user', 'moderator']
`$3
####
clear()Remove all data from the store.
`typescript
await driver.clear();
`####
getSize()Get the total number of records in the store.
`typescript
const size = driver.getSize();
// Returns: 42
`####
disconnect()Gracefully disconnect (no-op for memory driver).
`typescript
await driver.disconnect();
`Supported Query Operators
The Memory Driver supports all standard ObjectQL query operators:
$3
-
=, == - Equals
- !=, <> - Not equals
- > - Greater than
- >= - Greater than or equal
- < - Less than
- <= - Less than or equal$3
-
in - Value in array
- nin, not in - Value not in array$3
-
contains, like - Contains substring (case-insensitive)
- startswith, starts_with - Starts with string
- endswith, ends_with - Ends with string$3
-
between - Value between two values (inclusive)$3
-
and - Logical AND (default)
- or - Logical ORQuery Examples
$3
`typescript
const admins = await driver.find('users', {
filters: [['role', '=', 'admin']]
});
`$3
`typescript
const activeAdmins = await driver.find('users', {
filters: [
['role', '=', 'admin'],
'and',
['status', '=', 'active']
]
});
`$3
`typescript
const results = await driver.find('users', {
filters: [
['role', '=', 'admin'],
'or',
['permissions', 'contains', 'manage_users']
]
});
`$3
`typescript
const middleAged = await driver.find('users', {
filters: [['age', 'between', [30, 50]]]
});
`$3
`typescript
const sorted = await driver.find('users', {
sort: [
['role', 'asc'],
['created_at', 'desc']
]
});
`$3
`typescript
// Get page 2 with 10 items per page
const page2 = await driver.find('users', {
skip: 10,
limit: 10,
sort: [['created_at', 'desc']]
});
`$3
`typescript
const names = await driver.find('users', {
fields: ['id', 'name', 'email']
});
// Returns only id, name, and email fields
`Testing with Memory Driver
The Memory Driver is ideal for unit tests:
`typescript
import { MemoryDriver } from '@objectql/driver-memory';describe('User Service', () => {
let driver: MemoryDriver;
beforeEach(() => {
driver = new MemoryDriver({
initialData: {
users: [
{ id: '1', name: 'Test User', role: 'user' }
]
}
});
});
afterEach(async () => {
await driver.clear();
});
it('should find users by role', async () => {
const users = await driver.find('users', {
filters: [['role', '=', 'user']]
});
expect(users).toHaveLength(1);
});
});
`Performance Characteristics
- Create: O(1)
- Read by ID: O(1)
- Update: O(1)
- Delete: O(1)
- Find/Query: O(n) - Scans all records for the object type
- Count: O(n) - Scans all matching records
- Sort: O(n log n)
$3
1. Use specific filters - More filters reduce the result set faster
2. Limit results - Use
limit to avoid processing large result sets
3. Clear regularly - Call clear() to free memory in long-running processes
4. Consider size - Memory driver is best for < 10,000 records per object typeComparison with Other Drivers
| Feature | Memory | SQL | MongoDB | Redis |
|---------|--------|-----|---------|-------|
| Setup Required | ❌ None | ✅ Database | ✅ Database | ✅ Redis Server |
| Persistence | ❌ No | ✅ Yes | ✅ Yes | ✅ Yes |
| Performance | ⚡ Fastest | 🐢 Slower | 🏃 Fast | 🏃 Fast |
| Query Support | ✅ Full | ✅ Full | ✅ Full | ⚠️ Limited |
| Production Ready | ✅ Yes* | ✅ Yes | ✅ Yes | ⚠️ Example |
| Dependencies | 0 | 2-3 | 1 | 1 |
*For use cases where persistence is not required
Limitations
1. No Persistence - Data is lost when the process ends
2. Memory Bound - Limited by available RAM
3. Single Instance - No distribution or clustering
4. No Transactions - Operations are individual (though atomic)
5. Linear Scans - Queries scan all records (no indexes)
Migration Guide
$3
`typescript
// Before
import { RedisDriver } from '@objectql/driver-redis';
const driver = new RedisDriver({ url: 'redis://localhost:6379' });// After
import { MemoryDriver } from '@objectql/driver-memory';
const driver = new MemoryDriver();
`$3
`typescript
// Production
const driver = new SqlDriver({
client: 'pg',
connection: process.env.DATABASE_URL
});// Testing
const driver = new MemoryDriver({
initialData: {
users: [/ test data /],
posts: [/ test data /]
}
});
`Troubleshooting
$3
`typescript
// Problem: Too much data
const driver = new MemoryDriver();
// ... add millions of records// Solution: Clear periodically or use a persistent driver
await driver.clear();
`$3
`typescript
// Problem: Scanning large datasets
const results = await driver.find('users', {}); // Returns 100,000 records// Solution: Add filters and limits
const results = await driver.find('users', {
filters: [['status', '=', 'active']],
limit: 100
});
``- Driver Extensibility Guide
- Implementing Custom Drivers
- Driver Interface Reference
- ObjectQL Core Documentation
Found a bug or have a feature request? Please open an issue on GitHub.
MIT - Same as ObjectQL
See CHANGELOG.md for version history.