npm package: @johanlabs/rust-scriba
Description: Multi-tenant, high-performance asynchronous cache library for Node.js. Uses a persistent, sharded SQLite backend (WAL mode) with automatic checkpointing and per-key TTL support, offering a drop-in alternative to Redis for many caching scenarios.
Author: Johan Labs
Latest version: 0.5.7

# rust-scriba

**Rust Scriba** is a multi-tenant cache library written in Rust with Node.js bindings.  
It provides a persistent SQLite LRU cache with sharding, TTL support, automatic checkpoints, and easy integration to replace Redis in many scenarios.

---

## 🚀 Features

- **Multi-tenant cache** with sharding to reduce contention.
- **Persistent SQLite** backend (WAL mode) with automatic checkpointing.
- Supports **TTL** per key.
- **Asynchronous** operations for high performance.
- Drop-in cache replacement for Node.js.
- Benchmark included to compare with Redis.

---

## 🔧 Installation

```bash
npm install @johanlabs/rust-scriba
````

> Requires **Node.js 20+** and Rust (`cargo`) to build the native module.

---

## 🏁 Initialization

Before using the cache, initialize the system:

```js
const { initCacheSystem, scribaPath } = require("@johanlabs/rust-scriba");

// Set the base path for tenant databases
scribaPath(".scriba");

// Initialize the cache (automatic checkpointing)
initCacheSystem();
```

---

## 📦 Using the Database Class

You can use the `Database` class to manage tenants and execute queries with caching.

```js
const { Database } = require("@johanlabs/rust-scriba");

const db = new Database("tenant1", { ttl: 10000, path: ".scriba" });

(async () => {
    // Run a SELECT and return one row
    const row = await db.get("SELECT * FROM my_table WHERE id=1");
    console.log(row);

    // Run a SELECT and return all rows
    const rows = await db.all("SELECT * FROM my_table");
    console.log(rows);

    // Run an INSERT/UPDATE/DELETE
    const result = await db.run("INSERT INTO my_table (name) VALUES ('Alice')");
    console.log(result);
})();
```

### 📄 Methods

* `db.prepare(sql)` → returns a `Statement`.
* `db.get(sql)` → returns a JSON object with one row.
* `db.all(sql)` → returns an array of JSON rows.
* `db.run(sql)` → executes changes (INSERT, UPDATE, DELETE).
* `db.close()` → closes the tenant (optional, currently empty).

---

## ⚡ Direct Cache Usage

You can also interact with the cache directly:

```js
const { query } = require("@johanlabs/rust-scriba");

// Direct GET/SET
await query("tenant1", "SELECT * FROM my_table", 5000);
```

* `query(tenant, sql, ttl_ms?)` → returns a `Promise<string>` containing JSON result.

---

## 📊 Benchmark

A benchmark is included to compare RustCache against Redis:

```js
const { runBenchmark } = require("@johanlabs/rust-scriba");

(async () => {
    const results = await runBenchmark();
    console.log(JSON.stringify(results, null, 2));
})();
```

The benchmark measures:

* `get` and `set` latency.
* Concurrent operations.
* Latency percentiles (`p50`, `p95`, `p99`).
* Mixed `get`/`set` operations.
* Large value handling (100 KB payloads).

---

## 🛠 Configuration

Global configurations are defined in Rust, but you can adjust constants internally:

* `tenant_cache_limit`: max items per tenant.
* `global_cache_limit`: global cache limit.
* `shard_count`: number of shards per tenant.
* `default_ttl_secs`: default TTL.
* `checkpoint_interval_secs`: interval for automatic checkpoints.
* `checkpoint_retry_attempts` & `checkpoint_retry_delay_ms`: retry settings for checkpointing.

---

## 💡 Notes

* Each tenant is identified by its `tenantId` (typically the DB path).
* TTL is optional and sets cache expiration.
* SQLite persistence ensures data survives restarts.
* Supports **asynchronous and concurrent operations** with high throughput.