Conversation
The binding is napi-rs and not the C ABI, which is ADR 0002: the ABI is
the specification a client is graded against, and a client that links
the engine's crates directly implements its semantics without paying
for a second copy of every value on the way out.
Every engine call is a task on libuv's threadpool and every method
hands back a promise before the statement has started, so nothing here
can block the event loop. A connection is not thread safe in the
engine, so the one held here sits behind a mutex: not to make it
concurrent, since a statement holds the lock for as long as it runs,
but so that a program which shares one by accident waits rather than
corrupts.
A result is an array of row objects with the projection, the GQLSTATUS
and the notices beside the elements as properties that are not
enumerable, so iterating it is for...of and nothing else and the same
value still spreads, stringifies and compares as the plain array it is.
INT64 is bigint, always, which is ADR 0003. Going the other way a whole
number binds as INT64 and a fractional one as FLOAT, because { id: 1 }
is what a caller writes.
A failure is an ordinary Error carrying every field of the condition,
so nothing has to be parsed back out of a message: code is the
GQLSTATUS, condition is the standard's own words, line and column and
excerpt underline the token, retryable decides whether a retry loop
goes round again. A mistake this client caught before the engine saw it
is named ZuUsageError and carries no code, so a caller mapping codes to
branches can tell a missing one from an unknown one. Both kinds arrive
as a rejection of the promise the call already returned, including a
closed connection and a parameter of a type nothing can bind, so one
await catches everything one statement can do.
Thirty four tests over connecting, statements, values both ways and the
error surface, and a benchmark that measures what this package adds to
the engine by comparing a scan against the same scan with the rows
dropped.
33 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The first working piece of the JS client.
connect,query,exec,close,await using, named parameters both ways, every value the engine has, and the error surface.What it does
The binding is napi-rs and not the C ABI, which is ADR 0002. The ABI is the specification a client is graded against, and a client that links the engine's crates directly implements its semantics without paying for a second copy of every value on the way out.
Every engine call is a task on libuv's threadpool and every method hands back a promise before the statement has started, so nothing here can block the event loop. A connection is not thread safe in the engine, so the one held here sits behind a mutex. That is not a way of making it concurrent, since a statement holds the lock for as long as it runs and two statements that should overlap want two connections. It is there so that a program which shares one by accident waits rather than corrupts.
A result is an array of row objects, with the projection, the GQLSTATUS and the notices beside the elements as properties that are not enumerable. Iterating it is
for...ofand nothing else, and the same value still spreads, stringifies and deep-equals the plain array it is.INT64 is
bigint, always, which is ADR 0003. Going the other way a whole number binds as INT64 and a fractional one as FLOAT, because{ id: 1 }is what a caller writes and refusing it would be pedantry.A failure is an ordinary
Errorcarrying every field of the condition, so nothing has to be parsed back out of a message:codeis the GQLSTATUS and picks the branch,conditionis the standard's own words for it,lineandcolumnandexcerptunderline the token,retryabledecides whether a retry loop goes round again. A mistake this client caught before the engine saw it is namedZuUsageErrorand carries nocode, so a caller mapping codes to branches can tell a missing one from an unknown one. Both kinds arrive as a rejection of the promise the call already returned, including a closed connection and a parameter of a type nothing can bind, so oneawaitcatches everything one statement can do.await usingworks by puttingdisposeon each connection underSymbol.asyncDispose, which is the one thing about the class that the attribute declaring the rest of it cannot spell, since a method's name there is a string and this key is a symbol.Tests and numbers
Thirty four tests over connecting, statements, values both ways and the error surface, all green locally on Node 24. The CI workflow runs fmt, clippy and the suite on Node 24 and 26 across Linux, macOS and Windows.
npm run benchmeasures what this package adds to the engine rather than the engine itself: the same scan with the rows dropped is the floor, and the difference is the row object and one JavaScript value per column. On this machine, twenty thousand rows of two columns scan in about 9 ms against a floor of about 1.8 ms, so the boundary costs roughly 400 ns per row of two columns and about half that per column added.What is not here
Prebuilt binaries under
optionalDependencies,AsyncIterableand Web Streams,AbortSignalwired to the engine's interrupt,bigIntMode,toTemporal()and{ temporal: true }, dual ESM and CJS, and Bun and Deno in CI. They are the remaining lines of DX3 and each one lands with its own tests.Two things worth knowing while reading the tests.
CREATE NODE TABLEis not implemented in the engine yet, so a table is declared by its first insert and that one is written with literals because the engine works out what each column holds from the values it was given. And a read-only connection does not see writes that live only in the.wal, so no test depends on that.Milestone: tamnd/zu#169.