@veristamp/nqql-edge
v0.5.0
Published
Local QQL execution for Node.js with qdrant-edge and FastEmbed.
Maintainers
Readme
nqql-edge
Node N-API bindings for local QQL: qdrant-edge + FastEmbed, no remote Qdrant.
Proposition
Same language as @veristamp/nqql, executed in-process (qdrant-edge 0.8).
Cluster features (custom SHARD, GROUP BY … LOOKUP FROM, SHOW QUOTAS /
SET QUOTA, …) return explicit QQL-EDGE-UNSUPPORTED-* errors. Sparse
PARAMS (idf = …), ACORN search params, GROUP BY, and HNSW/optimizer
ALTER COLLECTION are supported offline.
Install
npm install @veristamp/nqql-edgeNode ≥ 18. Platforms: Linux x64, Linux arm64, macOS arm64, Windows x64 (not macOS Intel).
Quick start
const {
localExecutor, listEmbeddingModels, parse, injectFilter, version,
} = require("@veristamp/nqql-edge");
// Model load (and first-use download) runs off the JS thread — await it.
const client = await localExecutor("./qql-data", {
model: "bge-small-en-v1.5",
onDiskPayload: true,
});
await client.execute("CREATE COLLECTION docs HYBRID");
await client.execute('UPSERT INTO docs VALUES {id: 1, text: "hello from edge"}');
const report = await client.execute(
"QUERY TEXT 'hello' FROM docs USING dense LIMIT 5"
);
const [stmt] = parse("QUERY TEXT 'hello' FROM docs USING dense LIMIT 10");
stmt.injectFilter("tenant_id", "=", "acme");
// No custom SHARD on edge — use remote Qdrant for SHARD / CREATE SHARD KEY
await client.close();
console.log(version, listEmbeddingModels().length);WAL footprint
qdrant-edge pre-allocates each write-ahead-log segment (default 32 MiB), which
dominates the on-disk footprint of small embedded shards. Pass whole MiB to
walSegmentMb to shrink it; the resolved capacity persists in the shard's
edge_config.json:
const client = await localExecutor("./qql-data", { walSegmentMb: 8 });When unset, the 32 MiB engine default applies. Zero, negative, fractional, or
overflowing values fail closed with QQL-VALIDATION-CONFIG.
API
| Export | Role |
|--------|------|
| localExecutor(dataDir, options) → Promise<Client> | FastEmbed + edge (model load runs off the JS thread) |
| httpExecutor(dataDir, url, key, model, dim) → Promise<Client> | Edge + HTTP embedder |
| listEmbeddingModels() | ONNX model catalog (multi / image flags included) |
| parse / parseJson / isValid / tokenize | Frontend |
| injectFilter | Isolation |
| stmt.shardKey | AST property; edge rejects SHARD at execute |
| bind(query, params) | Substitute :name (object) or ? (array) |
| compile / explain / execute | Plan / run (options.params same as bind) |
| Client.scrollCursor / scrollCursor, Client.scrollStream / scrollStream | Lazy async scroll iteration + pull-driven WHATWG stream |
Quotas and custom sharding require remote Qdrant; GROUP BY runs offline
(including SIZE / LIMIT / OFFSET, but not LOOKUP FROM). Offline sparse
IDF works: PARAMS (idf = 'global') or PARAMS (idf = WHERE tenant_id = 'acme').
There is deliberately no HttpEmbedder class here: the edge SDK configures its
embedder at construction through localExecutor (on-device ONNX / BM25) or
httpExecutor (OpenAI-compatible endpoint), not per Client. Server-only
options — url, apiKey/api_key, useGrpc/use_grpc,
routeAffinity/route_affinity, embedder — are rejected with a TypeError
pointing at @veristamp/nqql instead of being silently ignored.
