Pre-1.0 hoardDB is pre-1.0. Expect breaking changes.
hoardDB Query Language (HQL) reference
HQL is what you type at the hoardDB-cli prompt, or pipe into it. This page
lists every statement the CLI accepts in this build and what each one prints.
Every example on it was run against a real server, and the output shown is what
that server printed. Where the CLI refuses a statement, the page quotes the
refusal, because a refusal is usually the first thing you meet when you bring
habits over from another database.
Each statement is in one of three states:
- Works: the CLI accepts it and the server serves it. Most of this page.
- Refused: the CLI or the server turns it down with a message that says what to do instead. These are quoted in full.
- Planned: not accepted yet. Marked Planned wherever it appears, with a link to Limitations, which says when it is due.
The examples use a database called shop. Output lines are copied from the
run; only the prompt differs between a terminal session and a piped one (see
The interactive REPL).
Contents
- Connect and authenticate
- How statements are read
- Databases
- Buckets
- Documents: hash and btree buckets
- Query and update operators
- Queues: fifo and lifo
- Heap
- B-tree ranges
- Blob
- Verbs that are not what they look like
- Users and roles
- Cluster and administration
- The interactive REPL
- Configuration as environment variables
- Where each statement is accepted
Connect and authenticate
A server started with no configuration writes a root password to
data/root.password and listens for clients on port 7433. Run the CLI from
the same directory and it reads that file, so this is the shortest path to a
prompt:
hoardDB-server &
hoardDB-cli -address 127.0.0.1:7433 -insecure
WARNING: TLS certificate verification is disabled (--insecure); the connection to 127.0.0.1:7433 cannot be trusted and may be intercepted. Use this only against a local development server.
2026/09/26 15:40:10 WARN TLS certificate verification disabled by an explicit insecure trust policy host=127.0.0.1:7433 reason="--insecure flag"
Authenticated as admin
Connected to 127.0.0.1:7433
hoardDB CLI devel
Type 'help' for help, 'exit' to quit.
[h]oardDB>
-insecure skips certificate verification, and the warning says so every
time. Use it against a local development server only. Without it, the first
connection to a server asks you to confirm the server’s fingerprint and
records it in ~/.hoarddb/known_servers:
The authenticity of server '127.0.0.1:7433' cannot be established.
ED25519 key fingerprint is SHA256:00feb48e7331de075a1607916ce804a397440d80c99c0c01b1a23624897d93c8.
Trust this server? [y/N]: y
Authenticated as admin
Connected to 127.0.0.1:7433
A script has nobody to answer that question, so a piped session refuses an unknown server instead of guessing:
The authenticity of server '127.0.0.1:7433' cannot be established.
ED25519 key fingerprint is SHA256:00feb48e7331de075a1607916ce804a397440d80c99c0c01b1a23624897d93c8.
Refusing to trust it non-interactively: pre-populate ~/.hoarddb/known_servers or pass --insecure to bypass.
Failed to connect to 127.0.0.1:7433: connect to 127.0.0.1:7433: dial 127.0.0.1:7433: server 127.0.0.1:7433 not trusted (fingerprint: SHA256:00feb48e7331de075a1607916ce804a397440d80c99c0c01b1a23624897d93c8)
Connect once from a terminal and answer y. Every later run, piped or not,
then connects without asking.
Credentials
Every statement needs an authenticated session, so the CLI authenticates when
it connects. It takes credentials from, in order: the -user/-password
flags, the config file, HOARDB_ROOT_USER/HOARDB_ROOT_PASSWORD, and finally
data/root.password in the directory you run it from. Run it from anywhere
else with none of those set and it says what to do:
Failed to connect to 127.0.0.1:7433: no credentials
pass -user <name> -password <password>, or set the environment:
HOARDB_ROOT_USER=admin HOARDB_ROOT_PASSWORD=<password> hoardDB-cli
the server's root user comes from HOARDB_ROOT_USER/HOARDB_ROOT_PASSWORD
when the server is started
A wrong password:
Failed to connect to 127.0.0.1:7433: authenticate as admin: authentication failed (CREDENTIALS): invalid username or password
Flags
| Flag | What it does |
|---|---|
-address <host:port> | The server’s client port. Default localhost:7433. |
-user <name>, -password <pw> | Credentials for this session. |
-auth-token <token> | Resume a session with a token instead of a password (also HOARDB_AUTH_TOKEN). |
-insecure | Skip certificate verification. Local development only. |
-extjson | Print dates in scan and search results as {"$date": "..."} instead of plain strings. |
-theme <path or plain> | Prompt theme; plain turns colour off. |
-password-file <path>, -password-stdin | Where create user and alter user ... password read a new password in a script. |
-config <path> | A YAML configuration file. |
-debug | Print each parsed statement before running it. |
-v, -version | Print the version and exit without connecting. |
There is no flag that runs a single statement. Pipe statements into the CLI instead, as the next section shows.
How statements are read
The CLI reads one statement per line, from the terminal or from standard input:
hoardDB-cli -address 127.0.0.1:7433 -insecure <<'EOF'
use shop
db.Users.count()
EOF
These rules come from the parser, and each one was checked against it:
- One statement per line. A trailing
;is optional, and so are several of them (db.Users.count();;works). A;in the middle does not separate statements:use shop; show bucketslooks for a database calledshop;. - A statement cannot span lines. A document broken across lines is refused
at the first line:
parse: parse args: expected parentheses, got: ({. Write documents on one line. - Put the
;straight after the closing parenthesis.db.Users.find({Name: "Ada"}) ;, with a space before the semicolon, is refused asexpected parentheses. - Keywords and verbs are case-insensitive; names are not.
SHOW DATABASES,DB.Users.count()anddb.Users.COUNT()all work.db.users.count()looks for a bucket calledusersand does not findUsers. - There are no comments.
--and/* */are refused asparse: unknown command: --andparse: unknown command: /*. (The CLI’s ownhelptext still lists them; the help text is wrong.) - An argument cannot contain
(. The parser finds the method call at the last opening parenthesis on the line, so a(inside an argument breaks the statement. This is whyISODate("...")does not work at the prompt; see Dates. - Documents accept relaxed syntax. Strict JSON, unquoted keys, single quotes and a trailing comma are all accepted:
[h]oardDB [shop]> db.Users.insert({"Name": "Grace", "Email": "grace@example.com", "Age": 17, "Status": "trial"})
OK id=01a0de60-9e4c-77c4-aea1-1274ceba1389
[h]oardDB [shop]> db.Users.insert({Name: 'Linus', Email: 'linus@example.com', Age: 29, Status: 'banned',})
OK id=01a0de60-9e4c-799e-8bee-d9b6b2dc4d1b
A script stops at the first failing statement. Piped input is
non-interactive: the CLI prints CLI error: <reason>, runs nothing after it,
and exits with status 1, so a script never carries on from a wrong
assumption. At a terminal the same failure prints Error: <reason> and the
session continues.
Databases
Works. create database, use, show databases, describe database and
drop database.
[h]oardDB> create database shop
OK created database shop
Next: use shop
Then: create bucket <name> {type: hash | btree | fifo | lifo | heap | blob} (hash is the default)
[h]oardDB> use shop
Switched to database 'shop'
[h]oardDB [shop]> show databases
DATABASES
---
NAME BUCKETS PATH
shop 0 data/shop
[h]oardDB [shop]> describe database shop
DATABASE shop
---
Buckets: 0
show dbs and create db <name> are accepted spellings. Creating a database
does not switch to it; run use next, as the hint says. use checks that the
database exists, so a typo fails at once instead of at the next statement:
[h]oardDB> use Nope
Error: database "Nope" not found — this server has no databases yet; create one with 'create database Nope'
[h]oardDB> create database shop
Error: database "shop" already exists
drop database <name> deletes the database and every bucket in it.
Refused: a replication factor on a database. The factor belongs to the bucket, and the refusal explains why the clause is not simply ignored:
[h]oardDB> create database app2 with replication_factor 3
Error: parse: replication_factor is not a database-level setting: this clause was accepted and ignored, so database "app2" would have been created with the node-wide factor and no extra copies. The factor belongs to the bucket — run 'create database app2', then 'create bucket <name> { replication_factor: N }'. That per-bucket clause is parsed but the server does not honour it yet; until it does, HOARDB_REPLICATION_FACTOR is what decides how many copies a bucket has
Buckets
A bucket has exactly one store type, chosen when you create it. There are
six: hash, btree, fifo, lifo, heap and blob.
Store types explains how to choose between them.
create bucket
Works. The braces carry the type and, optionally, the fields to index:
create bucket <name> [in <database>] { type: <store type> [, indices: ["<field>", ...]] }
[h]oardDB [shop]> create bucket Users { type: hash, indices: ["Email"] }
OK created bucket shop.Users (type hash)
Indexes: [Email]
[h]oardDB [shop]> create bucket Ledger { type: btree }
OK created bucket shop.Ledger (type btree)
[h]oardDB [shop]> create bucket Jobs { type: fifo }
OK created bucket shop.Jobs (type fifo)
[h]oardDB [shop]> create bucket Undo { type: lifo }
OK created bucket shop.Undo (type lifo)
[h]oardDB [shop]> create bucket Alerts { type: heap }
OK created bucket shop.Alerts (type heap)
[h]oardDB [shop]> create bucket Files { type: blob }
OK created bucket shop.Files (type blob)
Other forms the CLI accepts:
- No braces:
create bucket Cachemakes ahashbucket, the default. - No braces, with a type:
create bucket Events type fifo. b+treeis accepted as a spelling ofbtree.in <database>creates the bucket withoutuse:create bucket Remote in shop { type: hash }.
An unknown type is refused, and the refusal lists the valid ones:
[h]oardDB [shop]> create bucket Bad { type: queue }
Error: unknown bucket type "queue" — valid types: hash, btree, fifo, lifo, heap, blob
Indexes are declared at creation and cannot be added later (see
alter bucket). An index serves
search, which is equality lookup.
Three traps in create bucket, all checked against this build:
- Creating a bucket that already exists answers
OKand changes nothing.create bucket Users { type: fifo }on the existing hash bucket above printsOK created bucket shop.Users (type fifo), anddescribe bucket Usersstill saysType: hash, with the same entries and index. Check withshow bucketsbefore you rely on a create. replication_factorin the braces is accepted and not honoured.create bucket Rf { type: hash, replication_factor: 3 }answersOK, and the bucket gets the node-wide factor (HOARDB_REPLICATION_FACTOR). The clause is parsed so that it works unchanged once the server honours it.- A dotted name is one flat bucket.
create bucket Post.Comments { type: fifo }creates a single top-level bucket whose name contains a dot, stored atdata/shop/Post.Comments. It is not a sub-bucket ofPost. Avoid dots in bucket names: when nested buckets ship (below), a dotted name will be ambiguous.
Planned: fields and per-field store types (nested buckets)
Planned — the CLI does not accept this grammar yet. A bucket that declares its fields, where a field can be a store of its own, is due in v1.0; see Limitations: bucket engines. This is the shape it will take:
-- Planned. Not accepted by this build.
create bucket Post {
Caption string,
Photos blobStore,
Comments fifoStore
};
The six field store types are fifoStore, lifoStore, hashStore,
btreeStore, heapStore and blobStore. A store field belongs to each
document, not to the bucket: Comments fifoStore on Post means every post
has its own comments queue. That is the point of the design, and it is a
different thing from a bucket that contains a queue. The nested-buckets
specification describes the model in full.
What the current build does if you type it anyway. It does not refuse the
statement, and this is the part to know. Written on one line, the statement
creates a plain hash bucket and silently drops every declaration:
[h]oardDB [app]> create bucket User { _id_ uuid auto, FirstName string required, Email string unique, Friends heapStore };
OK created bucket app.User (type hash)
[h]oardDB [app]> describe bucket User
BUCKET app.User
---
Type: hash
Entries: 0
On disk: 0 B
Indexes: (none — declare them when you create the bucket)
Path: data/app/User
Written across lines as above, the first line creates Post as a hash
bucket before the second line is refused (parse: unknown command: _id_). In
both cases you have a bucket with no fields, no field stores and no
constraints. Use the one-type form until nested buckets ship, and drop any
bucket you created with this grammar.
show buckets, describe bucket, stats
Works.
[h]oardDB [shop]> show buckets
BUCKETS in shop
---
NAME TYPE ENTRIES
Alerts heap 0
Files blob 0
Jobs fifo 0
Ledger btree 0
Undo lifo 0
Users hash 0
[h]oardDB [shop]> describe bucket Users
BUCKET shop.Users
---
Type: hash
Entries: 0
On disk: 0 B
Indexes: Email (equality)
Path: data/shop/Users
show buckets in <database> works without use. db.<bucket>.stats()
prints the same facts as describe bucket, without the path. A bucket that does not exist is
named in the refusal, with the command to create it:
[h]oardDB [shop]> describe bucket Nope
Error: describing bucket "Nope": server error (1): bucket not found: bucket "Nope" not found in database "shop". Run 'show buckets in shop' to list what exists, or 'create bucket Nope in shop { type: hash }' to create it
drop bucket
Works. Dropping deletes the bucket’s data. The space comes back in the background:
[h]oardDB [shop]> drop bucket Cache
OK bucket "Cache" dropped from "shop". Its space is reclaimed in the background; watch hoarddb_reclaim_pending_records to follow it.
alter bucket
Refused. A bucket’s type and indexes are fixed at creation. The refusal names the workaround and its cost:
[h]oardDB [shop]> alter bucket Users { indices: ["Name"] }
Error: altering bucket "Users" is not supported yet
declare indexes when you create the bucket:
create bucket Users { type: hash, indices: ["Email"] }
to change indexes on an existing bucket, drop and recreate it —
note that dropping deletes its data: 'drop bucket Users'
Changing a bucket’s store type in place is planned for v1.1; see Limitations: bucket engines.
define bucket
Refused, by design. define bucket is the old name of create bucket. It
is kept as a named error rather than removed, so that old scripts fail loudly:
[h]oardDB [shop]> define bucket Users { type: hash }
Error: parse: define was renamed: use 'create bucket <name> { type: hash }'
(run 'help' for the full command list)
Documents: hash and btree buckets
Every bucket verb has the form db.<bucket>.<verb>(<arguments>) and applies to
the database chosen with use. Without one:
[h]oardDB> db.Users.find()
Error: no database selected — run 'use <database>' first ('show databases' lists what exists)
insert and _id_
Works. insert stores a document and prints its key. The key is the
_id_ field; leave it out and the server generates a time-ordered UUID:
[h]oardDB [shop]> db.Users.insert({_id_: "ada", Name: "Ada", Email: "ada@example.com", Age: 36, Status: "active"})
OK id=ada
[h]oardDB [shop]> db.Users.insert({_id_: "alan", Name: "Alan", Email: "alan@example.com", Age: 41, Status: "active"})
OK id=alan
[h]oardDB [shop]> db.Users.insert({"Name": "Grace", "Email": "grace@example.com", "Age": 17, "Status": "trial"})
OK id=01a0de60-9e4c-77c4-aea1-1274ceba1389
_id_ must be a string. db.Users.insert({_id_: 7, n: 1}) answers OK
with a generated key, and the 7 is not stored anywhere. Write _id_: "7".
Only _id_ is the key on insert. A field called id or key is stored as an
ordinary field, and that has a consequence for find, described next.
find: one document by key
Works. A bare key, or a document naming the key, is a point read:
[h]oardDB [shop]> db.Users.find("ada")
{"Age": 36, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
[h]oardDB [shop]> db.Users.find({_id_: "alan"})
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
[h]oardDB [shop]> db.Users.find("nobody")
NOT FOUND
get is the same point read on hash and btree buckets:
db.Users.get("ada") prints the same line.
A filter that names _id_, id, key or _key_ is a point read, and its
other fields are ignored. The CLI treats all four names as the key.
find({Status: "active", _id_: "ada"}) returns Ada without checking Status.
Worse, a document stored with a field called key cannot be filtered on it:
[h]oardDB [shop]> db.Users.insert({_id_: "sku-1", key: "blue", id: 7})
OK id=sku-1
[h]oardDB [shop]> db.Users.find({key: "blue"})
NOT FOUND
That find looked up a document whose key is blue. Avoid id, key and
_key_ as field names.
find: scan with a filter
Works. With no argument, or a filter that names no key field, find scans
the bucket and returns up to 100 documents:
[h]oardDB [shop]> db.Users.find()
{"Age": 17, "Email": "grace@example.com", "Name": "Grace", "Status": "trial", "_id_": "01a0de60-9e4c-77c4-aea1-1274ceba1389"}
{"Age": 29, "Email": "linus@example.com", "Name": "Linus", "Status": "banned", "_id_": "01a0de60-9e4c-799e-8bee-d9b6b2dc4d1b"}
{"Age": 36, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
[h]oardDB [shop]> db.Users.find({Status: "active"})
{"Age": 36, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
[h]oardDB [shop]> db.Users.find({Status: "nobody"})
NO MATCHES
find({}) is the same as find(). A filter needs no index: the server walks
the bucket in its natural order and applies the filter itself. Hash and btree
buckets walk by key ascending; fifo walks oldest first, lifo newest first, and
heap highest priority first. On a large bucket that is a walk of the whole
bucket, so use search on an indexed field
for a hot query. The filter operators are listed under
Query and update operators.
A bare value is an exact match. There is no wildcard. find({Name: "A*"})
looks for the literal two characters A* and prints NO MATCHES. Use
$regex: find({Name: {$regex: "^A"}}).
Paging, sort and projection
Works. A second document carries skip, limit, sort and projection.
When more matches exist than the page holds, the CLI prints the exact total
and the next command to run:
[h]oardDB [shop]> db.Users.find({}, {limit: 2})
{"Age": 17, "Email": "grace@example.com", "Name": "Grace", "Status": "trial", "_id_": "01a0de60-9e4c-77c4-aea1-1274ceba1389"}
{"Age": 29, "Email": "linus@example.com", "Name": "Linus", "Status": "banned", "_id_": "01a0de60-9e4c-799e-8bee-d9b6b2dc4d1b"}
showing 2 of 4 — next: find({}, {skip: 2})
[h]oardDB [shop]> db.Users.find({}, {sort: {Age: -1}, limit: 2})
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
{"Age": 36, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
showing 2 of 4 — next: find({}, {skip: 2})
[h]oardDB [shop]> db.Users.find({Status: "active"}, {projection: {Name: 1}})
{"Name": "Ada"}
{"Name": "Alan"}
[h]oardDB [shop]> db.Users.find({}, {projection: {Email: 0, Age: 0}, limit: 1})
{"Name": "Grace", "Status": "trial", "_id_": "01a0de60-9e4c-77c4-aea1-1274ceba1389"}
showing 1 of 4 — next: find({}, {skip: 1})
A page that is exactly full, with nothing after it, prints no next line.
In sort, 1 means ascending and -1 descending. In projection, 1
includes a field and 0 excludes it. An inclusion projection leaves out
_id_ unless you name it.
Refused: sorting by more than one field.
[h]oardDB [shop]> db.Users.find({}, {sort: {Age: 1, Name: -1}})
Error: find failed: server error (5): sorting by more than one field is not supported yet: this query sorts by Age, Name. To fix it, sort by one field (for example {sort: {Age: 1}}), or sort the result in your client
sort does not make paging safe. There is no server-side cursor and no
snapshot. Each page is a fresh scan that sorts the whole matched set and only
then applies skip and limit, so a write between two pages renumbers every
document after it. An insert ahead of the page boundary shows you a document
twice, and a delete ahead of it hides one entirely. Stop writes before paging
through a bucket you must read completely, or read it in one page with a
limit above the match count. See Limitations: queries.
update
Works. update takes the key, as a string or as {_id_: ...}, and an
operator document. It prints the whole document after the change:
[h]oardDB [shop]> db.Users.update("ada", {$set: {City: "London"}, $inc: {Age: 1}})
OK updated "ada"
{"Age": 37, "City": "London", "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
[h]oardDB [shop]> db.Users.update({_id_: "ada"}, {$unset: ["City"]})
OK updated "ada"
{"Age": 37, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
update changes one document, named by its key. There is no update by
filter. A key that does not exist is refused, not created:
[h]oardDB [shop]> db.Users.update("ghost", {$set: {City: "Paris"}})
Error: document "ghost" not found in shop.Users — insert it first or use find to check the key
The operators are $set, $unset and $inc; see
update operators for their rules and the ones that are
refused.
delete
Works. delete takes one key:
[h]oardDB [shop]> db.Users.delete("sku-1")
OK deleted "sku-1"
delete answers OK whether or not the key existed. Deleting a key that
was never there prints OK deleted "..." too. Use find first if you need to
know.
Refused: delete by filter.
[h]oardDB [shop]> db.Users.delete({Status: "banned"})
Error: delete needs a key: db.Users.delete("my-key")
count, length, distinct
Works. count and length are the same verb. Both take an optional
filter:
[h]oardDB [shop]> db.Users.count()
4
[h]oardDB [shop]> db.Users.count({Status: "active"})
2
[h]oardDB [shop]> db.Users.distinct("Status")
"trial"
"banned"
"active"
[h]oardDB [shop]> db.Users.distinct("Status", {Age: {$gt: 20}})
"banned"
"active"
search: the indexed fast path
Works, for equality on a declared index. search answers from an index
instead of walking the bucket:
[h]oardDB [shop]> db.Users.search({Email: "alan@example.com"})
Found 1 results:
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
On a field with no index, search does not fall back to a scan. The server
says so:
[h]oardDB [shop]> db.Users.search({Name: "Ada"})
Error: search failed: field Name is not indexed
That is the server’s reply, not a bug: use find({Name: "Ada"}) to scan, or
recreate the bucket with indices: ["Name"]. Operators do not work in
search. $in and $gt on an indexed field are refused:
[h]oardDB [shop]> db.Users.search({Email: {$gt: "b"}})
Error: search failed: encoding query value for Email: value type cannot be a btree key or an indexed field: map[string]interface {} (supported: null, bool, number, date, string, binary)
(help operators lists range operators for search. That help text is
wrong.)
Query and update operators
Filter operators
These work in find and count filters, and in the filter argument of
distinct:
| Operator | Meaning | Example |
|---|---|---|
| bare value | exact match | {Status: "active"} |
$gt $gte $lt $lte | comparison: numbers numerically, strings in byte order | {Age: {$gte: 36}} |
$in | value is one of a list | {Status: {$in: ["trial", "banned"]}} |
$nin | value is none of a list | {Status: {$nin: ["active"]}} |
$ne | not equal | {Status: {$ne: "active"}} |
$exists | field present (true) or absent (false) | {Nick: {$exists: false}} |
$regex | Go regular expression, unanchored | {Name: {$regex: "^A"}} |
$and | every condition matches (top level) | {$and: [{Status: "active"}, {Age: {$gte: 40}}]} |
$or | any condition matches (top level) | {$or: [{Name: "Ada"}, {Age: 17}]} |
Each row was run against the Users bucket above:
[h]oardDB [shop]> db.Users.find({$and: [{Status: "active"}, {Age: {$gte: 40}}]})
{"Age": 41, "Email": "alan@example.com", "Name": "Alan", "Status": "active", "_id_": "alan"}
[h]oardDB [shop]> db.Users.find({$or: [{Name: "Ada"}, {Age: 17}]})
{"Age": 17, "Email": "grace@example.com", "Name": "Grace", "Status": "trial", "_id_": "01a0de60-9e4c-77c4-aea1-1274ceba1389"}
{"Age": 36, "Email": "ada@example.com", "Name": "Ada", "Status": "active", "_id_": "ada"}
[h]oardDB [shop]> db.Users.find({Status: {$in: ["trial", "banned"]}})
{"Age": 17, "Email": "grace@example.com", "Name": "Grace", "Status": "trial", "_id_": "01a0de60-9e4c-77c4-aea1-1274ceba1389"}
{"Age": 29, "Email": "linus@example.com", "Name": "Linus", "Status": "banned", "_id_": "01a0de60-9e4c-799e-8bee-d9b6b2dc4d1b"}
$regex is unanchored, so {$regex: "o"} matches every value containing an
o. Anchor it with ^ and $ to match a whole value.
Refused, by name. Any other operator is an error that lists what is
supported, never an empty result. $eq, $not, $all, $elemMatch,
$size and $nor are all refused:
[h]oardDB [shop]> db.Users.find({Age: {$eq: 36}})
Error: find failed: server error (5): unsupported filter operator "$eq": this version supports $gt, $gte, $lt, $lte, $in, $nin, $ne, $exists and $regex on a field
[h]oardDB [shop]> db.Users.find({$nor: [{Name: "Ada"}]})
Error: find failed: server error (5): unsupported filter operator "$nor": this version supports $and, $or, $ne, $exists, $nin at the top level
For $eq, write the bare value: {Age: 36}.
Dates
A date is written in its Extended JSON form, {"$date": "<RFC 3339>"}. It is
stored as a date, not a string, and compares by instant:
[h]oardDB [shop]> create bucket Events { type: hash }
OK created bucket shop.Events (type hash)
[h]oardDB [shop]> db.Events.insert({_id_: "e1", ts: {"$date": "2026-02-01T00:00:00Z"}})
OK id=e1
[h]oardDB [shop]> db.Events.find({ts: {$gt: {"$date": "2026-01-01T00:00:00Z"}}})
{"_id_": "e1", "ts": "2026-02-01T00:00:00Z"}
A date field only matches a date operand. {ts: {$gt: "2026-01-01"}}
compares a date with a string and prints NO MATCHES.
Dates print as RFC 3339 strings. With -extjson, dates in find() scans and
search results print as {"$date": "..."} instead, which keeps their type
when you copy the output back in. A point read, find("<key>"), prints the
plain string with or without the flag.
Refused at the prompt: ISODate("..."), new Date("...") and now().
The document parser understands them, but each contains a ( inside the
argument, which the statement parser cannot handle (see
How statements are read). The statement fails
before it reaches the server:
[h]oardDB [shop]> db.Events.find({ts: {$gt: ISODate("2026-01-01")}})
Error: unknown bucket method "find({ts: {$gt: isodate" — run 'help' for the supported operations
[h]oardDB [shop]> db.Events.insert({_id_: "now", at: now()})
Error: unknown bucket method "insert({_id_: \"now\", at: now" — run 'help' for the supported operations
Use {"$date": "..."} until this is fixed. There is no server-clock function
you can use from the prompt.
Update operators
| Operator | Form | Rule |
|---|---|---|
$set | {$set: {field: value}} | sets one or more fields |
$unset | {$unset: ["field", ...]} | a list of field names |
$inc | {$inc: {field: N}} | adds a whole number |
$unset takes a list, not a document:
[h]oardDB [shop]> db.Users.update("ada", {$unset: {City: ""}})
Error: $unset needs a list of field names: {$unset: ["a", "b"]}
$inc truncates a fraction without saying so. {$inc: {Age: 1.5}}
answers OK and adds 1. Pass whole numbers.
Refused: every other update operator, and upsert. The refusal lists the three that work:
[h]oardDB [shop]> db.Users.update("ada", {$push: {Tags: "x"}})
Error: $push is not supported — supported update operators: $set, $unset, $inc
[h]oardDB [shop]> db.Users.update("ada", {$set: {City: "Paris"}}, {upsert: true})
Error: upsert is not supported — supported update operators: $set, $unset, $inc
(help operators also lists $push, $addToSet, $mul, $min, $max and
$rename as update operators. They are refused, as above; the help text is
wrong.)
Queues: fifo and lifo
Works. A fifo bucket returns the oldest entry first and a lifo bucket
the newest. Both use the same verbs:
[h]oardDB [shop]> db.Jobs.push({task: "resize", img: "a.jpg"})
OK id=01a0de61-859c-78cc-ab71-0306b893ec9f
[h]oardDB [shop]> db.Jobs.push({task: "resize", img: "b.jpg"})
OK id=01a0de61-85d6-7146-8d62-ff10337a3d1d
[h]oardDB [shop]> db.Jobs.length()
2
[h]oardDB [shop]> db.Jobs.peek()
{"_id_": "01a0de61-859c-78cc-ab71-0306b893ec9f", "img": "a.jpg", "task": "resize"}
[h]oardDB [shop]> db.Jobs.pop()
{"_id_": "01a0de61-859c-78cc-ab71-0306b893ec9f", "img": "a.jpg", "task": "resize"}
[h]oardDB [shop]> db.Jobs.pop()
{"_id_": "01a0de61-85d6-7146-8d62-ff10337a3d1d", "img": "b.jpg", "task": "resize"}
[h]oardDB [shop]> db.Jobs.pop()
EMPTY
The same verbs on a lifo bucket return the newest entry first:
[h]oardDB [shop]> db.Undo.push({op: "type", text: "hello"})
OK id=01a0de61-8864-705e-a7f7-111cacd00a0b
[h]oardDB [shop]> db.Undo.push({op: "delete", text: "o"})
OK id=01a0de61-889c-7185-8dd9-a99c12b3a9a2
[h]oardDB [shop]> db.Undo.pop()
{"_id_": "01a0de61-889c-7185-8dd9-a99c12b3a9a2", "op": "delete", "text": "o"}
find() lists a queue without consuming it, in pop order, and insert on a
queue is the same as push.
Refused: peek(N), and get on a queue.
[h]oardDB [shop]> db.Jobs.peek(2)
Error: peek(N) is not supported: the server returns one item per peek
walk the queue with db.Jobs.peek() and db.Jobs.pop()
[h]oardDB [shop]> db.Jobs.get("x")
Error: db.Jobs.get() is not defined for fifo buckets — they are read by position:
db.Jobs.peek() shows the next entry without removing it
db.Jobs.pop() removes and returns the next entry
Heap
Works. A heap bucket returns the highest priority first. priority is
a whole number that orders the entry; it is not stored in the document:
[h]oardDB [shop]> db.Alerts.push({priority: 5, msg: "High CPU", host: "node-2"})
OK id=01a0de61-89c0-7d7c-8b50-9ff40ccfa833
[h]oardDB [shop]> db.Alerts.push({priority: 10, msg: "Disk full", host: "node-1"})
OK id=01a0de61-89f9-7e08-bf1e-80403a1448cc
[h]oardDB [shop]> db.Alerts.push({priority: 8, msg: "Slow peer", host: "node-3"})
OK id=01a0de61-8a2e-7143-a76f-e931773c5231
[h]oardDB [shop]> db.Alerts.peek()
{"_id_": "01a0de61-89f9-7e08-bf1e-80403a1448cc", "host": "node-1", "msg": "Disk full"}
[h]oardDB [shop]> db.Alerts.pop()
{"_id_": "01a0de61-89f9-7e08-bf1e-80403a1448cc", "host": "node-1", "msg": "Disk full"}
[h]oardDB [shop]> db.Alerts.pop()
{"_id_": "01a0de61-8a2e-7143-a76f-e931773c5231", "host": "node-3", "msg": "Slow peer"}
A push with no priority is accepted at priority 0. length(), count()
and find() work as on a queue. get is refused, as on a queue:
db.Alerts.get() is not defined for heap buckets — use db.Alerts.peek() for the highest-priority entry, or db.Alerts.pop() to remove it.
B-tree ranges
Works. A btree bucket keeps its keys in order. insert, find, get,
update, delete, count and the filters all work as on a hash bucket. It
adds range, first and last:
[h]oardDB [shop]> db.Ledger.insert({_id_: "2026-01-03", amount: 120})
OK id=2026-01-03
[h]oardDB [shop]> db.Ledger.insert({_id_: "2026-01-01", amount: 40})
OK id=2026-01-01
[h]oardDB [shop]> db.Ledger.insert({_id_: "2026-01-02", amount: 75})
OK id=2026-01-02
[h]oardDB [shop]> db.Ledger.insert({_id_: "2026-02-10", amount: 5})
OK id=2026-02-10
[h]oardDB [shop]> db.Ledger.range({$gte: "2026-01-01", $lte: "2026-01-31"})
3 entries in range:
2026-01-01 {"_id_": "2026-01-01", "amount": 40}
2026-01-02 {"_id_": "2026-01-02", "amount": 75}
2026-01-03 {"_id_": "2026-01-03", "amount": 120}
[h]oardDB [shop]> db.Ledger.range({$gte: "2026-02-01"})
1 entry in range:
2026-02-10 {"_id_": "2026-02-10", "amount": 5}
[h]oardDB [shop]> db.Ledger.first()
first: 2026-01-01
{"_id_": "2026-01-01", "amount": 40}
[h]oardDB [shop]> db.Ledger.last()
last: 2026-02-10
{"_id_": "2026-02-10", "amount": 5}
The bounds of range apply to the key, and are written at the top level:
{$gte: low, $lte: high}. Either one may be left out. Both are inclusive.
Keys compare as strings, which is why dates written as YYYY-MM-DD sort
correctly. A document inserted without an _id_ gets a generated key, and
that key sorts among yours.
The field form, which names a field before the bounds, is refused:
[h]oardDB [shop]> db.Ledger.range({_id_: {$gte: "2026-01-01"}})
Error: range needs bounds: db.Ledger.range({$gte: "a", $lte: "z"})
To order by a field that is not the key, use find with that field in
sort, or make that field the key. range, first and last on a bucket
that is not a btree are refused with the bucket’s actual type:
[h]oardDB [shop]> db.Users.range({$gte: "a"})
Error: range failed: server error (5): bucket "Users" is type hash; this operation requires type btree
Blob
Works. A blob bucket stores a payload and its metadata under a key.
put takes the payload from the data field; every other field except the
key is stored as metadata:
[h]oardDB [shop]> db.Files.put({_id_: "hello.txt", data: "hello, world", type: "text/plain"})
OK key=hello.txt blob=01a0de61-f88c-730a-b5c6-a00262986153 12 B
[h]oardDB [shop]> db.Files.get("hello.txt")
Key: hello.txt
Blob: 01a0de61-f88c-730a-b5c6-a00262986153
Size: 12 B
Metadata: {"type": "text/plain"}
Data:
hello, world
[h]oardDB [shop]> db.Files.info("hello.txt")
Key: hello.txt
Blob: 01a0de61-f88c-730a-b5c6-a00262986153
Size: 12 B
Metadata: {"type": "text/plain"}
[h]oardDB [shop]> db.Files.get({_id_: "hello.txt", out: "hello-copy.txt"})
OK wrote hello-copy.txt (12 B)
[h]oardDB [shop]> db.Files.delete("hello.txt")
OK deleted "hello.txt"
getprints the payload when it is text. For binary content it prints the size and asks you to re-run with{out: "file"}.outwrites the file on the machine running the CLI, relative to the directory you started it in, readable only by you (mode0600).- Without
data, the whole document is stored as the payload, as JSON. With no_id_, a key is generated. find("<key>")on a blob bucket returns the metadata as a document, andcount()counts the keys.
Refused: scanning a blob bucket, and streaming.
[h]oardDB [shop]> db.Files.find()
Error: db.Files.find() does not scan blob buckets: a blob's value is binary content, not a document. Use db.Files.info("<key>") for one key's metadata, or db.Files.get("<key>") to read the content.
[h]oardDB [shop]> db.Files.stream({_id_: "hello.txt"})
Error: streaming is not available yet
the transport defines OpStreamOpen but the server does not implement
chunked reads. Read the whole blob instead:
db.Files.get({_id_: "key"}) print it
db.Files.get({_id_: "key", out: "f.bin"}) write it to a file
A single request is capped at 32 MiB, so a larger payload has to be split
before you put it. A dump does not capture blob payloads yet; see
Backup and restore.
Verbs that are not what they look like
Each of these was run against this build. Most of them are also covered in the section for their verb.
push,popandpeekare the same three requests for every store type. The CLI always sends the queue requests, and the server decides by the bucket’s type. That is why one set of verbs serves fifo, lifo and heap. On other types the result varies.pushon a hash bucket is an ordinary insert (OK id=...), whilepopandpeekon a hash bucket printEMPTYeven when it holds documents.pushon a blob bucket printsERR push not supported for bucket type blob. In a script that refusal does not stop the run, and the exit status stays0.getdepends on the store type. On hash and btree it is a point read, the same asfind("<key>"). On blob it returns the payload. On fifo, lifo and heap it is refused with the verb that works there.searchnever scans. On a field without an index it answersfield X is not indexedrather than walking the bucket. That is the server’s reply, not a bug.findis the verb that scans.- A filter naming
_id_,id,keyor_key_is a point read. Its other fields are ignored. See find: one document by key. define bucketis a rename error, kept on purpose so old scripts fail loudly. Usecreate bucket.create bucketon an existing name answersOKand changes nothing.- A dotted bucket name is one flat bucket, not a sub-bucket.
help <topic>prints the general help. The topic word is dropped, sohelp hashprints the same page ashelp.get-tokenandrotate-tokenact on the machine you run the CLI on. They read and rewrite thecluster.tokenfile in the CLI’s data directory (by default./data). They do not ask the server.
Users and roles
User changes are served by the cluster’s master node, which a single server
is for itself. Roles are read, readWrite, dbAdmin, userAdmin,
clusterAdmin, backup, restore and root. Each is bound to a database as
role@database; a role with no database means every database. What each role
grants, and how changes reach open sessions, are covered in
User management.
create user
Works. A password is never part of the statement. At a terminal the CLI asks twice, without echo:
[h]oardDB> create user alice roles [readWrite@shop, read@app]
New password:
Repeat new password:
user "alice" created (config version 2)
In a script, start the CLI with -password-file <path> (a file readable only
by you) or -password-stdin, and it reads the new password from there instead
of asking. create user <name> with no roles creates a user who can do
nothing until granted a role.
Refused: anything after the name other than roles [...], which includes
a password or a braced options document:
[h]oardDB> create user bob { roles: ["readWrite@shop"] }
Error: parse: usage: create user <name> roles [role@db, ...]
Read users back
Works. user list and show users are the same. Neither ever prints a
password hash:
[h]oardDB> user list
USERS (master: dalek-dev at 0.0.0.0:4433, config version 3)
---
admin: enabled, roles [root@*], epoch 0
alice: enabled, roles [read@app, readWrite@shop], epoch 0
carol: enabled, roles [(none)], epoch 0
[h]oardDB> user describe alice
user: alice
status: enabled
roles: [read@app, readWrite@shop]
epoch: 0
created: 2026-09-26T15:42:59Z
password changed: 2026-09-26T15:42:59Z
master prints the node that serves user changes. On a single server it is
that server, here named after its host:
cluster master for user changes: dalek-dev at 0.0.0.0:4433.
grant and revoke
Works. Each adds or removes one grant. The word role is optional:
[h]oardDB> grant role dbAdmin@shop to alice
granted dbAdmin@shop to "alice" (config version 4)
[h]oardDB> revoke role read@app from alice
revoked read@app from "alice" (config version 5)
Refused: the access form, and a role with an empty name.
[h]oardDB> grant access to "shop" for "alice"
Error: the 'access' form is not supported; grant a role instead:
grant role readWrite@shop to alice
[h]oardDB> grant role @shop to alice
Error: parse: role "@shop" must be <role>@<database> or a bare <role>
alter user, disable, enable, drop
Works.
alter user <name> password -- prompted twice, or -password-file / -password-stdin
alter user <name> disable -- also: disable user <name>
alter user <name> enable -- also: enable user <name>
alter user <name> roles [role@db, ...] -- replaces the whole role set
drop user <name>
[h]oardDB> alter user alice disable
user "alice" altered (config version 7)
[h]oardDB> enable user alice
user "alice" altered (config version 8)
[h]oardDB> drop user carol
user "carol" dropped
[h]oardDB> drop user carol
Error: dropping user "carol": server error (5): drop user "carol": user not found
alter user <name> roles [...] lowercases the role names in this build,
and a lowercased role grants nothing. alter user alice roles [readWrite@shop]
answers altered and stores readwrite@shop. alice is then refused:
Error: find failed: server error (5): permission denied: user "alice" lacks "read" on "shop"
alice's roles: readwrite@shop
ask an administrator to run: grant role read@shop to alice
Until this is fixed, change roles with grant and revoke, which keep the
name as you typed it. For the same reason, use a single-case role such as
read or root if you do use alter user ... roles.
Refused: alter user <name> databases [...]. Database access is part of
the role (readWrite@shop), so there is nothing separate to alter:
[h]oardDB> alter user alice databases ["shop"]
Error: usage: alter user <name> disable|enable|password|roles [role@db, ...]
Cluster and administration
status
Works. The node’s identity, its counts, and a capacity row per resource:
[h]oardDB> status
STATUS
---
Node ID: n1
Version: 0.1.0
Uptime: 11s
Buckets: 1
Entries: 1
Healthy: true
Capacity:
fds 0.00 threshold 0.80 ok
mappings 0.00 threshold 0.80 ok
memory 0.00 threshold 0.80 ok
disk 0.33 threshold 0.85 ok
What the capacity rows mean is covered in Is this node full?.
Cluster verbs
The examples in this section ran on a three-node cluster on one host, each node on its own ports. How to form a cluster is covered in Replication and Configuration.
nodes: works.
[h]oardDB> nodes
NODES
---
n1 127.0.0.1:14433 active 2026-09-26 15:44:57
n2 127.0.0.1:14443 active 2026-09-26 15:44:59
nodes prints the node records the node you are connected to holds. It is
not the committed membership: right after a remove-node, a node can still
list the removed member. The server log line cluster membership change committed is the authority.
join <address>: works on a cluster member. It adds a running node and
starts rebalancing. Name the node as the cluster’s seed list does
(id@host:port):
[h]oardDB> join n3@127.0.0.1:14453
Added n3@127.0.0.1:14453. added n3; cluster now at epoch 2 (data rebalancing)
remove-node <node-id>: works on a cluster member. Run it from a node
other than the one you are removing:
[h]oardDB> remove-node n3
Removed n3. removed n3; cluster now at epoch 3. Migrate the re-homed buckets to their new owners ('migrate <database> <bucket>' on each new owner)
hoardDB never removes a node on its own. See Limitations: cluster.
migrate <database> <bucket>: works on a cluster member. It pulls a
bucket onto the node you are connected to, when that node is its owner:
[h]oardDB> migrate app Orders
bucket "Orders" in "app" is now served by n1
consistent-get <database> <bucket> <key>: works. It reads the freshest
copy across a quorum of the bucket’s holders, and repairs a stale copy on the
way. It prints the document as a list of key and value pairs, not in the
one-line form find uses:
[h]oardDB> consistent-get app Orders o-1
[
{
"Key": "total",
"Value": 42
},
{
"Key": "_id_",
"Value": "o-1"
}
]
A copy that was repaired is marked (repaired), and a missing key prints
not found.
write-concern <one|majority|all>: works. It sets how many copies must
confirm each write for the rest of the session:
[h]oardDB [app]> write-concern all
Write concern set to all for subsequent writes.
[h]oardDB [app]> db.Orders.insert({_id_: "o-1", total: 42})
OK id=o-1
[h]oardDB [app]> write-concern two
Error: unknown write concern "two" — use one, majority, or all
On a single server, join, remove-node and migrate are refused by the
server, and the refusal says why:
[h]oardDB> join 127.0.0.1:59999
Error: join "127.0.0.1:59999": server error (5): replication is not enabled on this node; the node must be a cluster member to add another
[h]oardDB> migrate shop Users
Error: migrate shop Users: server error (5): replication is not enabled on this node; a standalone node has no bucket to migrate
(The CLI’s help lists join and remove-node as “not available yet”. They
are available on a cluster; the help text is out of date.)
connect, get-token, rotate-token
connect <host:port>moves the session to another server and authenticates again. A failedconnectleaves the session with no connection at all, not on the server it was on. The next statement answersnot connected to server, soconnectagain to the address you came from.get-tokenprints the cluster token from thecluster.tokenfile in the CLI’s data directory.rotate-tokenwrites a new one there. Both work on the local file; see Verbs that are not what they look like.
[h]oardDB> rotate-token
Old token: 22f6d9ae1f5cb855cc75f46ee29d6cbd746713d5a7d571ae67218803f6fa757d
New token: 0e77be7f1680837c2717aed272e0acb668ef4c59638e19876fcf20b15bc192c9
Note: The old token is valid for 1 hour during transition.
dump and restore
Works, both as a statement at the prompt and as a command of its own. Flags come before the database and bucket names, because flag parsing stops at the first name:
[h]oardDB> dump --out ./dump-shop shop
dumping shop/Alerts...
shop/Alerts: 2 documents, 314 bytes, sha256:7481de010b1c99cc6827720fb30c1887d885e6e64638b8ebb3edce10fdce6888
(one pair of lines per bucket, then a warning that blob payloads are not captured)
dump: 1 database(s), 7 bucket(s), 17 document(s), 1780 byte(s)
[h]oardDB> restore --dir ./dump-shop --dry-run
(the same blob warning)
shop/Alerts: would merge into existing bucket shop/Alerts (type heap)
(one line per bucket)
restore --dry-run: 1 database(s), 7 bucket(s), 0 document(s) applied, 0 skipped
The lines in parentheses stand in for output cut here for length.
hoardDB-cli dump --out ./dump-one --insecure --json shop Users
{"ok":true,"databases":["shop"],"buckets":1,"documents":5,"users_recreated":0,"users_awaiting_password":0,"bytes":507,"errors":null}
Written the other way round, dump shop --out ./dump-shop is refused with
hoardDB dump [database [bucket]] [flags] — too many positional arguments.
Every flag, and what a dump does and does not capture, is covered in
Backup and restore.
The interactive REPL
Started from a terminal, the CLI is an interactive session with line editing,
history and Tab completion of verbs and bucket names (db.Us then Tab becomes
db.Users). The prompt shows the current database:
[h]oardDB> use shop
Switched to database 'shop'
[h]oardDB [shop]> db.Users.count()
4
[h]oardDB [shop]> bogus
Error: parse: unknown command: bogus
[h]oardDB [shop]> exit
Goodbye.
| Statement | What it does |
|---|---|
help | The command summary. help <topic> prints the same summary; see above. |
version | hoardDB version=devel commit= build_date= protocol=1, without asking the server. |
theme | The prompt theme in use, where it came from, and whether colour is on. |
exit, quit | End the session (Goodbye.). Ctrl-D also ends it. Ctrl-C abandons the line you are typing and keeps the session. |
An unknown statement is refused as parse: unknown command: <word>, an unknown
bucket verb as unknown bucket method "<verb>" — run 'help' for the supported operations, and a verb without parentheses as parse: expected parentheses for method call.
The prompt is coloured on a terminal. Colour is off when output goes to a
pipe, when NO_COLOR is set, when TERM=dumb, or with -theme plain. Your
own theme goes in ~/.hoarddb/theme.yml; see
Configuration: prompt themes.
Configuration as environment variables
The CLI itself reads these:
| Variable | Used for |
|---|---|
HOARDB_ROOT_USER, HOARDB_ROOT_PASSWORD | Credentials when -user/-password are not given. |
HOARDB_AUTH_TOKEN | A session token instead of a password (-auth-token). |
HOARDB_CLUSTER_TOKEN | The cluster token for cluster-management verbs (-token). |
HOARDB_THEME | The prompt theme: a path, or plain. |
NO_COLOR, TERM=dumb | Turn the prompt’s colour off. |
These server settings decide what the statements on this page do:
| Variable | Default | Effect on HQL |
|---|---|---|
HOARDB_TCP_LISTEN | 0.0.0.0:7433 | The address -address connects to. |
HOARDB_DATA_DIR | ./data | Where databases, buckets and root.password live; the Path in describe. |
HOARDB_REPLICATION_FACTOR | 1 | How many copies every bucket has. replication_factor in create bucket does not change it yet. |
HOARDB_WRITE_CONCERN | set by the server; the cluster above logged majority | The default that write-concern overrides for a session. |
HOARDB_SEED_NODES, HOARDB_SEED_FINGERPRINTS, HOARDB_NODE_ID | none | Cluster membership, which nodes, join and migrate need. |
Every setting, with its YAML key, is in Configuration.
Where each statement is accepted
For contributors and for anyone checking this page against a build. The
parser entry point is cli/parser.go:ParseCommand, and bucket verbs are
dispatched by cli/handlers.go:handleBucket.
| Statement | Parsed by | Handled by |
|---|---|---|
use, show, describe | cli/parser.go:parseUse, parseShow, parseDescribe | cli/handlers.go:handleUse, handleShow, handleDescribe |
create database, drop database | cli/parser.go:parseCreate, parseDrop; refuseDatabaseReplicationFactor | cli/handlers.go:handleCreateDatabase, handleDropDatabase |
create bucket | cli/parser.go:parseCreateBucket | cli/handlers.go:handleCreateBucket, parseBucketSchema; types from cli/store_types.go:storeTypes |
drop bucket | cli/parser.go:parseDrop | cli/handlers.go:handleDropBucket |
alter bucket (refused) | cli/parser.go:parseAlter | cli/unsupported_features.go:errAlterBucket |
define (refused) | cli/parser.go:ParseCommand | tested by cli/create_bucket_test.go:TestDefineBucketIsARenameError |
db.<bucket>.<verb>(...) | cli/parser.go:parseBucketMethod, parseArgs; documents by cli/documents.go:parseDocument | cli/handlers.go:handleBucket |
insert | cli/handlers.go:handleInsert | |
find, get | cli/handlers.go:handleFind, planFind, handleGet; key names in cli/documents.go:keyFieldNames | |
| filter operators | server/scan_filter.go:matchesFilter, evalOperator | |
update | cli/handlers.go:handleUpdate, applyUpdateOperators | |
delete | cli/handlers.go:handleDelete | |
count, length, distinct | cli/handlers.go:handleCount, handleDistinct | |
search | cli/handlers.go:handleSearch; store/index_manager.go:IndexManager.Search | |
push, pop, peek | cli/handlers.go:handlePush, handlePop, handlePeek; server/service.go:Server.PushCtx | |
range, first, last | cli/handlers.go:handleRange, handleEdge | |
put, info, blob get | cli/handlers.go:handleBlobPut, handleBlobInfo, handleBlobContent | |
stream (refused) | cli/unsupported_features.go:errStreamUnsupported | |
stats | cli/handlers.go:handleBucketStats | |
create user | cli/parser.go:parseCreateUser | cli/user_commands.go:handleUserCreate |
alter user, disable, enable | cli/parser.go:parseAlter, parseDisableEnable | cli/user_commands.go:handleUserAlter |
drop user | cli/parser.go:parseDrop | cli/user_commands.go:handleUserDrop |
grant, revoke | cli/parser.go:parseGrant, parseRevoke, parseRoleSpec | cli/user_commands.go:handleUserGrant, handleUserRevoke |
user list, user describe, show users, master | cli/parser.go:parseUser, parseShow | cli/user_commands.go:handleUserList, handleUserDescribe, handleMaster |
status, nodes | cli/parser.go:ParseCommand | cli/handlers.go:handleStatus, handleNodes |
join, remove-node, migrate | cli/parser.go:parseJoin, parseRemoveNode, parseMigrate | cli/handlers.go:handleJoin, handleRemoveNode, handleMigrate |
consistent-get, write-concern | cli/parser.go:parseConsistentGet, parseWriteConcern | cli/handlers.go:handleConsistentGet, handleWriteConcern |
connect | cli/parser.go:parseConnect | cli/handlers.go:handleConnect |
get-token, rotate-token | cli/parser.go:ParseCommand | cli/handlers.go:handleGetToken, handleRotateToken |
dump, restore | cli/parser.go:ParseCommand | cli/dump.go:handleDump, handleRestore; standalone RunDumpCommand, RunRestoreCommand |
help, version, theme, exit | cli/parser.go:ParseCommand | cli/handlers.go:handleHelp; cli/cli.go:handle, printTheme |
Legal notes
hoardDB is an independent implementation. HQL’s syntax is JSON-shaped, its wire protocol is its own, and it is not a compatibility layer for any other database. No other database’s tools connect to hoardDB.
Source: docs/user/hql-spec.md in the repository.