# quickv

A fast, SQLite-backed key-value cache for Bun. No Redis required.

## Features

- **Zero dependencies** - Uses Bun's built-in SQLite
- **Persistent storage** - Data survives restarts
- **TTL support** - Automatic expiration with lazy + periodic cleanup
- **Atomic operations** - `incr`/`decr` are transaction-safe
- **Batch operations** - `mget`/`mset`/`mdel` for bulk operations
- **Type-safe** - Full TypeScript support

## Installation

```bash
bun add quickv
```

## Quick Start

```typescript
import { Cache } from "quickv";

const cache = new Cache();

// Basic operations
cache.set("user:1", { name: "Alice", email: "alice@example.com" });
const user = cache.get<User>("user:1");

// With TTL (in seconds)
cache.set("session:abc", sessionData, 3600); // 1 hour
```

## API Reference

### Constructor

```typescript
const cache = new Cache({
  path: "./cache.db", // Default: ":memory:" (in-memory)
  cleanupInterval: 60_000, // Default: 60000ms (1 min). Set to 0 to disable.
});
```

### Basic Operations

| Method                  | Description                                                   |
| ----------------------- | ------------------------------------------------------------- |
| `set(key, value, ttl?)` | Store a value with optional TTL in seconds                    |
| `get<T>(key)`           | Retrieve a value. Returns `undefined` if not found or expired |
| `del(key)`              | Delete a key                                                  |
| `has(key)`              | Check if a key exists and is not expired                      |

### TTL Management

| Method             | Description                                                                           |
| ------------------ | ------------------------------------------------------------------------------------- |
| `ttl(key)`         | Get remaining TTL in seconds. Returns `undefined` if missing, `null` if no expiry     |
| `expire(key, ttl)` | Set/update expiry. Pass `null` to remove expiry. Returns `false` if key doesn't exist |

### Counters

```typescript
cache.incr("views"); // 1
cache.incr("views"); // 2
cache.incr("views", 5); // 7
cache.decr("views"); // 6
```

Both preserve existing TTL on the key.

### Batch Operations

```typescript
// Set multiple values
cache.mset({ a: 1, b: 2, c: 3 }, ttl?);
cache.mset(new Map([["a", 1], ["b", 2]]));
cache.mset([["a", 1], ["b", 2]]);

// Get multiple values
const values = cache.mget<number>(["a", "b", "c"]); // Map<string, number>

// Delete multiple keys
cache.mdel(["a", "b"]);
```

### Utility Methods

| Method           | Description                                            |
| ---------------- | ------------------------------------------------------ |
| `keys(pattern?)` | List keys. Supports `*` and `?` wildcards              |
| `size()`         | Count of non-expired entries                           |
| `clear()`        | Delete all entries                                     |
| `cleanup()`      | Manually remove expired entries. Returns count removed |
| `close()`        | Close database and stop cleanup timer                  |

### Pattern Matching

```typescript
cache.set("user:1", "alice");
cache.set("user:2", "bob");
cache.set("post:1", "hello");

cache.keys("user:*"); // ["user:1", "user:2"]
cache.keys("*:1"); // ["user:1", "post:1"]
```

## Persistence

```typescript
// In-memory (default) - fastest, lost on restart
const cache = new Cache();

// File-based - persists across restarts
const cache = new Cache({ path: "./cache.db" });
```

SQLite WAL mode is enabled automatically for better concurrent performance.

## Performance

Benchmarked on Apple M4 Pro:

```
~600,000 writes/sec
~1,650,000 reads/sec
```

## When to Use

**Use quickv when:**

- Single Bun instance
- Need persistent caching without external dependencies
- Want Redis-like API with zero setup

**Use Redis when:**

- Multiple instances need shared cache
- Need pub/sub or streams
- Distributed systems

## License

MIT
