Queries
(import yen).lib.eval module gives a set of queries. Each one is lazy: you pay only for what you read.
Every answer is plain data, so builtins.toJSON prints it. This small fleet answers each query below.
{ yen, lib, ... }:{ yen.kinds.fleet = { spawns.host = _: yen.host; sinks.out.reduce = yen.lib.reduce.merge; }; yen.kinds.host = { fields.addr = lib.types.str; spawns.user = s: lib.filterAttrs (_: u: yen.lib.same u.on s) yen.user; sinks.packages = { reduce = yen.lib.reduce.set; out = { host, packages, ... }: { packages.${host.name} = packages; }; }; }; yen.kinds.user.fields.on = yen.kinds.host;
yen.fleet.main = { }; yen.host.web.addr = "10.0.0.1"; yen.user.ana.on = yen.host.web; yen.aspects.git = { at = [ yen.kinds.host yen.kinds.user ]; packages = "git"; }; yen.aspects.nginx = { at = yen.host.web; packages = "nginx"; }; yen.flake = { out, ... }: out;}| Query | Answer |
|---|---|
errors | [ { error; from; code; … } ], empty when the fleet is valid |
graph | { scopes; edges; }: every scope and every routed element, with its origin |
scopes | the scopes in order |
active | aspect, then scope id, then true or false |
undefined | aspects that at cannot decide (a cycle through not) |
reduced | sink, then receiver id, then the value |
flake | the answer of yen.flake |
data | every instance’s declared fields |
schema | every kind, aspect and invariant, as JSON-safe data |
declaredIn path | the files that answer a declaration path |
facts | the fleet as ground atoms, for Datalog |
context id { } | one scope: parent, children, aspects, what it gives and receives |
check | the invariants: see Invariants |
{ out = { "fleet:main" = { packages = { web = [ "git" "nginx" ]; }; }; }; packages = { "fleet:main/host:web" = [ "git" "nginx" ]; };}[ { from = "fleet:main/host:web"; origin = "aspect git"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web"; origin = "aspect nginx"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web/user:ana"; origin = "aspect git"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web"; origin = "sink packages"; sink = "out"; to = "fleet:main"; }][ "scope:fleet:main" "scope:fleet:main/host:web" "scope:fleet:main/host:web/user:ana" "kind:fleet:fleet:main" "kind:host:fleet:main/host:web" "kind:user:fleet:main/host:web/user:ana" "has:git:fleet:main/host:web" "has:git:fleet:main/host:web/user:ana" "has:nginx:fleet:main/host:web" "edge:packages:fleet:main/host:web:fleet:main/host:web" "edge:packages:fleet:main/host:web:fleet:main/host:web" "edge:packages:fleet:main/host:web/user:ana:fleet:main/host:web" "edge:out:fleet:main/host:web:fleet:main" "val:addr:fleet:main/host:web:10.0.0.1" "ref:on:fleet:main/host:web/user:ana:host:web"]One scope in context
Section titled “One scope in context”r.context id { maxEdges; maxAspects; } is what an agent or a person reads first about a scope.
Each list says how much it shows of how much there is:
{ aspects = { items = [ "git" "nginx" ]; truncated = { of = 2; shown = 2; }; }; children = [ "fleet:main/host:web/user:ana" ]; errors = [ ]; given = { items = [ { from = "fleet:main/host:web"; origin = "aspect git"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web"; origin = "aspect nginx"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web"; origin = "sink packages"; sink = "out"; to = "fleet:main"; } ]; truncated = { of = 3; shown = 3; }; }; kind = "host"; name = "web"; parent = "fleet:main"; received = { items = [ { from = "fleet:main/host:web"; origin = "aspect git"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web"; origin = "aspect nginx"; sink = "packages"; to = "fleet:main/host:web"; } { from = "fleet:main/host:web/user:ana"; origin = "aspect git"; sink = "packages"; to = "fleet:main/host:web"; } ]; truncated = { of = 3; shown = 3; }; }; scope = "fleet:main/host:web"; undefined = [ ];}Which aspects reach this host?
Section titled “Which aspects reach this host?”Each edge of graph has origin: the aspect that gave the element. “Which aspects reach web” is a filter,
not a registry: map (e: e.origin) (filter (e: e.to == "fleet:main/host:web") r.graph.edges).
nix eval --impure --file query.nix errorsnix eval --impure --json --file query.nix graphnix eval --impure --expr '(import ./query.nix).context "fleet:main/host:web" { }'