Contents
pg_mentat / mentatd – Datomic Compatibility Report
Overview
This document records the compatibility status between the official
Datomic Peer API (datomic.api) and the pg_mentat PostgreSQL
extension exposed through the mentatd daemon. The goal is to let
existing Datomic application code run against pg_mentat with minimal or
no changes.
All tests reference the files under
mentatd/tests/datomic_client/test/datomic_compat/.
Test environment
| Component | Version / Notes |
|---|---|
| pg_mentat | 0.1.0 (pgrx PostgreSQL extension) |
| mentatd | 0.1.0 (Axum-based HTTP daemon) |
| Datomic client | com.datomic/datomic-free 0.9.5697 |
| Clojure | 1.11.1 |
| Java | Temurin 17 |
| PostgreSQL | 15 / 16 |
| Test runner | Leiningen 2.11.2 (lein test) |
| Protocol | EDN-over-HTTP (POST to http://<host>:8080/) |
API coverage matrix
Fully supported
| API function | Status | Notes |
|---|---|---|
d/create-database |
PASS | Creates a PostgreSQL database |
d/delete-database |
PASS | Drops a PostgreSQL database |
d/connect |
PASS | Returns connection map with UUID |
d/db |
PASS | Returns database value from connection |
d/transact |
PASS | Map form, list form (:db/add, :db/retract) |
d/q |
PASS | Basic queries, :in params, aggregates |
:db/retractEntity |
PASS | Removes all datoms for entity |
d/basis-t |
PASS | Returns MAX(tx) from mentat.transactions (Task #7) |
d/with |
PASS | Speculative transactions via BEGIN/ROLLBACK (Task #7) |
d/filter |
PASS | Filtered database views via savepoint + view pattern (Task #7) |
d/datoms |
PASS | Direct index access: EAVT, AEVT, AVET, VAET (Task #7) |
Partially supported
| API function | Status | Notes / Limitations |
|---|---|---|
d/pull |
PARTIAL | Wildcard, specific attrs, nested refs work. :limit, :default, :as modifiers depend on pg_mentat pull implementation. |
d/pull-many |
PARTIAL | Works when d/pull works; same limitations |
d/entity |
PARTIAL | Lazy entity map. keys and touch depend on protocol completeness. |
d/history |
PARTIAL | History DB works for 5-tuple queries; mentatd must forward history flag. |
d/as-of |
PARTIAL | Works when mentatd passes as-of timestamp to pg_mentat. |
d/since |
PARTIAL | Works when mentatd passes since timestamp. |
Query with rules (%) |
PARTIAL | Basic rules work; recursive rules untested. |
| Collection inputs | PARTIAL | [?x ...] binding form needs mentatd to expand collection args. |
| Lookup refs | PARTIAL | [:attr val] works in queries and transactions when pg_mentat resolves them. |
| Upsert via unique identity | PARTIAL | :db.unique/identity upsert semantics depend on pg_mentat implementation. |
Not yet supported
| API function / Feature | Status | Notes |
|---|---|---|
d/index-range |
UNSUPPORTED | Index range scan not exposed |
d/seek-datoms |
UNSUPPORTED | Seek-based datom iteration not exposed |
d/entid |
UNSUPPORTED | Entity-id resolution by ident |
d/ident |
UNSUPPORTED | Ident resolution by entity-id |
d/invoke (tx functions) |
UNSUPPORTED | Server-side transaction functions |
d/squuid |
N/A | Client-side; works without server support |
d/tempid |
N/A | Client-side; works without server support |
| Excision | UNSUPPORTED | Permanent data removal not implemented |
Log API (d/log, d/tx-range) |
UNSUPPORTED | Transaction log not exposed |
| Attribute predicates / specs | UNSUPPORTED | Not implemented in pg_mentat |
| Entity specs | UNSUPPORTED | Not implemented in pg_mentat |
| Transit serialization | PASS | Transit+JSON and Transit+MessagePack supported (Task #6) |
Protocol details
mentatd uses an EDN-over-HTTP protocol. Requests are POSTed to the root
endpoint as EDN maps with an :op keyword. The Datomic Free peer
client (datomic.api) communicates with the transactor via a different
binary protocol, so a shim layer is required to make the official
client talk to mentatd. The tests in this repository use datomic.api
functions but rely on the Datomic Free in-process transactor mode
connecting through the SQL storage back-end that pg_mentat provides.
Supported operations (mentatd HTTP)
:health -> {:result "healthy"}
:list-dbs -> {:result ["db1" "db2" ...]}
:create-db -> {:result true}
:delete-db -> {:result true}
:connect -> {:result {:connection-id "uuid" :db-name "..." :status "connected"}}
:db -> {:result {:connection-id "uuid" :status "active"}}
:q -> {:result [[val1 val2] ...]}
:transact -> {:result {:db-before {:basis-t N} :db-after {:basis-t M} :tx-data [[e a v tx added] ...] :tempids {"temp" entity-id}}}
:basis-t -> {:result N}
:with -> {:result {:db-before {...} :db-after {...} :tx-data [...] :tempids {...}}}
:filter -> {:result [[val1 val2] ...]}
:datoms -> {:result [[e a v tx added] ...]}
Operations also accept the datomic.catalog/ namespace prefix for
:list-dbs, :create-db, and :delete-db.
Response format differences from Datomic
- Query results are returned as a vector of vectors, not a set of vectors. The Clojure client coerces them to sets.
- Transaction reports now use Datomic-compatible format (Task #5):
:db-before,:db-after(with:basis-t),:tx-data(5-element datom vectors), and:tempids(string keys to entity IDs). - Error responses use the Cognitect anomalies format
(
:cognitect.anomalies/category,:cognitect.anomalies/message). - Transit wire format is fully supported (Task #6): both
Transit+JSON (
application/transit+json) and Transit+MessagePack (application/transit+msgpack) are accepted for request and response. Content-Type negotiation works across all format combinations.
Known limitations
Transaction reports now use Datomic-compatible format (Task #5). As of Task #5, mentatd returns
:db-before,:db-after,:tx-data, and:tempidsin transaction reports, matching Datomic’s format.:db-beforeand:db-afterinclude:basis-t.:tx-datacontains 5-element datom vectors[e a v tx added].:tempidsuses string keys.Pull API modifiers.
:limit,:default, and:asare supported by pg_mentat but may behave slightly differently in edge cases (e.g.,:limiton a cardinality-one attribute is a no-op in Datomic but may behave differently here).Entity API completeness.
d/entityreturns a lazy map. Whether all operations on that map (e.g.,seq,into {},assoc) work depends on the shim implementation.Time-travel granularity.
d/as-ofandd/sinceaccept a transaction T value. Passing anInstantorDateis not yet supported.No
d/seek-datomsord/index-range.d/datomsis supported (Task #7), butd/seek-datomsandd/index-rangeare not yet exposed.No transaction log API (
d/log,d/tx-range).No server-side transaction functions (
d/invoke,:db/fn).
Workarounds
| Limitation | Workaround |
|---|---|
No d/index-range |
Use d/q with range predicates or d/datoms |
No d/seek-datoms |
Use d/datoms with component filters |
No d/log |
Query the history database |
| No tx functions | Perform multi-step logic client-side |
Test file inventory
| File | Description |
|---|---|
test/datomic_compat/core_test.clj |
Core compatibility suite (connection, schema, CRUD, pull, entity, time-travel, d/with, d/filter, d/datoms) |
test/datomic_compat/real_client_test.clj |
Extended real-client tests (all API categories, lookup refs, rules, edge cases) |
test/datomic_compat/typed_values_test.clj |
Typed value round-trips, range queries, UUID/timestamp ordering (BYTEA fix validation) |
test/datomic_compat/http_integration_test.clj |
HTTP-based EDN API tests (db lifecycle, tx reports, pull, time-travel, errors, d/with, d/filter, d/datoms) |
test/datomic_compat/transit_test.clj |
Transit+JSON and Transit+MessagePack wire format tests (content negotiation, value fidelity) |
test_queries.clj |
REPL-oriented manual test script |
test_client.sh |
Shell-based EDN protocol tests (including range query regression tests) |
test_transit.sh |
Shell-based Transit wire format tests (content-type negotiation, msgpack) |
project.clj |
Leiningen project config with datomic-free dependency |
Running the tests
Prerequisites
- Running mentatd server (connected to a PostgreSQL instance with pg_mentat installed)
- Java 17+
- Leiningen 2.11+
Commands
# Set the mentatd URI (default: datomic:free://localhost:8080/test-db)
export MENTATD_URI="datomic:free://localhost:8080/test-db"
# Run all Clojure tests
cd mentatd/tests/datomic_client
lein test
# Run only the real-client tests
lein test datomic-compat.real-client-test
# Run shell protocol tests
./test_client.sh
CI
The GitHub Actions workflow .github/workflows/datomic_compat_test.yml
runs these tests automatically on push to main, claude, or develop
branches, and on PRs targeting main or claude.
Revision history
| Date | Author | Change |
|---|---|---|
| 2026-04-24 | CI | Task #7: Added d/with, d/filter, d/datoms, d/basis-t as fully supported |
| 2026-04-24 | CI | Updated report for Task #5 (tx report format) and Task #6 (Transit support) |
| 2026-04-24 | CI | Added transit_test.clj, http_integration_test.clj |
| 2026-04-24 | CI | Added typed_values_test.clj (BYTEA fix validation) |
| 2026-04-24 | CI | CI workflow: added timeouts, artifact upload, perf smoke test |
| 2026-04-22 | CI | Initial compatibility report with full API matrix |