Pog

repository·main·Indexed 42 days ago

https://github.com/lpil/pog

A PostgreSQL database client for the Gleam programming language, built on top of the Erlang PGO library. It provides connection pooling, SQL query execution with row decoding, support for connection URIs, and configurable SSL modes including SslDisabled, SslUnverified, and SslVerified.

Tokens
2.3K
Snippets
7
Records
13
Agent score
4%

What's inside Pog

  1. Handle JSON data in Pog

    main

    Postgres json and jsonb types are treated as simple strings by Pog.

    • Reading JSON: Use decode.string to decode the column value into a string, then parse it with your preferred JSON library.
    • Writing JSON: Convert your JSON object to a string (e.g., using json.to_string) and pass it as a text parameter.
  2. How pog handles CA certificates

    main

    Instead of requiring you to manually load certificate files into your application code, pog automatically attempts to read the system's CA certificates from the Operating System using the Erlang function public_key:cacerts_get().

    To resolve SSL verification errors, you should add the required CA certificates to your OS's trusted certificate store rather than modifying your pog configuration.

  3. Configure query timeouts

    main

    Pog has a default query timeout of 5 seconds. You can manage timeouts in two ways:

    1. Global Timeout: Use pog.default_timeout on the Config to set a timeout for every query executed by that connection.
    2. Per-Query Timeout: Use pog.timeout on a specific query to override the default for that single execution.
  4. Configure and supervise a Pog connection pool

    main

    Pog uses connection pools that should be added to your OTP supervision tree. Pools are identified by a process.Name(pog.Message). You should create this name outside the supervision tree and pass it in.

    Use pog.default_config(pool_name) to start a configuration, then chain configuration functions like host, database, and pool_size. Use .supervised to turn the configuration into a supervision child.

    import gleam/otp/static_supervisor as supervisor
    import gleam/erlang/process
    import pog
    
    pub fn start_application_supervisor(pool_name: process.Name(pog.Message)) {
      let pool_child = 
        pog.default_config(pool_name)
        |> pog.host("localhost")
        |> pog.database("my_database")
        |> pog.pool_size(15)
        |> pog.supervised
    
      supervisor.new(supervisor.RestForOne)
      |> supervisor.add(pool_child)
      |> supervisor.start
    }
  5. Add custom CA certificates to Linux

    main

    On Linux systems, CA certificates are managed via the ca-certificates package. To add a custom certificate:

    1. Ensure the ca-certificates package is installed.
    2. Convert your certificate to .pem format if it isn't already.
    3. Place the certificate in /usr/local/share/ca-certificates/ with a .crt extension.
    4. Run the command update-ca-certificates to update the system chain.

    Note on PEM files: If your PEM file contains multiple certificates, you can either split them into individual .crt files or append them directly to the system bundle using: cat my-certificates.pem >> /etc/ssl/certs/ca-certificates.crt. However, using /usr/local/share/ca-certificates is preferred as manual appends may be overwritten by system updates.

    # Example for Linux
    # 1. Install package
    sudo apt install ca-certificates
    
    # 2. Add certificate
    sudo cp my-cert.pem /usr/local/share/ca-certificates/my-cert.crt
    
    # 3. Update chain
    sudo update-ca-certificates
  6. Configure Pog using a connection URI

    main

    Instead of setting host, port, and user manually, you can use a standard Postgres connection URI (e.g., postgresql://[username:password@][host:port][/dbname][?query]).

    Use pog.url_config(name, uri_string) to automatically generate a pog.Config from the URI.

    import envoy
    import gleam/erlang/process.{type Name}
    import pog
    
    pub fn read_connection_uri(name: Name(pog.Message)) -> Result(pog.Config, Nil) {
      use database_url <- result.try(envoy.get("DATABASE_URL"))
      pog.url_config(name, database_url)
    }
  7. Verify if SSL issues are caused by CA certificates

    main

    If you are experiencing connection errors, you can determine if they are caused by missing or untrusted CA (Certificate Authority) certificates by temporarily disabling SSL verification in pog.

    Set the ssl option to pog.SslUnverified. If the connection works with this setting, your issue is related to the CA certificate chain. If it still fails, the problem lies elsewhere (e.g., network, credentials, or database configuration).

    // Example of disabling SSL verification to debug
    const connection = await pog.connect({
      // ... other config
      ssl: pog.SslUnverified
    });
  8. Return rows as Maps instead of Tuples

    main
    By default, Pog returns query results as tuples. To receive results as Dict objects where keys correspond to column names, activate rows_as_map in your pog.Config.
  9. Execute SQL queries with Pog

    main

    To run queries, obtain a pog.Connection (typically via pog.named_connection using the pool name).

    Use the following pattern to execute a query:

    1. Define your SQL string with $n placeholders for parameters.
    2. Define a row_decoder using gleam/dynamic/decode to map database columns to Gleam types.
    3. Chain pog.query, pog.parameter, and pog.returning before calling pog.execute(db).
    import pog
    import gleam/dynamic/decode
    
    pub fn run(db: pog.Connection) {
      let sql_query = "
      select
        name, age, colour, friends
      from
        cats
      where
        id = $1"
    
      let row_decoder = {
        use name <- decode.field(0, decode.string)
        use age <- decode.field(1, decode.int)
        use colour <- decode.field(2, decode.string)
        use friends <- decode.field(3, decode.list(decode.string))
        decode.success(#(name, age, colour, friends))
      }
    
      let assert Ok(data) =
        pog.query(sql_query)
        |> pog.parameter(pog.int(1))
        |> pog.returning(row_decoder)
        |> pog.execute(db)
    
      // data contains the decoded results
    }
  10. Configure CA certificates in a Dockerfile (Alpine/Debian)

    main

    When building Docker images (especially those based on Alpine or minimal Debian), CA certificates are often missing. To ensure pog can connect to secured databases like AWS RDS, include these steps in your Dockerfile:

    1. Install ca-certificates and curl.
    2. Download the required CA bundle (e.g., from AWS).
    3. Append the bundle to the OS certificate store.

    Example for a Debian-based image:

    # Update your package manager.
    RUN apt update
    # Add the main CA certificates.
    RUN apt install -y ca-certificates inotify-tools curl
    # Get the latest CA certificates.
    RUN update-ca-certificates
    # Get the certificate form AWS.
    RUN mkdir -p /aws-certificates
    RUN curl -o /aws-certificates/rds.pem https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
    # Provide the CA certificate in the OS directly.
    RUN cat /aws-certificates/rds.pem >> /etc/ssl/certs/ca-certificates.crt