tina4stack/ultipa

Thin gRPC client for the Ultipa graph database (ultipa-gqldb) — the Ultipa driver behind Tina4's graph layer. Zero-runtime-dep on protobuf.

Maintainers

Package info

github.com/tina4stack/ultipa-php

pkg:composer/tina4stack/ultipa

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 2

Stars: 0

Open Issues: 0

v0.2.1 2026-08-22 07:47 UTC

This package is auto-updated.

Last update: 2026-08-22 08:46:00 UTC


README

Tina4   ×   Ultipa

tina4-ultipa

The Ultipa graph driver for PHP

A full-fidelity gRPC client for the Ultipa graph database — every GQL type decoded, no Tina4 lock-in.

Packagist Tests MIT Ultipa Tina4

Quick StartType SupportUltipa DocsProtocoltina4.com

A thin, standalone gRPC driver for the Ultipa graph database (ultipa-gqldb), written in PHP. 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 package loaded only for ultipa:// connections, speaking gRPC directly (the grpc PECL extension plus grpc/grpc for framing, and this package's own hand-rolled proto3 codec for the payloads — no google/protobuf runtime dependency).

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 PropertyType is decoded to a natural PHP value — including the composites and temporals most thin clients skip (see Type support).
  • Real gRPC, no protobuf runtime. Uses the grpc PECL extension for HTTP/2 + gRPC framing, and this package's own hand-rolled proto3 codec (src/Pb/) for the payloads — so composer require never drags in google/protobuf and its version churn.
  • Fails loud. A bad statement throws; it never returns a falsy value you might miss. An unreachable host throws within your connectTimeout.
  • Cross-language parity. The same driver exists for Python, Node.js, Ruby and PHP, decoding byte-for-byte identically.

Requirements

  • PHP >= 8.1
  • The grpc PECL extension (ext-grpc) at runtime
    • Linux/macOS: pecl install grpc
    • Windows: install a matching php_grpc.dll and add extension=grpc to php.ini
  • Composer package grpc/grpc (pulled in automatically); no google/protobuf

Install

composer require tina4stack/ultipa

Quick start

require 'vendor/autoload.php';

use Tina4\Ultipa\Client;

// from a URL...
$db = Client::fromUrl("ultipa://admin:password@localhost:60061/mygraph")->connect();
// ...or explicitly
$db = new Client(
    host: "localhost",
    port: 60061,
    username: "admin",
    password: "password",
    graph: "mygraph"
);

// read — GQL text + optional named params
foreach ($db->query(
    "MATCH (n:Person) WHERE n.age > \$min RETURN n.name AS name",
    params: ["min" => 21]
) as $row) {
    echo $row["name"], "\n";
}

// write — dml stats on success, throws on a bad statement
$r = $db->execute("INSERT (:Person {name: 'Alice', age: 30})");
echo $r->dmlStats["inserted_nodes"], "\n";   // 1

$db->close();

query() runs a read, execute() a write — both take GQL and optional params and return a Result:

Member Meaning
->columns column names
->rows decoded rows (lists of PHP values)
->dicts() rows as associative arrays keyed by column
->scalar() first cell of the first row
->rowsAffected, ->dmlStats, ->warnings write metadata

Result is iterable and countable, so foreach ($result as $row) yields the associative rows directly. Errors: a bad statement throws Tina4\Ultipa\UltipaError; an unreachable host throws Tina4\Ultipa\ConnectError within connectTimeout, naming host, port and elapsed seconds.

Type support

Every gqldb PropertyType decodes to a natural PHP value:

Category Types Decodes to
Numeric int32/uint32/int64/uint64, float, double int / float
Text string, text string
Boolean / null bool, null, unset bool / null
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'] assoc array
Vector vector array of float
Graph node, edge, path assoc array (_kind node/edge/path; nodes/edges carry id, labels/type, properties, internal uuid)
Tabular list, set, map, record, table array (list) / assoc array
Error error ['code' => …, 'message' => …]

Node/edge arrays include the 8-byte internal-id (uuid) trailer emitted by gqldb 6.1.147+. Binary parameters go the other way with Codec::blob($bytes).

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 and strings are UTF-8. 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 CE.

Because PHP gRPC needs the grpc extension (ext-grpc), this is the heaviest of the Tina4 language drivers to install — but only when you actually use Ultipa.

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:

php examples/seed.php 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/sample_data/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 (via Codec::blob()), 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. They use the existing default graph with a dedicated Tina4TestPhp label they insert and delete, so they never touch real data:

composer install
TINA4_TEST_ULTIPA_URL=ultipa://admin:password@host:60061 php tests/test_driver.php

The suite covers scalar round-trip, node write/read with a bound parameter, a bad statement throwing UltipaError, and a connect timeout throwing ConnectError.

Links

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.