npm package: @matteuccimarco/slim-redis
Description: Redis client with automatic SLIM compression for JSON values - reduce memory usage by 40-50%
Author: Marco Matteuccci
Latest version: 0.1.0

# @matteuccimarco/slim-redis

[![npm version](https://img.shields.io/npm/v/@matteuccimarco/slim-redis.svg)](https://www.npmjs.com/package/@matteuccimarco/slim-redis)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

**Redis client with automatic SLIM compression for JSON values.**

Reduce your Redis memory usage by **40-50%** without changing your code. SlimRedis is a drop-in wrapper for [ioredis](https://github.com/redis/ioredis) that automatically encodes JSON values using the [SLIM protocol](https://github.com/matteuccimarco/slim-protocol-core).

## Why SlimRedis?

| Problem | Solution |
|---------|----------|
| Redis stores JSON as strings (inefficient) | SLIM compresses structured data by 40-50% |
| High Redis Cloud/memory costs | Same data, less storage |
| Large payloads = high latency | Smaller values = faster network transfer |
| Learning new APIs is tedious | Same ioredis API with `Json` suffix |

## Quick Start

```bash
npm install @matteuccimarco/slim-redis ioredis
```

```typescript
import { createSlimRedis } from '@matteuccimarco/slim-redis';

const redis = createSlimRedis('redis://localhost:6379');

// Store JSON with automatic SLIM compression
await redis.setJson('user:123', {
  name: 'Alice',
  preferences: { theme: 'dark', notifications: true },
  roles: ['admin', 'user']
});

// Retrieve with automatic decoding
const user = await redis.getJson('user:123');
// => { name: 'Alice', preferences: { theme: 'dark', notifications: true }, roles: ['admin', 'user'] }

// Check your savings
console.log(redis.getStats().savingsPercent); // "~42%"
```

## Features

- **40-50% compression** on typical JSON data
- **Zero config** - just add `Json` suffix to your methods
- **Full ioredis compatibility** - access underlying client anytime
- **Automatic fallback** - reads legacy JSON data seamlessly
- **Built-in statistics** - track compression ratios in real-time
- **TypeScript first** - full type safety

## API Reference

### String Commands

```typescript
// Set with optional TTL
await redis.setJson('key', { data: 'value' });
await redis.setJson('key', { data: 'value' }, 3600); // expires in 1 hour
await redis.setexJson('key', 3600, { data: 'value' }); // same as above

// Get
const value = await redis.getJson<MyType>('key');

// Batch operations
await redis.msetJson({
  'user:1': { name: 'Alice' },
  'user:2': { name: 'Bob' },
});
const users = await redis.mgetJson<User>(['user:1', 'user:2']);
```

### Hash Commands

```typescript
// Set hash fields
await redis.hsetJson('user:123', 'profile', { name: 'Alice' });
await redis.hmsetJson('user:123', {
  profile: { name: 'Alice' },
  settings: { theme: 'dark' },
});

// Get hash fields
const profile = await redis.hgetJson('user:123', 'profile');
const all = await redis.hgetallJson('user:123');
```

### List Commands

```typescript
// Push to lists
await redis.lpushJson('events', { type: 'click' }, { type: 'view' });
await redis.rpushJson('events', { type: 'submit' });

// Pop from lists
const first = await redis.lpopJson('events');
const last = await redis.rpopJson('events');

// Get range
const events = await redis.lrangeJson('events', 0, -1);
```

### Pub/Sub Commands

```typescript
// Publish SLIM-encoded messages
await redis.publishJson('channel', { event: 'update', data: {...} });

// Subscribe with automatic decoding
redis.subscribeJson('channel', (message, channel) => {
  console.log('Received:', message);
});
```

### Statistics

```typescript
const stats = redis.getStats();
// {
//   bytesBeforeEncoding: 10240,
//   bytesAfterEncoding: 6144,
//   operationCount: 100,
//   errors: 0,
//   compressionRatio: 0.6,
//   savingsPercent: "40.0%"
// }

redis.resetStats(); // Reset counters
```

### Underlying Client

```typescript
// Access ioredis client for non-JSON operations
await redis.client.incr('counter');
await redis.client.expire('key', 3600);
await redis.client.del('key');

// Connection management
await redis.quit();     // Graceful close
redis.disconnect();     // Force close
```

## Configuration

```typescript
import { SlimRedis } from '@matteuccimarco/slim-redis';

const redis = new SlimRedis('redis://localhost:6379', {
  // Add prefix to all keys (default: '')
  keyPrefix: 'myapp',

  // Track compression stats (default: true)
  trackStats: true,

  // Fallback to JSON.parse for legacy data (default: true)
  fallbackToJson: true,
});
```

## Compression Examples

| Data Type | JSON | SLIM | Savings |
|-----------|------|------|---------|
| User session | 500B | 300B | 40% |
| Product list (10 items) | 2KB | 1.1KB | 45% |
| Analytics event | 200B | 115B | 42% |
| Cache entry (complex) | 5KB | 2.8KB | 44% |

**Real-world impact:**
- 100K sessions × 200B saved = **~20MB** less RAM
- At $0.10/MB/month on Redis Cloud = **$2/month** saved per 100K sessions

## Use Cases

### Session Storage

```typescript
const sessions = new SlimRedis('redis://...', { keyPrefix: 'sess' });

await sessions.setexJson('abc123', 86400, {
  userId: 'user_001',
  role: 'admin',
  permissions: ['read', 'write', 'delete'],
  preferences: { theme: 'dark', lang: 'en' },
});
```

### Caching Layer

```typescript
async function getCached<T>(key: string, factory: () => Promise<T>): Promise<T> {
  const cached = await redis.getJson<T>(key);
  if (cached) return cached;

  const fresh = await factory();
  await redis.setexJson(key, 300, fresh);
  return fresh;
}

const user = await getCached('user:123', () => db.users.findById(123));
```

### Real-time Events

```typescript
// Publisher
await redis.publishJson('events', {
  type: 'order_placed',
  orderId: 'ord_123',
  timestamp: Date.now(),
});

// Subscriber
redis.subscribeJson('events', (event) => {
  if (event.type === 'order_placed') {
    processOrder(event.orderId);
  }
});
```

## Benchmarks

Run benchmarks locally:

```bash
npm run benchmark
```

Typical results (500 iterations, localhost Redis):

| Metric | JSON | SLIM | Difference |
|--------|------|------|------------|
| SET (small) | 45ms | 52ms | +15% |
| GET (small) | 38ms | 44ms | +16% |
| Storage | 156B | 89B | **-43%** |
| SET (large) | 120ms | 145ms | +21% |
| GET (large) | 95ms | 118ms | +24% |
| Storage | 8.2KB | 4.5KB | **-45%** |

**Trade-off:** ~15-25% CPU overhead for 40-45% memory savings.

## Compatibility

- **Node.js:** 18+
- **ioredis:** 5.x
- **Redis:** 5.x, 6.x, 7.x
- **Redis Cluster:** Supported
- **TypeScript:** 5.x

## How It Works

SlimRedis uses the [SLIM protocol](https://github.com/matteuccimarco/slim-protocol-core) to encode JSON:

```
JSON:  {"users":[{"id":1,"name":"Mario","active":true},{"id":2,"name":"Luigi","active":false}]}
SLIM:  {users:|2|id#,name$,active?|
       1,Mario,T
       2,Luigi,F}
```

Key optimizations:
- **Tabular format** for arrays of objects (keys declared once)
- **Type prefixes** (`#` number, `?` boolean) instead of syntax
- **Minimal delimiters** (no quotes on keys/simple strings)

## Related Projects

- [slim-protocol-core](https://github.com/matteuccimarco/slim-protocol-core) - Core SLIM encoder/decoder
- [slim-db](https://github.com/matteuccimarco/slim-db) - Embedded database with SLIM storage (coming soon)

## Contributing

Contributions are welcome! Please read our contributing guidelines and submit PRs.

```bash
git clone https://github.com/matteuccimarco/slim-redis
cd slim-redis
npm install
npm test
```

## License

MIT - see [LICENSE](LICENSE)

---

Built with SLIM by [Marco Matteuccci](https://github.com/matteuccimarco)