Query model
Every Jnu method takes a query object in the ormdb style. This page is the full grammar as the Jnu service accepts it, with the behaviour of each variant checked against the live scheduler.
The query object
const query = {
table: 'jobs', // policy name; see the data pages
prototype: { status: 'running' }, // partial row every result must match
columns: ['opaqueId', 'name'], // optional: only these columns
order: 'startTime', // or ['startTime', 'id'], or 'random'
desc: true, // sort direction for order
limit: 20,
skip: 0, // with limit, enables totalRowCount
};
Property |
Meaning |
|---|---|
|
Required. The policy name, which is usually the table name. Some tables have several policies, for example |
|
Required, |
|
Restrict the returned columns. Useful on |
|
A column name, an array of column names, or |
|
|
|
Maximum rows. |
|
Rows to skip. When both |
|
For |
Queries are signed with the connection’s identity and expire one hour after they’re made (expiry in makeQuery), so a prepared query can’t be replayed later.
Value descriptors
A prototype value that’s an object is a value descriptor. Properties combine with AND.
Descriptor |
Matches |
|---|---|
|
Equal to |
|
Any of the listed values. |
|
None of the listed values. |
|
Not equal to |
|
|
|
SQL |
|
Case-insensitive |
|
Equal to |
Example: your jobs that are still running or estimating, started in the last 30 days, newest first, three columns only:
const rs = await db.select({
table: 'jobs',
prototype: {
status: { in: ['running', 'estimation'] },
startTime: { min: new Date(Date.now() - 30 * 864e5) },
},
columns: ['opaqueId', 'name', 'startTime'],
order: 'startTime',
desc: true,
limit: 20,
skip: 0,
});
Variants
The methods on a Connection are the select variants plus change, add and delete. What each one returns, as observed on the live service:
Method |
Returns |
|---|---|
|
A |
|
A number. |
|
A number. |
|
A |
|
A number for numeric columns. On a timestamp column |
|
Fails in the client (known issue, see below). Use |
|
Meant to apply |
|
|
|
Variants of |
|
Inserts |
|
Deletes rows matching |
Note
Known issues as of 2026-10-03, expected to be fixed: search() and isearch() match nothing because the client builds the LIKE clause from the wrong object; groupCount() and selectMax() on a timestamp column fail inside the client’s result handling. The workarounds in the table above work today.
A ResultSet holds all rows in memory. rowCount is the number returned, totalRowCount the number matching when paging. Iterate with getFirst() and getNext(), which return false when exhausted, or await rs.rows.forEach(fn).
Errors
Error text |
Meaning |
|---|---|
|
The table has no policy, or your key doesn’t carry that operation. |
|
You filtered on a column the policy doesn’t allow in a where clause. |
|
A |
|
Thrown client-side before sending; every query needs |
Queries that are allowed but match nothing return an empty result, not an error. A job that exists but belongs to someone else looks the same as a job that doesn’t exist.
Values in results
Results are KVIN-serialized, so types survive the trip:
Timestamps are
Dateobjects.ethAddresscolumns areAddressobjects.String(addr)gives the hex form; compare withaddr.eq(other), not===.finNumcolumns (DCC amounts) areBigNumberobjects.Number(String(x))orx.toNumber()gives a float.jsoncolumns are parsed. Integers and floats are plain numbers.
The schema is available on every connection as db.schema.tables[name], with each column’s type under __name, so a program can discover columns and types at run time.