Rill v0.13 Reference

Standard library Β· Databases

db/oxidb

Imported as import "db/oxidb" as oxidb, its names are then oxidb.…. Every signature below is the one the checker infers.

Functions

fn dial(host: Str, port: Int) -> Result(Int, Str)

# not run
import "db/oxidb"
fd = dial("127.0.0.1", 7411)?   # a socket, or Err(cannot connect to 127.0.0.1:7411)

fn hang_up(fd: Int) -> Unit

# not run
import "db/oxidb"
hang_up(fd)

fn call(fd: Int, request: Json) -> Result(Json, Str)

One request, one reply, unwrapped into a Result.

# not run
import "db/oxidb"
reply = call(fd, command("ping", Nil))   # Ok(the value the server answered), or Err(its message)

fn command(name: Str, fields: List(Field)) -> Json

command("find", Cons(field("collection", JStr(c)), Nil)) β€” the cmd field is added here so no caller has to remember its name.

import "db/oxidb"
command("find", Cons(field("collection", text("people")), Nil))   # => JObj(Cons(Field(cmd, JStr(find)), Cons(Field(collection, JStr(people)), Nil)))

fn field(key: Str, value: Json) -> Field

import "db/oxidb"
field("age", int(36))   # => Field(age, JInt(36))

fn text(s: Str) -> Json

import "db/oxidb"
text("ada")   # => JStr(ada)

fn int(n: Int) -> Json

import "db/oxidb"
int(36)   # => JInt(36)

fn on(collection: Str, fields: List(Field)) -> List(Field)

import "db/oxidb"
on("people", Cons(field("query", JObj(Nil)), Nil))   # => Cons(Field(collection, JStr(people)), Cons(Field(query, JObj(Nil)), Nil))

fn ping(fd: Int) -> Result(Json, Str)

# not run
import "db/oxidb"
ping(fd)   # Ok(JStr("pong"))

fn hello(fd: Int) -> Result(Json, Str)

The handshake, and the one command whose reply is not on the wire the request was written in: the server answers hello before it has looked at the format, so what comes back is JSON whatever went out, and it is the server's own shape rather than the usual envelope β€” {"ok":true, "server":{...}}. So this reads either, and hands back what the reply says about the server.

# not run
import "db/oxidb"
info = hello(fd)?
server_name(info)   # "oxidb"

fn server_name(info: Json) -> Str

What the handshake says, for a client that wants to know before it asks.

import "db/oxidb"
server_name(JObj(Cons(Field("name", JStr("oxidb")), Nil)))   # => oxidb

fn server_version(info: Json) -> Str

import "db/oxidb"
server_version(JObj(Cons(Field("version", JStr("0.9.0")), Nil)))   # => 0.9.0

fn wire_version(info: Json) -> Int

import "db/oxidb"
wire_version(JObj(Cons(Field("wire_version", JInt(2)), Nil)))   # => 2

fn server_features(info: Json) -> List(Str)

import "db/oxidb"
server_features(JObj(Cons(Field("features", JArr(Cons(JStr("tsdb"), Cons(JStr("sql"), Nil)))), Nil)))   # => Cons(tsdb, Cons(sql, Nil))

fn list_collections(fd: Int) -> Result(Json, Str)

# not run
import "db/oxidb"
list_collections(fd)   # Ok(JArr(the names))

fn insert(fd: Int, collection: Str, doc: Json) -> Result(Json, Str)

# not run
import "db/oxidb"
inserted_id(insert(fd, "people", JObj(Cons(field("name", text("ada")), Nil)))?)   # the new document's id

fn insert_many(fd: Int, collection: Str, docs: List(Json)) -> Result(Json, Str)

# not run
import "db/oxidb"
inserted_ids(insert_many(fd, "people", Cons(doc1, Cons(doc2, Nil)))?)   # Cons(id1, Cons(id2, Nil))

fn find(fd: Int, collection: Str, query: Json) -> Result(Json, Str)

# not run
import "db/oxidb"
docs(find(fd, "people", JObj(Cons(field("age", int(36)), Nil)))?)   # every document with age 36

fn find_sorted(fd: Int, collection: Str, query: Json, sort: Json, limit: Int) -> Result(Json, Str)

sort is a document like {"age": -1}; a limit of 0 asks for no limit.

# not run
import "db/oxidb"
docs(find_sorted(fd, "people", JObj(Nil), JObj(Cons(field("age", int(-1)), Nil)), 10)?)   # the ten oldest

fn count(fd: Int, collection: Str) -> Result(Json, Str)

# not run
import "db/oxidb"
counted(count(fd, "people")?)   # how many documents

fn count_where(fd: Int, collection: Str, query: Json) -> Result(Json, Str)

How many match, which is what a pager needs before it can say "of 4200".

# not run
import "db/oxidb"
counted(count_where(fd, "people", JObj(Cons(field("role", text("admin")), Nil)))?)

fn find_page(fd: Int, collection: Str, query: Json, sort: Json, limit: Int, skip: Int) -> Result(Json, Str)

One page of a query: limit documents, the first skip of them passed over. The sort has to be given, because a page is only a page if the order is the same each time.

# not run
import "db/oxidb"
docs(find_page(fd, "people", JObj(Nil), JObj(Cons(field("name", int(1)), Nil)), 20, 40)?)   # the third page of twenty, by name

fn update(fd: Int, collection: Str, query: Json, changes: Json) -> Result(Json, Str)

# not run
import "db/oxidb"
modified(update(fd, "people", JObj(Cons(field("name", text("ada")), Nil)), set(Cons(field("age", int(37)), Nil)))?)   # how many changed

fn delete(fd: Int, collection: Str, query: Json) -> Result(Json, Str)

# not run
import "db/oxidb"
deleted(delete(fd, "people", JObj(Cons(field("name", text("ada")), Nil)))?)   # how many went

fn aggregate(fd: Int, collection: Str, pipeline: Json) -> Result(Json, Str)

A pipeline β€” a list of stages, $match, $group, $sort, $facet and the rest, each a document like {"$group": {"_id": "$role", "n": {"$sum": 1}}} β€” and what comes out of the end of it.

# not run
import "db/oxidb"
pipeline = JArr(Cons(JObj(Cons(field("$group", JObj(Cons(field("_id", text("$role")), Cons(field("n", JObj(Cons(field("$sum", int(1)), Nil))), Nil)))), Nil)), Nil))
docs(aggregate(fd, "people", pipeline)?)   # one document per role, with its count

fn create_index(fd: Int, collection: Str, field_name: Str) -> Result(Json, Str)

# not run
import "db/oxidb"
create_index(fd, "people", "name")

fn proc_status(fd: Int) -> Result(Json, Str)

What the server process itself is doing: how much memory it is holding, how busy it is, how many threads it has, how long it has been up. Nothing about the data, so a page can show it to anyone who may see the page.

# not run
import "db/oxidb"
st = proc_status(fd)?
rss_mb(st)   # the server's resident memory, in MB

fn rss_mb(data: Json) -> Float

import "db/oxidb"
rss_mb(JObj(Cons(Field("mem_rss_mb", JNum(12.5)), Nil)))   # => 12.5

fn cpu_percent(data: Json) -> Float

import "db/oxidb"
cpu_percent(JObj(Cons(Field("cpu_percent", JNum(3.0)), Nil)))   # => 3

fn uptime_s(data: Json) -> Int

import "db/oxidb"
uptime_s(JObj(Cons(Field("uptime_s", JInt(3600)), Nil)))   # => 3600

fn set(fields: List(Field)) -> Json

$set is the update operator the server expects for a partial change.

import "db/oxidb"
set(Cons(field("age", int(37)), Nil))   # => JObj(Cons(Field($set, JObj(Cons(Field(age, JInt(37)), Nil))), Nil))

fn docs(data: Json) -> List(Json)

find answers with an array; insert with {"id": n}; count with {"count": n}. These name those shapes so callers do not repeat them.

import "db/oxidb"
docs(JArr(Cons(JObj(Nil), Cons(JObj(Nil), Nil))))   # => Cons(JObj(Nil), Cons(JObj(Nil), Nil))

fn inserted_id(data: Json) -> Int

import "db/oxidb"
inserted_id(JObj(Cons(Field("id", JInt(42)), Nil)))   # => 42

fn inserted_ids(data: Json) -> List(Int)

import "db/oxidb"
inserted_ids(JArr(Cons(JInt(1), Cons(JInt(2), Nil))))   # => Cons(1, Cons(2, Nil))

fn counted(data: Json) -> Int

import "db/oxidb"
counted(JObj(Cons(Field("count", JInt(7)), Nil)))   # => 7

fn modified(data: Json) -> Int

import "db/oxidb"
modified(JObj(Cons(Field("modified", JInt(1)), Nil)))   # => 1

fn deleted(data: Json) -> Int

import "db/oxidb"
deleted(JObj(Cons(Field("deleted", JInt(2)), Nil)))   # => 2

fn field_str(doc: Json, key: Str) -> Str

A field of one document, as text β€” field_str(doc, "name").

import "db/oxidb"
field_str(JObj(Cons(Field("name", JStr("ada")), Nil)), "name")   # => ada
field_str(JObj(Nil), "name")                                    # =>

fn field_int(doc: Json, key: Str) -> Int

import "db/oxidb"
field_int(JObj(Cons(Field("age", JInt(36)), Nil)), "age")   # => 36