Skip to content

v2.10.0

Choose a tag to compare

@linked-cm-release-bot linked-cm-release-bot released this 30 Jun 07:00
· 360 commits to main since this release
f6cadde

Minor Changes

  • #114 30dd8d4 Thanks @flyon! - Flip the query contract: datasets receive the live query, DSL-JSON is the wire format, and the IR becomes an opt-in store detail behind a free lower().

    Breaking changes (the package is pre-adoption, so this ships as a minor rather than a major — there are no published consumers to protect yet)

    • build() is removed from all builders. Use the free lower(query) function to produce IR:
      import { lower } from "@_linked/core";
      const ir = lower(query); // select or any mutation
    • IDataset methods now receive the live (closed) query object, not IR. A dataset opts into the IR by calling lower(query), or forwards the query as DSL-JSON via query.toJSON():
      class MyStore implements IDataset {
        async selectQuery(query: SelectQuery) {
          return run(lower(query));
        }
      }
    • SelectQuery/CreateQuery/UpdateQuery/DeleteQuery are now closed read-only interfaces (the live query), not aliases of the IR. The IR types are IRSelectQuery / IRCreateMutation / IRUpdateMutation / IRDeleteMutation.
    • QueryBuilder is renamed to SelectBuilder (a deprecated QueryBuilder alias is still exported).

    New: DSL-JSON, the standardized wire format

    Every query — select and every mutation — serializes losslessly to a compact, versioned JSON structure and rehydrates anywhere:

    import { fromJSON } from "@_linked/core";
    const json = query.toJSON(); // builder → DSL-JSON (carries a wire version `v` and the shape)
    await fromJSON(json).exec(); // DSL-JSON → live query → run (kind-detected by `op`)

    See the new DSL-JSON specification for the envelope shapes, value encodings, and versioning.

    New: {$ctx} query-context references

    A query can reference the current context (e.g. the signed-in user) without resolving it yet — it travels on the wire as {$ctx: "user"} and is resolved at lowering time, whether the context is set or unset when the query is built. Works for the select subject, update target, mutation field values, delete ids, and where-clause args:

    Person.select((p) => p.name).for(getQueryContext("user")); // subject: {$ctx:"user"}
    Person.delete(getQueryContext("user")); // delete-by-context (no .for() needed)
    Person.update({ hobby: "x" }).for(getQueryContext("user"));

    Mutations throw UnresolvedContextError if the context isn't set at lowering; selects resolve to null. subscribeQueryContext(fn) is exported as the reactivity primitive for re-running queries when a context lands.

    New / changed exports

    lower, fromJSON, lowerMutationJSON, encodeNodeData, decodeNodeData, subscribeQueryContext, UnresolvedContextError, encodeContextRef, isContextRefJSON, resolveContextId, CONTEXT_REF_KEY, and the types ContextRefJSON / DeleteId / IRSelectQuery / IR*Mutation.

    Tree-shaking

    The IR pipeline (and the SPARQL layer) is reachable only through lower(). A client that builds, serializes, and forwards queries but never lowers them tree-shakes the entire IR + SPARQL pipeline out of its bundle. package.json now declares sideEffects accordingly.