npm package: @omodaka/pinatinodb-adapter-neon
Description: Neon/PostgreSQL adapter for PinatinoDB - serverless Postgres with IPFS sync
Author: Branislav Đalić
Latest version: 0.1.0

# @pinatinodb/neon-adapter

Automatically sync your Neon/PostgreSQL data to IPFS - perfect for **serverless** and **edge functions**.

## 🚀 Why Neon + PinatinoDB?

- ✅ **Serverless-First** - Built for Vercel, Netlify, Cloudflare Workers
- ✅ **Edge-Compatible** - Runs in edge runtimes (no Node.js required)
- ✅ **Zero Cold Starts** - Neon's instant connections + IPFS backup
- ✅ **Automatic Sync** - SQL queries auto-sync to IPFS
- ✅ **Type-Safe** - Full TypeScript support
- ✅ **Cost-Effective** - Pay only for what you use

## 📦 Installation

```bash
pnpm add @pinatinodb/neon-adapter @pinatinodb/core @neondatabase/serverless
```

## 🎯 Quick Start

```typescript
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

// 1. Initialize PinatinoDB
const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});
await pinatino.initialize();

// 2. Wrap Neon SQL with PinatinoDB
const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  strategy: 'write-through',
  logging: true
});

// 3. Use SQL normally - auto-syncs to IPFS!
const users = await sql`
  INSERT INTO users (name, email)
  VALUES ('Alice', 'alice@example.com')
  RETURNING *
`;
// ✅ Now in both Postgres AND IPFS!
```

## 🔧 Configuration

### Basic Configuration

```typescript
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino, // PinatinoDB instance (required)
  strategy: 'write-through', // Sync strategy (optional)
  tables: ['users', 'posts'], // Only sync these (optional)
  excludeTables: ['sessions'], // Skip these (optional)
  logging: true, // Enable logging (optional)
  primaryKey: 'id', // Primary key field (default: 'id')
  onError: (error, operation, table) => {
    // Custom error handler (optional)
    console.error(`Error in ${table}.${operation}:`, error);
  }
});
```

### Selective Table Sync

```typescript
// Only sync important tables
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  tables: ['users', 'posts', 'products']
});

// Or exclude temporary tables
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  excludeTables: ['sessions', 'logs', 'cache']
});
```

## 🔄 Sync Strategies

### Write-Through (Default)

```typescript
{
  strategy: 'write-through';
}
```

- Writes to both Postgres and IPFS synchronously
- **Pros:** Guaranteed consistency
- **Cons:** Slower writes (~50ms IPFS overhead)
- **Use when:** Data integrity is critical

### Write-Behind

```typescript
{
  strategy: 'write-behind';
}
```

- Writes to Postgres immediately, queues IPFS async
- **Pros:** Fast writes, no user-facing latency
- **Cons:** Eventual consistency
- **Use when:** Performance is critical (recommended for production)

### None

```typescript
{
  strategy: 'none';
}
```

- No automatic sync
- **Use when:** You want manual control or testing

## 📝 Usage Examples

### Basic CRUD

```typescript
// INSERT - Automatically synced to IPFS
const result = await sql`
  INSERT INTO users (name, email, age)
  VALUES ('Bob', 'bob@example.com', 35)
  RETURNING *
`;

// SELECT - Query from Postgres
const users = await sql`
  SELECT * FROM users
  WHERE age >= 18
  ORDER BY created_at DESC
  LIMIT 10
`;

// UPDATE - Synced to IPFS
await sql`
  UPDATE users
  SET age = 36
  WHERE email = 'bob@example.com'
  RETURNING *
`;

// DELETE - Removed from IPFS
await sql`
  DELETE FROM users
  WHERE id = ${userId}
`;
```

### Transactions

```typescript
import { neon, neonConfig } from '@neondatabase/serverless';

neonConfig.fetchConnectionCache = true;

const sql = withPinatino(neon(DATABASE_URL), { pinatino });

// Transactions work normally
await sql.transaction(async tx => {
  await tx`INSERT INTO users (name) VALUES ('Charlie')`;
  await tx`INSERT INTO posts (title, author_id) VALUES ('Hello', currval('users_id_seq'))`;
});
// Both inserts synced to IPFS after commit
```

### Batch Operations

```typescript
// Batch insert
const newUsers = [
  { name: 'Alice', email: 'alice@example.com' },
  { name: 'Bob', email: 'bob@example.com' },
  { name: 'Charlie', email: 'charlie@example.com' }
];

for (const user of newUsers) {
  await sql`INSERT INTO users ${sql(user)} RETURNING *`;
}
// All synced to IPFS
```

## 🌐 Serverless Examples

### Vercel Edge Function

```typescript
// app/api/users/route.ts
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

export const runtime = 'edge';

const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});
await pinatino.initialize();

const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  strategy: 'write-behind' // Fast for edge
});

export async function POST(request: Request) {
  const body = await request.json();

  const user = await sql`
    INSERT INTO users ${sql(body)}
    RETURNING *
  `;

  return Response.json(user);
}
```

### Cloudflare Workers

```typescript
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';

export default {
  async fetch(request: Request, env: Env) {
    const pinatino = new PinatinoDB({
      pinata: { apiKey: env.PINATA_JWT }
    });
    await pinatino.initialize();

    const sql = withPinatino(neon(env.DATABASE_URL), {
      pinatino,
      strategy: 'write-behind'
    });

    const users = await sql`SELECT * FROM users LIMIT 10`;
    return new Response(JSON.stringify(users), {
      headers: { 'Content-Type': 'application/json' }
    });
  }
};
```

