Database Adapters

Connect genaql to any supported database with the appropriate adapter.

PostgreSQL

postgres.ts
import { createClient } from 'genaql';
import { Pool } from 'pg';

const pool = new Pool({
  host: 'localhost',
  port: 5432,
  database: 'myapp',
  user: 'postgres',
  password: 'secret',
  // Or use connection string
  // connectionString: process.env.DATABASE_URL
});

const db = createClient({
  dialect: 'postgres',
  pool,
  // Optional: log all queries
  logging: process.env.NODE_ENV === 'development'
});

// Test connection
await db.raw('SELECT NOW()');

MySQL

mysql.ts
import { createClient } from 'genaql';
import mysql from 'mysql2/promise';

const pool = mysql.createPool({
  host: 'localhost',
  port: 3306,
  database: 'myapp',
  user: 'root',
  password: 'secret',
  waitForConnections: true,
  connectionLimit: 10
});

const db = createClient({
  dialect: 'mysql',
  pool
});

SQLite

sqlite.ts
import { createClient } from 'genaql';
import Database from 'better-sqlite3';

// File-based database
const db = createClient({
  dialect: 'sqlite',
  database: './data/app.db'
});

// In-memory database (great for testing)
const testDb = createClient({
  dialect: 'sqlite',
  database: ':memory:'
});

// With better-sqlite3 instance
const sqlite = new Database('./data/app.db');
const db = createClient({
  dialect: 'sqlite',
  connection: sqlite
});

Connection Options

options.ts
const db = createClient({
  // Required
  dialect: 'postgres' | 'mysql' | 'sqlite',

  // Database connection (one of these)
  pool: Pool,              // pg or mysql2 pool
  connection: Connection,  // Single connection
  database: string,        // SQLite file path

  // Optional
  schema: Schema,          // For type safety
  logging: boolean | ((sql: string) => void),
  validate: boolean,       // Runtime validation

  // Pool settings (PostgreSQL/MySQL)
  poolConfig: {
    min: 2,
    max: 10,
    idleTimeoutMs: 30000
  }
});

Custom Adapters

custom-adapter.ts
import { createAdapter, Adapter } from 'genaql';

const customAdapter: Adapter = {
  dialect: 'custom',

  async query(sql: string, params: unknown[]) {
    // Execute query and return rows
    return rows;
  },

  async execute(sql: string, params: unknown[]) {
    // Execute statement (INSERT/UPDATE/DELETE)
    return { rowCount, lastInsertId };
  },

  escape(value: unknown): string {
    // Escape value for safe SQL interpolation
    return escaped;
  },

  placeholder(index: number): string {
    // Return placeholder syntax ($1, ?, etc.)
    return `$${index + 1}`;
  }
};

const db = createClient({
  dialect: 'custom',
  adapter: customAdapter
});

Best Practice

Always use connection pooling in production. Create the pool once at startup and reuse it for all queries. Don't create new connections per request.