Skip to content
NarDBv0.2.0-dev

With LexerLang

use nardb — connection forms, credentials, how the NarQL chain reads in LexerLang, types, security.

NarDB is embedded in the LexerLang binary. A LexerLang application that writes use nardb opens the database without installing a server; the chain is NarQL itself.

LexerLang
use nardb, env_parser

$env = new env_parser(path.pwd + "/.env")
$db  = nardb.connect('data/app.ndbc').credentials({user: 'root', pass: $env.require('NARDB_PASS')})

$members = $db.from('members').where({'age': {gte: 18}}).order({'name': 'asc'}).to_array()
$member  = $db.from('members').where({'id': 123}).fetch_one().to_object()
$json    = $db.from('members').fields('id', 'name').limit(10).to_json()

NarQL → LexerLang#

Every step keeps its name. The only difference is the end: NarQL ends with .get();, in LexerLang you say which shape you want the result in.

NarQLLexerLang
from('members', 'm')$db.from('members', 'm')
.where({'id': 1245, 'age': {gte: 18}}).where({'id': 1245, 'age': {gte: 18}})
.fields('id', 'name').fields('id', 'name')
.fields(CAST('m.name', 'full_name'), FORMAT('birthday', 'yyyy-mm-dd')).fields(nardb.cast('m.name', 'full_name'), nardb.format('birthday', 'yyyy-mm-dd'))
.order({'name': 'asc'}).limit(10).offset(20)the same
.get();.to_array() · .to_json() · .to_object() · .fetch_one() · .fetch_all() · .count()
.insert_one({...}).get();.insert_one({...}) — returns the inserted row
.insert_many([...]);.insert_many([...])
.where({...}).update({...}).commit();.where({...}).update({...})
.where({...}).delete();.where({...}).delete()

Writes run when called. .commit() may be written but, as in NarQL, does nothing extra — every statement is already one transaction.

Any NarQL script can also be run directly:

LexerLang
$r = $db.query("from('members').where({'email': $1}).fields('id').get();", $email)

Connecting#

There are two modes; the chain is the same in both.

EmbeddedServer
Dataa .ndbc folder next to the applicationthe data directory of nardb serve (~/.nardb/data)
Portnone7070
Whenone application, developmentseveral processes; opening the shell while the app runs
LexerLang
# embedded
$db = nardb.connect('data/app.ndbc').credentials({user: 'root', pass: $password})
$db = nardb.connect({path: 'data/app.ndbc', user: 'root', pass: $password})

# server
$db = nardb.connect('nardb://root@localhost:7070/shop').credentials({pass: $password})
$db = nardb.connect({host: 'localhost', port: 7070, user: 'root', pass: $password, db: 'shop'})
OptionNote
pathpath of the embedded database, relative to the app directory. Default data/app.ndbc
create: falsefail if the embedded database is missing
encryption, passphraseencrypts a new embedded database
host, portthe server; port defaults to 7070
dbthe database's name on the server (shop → ~/.nardb/data/shop.ndbc); not a path
user, passcredentials; here or with .credentials()
ca, cert, keycertificate files for a server on another machine

Credentials are required#

A $db without credentials runs no queries:

Text
nardb: once kimlik verin: $db.credentials({user: 'root', pass: ...})

Every statement runs with the connected user's grants, in embedded mode too. root is admin on every schema; opening a narrower user for the application is a good habit:

Terminal
nardb user add ./data/app.ndbc web
nardb grant ./data/app.ndbc web members write
  • First run: in a new embedded database without users, root is created with the password of the first .credentials({user: 'root', pass: ...}) call. To set it up beforehand: nardb create ./data/app.ndbc.
  • Speed: the password is verified with Argon2id once per process; later requests in the same process are compared against a salted hash in memory.
  • No password in the address: nardb://root:password@... and ?pass= fail; addresses end up in logs and error messages.
  • Certificates: a server on the same machine needs no certificate files; the connection is still TLS. For another machine give ca, cert, key (see Server).

Opened once per process#

An embedded database is opened once per process. LexerLang pages run again on every request; nardb.connect returns the same open database for the same path, and it is closed when the process stops. Because only one process can open a .ndbc at a time, NarDB Shell or nardb user ... cannot open it while the application runs; in that case serve it with nardb serve.

Types#

Results arrive typed (Result.Values in the Go API):

FieldLexerLang
integersint
float32 / float64float
boolbool
string, text, decimalstring
date, datetime, time, timestampstring, in the schema's format
empty fieldnull
password_hash() field"••••••"

Security#

Values are not written into the NarQL text; they travel separately as $1, $2 parameters. Field names are quoted and escaped. A form value such as x'}).delete().all(); from('... stays a string to search for.

LexerLang-side details: lexer.gurerlabs.com — NarDB.