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.