### Next.js API Route

```typescript
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { neon } from '@neondatabase/serverless';
import { withPinatino } from '@pinatinodb/neon-adapter';
import { PinatinoDB } from '@pinatinodb/core';

const pinatino = new PinatinoDB({
  pinata: { apiKey: process.env.PINATA_JWT! }
});

const sql = withPinatino(neon(process.env.DATABASE_URL!), {
  pinatino,
  logging: process.env.NODE_ENV === 'development'
});

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method === 'POST') {
    const user = await sql`
      INSERT INTO users (name, email)
      VALUES (${req.body.name}, ${req.body.email})
      RETURNING *
    `;
    res.json(user[0]);
  } else {
    const users = await sql`SELECT * FROM users`;
    res.json(users);
  }
}
```

## 🎨 Advanced Patterns

### Hybrid Query (Postgres + IPFS)

```typescript
// Fast queries from Postgres
const recentUsers = await sql`
  SELECT * FROM users
  ORDER BY created_at DESC
  LIMIT 10
`;

// Historical queries from IPFS
const userCollection = pinatino.getCollection('users');
const allIPFSUsers = await userCollection.findAll();
console.log(`Total users in IPFS: ${allIPFSUsers.length}`);
```

### Environment-Based Sync

```typescript
const isDev = process.env.NODE_ENV === 'development';

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  strategy: isDev ? 'none' : 'write-behind',
  logging: isDev
});
```

### Custom Error Handling

```typescript
import * as Sentry from '@sentry/node';

const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  onError: (error, operation, table) => {
    Sentry.captureException(error, {
      tags: { table, operation, adapter: 'neon' }
    });
  }
});
```

## 📊 Performance

### Neon vs Traditional Postgres

| Feature         | Traditional Postgres | Neon              |
| --------------- | -------------------- | ----------------- |
| **Cold Start**  | ~1-5s                | ~0ms (instant)    |
| **Scaling**     | Manual               | Automatic         |
| **Edge Deploy** | ❌                   | ✅                |
| **Cost**        | Fixed                | Pay-per-use       |
| **IPFS Sync**   | ✅ (with adapter)    | ✅ (with adapter) |
| **Serverless**  | Limited              | ✅ Optimized      |

### Query Performance

| Operation  | Neon  | + IPFS (write-through) | + IPFS (write-behind) |
| ---------- | ----- | ---------------------- | --------------------- |
| **SELECT** | ~5ms  | ~5ms (no sync)         | ~5ms (no sync)        |
| **INSERT** | ~10ms | ~60ms                  | ~10ms                 |
| **UPDATE** | ~10ms | ~60ms                  | ~10ms                 |
| **DELETE** | ~5ms  | ~5ms                   | ~5ms                  |

**Recommendation:** Use `write-behind` for production (10ms latency instead of 60ms)

## 🔍 Querying

### From Postgres (Fast)

```typescript
// Indexed, fast queries
const users = await sql`
  SELECT * FROM users
  WHERE email = ${email}
  LIMIT 1
`;
```

### From IPFS (Decentralized)

```typescript
// Permanent, decentralized storage
const userCollection = pinatino.getCollection('users');
const ipfsUser = await userCollection.findById(userId);
console.log(`User CID: ${ipfsUser._cid}`);
```

### Hybrid Fallback

```typescript
async function getUser(id: string) {
  try {
    // Try Postgres first (fast)
    const result = await sql`SELECT * FROM users WHERE id = ${id}`;
    return result[0];
  } catch (error) {
    // Fallback to IPFS
    const collection = pinatino.getCollection('users');
    return await collection.findById(id);
  }
}
```

## 🎯 Best Practices

### 1. Use Write-Behind in Production

```typescript
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  strategy: 'write-behind' // Fast, async sync
});
```

### 2. Selective Sync

```typescript
// Only sync permanent data
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  tables: ['users', 'posts', 'products'],
  excludeTables: ['sessions', 'logs', 'cache']
});
```

### 3. Enable Connection Pooling

```typescript
import { neonConfig } from '@neondatabase/serverless';

neonConfig.fetchConnectionCache = true;
```

### 4. Handle Errors Gracefully

```typescript
const sql = withPinatino(neon(DATABASE_URL), {
  pinatino,
  onError: error => {
    // Postgres operation succeeds even if IPFS fails
    console.error('IPFS sync failed:', error);
  }
});
```

## 🚨 Limitations

1. **DELETE Operations**: Cannot automatically sync deletes (need to query before delete)
2. **Complex Queries**: Only basic INSERT/UPDATE/DELETE are auto-synced
3. **Bulk Operations**: Large batch operations may be slow with write-through

## 🧪 Testing

```typescript
// Disable IPFS sync in tests
const sql = withPinatino(neon(TEST_DATABASE_URL), {
  pinatino,
  strategy: 'none'
});
```

## 📚 More Examples

Check out the [complete working example](../../../examples/with-neon/) for serverless patterns.

## 🤝 Contributing

Found a bug? [Open an issue](https://github.com/Omodaka9375/pinatinodb/issues)!

## 📄 License

MIT

---

**Made with ❤️ for serverless developers who want Web3 without complexity**