pg

A PostgreSQL client for Quarz, written in Quarz: it speaks the server's wire protocol (version 3) over Quarz's sockets, so a query suspends only the task that waits for it.

# Cog.toml of an application
[dependencies]
PG = { git = "https://github.com/quarz-lang/pg", tag = "v0.1.0" }

The API reference of the main branch is at https://pg.api.quarz.dev.

Work in progress. What exists:

conn = PG.connect("postgres://ann:secret@localhost/shop")
conn.query("SELECT id, name FROM users WHERE id = $1", [42]).each do |row|
  puts "#{row.int("id")} #{row.string("name")}"
end
conn.close

Errors: PG::Error is the root of every error the cog raises. PG::ServerError is what the server reported (SQLSTATE code, detail, hint, position; a refused login included, 28P01 for a wrong password); PG::ConnectionError (with PG::AuthenticationError and PG::ProtocolError under it) means the connection failed or cannot be used any further; PG::TransactionError and PG::NullError are misuses.

PG::Pool.open("postgres://app@localhost/shop", size: 8) do |pool|
  Task.scope do |s|
    100.times { |i| s.spawn { pool.query("INSERT INTO hits VALUES ($1)", [i]) } }
  end
end
notes = Channel[PG::Notification].new(100)
Task.scope do |s|
  s.spawn do
    conn = PG.connect(url)
    begin
      conn.listen("jobs")
      loop do
        if (n = conn.wait_for_notify)
          notes.send(n)
        end
      end
    ensure
      conn.close
    end
  end
  s.spawn do
    while (n = notes.receive?)
      puts n.payload
    end
  end
end

Listen with listen, not exec("LISTEN ..."), which is not tracked. PG::Pool sends UNLISTEN * on a connection given back that listening?, and drops what it received: use a dedicated PG.connect for a listener.

Not yet: COPY, cancel requests, client certificates, channel binding.

Differences from libpq

For now, to be revisited:

Development

quarz test runs the tests, quarz test --doc the documentation's examples. The integration tests use PG::Testing: PG_TEST_URL when it is set; otherwise, where PostgreSQL's server programs are installed (/usr/lib/postgresql/*/bin), a throwaway cluster in a temporary directory (SCRAM-SHA-256, a random port on 127.0.0.1), removed afterwards; with neither, they are omitted. The TLS tests (test/tls_test.qz) always make clusters of their own, with the certificates of test/fixtures/tls/, and are omitted without initdb. Licensed under MIT No Attribution (LICENSE).

To develop another cog against a local checkout of pg, write Cog.local.toml beside that cog's Cog.toml (git should ignore it; quarz cog init lists it in .gitignore):

[patch]
PG = { path = "../quarz-pg" }

That cog's lock ignores the file: it keeps pg's git source.

Classes and modules