API · 3 of 3

SDKs — Go, Python, .NET

Each official client wraps the wire commands.

Go

script := `proc transfer(from, to, amount) {
    let s = find_one("accounts", {_id: from})
    if s == null { abort "sender not found" }
    if s.balance < amount { abort "insufficient funds" }
    update("accounts", {_id: from}, {$inc: {balance: -amount}})
    update("accounts", {_id: to},   {$inc: {balance:  amount}})
    return {ok: true}
}`

client.CreateProcedure("transfer", script)

resp, err := client.CallProcedure("transfer", map[string]any{
    "from": "alice", "to": "bob", "amount": 1500,
})
if err != nil {
    log.Fatal(err) // abort comes back as an error
}

names, _ := client.ListProcedures()
def, _ := client.GetProcedure("transfer")
client.DeleteProcedure("transfer")

Python

from oxidb import OxiDbClient

with OxiDbClient("127.0.0.1", 4444) as db:
    db.create_procedure("award_points", """
        proc award_points(email, amount) {
            let user = find_one("users", {email: email})
            if user == null { abort "user not found" }
            update("users", {email: email}, {$inc: {points: amount}})
            return {ok: true, new_total: user.points + amount}
        }
    """)

    r = db.call_procedure("award_points", {
        "email": "alice@example.com",
        "amount": 100
    })
    print(r)

    db.list_procedures()
    db.get_procedure("award_points")
    db.delete_procedure("award_points")

.NET (TCP client)

using OxiDb.Client.Tcp;

var client = new OxiDbClient("127.0.0.1", 4444);

var script = @"
    proc transfer(from, to, amount) {
        let s = find_one(""accounts"", {_id: from})
        if s.balance < amount { abort ""insufficient funds"" }
        update(""accounts"", {_id: from}, {$inc: {balance: -amount}})
        update(""accounts"", {_id: to},   {$inc: {balance:  amount}})
        return {ok: true}
    }";

await client.CreateProcedureAsync("transfer", script);

var result = await client.CallProcedureAsync("transfer", new {
    from = "alice", to = "bob", amount = 1500
});

JS / TypeScript (oxidb-js)

import { OxiDb } from "oxidb"

const db = new OxiDb({rest: "http://localhost:8080"})

await db.createProcedure("transfer", `
  proc transfer(from, to, amount) {
    let s = find_one("accounts", {_id: from})
    if s.balance < amount { abort "insufficient funds" }
    update("accounts", {_id: from}, {$inc: {balance: -amount}})
    update("accounts", {_id: to},   {$inc: {balance:  amount}})
    return {ok: true}
  }
`)

const r = await db.callProcedure("transfer", {
  from: "alice", to: "bob", amount: 1500
})

Common pattern: load procs from disk on boot

import os, glob

for path in glob.glob("procs/*.oxs"):
    name = os.path.splitext(os.path.basename(path))[0]
    with open(path) as f:
        db.create_procedure(name, f.read())
Versioning tip: keep your procedures in source control as .oxs files and re-create them on deploy. There is no migration concept — create_procedure overwrites by name.
Report Issue