Hi. TypeDB engineer here!
Is this still something you’d be interested in seeing @Sergiusz ? Unfortunately my experience in Elixir and Erlang is zero, but as @jkwchui noted, the fastest way to build a new DB driver is by piggybacking on the Rust driver.
I’d imagine that, if you wanted an Erlang driver for TypeDB, one engineer with AI assistance could whip up something functional within days 
As an experiment, I asked AI to sketch the project keeping it high-level; this is what it came up with - I have no idea how accurate it is.
typedb_ex/
├── mix.exs
├── native/
│ └── typedb_ex_nif/
│ ├── Cargo.toml
│ └── src/lib.rs
└── lib/
└── typedb_ex.ex
defp deps do
[
{:rustler, "~> 0.30"}
]
end
def project do
[
compilers: [:rustler] ++ Mix.compilers(),
rustler_crates: rustler_crates()
]
end
defp rustler_crates do
[
typedb_ex_nif: [
path: "native/typedb_ex_nif",
mode: :release
]
]
end
[package]
name = "typedb_ex_nif"
version = "0.1.0"
edition = "2021"
[lib]
name = "typedb_ex_nif"
crate-type = ["cdylib"]
[dependencies]
rustler = "0.30"
typedb-driver = "2.28" # Official TypeDB Rust driver
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
use rustler::{Env, Term, NifResult, ResourceArc};
use typedb_driver::{DatabaseManager, Session, Transaction, TypeDBDriver, Driver, SessionType, TransactionType};
use std::sync::Mutex;
rustler::init!("Elixir.TypeDBEx.Nif", [connect, query]);
struct DriverResource {
driver: Mutex<TypeDBDriver>,
}
#[rustler::nif]
fn connect<'a>(env: Env<'a>, address: String) -> NifResult<Term<'a>> {
let driver = TypeDBDriver::new(address).map_err(|e| rustler::Error::Atom("connection_failed"))?;
let resource = ResourceArc::new(DriverResource { driver: Mutex::new(driver) });
Ok(resource.to_term(env))
}
#[rustler::nif(schedule = "DirtyCpu")]
fn query<'a>(
env: Env<'a>,
driver_res: ResourceArc<DriverResource>,
database: String,
query_str: String,
) -> NifResult<Term<'a>> {
let driver = driver_res.driver.lock().unwrap();
let databases = DatabaseManager::new(&driver);
let session = Session::new(&databases, &database, SessionType::Data)
.map_err(|_| rustler::Error::Atom("session_failed"))?;
let mut tx = session
.transaction(TransactionType::Read)
.map_err(|_| rustler::Error::Atom("tx_failed"))?;
let answers = tx
.query(&query_str)
.map_err(|_| rustler::Error::Atom("query_failed"))?;
let mut results = vec![];
for answer in answers {
results.push(format!("{:?}", answer)); // Simplified
}
Ok(results.to_term(env))
}
defmodule TypeDBEx do
use Rustler, otp_app: :typedb_ex, crate: "typedb_ex_nif"
def connect(_address), do: :erlang.nif_error(:nif_not_loaded)
def query(_driver, _db, _query), do: :erlang.nif_error(:nif_not_loaded)
# High-level wrapper
def with_connection(address, fun) do
{:ok, driver} = connect(address)
try do
fun.(driver)
after
# Close driver (add close/1 NIF if needed)
end
end
def run_query(driver, db, query) do
query(driver, db, query)
end
end
{:ok, driver} = TypeDBEx.connect("localhost:1729")
result = TypeDBEx.run_query(driver, "my_db", "match $x isa person, has name $n; get $n;")
IO.inspect(result)
# => ["name: \"Alice\"", "name: \"Bob\""]