← Docs

Ruby

One import, one connection. Microsecond reads from L1 cache.

Install

gem install goldlapel
# or in your Gemfile
gem "goldlapel"

# You also need a Postgres driver — pg is the most common:
gem "pg"

Gold Lapel is driver-agnostic — install whichever Postgres driver you prefer (pg is typical) and point it at gl.url.

Quick Start

Sync

require "goldlapel"
require "pg"

# Spawn the proxy in front of your upstream DB — returns a GoldLapel instance
gl = GoldLapel.start("postgresql://user:pass@localhost:5432/mydb", proxy_port: 7932)

# Use gl.url with any Postgres driver for raw SQL
conn = PG.connect(gl.url)
conn.exec_params("SELECT * FROM users WHERE id = $1", [42])

# Or use Gold Lapel's wrapper methods directly — no conn arg needed
hits = gl.search("articles", "body", "postgres tuning")
gl.doc_insert("events", type: "signup", user: "steve")

# Clean up (also runs automatically on process exit)
gl.stop

Repeated reads serve in microseconds from the built-in L1 cache.

Async

Use GoldLapel::Async inside an Async reactor from the async gem. Install separately — the async gem is not a hard dependency of goldlapel, so require "goldlapel/async" fails with a clear message if it isn't present.

require "goldlapel/async"
require "async"

Async do
  gl = GoldLapel::Async.start("postgresql://user:pass@localhost:5432/mydb")

  hits = gl.search("articles", "body", "postgres tuning")
  gl.doc_insert("events", type: "signup")

  gl.stop
end

v0.2.0 caveat: the async API shape is stable, but the underlying IO is still blocking under the hood. Native async-pg integration lands in v0.2.1.

Gold Lapel prints the proxy and dashboard URLs on startup to $stderr. Access the dashboard programmatically:

gl.dashboard_url  # "http://127.0.0.1:7933" (or nil if disabled / not running)

Banner goes to $stderr so it never pollutes $stdout-piped application output. Pass silent: true to GoldLapel.start to suppress it entirely — useful for daemons and structured-log pipelines that inspect both streams.

Transactional coordination

When you want wrapper methods to run inside your own transaction, pass your connection via gl.using(conn) do |gl| ... end (scoped) or the conn: keyword (per call):

require "pg"
gl = GoldLapel.start("postgresql://...")
conn = PG.connect(gl.url)

conn.exec("BEGIN")

# Scoped: every wrapper call in this block uses `conn`
gl.using(conn) do |gl|
  gl.doc_insert("events", type: "order.created")
  gl.incr("counters", "orders")
end

conn.exec("COMMIT")

# Or per-call
gl.doc_insert("events", { type: "x" }, conn: conn)

The block form is the idiomatic Ruby shape — every wrapper call inside the block binds to conn. For one-off overrides, pass conn: as the last keyword argument on any wrapper method.

API

gl = GoldLapel.start(upstream, proxy_port: nil, dashboard_port: nil, invalidation_port: nil, log_level: nil, mode: nil, license: nil, client: nil, config_file: nil, config: {}, extra_args: [], silent: false, mesh: false, mesh_tag: nil)

