Code generator: a folder of .xsql → committed Clojure source.
Connects to a running Synthigy backend ONCE (op:describe = the XSQL compiler) and emits one namespace per XSQL @namespace, with a named, documented function per operation. The generated code carries NO parser and needs NO backend at runtime — it embeds each op's compiled XSQL source string and sends it via synthigy.client. Connection is a BUILD-time dependency, like Prisma/sqlc/genqlient; commit the output and it runs offline forever after.
clj -X:gen :dir '"xsql"' :out '"src"'
:ns-prefix myapp.ops :endpoint '"http://localhost:7887"'
Auth for the pull: THE APP'S OWN client credentials (:client-id/:client-secret
or SYNTHIGY_CLIENT_ID/SYNTHIGY_CLIENT_SECRET) — /schema + describe are
IAM-filtered per principal, so generating as the app makes the generated
contract exactly what the app can do at runtime (a personal/dev identity
would generate a surface the app can't honor). Grant the client schema:read
(or the broader dataset:load). :token / SYNTHIGY_TOKEN and authless remain
for bare dev servers. Regenerate any time you edit an .xsql — the diff shows
exactly what changed.
Code generator: a folder of .xsql → committed Clojure source.
Connects to a running Synthigy backend ONCE (op:describe = the XSQL
compiler) and emits one namespace per XSQL @namespace, with a named,
documented function per operation. The generated code carries NO parser and
needs NO backend at runtime — it embeds each op's compiled XSQL source string
and sends it via synthigy.client. Connection is a BUILD-time dependency, like
Prisma/sqlc/genqlient; commit the output and it runs offline forever after.
clj -X:gen :dir '"xsql"' :out '"src"' \
:ns-prefix myapp.ops :endpoint '"http://localhost:7887"'
Auth for the pull: THE APP'S OWN client credentials (:client-id/:client-secret
or SYNTHIGY_CLIENT_ID/SYNTHIGY_CLIENT_SECRET) — /schema + describe are
IAM-filtered per principal, so generating as the app makes the generated
contract exactly what the app can do at runtime (a personal/dev identity
would generate a surface the app can't honor). Grant the client `schema:read`
(or the broader `dataset:load`). :token / SYNTHIGY_TOKEN and authless remain
for bare dev servers. Regenerate any time you edit an .xsql — the diff shows
exactly what changed.(cached-ir dir src)The IR in <dir>/ops.ir.json when its sourceHash matches src, else nil.
The IR in `<dir>/ops.ir.json` when its sourceHash matches `src`, else nil.
(check opts)CI gate: verify the committed files under out match what generate
would write, from the saved IR while it is current, else a live describe. Prints each missing/drifted/stale file and throws
(non-zero exit under -X) when anything is out of sync.
clj -X:gen-check :dir '"xsql"' :out '"src"' :ns-prefix myapp.ops
CI gate: verify the committed files under `out` match what `generate` would write, from the saved IR while it is current, else a live describe. Prints each missing/drifted/stale file and throws (non-zero exit under -X) when anything is out of sync. clj -X:gen-check :dir '"xsql"' :out '"src"' :ns-prefix myapp.ops
(check*
operations
{:keys [out ns-prefix] :or {out "src" ns-prefix "synthigy.ops"} :as opts})The offline half of check: diff emit-files output for operations
against what's on disk. Returns {:missing [..] :drifted [..] :stale [..]}
(all empty = in sync). :stale = .clj files under the ns-prefix subtree of
out that the IR no longer produces (deleted ops leaving orphans).
The offline half of `check`: diff `emit-files` output for `operations`
against what's on disk. Returns `{:missing [..] :drifted [..] :stale [..]}`
(all empty = in sync). `:stale` = .clj files under the ns-prefix subtree of
`out` that the IR no longer produces (deleted ops leaving orphans).(describe! dir src)op:describe src against the backend and save it as <dir>/ops.ir.json.
Requires score/*client* to be bound.
op:describe `src` against the backend and save it as `<dir>/ops.ir.json`. Requires `score/*client*` to be bound.
(emit-all operations opts)Emit generated namespaces from IR operations into out under ns-prefix.
No network (drives the proof against a committed ops.ir.json too).
Returns the seq of written paths.
Emit generated namespaces from IR `operations` into `out` under `ns-prefix`. No network (drives the proof against a committed ops.ir.json too). Returns the seq of written paths.
(emit-files operations
{:keys [out ns-prefix] :or {out "src" ns-prefix "synthigy.ops"}})Pure half of the generator: IR operations →
{:files {path {:content s :ops n :batches n}} :skipped [op …]}.
No I/O, no printing — emit-all writes it, check diffs it against disk.
Pure half of the generator: IR `operations` →
`{:files {path {:content s :ops n :batches n}} :skipped [op …]}`.
No I/O, no printing — `emit-all` writes it, `check` diffs it against disk.(generate opts)Emit source from dir's .xsql: offline from a matching ops.ir.json, else
via a live op:describe that also refreshes it and <dir>/schema.json.
:pull true forces the refresh. Returns the seq of written paths.
Emit source from `dir`'s .xsql: offline from a matching `ops.ir.json`, else via a live op:describe that also refreshes it and `<dir>/schema.json`. `:pull true` forces the refresh. Returns the seq of written paths.
(load-ir {:keys [dir pull] :or {dir "xsql"} :as opts})IR operations for dir: the saved ops.ir.json while it matches the
sources (offline), else a live describe that refreshes it. Never returns a
stale IR. :pull true forces the live describe. Returns
{:operations [..] :pulled? bool}.
IR operations for `dir`: the saved `ops.ir.json` while it matches the
sources (offline), else a live describe that refreshes it. Never returns a
stale IR. `:pull true` forces the live describe. Returns
`{:operations [..] :pulled? bool}`.(pull-schema! {:keys [dir] :or {dir "xsql"}})GET /schema → <dir>/schema.json. Nothing at runtime reads this file; it is
the snapshot XSQL editor tooling lints and completes against (xsql-lint,
and the LSP when it lands). Same filename and
same indentation the JS and Go generators write, so a polyglot repo gets one
artifact rather than one per language. Requires score/*client* bound: the
snapshot must describe the same principal the IR did.
GET /schema → `<dir>/schema.json`. Nothing at runtime reads this file; it is the snapshot XSQL editor tooling lints and completes against (`xsql-lint`, and the LSP when it lands). Same filename and same indentation the JS and Go generators write, so a polyglot repo gets one artifact rather than one per language. Requires `score/*client*` bound: the snapshot must describe the same principal the IR did.
(read-files dir)Every .xsql under dir as [{:path :source}] for describe, in read-source order.
Every .xsql under `dir` as `[{:path :source}]` for describe, in `read-source` order.
(read-source dir)Every .xsql under dir (recursive, sorted by relative path) merged into one
describe document; only the first file keeps its @workspace.
Every .xsql under `dir` (recursive, sorted by relative path) merged into one describe document; only the first file keeps its `@workspace`.
Cheshire printer tuned to JSON.stringify(x, null, 2) — byte-identical to
what the JS and Go generators write, so a polyglot repo keeps one artifact.
Cheshire's defaults differ: : between key and value, and inline arrays.
Cheshire printer tuned to `JSON.stringify(x, null, 2)` — byte-identical to what the JS and Go generators write, so a polyglot repo keeps one artifact. Cheshire's defaults differ: ` : ` between key and value, and inline arrays.
(source-hash src)sha256 hex of the merged source — the sourceHash every SDK's generator
stamps on ops.ir.json, so one IR file serves all of them.
sha256 hex of the merged source — the `sourceHash` every SDK's generator stamps on `ops.ir.json`, so one IR file serves all of them.
(warn-stale-schema! {:keys [dir endpoint] :or {dir "xsql"}})One stderr line when <dir>/schema.json's deploy stamp is older than the
model at /.well-known/synthigy. Silent on any failure.
One stderr line when `<dir>/schema.json`'s deploy stamp is older than the model at /.well-known/synthigy. Silent on any failure.
(watch! {:keys [interval-ms] :or {interval-ms 500} :as opts})Dev loop for user.clj: poll dir for .xsql content changes (also fires once
on start); on change re-describe against the backend, rewrite out, and
load-file every written file so the running REPL picks the new fns up
immediately. Backend errors don't kill the loop — it reports once per
distinct error and retries each poll until the regen succeeds. Returns a
0-arg stop fn.
(defonce stop-gen (gen/watch! {:dir "xsql" :out "src" :ns-prefix "myapp.ops"}))
Dev loop for user.clj: poll `dir` for .xsql content changes (also fires once
on start); on change re-describe against the backend, rewrite `out`, and
`load-file` every written file so the running REPL picks the new fns up
immediately. Backend errors don't kill the loop — it reports once per
distinct error and retries each poll until the regen succeeds. Returns a
0-arg stop fn.
(defonce stop-gen
(gen/watch! {:dir "xsql" :out "src" :ns-prefix "myapp.ops"}))cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |