Skip to content

bnlang/mongodb

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mongodb

MongoDB driver for bnl — pure bnl, no native deps. Implements the MongoDB OP_MSG wire protocol directly over net + tls + crypto, so it runs anywhere bnl runs.

Install

bpm install mongodb

Use

import "mongodb" as mongo;

function main() {
    var client = wait mongo.connect({
        host:     "127.0.0.1",
        port:     27017,
        user:     "appuser",
        password: "secret"
    });

    var users = client.db("app").collection("users");

    var ins = wait users.insert_one({name: "Alice", age: 30});
    print("inserted:", ins.inserted_id);

    var alice = wait users.find_one({name: "Alice"});
    print("found:", alice.name, alice.age);

    var rows = wait users.find({age: {"$gte": 18}});
    print("adults:", rows.length);

    wait users.update_one({name: "Alice"}, {"$inc": {age: 1}});
    var n = wait users.count_documents({});
    print("count:", n);

    client.close();
}

main();

Every method on client / db / collection returns a Future — pair with wait.

API

mongodb.connect(uri_or_opts)Future<client>

Accepts either a mongodb:// URI string or an opts map.

// URI form
var client = wait mongo.connect("mongodb://root:secret@127.0.0.1:27017/myapp?authSource=admin");

// Opts form (equivalent)
var client = wait mongo.connect({
    host:        "127.0.0.1",
    port:        27017,
    user:        "root",
    password:    "secret",
    database:    "myapp",
    auth_source: "admin"
});

URI: mongodb://[user[:password]@]host[:port][/db][?param=value&…]

URI query param Maps to Notes
authSource auth_source falls back to the path /db if absent, then "admin"
tls / ssl ssl accepts true / 1 / yes
tlsAllowInvalidCertificates ssl_verify=false for self-signed dev servers

mongodb+srv:// (Atlas SRV discovery) is not supported in v0.1 — resolve the SRV record yourself and pass the explicit host:port. Multiple hosts (replica set) parse but only the first is used.

Opts map keys:

Key Type Default
host string "127.0.0.1"
port number 27017
user string none (omit for unauthenticated mongod)
password string none (required when user is set)
auth_source string "admin"
ssl bool false
ssl_verify bool true

Resolves to a client once the SCRAM-SHA-256 handshake completes.

client methods

Method Returns Notes
client.db(name) db namespace handle
client.run_command(db_name, cmd) Future<reply> raw command for admin / unsupported ops
client.ping() Future<reply> {ping: 1} against admin
client.server_info() map the hello reply (server version, max wire version, …)
client.close() tear down the socket

db methods

var db = client.db("app");

Method Returns
db.collection(name) collection
db.run_command(cmd) Future<reply>
db.list_collections() Future<list of map> (firstBatch)
db.drop() Future<reply>

collection methods

var users = db.collection("users");

Method Returns Notes
insert_one(doc) Future<{inserted_id, n}> auto-generates _id ObjectId if absent
insert_many(docs) Future<{inserted_ids, n}> same
find(filter?, opts?) Future<list of map> drains the cursor (getMore loop)
find_one(filter?, opts?) Future<map | null> first match or null
update_one(filter, update) Future<{matched, modified}>
update_many(filter, update) Future<{matched, modified}>
replace_one(filter, replacement) Future<{matched, modified}>
delete_one(filter) Future<{deleted}>
delete_many(filter) Future<{deleted}>
count_documents(filter?) Future<number>
aggregate(pipeline, opts?) Future<list of map> drains the cursor
drop() Future<reply>

opts (when accepted) recognises: projection, sort, limit, skip, batch_size.

mongodb.pool(opts) → pool

Same opts as connect, plus max (default 10). Exposes:

var pool = mongo.pool({host: "...", user: "...", password: "...", max: 20});

wait pool.run(function (client) {
    return client.db("app").collection("users").insert_one({name: "x"});
});

pool.size();
pool.idle_size();
pool.close();

run(fn) acquires a client, hands it to fn, releases on settle.

Helpers

Function Returns
mongodb.new_object_id() {$oid: "<24-hex>"} ready to drop into documents
mongodb.encode_bson(doc) raw BSON bytes (mostly useful for debugging)
mongodb.decode_bson(buf, off?) [doc, end_offset]
mongodb.version() "0.1.0"

BSON value mapping

Most bnl values map naturally to BSON. Special types use a marker map convention (MongoDB Extended JSON) so they survive a round trip:

bnl BSON
null null
true / false bool
integer-valued number, |n| < 2^31 int32
integer-valued number, 2^31 ≤ |n| ≤ 2^53 - 1 int64
non-integer number double (IEEE-754 LE, encoded in pure bnl)
string utf8
map document
list array
{$oid: "<24-hex>"} ObjectId
{$date: ms} UTC datetime
{$binary: bytes, $subtype: n} binary (subtype defaults to 0)
{$regex: "...", $options: "..."} regex
{$timestamp: {t: secs, i: incr}} timestamp
{$minKey: 1} / {$maxKey: 1} MinKey / MaxKey
{$numberLong: "<digits>"} int64 (for values outside safe-int range)

Int64 values whose absolute value exceeds 2^53 - 1 are decoded as {$numberLong: "..."} so precision survives — bnl numbers are doubles.

Errors

Server errors reject with a structured map:

try {
    wait users.insert_one(...);
} catch (e) {
    if (type(e) == "map" and e.code == 11000) {
        print("duplicate key:", e.message);
    } else {
        throw e;
    }
}
Field Notes
code Mongo numeric error code (e.g. 11000 duplicate key)
codeName Symbolic name ("DuplicateKey") when sent
message Server's errmsg

Client-side errors (TCP failure, malformed BSON, etc.) reject with a string prefixed "mongo: ".

License

MIT.

Releases

No releases published

Packages

 
 
 

Contributors