README.md

<div align="center">
  <img src="https://raw.githubusercontent.com/TrustBound/dream/main/ricky_and_lucy.png" alt="Dream Logo" width="200">
  
  <a href="https://hexdocs.pm/dream_postgres">
    <img src="https://img.shields.io/badge/hex-docs-lightgreen.svg" alt="HexDocs">
  </a>
</div>

# dream_postgres

**PostgreSQL utilities for Gleam with type-safe query helpers.**

A standalone module providing clean interfaces for PostgreSQL operations using [Pog](https://hex.pm/packages/pog). Includes query result helpers and a builder pattern for connection management. Built with the same quality standards as [Dream](https://github.com/TrustBound/dream), but completely independent—use it in any Gleam project.

## Features

- ✅ Builder pattern for connection configuration
- ✅ Type-safe query result extraction
- ✅ Simplified error handling
- ✅ Connection pooling via Pog
- ✅ Zero dependencies on Dream or other frameworks

## Installation

```bash
gleam add dream_postgres
```

## Quick Start

### Connection Setup

```gleam
import dream_postgres/client as postgres
import gleam/erlang/process

let pool_name = process.new_name("db_pool")
let assert Ok(db) = postgres.new(pool_name)
  |> postgres.host("localhost")
  |> postgres.port(5432)
  |> postgres.database("myapp")
  |> postgres.user("postgres")
  |> postgres.password("secret")
  |> postgres.pool_size(15)
  |> postgres.connect()
```

### Or from URL

```gleam
import dream_postgres/client as postgres

let db = postgres.from_url("postgresql://user:pass@localhost:5432/myapp")
```

### Query Execution

Use with [Squirrel](https://hex.pm/packages/squirrel) or Pog directly:

```gleam
import dream_postgres/query
import user/sql  // Your Squirrel-generated queries

// Get first row
case sql.get_user(db, id) |> query.first_row() {
  Ok(user) -> decode_user(user)
  Error(query.NotFound) -> handle_not_found()
  Error(query.DatabaseError) -> handle_error()
}

// Get all rows
case sql.list_users(db) |> query.all_rows() {
  Ok(users) -> list.map(users, decode_user)
  Error(query.DatabaseError) -> handle_error()
}
```

## Usage

### Connection Builder Pattern

Configure your database connection step by step:

```gleam
import dream_postgres/client as postgres
import gleam/erlang/process

let pool_name = process.new_name("my_db_pool")
let config = postgres.new(pool_name)
  |> postgres.host("localhost")
  |> postgres.port(5432)
  |> postgres.database("myapp_prod")
  |> postgres.user("postgres")
  |> postgres.password("secret")
  |> postgres.pool_size(20)  // Max 20 connections

let assert Ok(db) = postgres.connect(config)
```

### Query Result Helpers

The `query` module provides simple helpers for extracting data from Pog results:

```gleam
import dream_postgres/query

// First row (for "get by ID" queries)
case sql.get_user(db, id) |> query.first_row() {
  Ok(row) -> {
    // Decode row to your type
    decode_user(row)
  }
  Error(query.NotFound) -> {
    // Query succeeded but no rows returned
    Error("User not found")
  }
  Error(query.DatabaseError) -> {
    // Query failed (connection error, SQL error, etc.)
    Error("Database error")
  }
}

// All rows (for "list" queries)
case sql.list_users(db) |> query.all_rows() {
  Ok(rows) -> {
    // Process all rows
    list.map(rows, decode_user)
  }
  Error(query.DatabaseError) -> {
    Error("Database error")
  }
}
```

### Error Handling

The `QueryError` type simplifies error handling:

```gleam
pub type QueryError {
  NotFound          // Query succeeded but no rows
  DatabaseError     // Query failed (connection, SQL, etc.)
}
```

This is much simpler than Pog's error types, making it easier to handle common cases.

## API Reference

### Client Configuration

- `postgres.new(pool_name)` - Create new config
- `postgres.host(config, host)` - Set database host
- `postgres.port(config, port)` - Set database port
- `postgres.database(config, name)` - Set database name
- `postgres.user(config, user)` - Set database user
- `postgres.password(config, password)` - Set database password
- `postgres.pool_size(config, size)` - Set connection pool size
- `postgres.connect(config)` - Start connection pool
- `postgres.from_url(url)` - Connect from PostgreSQL URL

### Query Helpers

- `query.first_row(result)` - Extract first row or `NotFound`
- `query.all_rows(result)` - Extract all rows (empty list if none)

## Design Principles

This module follows the same quality standards as [Dream](https://github.com/TrustBound/dream):

- **No nested cases** - Clear, flat control flow
- **No anonymous functions** - Named functions for clarity
- **Builder pattern** - Consistent, composable APIs
- **Type safety** - `Result` types force error handling
- **Quality testing** - Comprehensive test coverage

## About Dream

This module was originally built for the [Dream](https://github.com/TrustBound/dream) web toolkit, but it's completely standalone and can be used in any Gleam project. It follows Dream's design principles and will be maintained as part of the Dream ecosystem.

## License

MIT License - see LICENSE file for details.