×
tina4-ultipa
The Ultipa graph driver for Ruby
A full-fidelity gRPC client for the Ultipa graph database — every GQL type decoded, no Tina4 lock-in.
Quick Start • Type Support • Ultipa Docs • Protocol • tina4.com
A thin, standalone gRPC driver for the Ultipa graph
database (ultipa-gqldb). It is the Ultipa driver behind
Tina4's graph data layer — but has no Tina4 dependency and
is perfectly usable on its own. Tina4's core stays zero-dependency; this driver is
an optional gem loaded only for ultipa:// connections, speaking gRPC directly
(grpc + google-protobuf).
Ultipa is a high-performance graph database with a GQL (ISO/IEC 39075) query surface. Learn more at ultipa.com · docs at ultipa.com/docs.
Why this driver
- Complete value decoding. Every gqldb
PropertyTypeis decoded to a natural Ruby value — including the composites and temporals most thin clients skip (see Type support). - Real gRPC, vendored stubs. Generated protobuf stubs ship inside the gem
(
lib/tina4_ultipa/gen/), so there is no reflection round-trip and no codegen step at install time. - Fails loud. A bad statement raises; it never returns a falsy value you might
miss. An unreachable host raises within your
connect_timeout. - Cross-language parity. The same driver exists for Python, Node.js, Ruby and PHP, decoding byte-for-byte identically.
Install
gem install tina4-ultipa
or in a Gemfile:
gem "tina4-ultipa"
Quick start
require "tina4_ultipa"
# from a URL...
db = Tina4Ultipa::Client.from_url("ultipa://admin:password@localhost:60061/mygraph").connect
# ...or explicitly
db = Tina4Ultipa::Client.new(
host: "localhost", port: 60061,
username: "admin", password: "password", graph: "mygraph"
).connect
# read — GQL text + optional named params
db.query("MATCH (n:Person) WHERE n.age > $min RETURN n.name AS name",
params: { min: 21 }).each do |row|
puts row["name"]
end
# write — dml stats on success, raises on a bad statement
r = db.execute("INSERT (:Person {name: 'Alice', age: 30})")
puts r.dml_stats[:inserted_nodes] # 1
db.close
query runs a read, execute a write — both take GQL and optional params
and return a Tina4Ultipa::Result:
| Member | Meaning |
|---|---|
#columns |
column names |
#rows |
decoded rows (arrays of Ruby values) |
#to_h_rows / #dicts |
rows as hashes keyed by column |
#scalar |
first cell of the first row |
#rows_affected, #dml_stats, #warnings |
write metadata |
Result is Enumerable and yields each row as a hash, so each, map and
select work directly on a result.
Errors: a bad statement raises Tina4Ultipa::Error; an unreachable host raises
Tina4Ultipa::ConnectError within connect_timeout, naming host, port and elapsed time.
Type support
Every gqldb PropertyType decodes to a natural Ruby value:
| Category | Types | Decodes to |
|---|---|---|
| Numeric | int32/uint32/int64/uint64, float, double | Integer / Float |
| Text | string, text | String |
| Boolean / null | bool, null, unset | true/false / nil |
| Binary | blob | binary String (e.g. an image, round-trips intact) |
| Decimal | decimal | String (precision-preserving) |
| Temporal | date, local/zoned time, local/zoned datetime, timestamp | ISO-8601 String |
| Interval | year-to-month, day-to-second | {"months" => …} / {"seconds" => …, "nanoseconds" => …} |
| Spatial | point, point3d | {"x", "y"[, "z"], "srid"} Hash |
| Vector | vector | Array of Float |
| Graph | node, edge, path | Hash (_kind node/edge/path; nodes/edges carry id, labels/type, properties, internal uuid) |
| Tabular | list, set, map, record, table | Array / Hash |
| Error | error | {"code", "message"} |
Node/edge hashes include the 8-byte internal-id (uuid) trailer emitted by
gqldb 6.1.147+.
Protocol
ultipa-gqldb speaks gRPC (default port 60061, protobuf package gqldb). The
driver authenticates with SessionService.Login, passes the returned session_id
on every call as the session-id metadata header (as an unsigned decimal), then
runs QueryService.Gql. Each value is a TypedValue{type, bytes}; all multi-byte
integers are little-endian. The full byte-level encoding is documented in
PROTOCOL.md — grounded in Ultipa's official gqldb SDK and proto,
and verified live against gqldb-grpc 6.2.130 CE.
Sample data pack
Get a real graph into your community-edition instance in seconds - 10 people (with photos), 3 companies, 3 projects, 5 skills and 62 relationships:
ruby examples/seed.rb ultipa://admin:PASSWORD@HOST:60061
# graph defaults to "default"; override with TINA4_ULTIPA_GRAPH
Then explore it:
MATCH (n:Person)-[e]->(m) RETURN n, e, m LIMIT 100
RETURN db.overview()
The pack lives in examples/ - people.json describes the graph and
sample_data/faces/*.jpg are 64px portraits of AI-generated, non-existent people
(thispersondoesnotexist.com) stored as BLOB
properties, so it also demonstrates binary round-tripping through gqldb. Re-running is
safe - it clears the demo labels (Person/Company/Project/Skill) first.
Testing
Real, no-mock tests run against a live server:
TINA4_TEST_ULTIPA_URL=ultipa://admin:password@host:60061 ruby test/test_driver.rb
They cover scalars, node/edge/list/map decoding, the full temporal/spatial/interval set, path decoding, and a BLOB image round-trip.
Links
- Ultipa — website ultipa.com · docs ultipa.com/docs · GQL query language reference in the docs
- Tina4 — tina4.com · the framework this driver powers
- This driver — github.com/tina4stack/ultipa-ruby · sibling drivers for Python, Node.js, PHP
License
MIT. Note: the Ultipa community-edition server is licensed by Ultipa for personal / non-commercial use — review Ultipa's terms before you deploy it. This driver is an independent client and may not be officially supported by Ultipa.
Sponsored by Code Infinity · part of the Tina4 stack.