Nobody should have to learn a query language to use a database. That sentence cost us one. neSQL is the name for what NEDB now speaks: PostgreSQL's SQL, inherited whole — plus the clauses a permanent, hash-chained store can answer.
The equation
neSQL = PostgreSQL SQL · inherited whole, not reimplemented
+ NEDB SQL · AS OF SYSTEM TIME, VALID AS OF, SEARCH, TRACE, TRAVERSE
The left-hand side is PostgreSQL's real grammar — gram.y, 19,513 lines and 492
keywords, vendored from 17.4 at vendor/postgresql/ with its licence intact. The
right-hand side is added to the grammar, never deviating from it. Why the temporal clauses
were never free: SYSTEM_TIME, PERIOD and PORTION appear
zero times in PostgreSQL's grammar — Postgres has no temporal SQL at all;
AS OF SYSTEM TIME is a CockroachDB extension. What the vendored grammar hands over
free: WITH RECURSIVE, window functions, GROUPING SETS, MERGE.
One evaluator, no flag
The SQL evaluator answers every SELECT it can parse — joins (nested-loop
and hash), subqueries, EXISTS, set operations, DISTINCT, derived tables,
LATERAL, array_agg(x ORDER BY y) — with nothing to enable. The
translator that once served SELECT is kept only for writes and unparsable
statements, so every statement gets an answer rather than a syntax error.
NQL's own verbs are SQL clauses now, and they compose:
-- full-text search from NQL, a join from SQL, one statement
SELECT o._id, d.name FROM orders SEARCH 'acme' o
JOIN drivers d ON o.driver = d._id;
-- one relation in the past, joined against another at the tip
SELECT h.total, n.total FROM orders AS OF SYSTEM TIME 412 h
JOIN audit n ON h._id = n._id;
There is one implementation of each verb — the SQL side parses, the NQL engine executes —
so neither language reimplements the other. AS OF SYSTEM TIME,
VALID AS OF and SEARCH are unreserved keywords: a collection aliased
search keeps working.
Routing is structural
NQL statements begin FROM; PostgreSQL has no statement form that begins with
FROM. The leading keyword partitions the two vocabularies — a first word in neither
is refused naming both, never handed to whichever parser seems likelier. The same router
(nedb_engine::neql::route) serves the daemon's /query endpoint and the
nesql CLI; two implementations of that decision would let the two disagree about
what a statement means, which is worse than disagreeing about a result.
Writes
SQL write semantics line up with append-only storage: INSERT is a put,
UPDATE creates a new version, DELETE writes a tombstone —
and verify() still passes afterwards, because a SQL write is an ordinary engine
write, not a side door. INSERT requires an explicit column list (there is no schema
to infer order from) and literal values only. _caused_by is an insertable column.
TRUNCATE and DDL are refused on purpose: TRUNCATE discards history — that
is the one thing NEDB exists to make impossible — and collections are created by the first write
to them.
The nesql CLI
$ nesql --db ./store query "SELECT who, total FROM orders ORDER BY total DESC"
$ nesql --db ./store query "FROM orders WHERE total > 150"
One query command, two dialects, routed on the leading keyword;
--nql/--sql force a dialect when you want that dialect's error.
Exit codes carry the verdict: 0 success, 1 failure, 2
usage, 3 could not determine (pruned history — a pruned store is not a corrupt
one, and an operator who cannot tell those apart will ignore a real alarm or panic at a routine
one), 4 not found, 5 unsupported. root verify reports the
stored record and the recomputation as two independent facts, never collapsed.
The packages are real and version-aligned with the engine: the crates.io crate
nesql is the CLI itself (cargo add nesql, building against the registry
engine); PyPI nesql and npm nesql-engine carry the language reference. And the
same CLI binary is staged into every platform build of nedb-engine — one install
carries everything. The neSQL repository
is the language's home: vendored grammar, CLI source, NQL reference, NEDB specs.
tools/build_docs_site.py.