Factory that spawns the proxy and returns a GoldLapel instance. Eagerly opens the wrapper's internal pg connection so wrapper methods are fast from the first call.

  • upstream — your Postgres connection string (e.g. postgresql://user:pass@localhost:5432/mydb)
  • proxy_port: — proxy port (default: 7932)
  • dashboard_port: — dashboard port (default: proxy_port + 1; set to 0 to disable)
  • invalidation_port: — cache-invalidation port (default: proxy_port + 2)
  • log_level: — one of trace | debug | info | warn | error
  • mode: — operating mode (waiter, bellhop)
  • license: — path to the signed license file
  • client: — client identifier for telemetry tagging (defaults to "ruby")
  • config_file: — path to a TOML config file read by the Rust binary
  • config: — hash of structured tuning knobs (see GoldLapel.config_keys)
  • extra_args: — additional raw CLI flags (e.g. ["--threshold-impact", "5000"])
  • silent: — suppress the $stderr startup banner (default: false)
  • mesh: — opt into the mesh at startup (HQ enforces the license; denial is non-fatal)
  • mesh_tag: — optional mesh tag; instances sharing a tag cluster together

Promoted top-level kwargs are not valid keys inside config: — passing them there raises ArgumentError.

GoldLapel::Async.start(upstream, ...)

Async factory. Same signature as the sync factory but intended for use inside an Async reactor. Requires require "goldlapel/async" and the async gem.

gl.url

Proxy connection string — pass to any Postgres driver.

gl.dashboard_url

Dashboard URL (e.g. http://127.0.0.1:7933), or nil if not running or the dashboard is disabled.

gl.using(conn) { |gl| ... }

Block form that scopes every wrapper call inside the block to conn. All wrapper methods also accept a conn: keyword for one-off overrides.

gl.stop

Stops the proxy and closes the internal connection. Idempotent. Also runs automatically on process exit.

GoldLapel.config_keys

Returns an array of all valid config key names.

require "goldlapel"
puts GoldLapel.config_keys

Multiple instances

GoldLapel.start is a factory — each call spawns its own proxy subprocess and returns a fresh instance. Use different ports to run several side by side.

# Each GoldLapel.start call returns a fresh instance on its own port
gl_primary = GoldLapel.start("postgresql://primary/mydb", proxy_port: 7932)
gl_replica = GoldLapel.start("postgresql://replica/mydb", proxy_port: 7942)

gl_primary.search("articles", "body", "query")  # hits primary
gl_replica.search("articles", "body", "query")  # hits replica

gl_primary.stop
gl_replica.stop

Configuration

Pass a config: hash to start. Keys use snake_case symbols or strings and map directly to CLI flags (pool_size--pool-size). The log_level key accepts string levels (trace / debug / info / warn / error) and translates to the binary's verbose flags internally.

require "goldlapel"

gl = GoldLapel.start(
  "postgresql://user:pass@localhost/mydb",
  mode: "waiter",                 # top-level: waiter | bellhop
  log_level: "info",              # top-level: trace | debug | info | warn | error
  mesh: true,                     # top-level: opt into the mesh at startup
  mesh_tag: "prod-east",         # top-level: optional mesh tag
  config: {                        # structured tuning knobs only
    pool_size: 50,
    disable_matviews: true,
    replica: ["postgresql://user:pass@replica1/mydb"],
  },
)

Unknown keys raise ArgumentError immediately. There is a configuration reference covering every available setting.

Environment variables

The binary also reads GOLDLAPEL_PROXY_PORT, GOLDLAPEL_UPSTREAM, and all other GOLDLAPEL_* env vars automatically. Set GOLDLAPEL_BINARY to override the binary location.

Framework integrations

Gold Lapel is driver-agnostic, so any Ruby framework that speaks to Postgres just works against gl.url.

  • Rails — integration code ships inside the goldlapel gem. Add require "goldlapel/rails" to your initializer and point database.yml at gl.url. See the Rails guide.
  • Sinatra / Sequel / plain Ruby — use GoldLapel.start directly with pg and hand gl.url to whatever speaks Postgres.
  • Async Ruby — use GoldLapel::Async.start inside an Async reactor.

Upgrading from v0.1

v0.2 is a breaking redesign. The class-based GoldLapel.new(url).start shape (which returned a wrapped connection) is replaced by a GoldLapel.start(url) factory that returns a GoldLapel instance. Bring your own driver and point it at gl.url.

# v0.1.x (old) — class constructor + start returns a connection
gl = GoldLapel.new("postgresql://...")
conn = gl.start
conn.exec("SELECT 1")
gl.stop

# v0.2 (new) — factory returns an instance, bring your own driver
require "pg"
gl = GoldLapel.start("postgresql://...")
conn = PG.connect(gl.url)
conn.exec("SELECT 1")
gl.stop

# v0.1 async (old) — not available
# v0.2 async — separate submodule, opt-in require
require "goldlapel/async"
Async do
  gl = GoldLapel::Async.start("postgresql://...")
  gl.stop
end
  • GoldLapel.start(url) returns a GoldLapel instance (previously GoldLapel.new(url).start returned a connection).
  • Module name is now GoldLapel (lower-case l) — matches the gem name.
  • Bring your own pg connection against gl.url instead of using the one returned from start.
  • Async is a separate opt-in: require "goldlapel/async" and the async gem (not a hard dep).
  • All wrapper methods now accept an optional conn: keyword, and gl.using(conn) do |gl| ... end provides scoped override.
  • Multiple instances are first-class — each start call spawns its own proxy.

Redis Replacement

Gold Lapel includes a Redis Replacement API — common Redis patterns backed by PostgreSQL. Every method hangs directly off gl and accepts an optional trailing conn: keyword for transactional coordination.

Pub/Sub

# Pub/Sub — backed by PostgreSQL LISTEN/NOTIFY
gl.publish("orders", "new order")
gl.subscribe("orders") { |msg| puts msg }

Queues

# Queues — backed by FOR UPDATE SKIP LOCKED
gl.enqueue("jobs", { task: "send_email" })
job = gl.dequeue("jobs")

Counters

# Counters — backed by INSERT ON CONFLICT
gl.incr("page_views", "home")
count = gl.get_counter("page_views", "home")

Sorted Sets

# Sorted Sets — backed by ORDER BY and window functions
gl.zadd("leaderboard", "player1", 100)
top = gl.zrange("leaderboard", 0, 9)

Streams

# Streams — append-only log with consumer groups
id = gl.stream_add("events", { type: "signup" })
gl.stream_create_group("events", "workers")
msgs = gl.stream_read("events", "workers", "worker-1")
gl.stream_ack("events", "workers", msgs[0].id)

See the Redis Replacement docs for the complete API — including geospatial, rate limiting, sessions, and scripting.

Document Store

doc_find, doc_insert, doc_update, doc_delete and friends operate on JSONB-backed collections. Tables are auto-created on first use.

Filter operators

doc_find supports the MongoDB filter operators you'd reach for — $elemMatch, $text, $gt, $in, and more.

# $elemMatch — scope multi-condition filters to a single array element
orders = gl.doc_find("orders", {
  items: { "$elemMatch" => { sku: "ABC-123", qty: { "$gte" => 2 } } }
})
# $text — full-text search, document-wide or field-scoped
hits = gl.doc_find("articles", {
  "$text" => { "$search" => "postgres tuning" }
})

See Appendix D: Filter Operator Reference for the full list, Postgres translations, and index notes.

Search

Full-text search utilities backed by PostgreSQL tsvector/tsquery. No extensions required.

Facets

# Facets — value counts, optionally filtered by a search query
results = gl.facets("articles", "category")
filtered = gl.facets("articles", "category",
  query: "machine learning", query_column: "body")

Aggregations

# Aggregations — count, sum, avg, min, max with optional grouping
by_region = gl.aggregate("orders", "total", "avg", group_by: "region")

Custom Search Config

# Custom search config
gl.create_search_config("my_english", copy_from: "english")

Percolator

Store queries, then match documents against them. Like Elasticsearch percolate.

# Percolator — store queries, match documents against them
gl.percolate_add("alerts", "breaking-news",
  "breaking news earthquake", metadata: { notify: "slack" })

matches = gl.percolate("alerts",
  "A 6.2 magnitude earthquake struck the coast.")

gl.percolate_delete("alerts", "breaking-news")

Analyze

# Analyze — show tokenization pipeline
tokens = gl.analyze("The quick brown foxes")

Explain Score

# Explain score — score breakdown for a specific document
result = gl.explain_score("articles", "body",
  "machine learning", "id", 42)

See the API reference for full parameter details on all search methods.