new SencilloDB(config)- Database methods
- Transaction methods
- The instructions object
quickTxcreateResourceManager- Errors
- Events
Every field is optional.
| Option | Type | Default | Meaning |
|---|---|---|---|
file |
string | "./sencillo.json" |
Single file mode. Parent folders are created if needed. |
folder |
string | — | Folder mode: one file per collection, loaded on demand. |
sharding |
boolean | false |
Folder mode only: one file per index bucket. |
compression |
boolean | false |
gzip the persisted files. |
aof |
boolean | false |
Append writes to a log instead of rewriting the store. |
appendfsync |
"always" | "everysec" | "no" |
"everysec" |
How aggressively the log is flushed to disk. |
maxCacheSize |
number | 0 |
Collections/shards kept in memory. 0 means no limit. |
clone |
boolean | true |
Return deep copies instead of live references. |
lock |
boolean | { staleMs, timeoutMs, retryMs } |
false |
Advisory cross process lock file. |
loadHook |
() => Promise<string> |
— | Single file mode: load the store from somewhere else. |
saveHook |
(json: string) => Promise<void> |
— | Single file mode: save the store somewhere else. |
debug |
boolean | false |
Also print internal warnings to stderr. |
autoCompact |
false | { maxBytes?, maxEffects? } |
false |
Compact the AOF after either positive threshold. |
Rejected combinations throw a ValidationError: sharding without folder, file together with folder, and hooks together with folder.
Runs callback(tx) and commits when it returns. Resolves to the callback's return value. If the callback throws, every change is discarded and the error is re-thrown.
Folds the append only log back into the store and deletes the log. Also purges expired documents. Safe to call in any mode.
Writes anything still pending and drops the in-memory cache. The instance stays usable — the next transaction reloads from disk.
Loads every collection (and every shard) and resolves to a plain object copy of the whole store.
Replaces the store with data. With { merge: true }, existing collections are kept and merged rather than removed. The result is written straight through and the log is reset.
Writes export() to path. Gzipped when the path ends in .gz.
Runs any migration whose version has not been recorded yet, in ascending version order, each inside its own transaction. Applied versions are stored in the __migrations collection. Resolves to the list of versions applied by this call.
await db.migrate([
{
version: 1,
name: "seed",
up: async (tx) => {
await tx.create({ collection: "users", data: { name: "root" } });
},
},
{
version: 2,
name: "add-role",
up: async (tx) => {
await tx.updateMany({
collection: "users",
filter: {},
$set: { role: "member" },
});
},
},
]);A migration that throws is not recorded, so it runs again next time.
Returns a collection-scoped handle whose methods each open their own transaction. With new SencilloDB<AppSchema>(), collection names, input documents and returned documents are typed. The handle exposes create, createMany, update, updateMany, destroy, destroyMany, find, findMany, count, page, stream, ensureIndex and ensureTTL.
Returns live document totals, per-collection bucket/index counts, cache entries and AOF bytes.
Returns the selected query strategy (id, secondary-index, bucket, or collection-scan) and its estimated candidate count. It does not execute the query.
validate() checks IDs, totals, ID maps and secondary index entries. repair() transactionally rebuilds stats, ID maps and indexes, then returns a fresh integrity report. Back up damaged stores before repair; irrecoverably malformed documents and duplicate IDs require manual review.
SencilloDB extends EventEmitter; see Events.
All are asynchronous and take a single instructions object.
| Method | Returns | Notes |
|---|---|---|
tx.create |
the created document | Needs data. |
tx.createMany |
array of created documents | data must be an array. index may be a function. |
tx.update |
the updated document | Needs _id or filter, and data or an update operator. |
tx.updateMany |
array of updated documents | Applies the same patch to every match. |
tx.destroy |
the removed document | Needs _id or filter. |
tx.destroyMany |
array of removed documents | Removes every match. |
tx.find |
the first match or undefined |
|
tx.findMany |
array of matches | Honours sort, skip, limit, populate. |
tx.count |
number | Same matching rules as findMany. |
tx.dropCollection |
void |
Deletes the collection and its files. |
tx.dropIndex |
void |
Deletes one index bucket, its documents and (in sharded mode) its file. |
tx.rewriteCollection |
void |
Rebuilds the collection: renumbers ids, re-sorts, re-buckets. Secondary indexes and TTL rules are preserved. |
tx.ensureIndex |
void |
{ collection, field, unique? }. Builds the index over existing documents. |
tx.dropSecondaryIndex |
void |
{ collection, field }. |
tx.ensureTTL |
void |
{ collection, field, seconds }. |
// full replacement (fields not present are dropped)
await tx.update({
collection: "users",
_id: 1,
data: { name: "Alice", age: 31 },
});
// partial patch
await tx.update({ collection: "users", _id: 1, $set: { age: 31 } });
await tx.update({ collection: "users", _id: 1, $inc: { visits: 1 } });
await tx.update({ collection: "users", _id: 1, $unset: ["temporary"] });
// by filter, creating the document when nothing matches
await tx.update({
collection: "settings",
filter: { key: "theme" },
$set: { value: "dark" },
upsert: true,
});$set and $unset accept dot paths ("profile.theme"). Update operators are applied on top of data when both are given.
| Field | Used by | Meaning |
|---|---|---|
collection |
all | Collection name. Defaults to "default". |
index |
all | Index bucket. A string, a (document) => string function (create/createMany/update), or { current, new } to move a document. For reads it restricts the search to one bucket. |
data |
create, createMany, update | The document (or array of documents). |
_id |
update, destroy | Target document id. |
filter |
reads, update, destroy, *Many | Query object — see Querying. |
callback |
reads | (document) => boolean, combined with filter via AND. |
sort |
findMany, rewriteCollection | Array.sort comparator. Defaults to ascending _id. |
limit / skip / cursor |
findMany | Offset or ascending _id cursor pagination. Values must be non-negative integers. |
populate |
find, findMany | [{ field, collection, targetField? }]. targetField defaults to _id. |
$set / $inc / $unset |
update, updateMany | Partial update operators. |
upsert |
update | Create the document when nothing matches. |
Unknown query operators, invalid regular expressions, unsafe prototype paths and invalid pagination values throw ValidationError.
type AppSchema = { users: { name: string; active: boolean } };
const db = new SencilloDB<AppSchema>({ file: "./app.json" });
const users = db.collection("users");
await users.create({ data: { name: "Alice", active: true } });
const first = await users.page({ limit: 50 });
const second = await users.page({ limit: 50, cursor: first.nextCursor });
for await (const user of users.stream({ limit: 100 })) {
console.log(user._id, user.name);
}page and stream use ascending _id order and reject a custom sort. Their limit is the page/batch size.
Documents must be JSON-compatible objects. Date values are normalized to ISO strings. Circular references, undefined, functions, symbols, bigint, NaN, infinities, arrays as top-level documents, and prototype-control keys are rejected instead of being silently altered by serialization.
Wraps a single operation in its own transaction:
import { quickTx } from "sencillodb";
const qtx = quickTx(db);
const user = await qtx("create", {
collection: "users",
data: { name: "Alice" },
});A schema-validating, hook-aware wrapper around one collection. See Schemas and Resource Managers.
const User = createResourceManager({
db,
collection: "users",
index: (user) => user.country,
schema: { name: String, age: { type: Number, required: false, default: 0 } },
hooks: {
beforeCreate: (data) => ({ ...data, createdAt: new Date().toISOString() }),
},
});
await User.create({ data: { name: "Alice" } });
await User.findMany({ filter: { age: { $gte: 18 } } });Returned object: schema, validate(document), errors(document), withDefaults(document), execute(operation, instructions) and shorthands create, createMany, update, updateMany, destroy, destroyMany, find, findMany, count.
All extend SencilloDBError, which extends Error.
| Error | Thrown when |
|---|---|
ValidationError |
Bad instructions, bad config, or a schema violation. |
CollectionNotFoundError |
The collection does not exist. |
IndexNotFoundError |
The index bucket does not exist. |
DocumentNotFoundError |
No document matched the _id or filter. |
UniqueConstraintError |
A write would duplicate a value on a unique index. |
CorruptDataError |
A store file exists but could not be read. |
LockError |
The advisory lock could not be acquired before the timeout. |
DatabaseNotLoadedError |
An operation was used outside a transaction before any load. |
db.on("create", ({ collection, index, _id, doc }) => {
/* … */
});| Event | Payload | Fires |
|---|---|---|
create, update, destroy |
{ collection, index, _id, doc } |
After the transaction commits |
dropCollection, dropIndex, rewriteCollection |
{ collection, index? } |
After commit |
ensureIndex, dropSecondaryIndex, ensureTTL |
{ collection } |
After commit |
expire |
{ collection, index, _id, doc } |
During compact() |
commit |
array of the events just emitted | After commit |
rollback |
{ error } |
After a failed transaction |
warning |
{ message, detail } |
On a recoverable problem, e.g. an unreadable log line |