Storage Adapters
jcell uses a pluggable adapter pattern — the same API works across different storage backends.
import { createDB } from '@sajjadbzn/jcell'
// Pick your adapter:
const db = createDB({ adapter: memoryAdapter() })
// or fileAdapter({ path: './data' })
// or sqliteAdapter({ path: './app.db' })
// or d1Adapter({ binding: env.DB })
Strategy Pattern
Adapters support two operational strategies:
- Cache — Loads all documents into memory, filters/sorts in JS. Used by file and memory adapters.
- Delegate — Delegates queries to the backend (SQL). Used by SQLite and D1 adapters for efficient SQL-level filtering.
File Adapter
Persists each collection as a JSON file on disk. Best for small to medium projects that need persistence without a database server.
import { fileAdapter } from '@sajjadbzn/jcell'
const db = createDB({
adapter: fileAdapter({ path: './data' })
})
Features
- Atomic writes — writes to a temp file, then renames over the target
- Crash recovery —
.bakbackup files if the main file gets corrupted - Write queue — serialized writes per collection (no race conditions)
- Delegate strategy — in-memory filtering for efficient queries
File Structure
./data/
users.json # Collection: users
posts.json # Collection: posts
users.json.bak # Auto-backup after write
posts.json.bak
Configuration
| Option | Default | Description |
|---|---|---|
path | './data' | Directory for collection JSON files |
Memory Adapter
Stores everything in a Map. Data is lost when the process exits.
import { memoryAdapter } from '@sajjadbzn/jcell'
const db = createDB({ adapter: memoryAdapter() })
Best Uses
- Unit tests — fast, isolated, no cleanup needed
- Serverless functions — data lives only for the request lifetime
- Prototyping — rapid iteration without file I/O
Configuration
No options needed.
SQLite Adapter
Uses better-sqlite3 to store data in a local SQLite database with full SQL query support.
npm install better-sqlite3
import { sqliteAdapter } from '@sajjadbzn/jcell'
const db = createDB({
adapter: sqliteAdapter({ path: './app.db' })
})
Features
- Real SQL DDL — schemas auto-generate CREATE TABLE statements
- Parameterized queries — safe from SQL injection
- Native indexes — real SQL-level indexes
- WAL mode — better concurrent read performance
- Foreign key enforcement — for reference fields
- Transactions — atomic multi-operation transactions
Configuration
| Option | Default | Description |
|---|---|---|
path | './data.db' | Path to the SQLite database file |
tablePrefix | '' | Optional table name prefix (e.g. "jcell_") |
D1 Adapter
Connects to Cloudflare D1, Cloudflare's serverless SQLite database available in Workers.
import { d1Adapter } from '@sajjadbzn/jcell/d1'
// In your Worker:
export default {
async fetch(request, env) {
const db = createDB({
adapter: d1Adapter({ binding: env.DB })
})
// ...
}
}
Features
- SQL DDL — auto-creates tables from schemas
- Parameterized queries — uses D1's bound parameters
- Batch operations — for efficient multi-document writes
- Transactions — via D1's batch API
- Indexes — real SQL indexes
Import Path
Import from @sajjadbzn/jcell/d1 — this subpath avoids Node.js APIs so it works in the Workers runtime.
Configuration
| Option | Default | Description |
|---|---|---|
binding | (required) | A Cloudflare D1 database binding |
tablePrefix | '' | Optional table name prefix |
Adapter Comparison
| Feature | File | Memory | SQLite | D1 |
|---|---|---|---|---|
| Persistence | ✅ Disk | ❌ Ephemeral | ✅ Disk | ✅ Cloud |
| Strategy | Cache/Delegate | Cache/Delegate | Delegate | Delegate |
| Transactions | ❌ | ❌ | ✅ | ✅ |
| Native Indexes | ❌ | ❌ | ✅ | ✅ |
| Aggregation | ✅ JS | ✅ JS | ✅ SQL | ✅ SQL |
| Runtime | Node/Bun | Any | Node/Bun | Workers |
| External Deps | None | None | better-sqlite3 | None |