Idiomatic Clojure authoring for URPX entities. Output of every builder is
a coerced (typed) entity ready for urpx.price/resolve-prices,
urpx.emit/write-*, or any other consumer of urpx.schema-shaped data.
(require '[urpx.dsl :as dsl])
(dsl/dsl-scope (dsl/season :as :ex/summer :season-name "Summer" :month [5 6 7 8 9 10]) (dsl/ledger :as :ex/commodity :name "Commodity" :ledger-type :urpx/supplyLedger) (dsl/price-definition :as :ex/pd-summer :name "Commodity Summer" :applies-in-season :ex/summer :references-ledger :ex/commodity))
dsl-scope macro naming entities by keywordcurie the default keyword -> @id functionrdf-list an ordered RDF list valuemake-builder generator: schema → constructor functionentity-type introspect a schema for its @type literalurpx.schema
(season, metric-input, price-definition,
rate-plan, urpx-package, coverage-claim, …),
with no exceptions. Where a schema dual-accepts
two @type spellings (source-publication), the
builder sets the v0.5.1 one; the schema still
validates the v0.2.x spelling on parse.Every builder:
:jsonld/type automatically from the schema (no boilerplate).:urpx/* keys (:urpx/seasonName) or auto-derived kebab-case short
forms (:season-name); both can be mixed in one call.:decode/urpx-jsonld
decoders: BigDecimal, integer, exact ratio or numeric string →
BigDecimal (a double, a float or an inexact ratio refuses, since
it has already lost the written scale), ISO string → LocalDate /
LocalDateTime / LocalTime (zoned forms when a dateTime or time
carries an offset),
--MM xsd:gMonth → int month-of-year,
ISO 8601 string → Duration / Period.:urpx/X keyword value as the vocabulary term
{:jsonld/id "urpx:X"} (:day-type :urpx/allDays), element-wise
in a vector.nil-valued kwargs (so (builder :foo (when … x)) cleanly
omits the field). Explicit false is preserved.ex-info with the Malli explanation on failure.Inside a dsl-scope, builders also take :as k for the entity's @id
and read other qualified keywords as references; see dsl-scope.
Idiomatic Clojure authoring for URPX entities. Output of every builder is
a coerced (typed) entity ready for `urpx.price/resolve-prices`,
`urpx.emit/write-*`, or any other consumer of `urpx.schema`-shaped data.
## At a glance
(require '[urpx.dsl :as dsl])
(dsl/dsl-scope
(dsl/season :as :ex/summer :season-name "Summer" :month [5 6 7 8 9 10])
(dsl/ledger :as :ex/commodity
:name "Commodity"
:ledger-type :urpx/supplyLedger)
(dsl/price-definition :as :ex/pd-summer
:name "Commodity Summer"
:applies-in-season :ex/summer
:references-ledger :ex/commodity))
## Public API
- `dsl-scope` macro naming entities by keyword
- `curie` the default keyword -> @id function
- `rdf-list` an ordered RDF list value
- `make-builder` generator: schema → constructor function
- `entity-type` introspect a schema for its @type literal
- a named builder for every entity-type schema in `urpx.schema`
(`season`, `metric-input`, `price-definition`,
`rate-plan`, `urpx-package`, `coverage-claim`, …),
with no exceptions. Where a schema dual-accepts
two @type spellings (`source-publication`), the
builder sets the v0.5.1 one; the schema still
validates the v0.2.x spelling on parse.
## Builder semantics
Every builder:
- Sets `:jsonld/type` automatically from the schema (no boilerplate).
- Accepts kwargs (or a Clojure 1.11+ trailing map) of either canonical
`:urpx/*` keys (`:urpx/seasonName`) or auto-derived kebab-case short
forms (`:season-name`); both can be mixed in one call.
- Auto-coerces raw inputs through the schema's `:decode/urpx-jsonld`
decoders: BigDecimal, integer, exact ratio or numeric string →
`BigDecimal` (a double, a float or an inexact ratio refuses, since
it has already lost the written scale), ISO string → `LocalDate` /
`LocalDateTime` / `LocalTime` (zoned forms when a dateTime or time
carries an offset),
`--MM` xsd:gMonth → int month-of-year,
ISO 8601 string → `Duration` / `Period`.
- Reads a `:urpx/X` keyword value as the vocabulary term
`{:jsonld/id "urpx:X"}` (`:day-type :urpx/allDays`), element-wise
in a vector.
- Drops `nil`-valued kwargs (so `(builder :foo (when … x))` cleanly
omits the field). Explicit `false` is preserved.
- Validates the assembled entity against the schema and throws
`ex-info` with the Malli explanation on failure.
Inside a `dsl-scope`, builders also take `:as k` for the entity's @id
and read other qualified keywords as references; see `dsl-scope`.(curie k)The default dsl-scope :id-fn: :scl/summer -> "scl:summer".
The default `dsl-scope` `:id-fn`: `:scl/summer` -> "scl:summer".
(dsl-scope & body)Evaluate body in a scope where entities are named by keyword. An
optional leading map literal holds options:
:id-fn keyword -> @id string; default curie (:scl/summer ->
"scl:summer")
Inside the scope, a builder:
:as k to set the entity's @id to (id-fn k);urpx and jsonld
namespaces as the Ref {:jsonld/id (id-fn k)};:as or by an
explicit :jsonld/id.A reference may come before or after its declaration. When the body
finishes, the scope realizes every lazy sequence in its value, so a
builder inside for or map runs in the scope. Then every keyword
referenced whose @id no builder in the scope declared is refused in one
ex-info naming each such keyword and the @type of each builder that
referenced it, under :unresolved. A reference to an entity outside
the scope is a Ref map, {:jsonld/id "…"}.
Each scope has its own state; an inner scope does not see the outer.
Evaluate `body` in a scope where entities are named by keyword. An
optional leading map literal holds options:
:id-fn keyword -> @id string; default `curie` (`:scl/summer` ->
"scl:summer")
Inside the scope, a builder:
- takes `:as k` to set the entity's @id to `(id-fn k)`;
- reads a qualified-keyword value outside the `urpx` and `jsonld`
namespaces as the Ref `{:jsonld/id (id-fn k)}`;
- refuses an @id already declared in the scope, by `:as` or by an
explicit `:jsonld/id`.
A reference may come before or after its declaration. When the body
finishes, the scope realizes every lazy sequence in its value, so a
builder inside `for` or `map` runs in the scope. Then every keyword
referenced whose @id no builder in the scope declared is refused in one
ex-info naming each such keyword and the @type of each builder that
referenced it, under `:unresolved`. A reference to an entity outside
the scope is a Ref map, `{:jsonld/id "…"}`.
Each scope has its own state; an inner scope does not see the outer.(entity-type schema)Extract the @type literal (e.g. "urpx:Season") from a Malli entity
schema by introspecting its :jsonld/type entry — which must have the
form [:= "urpx:X"]. Schemas wrapped in [:schema {:registry ...} <inner>] (e.g. ConditionExpression) are unwrapped via m/deref first.
Returns nil if the schema doesn't carry a :jsonld/type entry shaped
that way.
Extract the @type literal (e.g. "urpx:Season") from a Malli entity
schema by introspecting its :jsonld/type entry — which must have the
form `[:= "urpx:X"]`. Schemas wrapped in `[:schema {:registry ...}
<inner>]` (e.g. ConditionExpression) are unwrapped via `m/deref` first.
Returns nil if the schema doesn't carry a :jsonld/type entry shaped
that way.(make-builder schema)(make-builder schema {:keys [passthrough]})Given a urpx.schema entity schema, return a constructor function. The constructor:
dsl-scope, takes :as k for the entity's @id and reads
other qualified-keyword values as references; see dsl-scope.
Outside one, refuses :as.:urpx/X keyword value as the Ref {:jsonld/id "urpx:X"},
inside a scope or not.:jsonld/* key, nor in :passthrough, naming the key and the
entity type, so a misspelled key throws instead of being emitted.urpx.coerce/jsonld-transformer:
already-typed values pass through; raw values (numbers, strings,
gMonth strings, …) are decoded per the schema's :decode/urpx-jsonld
decoders.:reason ::inexact-decimal.The schema must carry a :jsonld/type entry with shape [:= "urpx:X"]
so the @type can be inferred.
Options:
:passthrough, a collection of further keys the constructor admits,
for a property the schema does not model:
(make-builder schema/RatePlanVersion {:passthrough #{:ex/note}})
Given a urpx.schema entity schema, return a constructor function. The
constructor:
- Accepts kwargs (or a trailing map per Clojure 1.11+ unification) of
canonical :urpx/* keys; the entity's :jsonld/type is set automatically
from the schema.
- Inside a `dsl-scope`, takes `:as k` for the entity's @id and reads
other qualified-keyword values as references; see `dsl-scope`.
Outside one, refuses `:as`.
- Reads a `:urpx/X` keyword value as the Ref `{:jsonld/id "urpx:X"}`,
inside a scope or not.
- Refuses a key that is neither a key of the schema, a short form of
one, a `:jsonld/*` key, nor in `:passthrough`, naming the key and the
entity type, so a misspelled key throws instead of being emitted.
- Drops kwargs whose value is nil so optional fields can be supplied
conditionally without producing present-but-nil entries.
- Decodes against the schema with `urpx.coerce/jsonld-transformer`:
already-typed values pass through; raw values (numbers, strings,
gMonth strings, …) are decoded per the schema's :decode/urpx-jsonld
decoders.
- Refuses a double, a float or an inexact ratio for an xsd:decimal
field, naming the field, under `:reason ::inexact-decimal`.
- Validates the assembled entity against the schema; throws ex-info
(with the Malli explanation attached) on validation failure.
The schema must carry a :jsonld/type entry with shape `[:= "urpx:X"]`
so the @type can be inferred.
Options:
- `:passthrough`, a collection of further keys the constructor admits,
for a property the schema does not model:
(make-builder schema/RatePlanVersion {:passthrough #{:ex/note}})(rdf-list members)The ordered RDF list of members, {:jsonld/list [...]}, emitted as a
JSON-LD @list. A member is written as given, except that a builder
reads a keyword member as it reads a keyword value:
(dsl/rdf-list [{:jsonld/value "P" :jsonld/type "xsd:string"} {:jsonld/value "Q" :jsonld/type "xsd:string"}]) (dsl/rdf-list [:ex/summer :ex/winter]) ; in a dsl-scope
The ordered RDF list of `members`, `{:jsonld/list [...]}`, emitted as a
JSON-LD `@list`. A member is written as given, except that a builder
reads a keyword member as it reads a keyword value:
(dsl/rdf-list [{:jsonld/value "P" :jsonld/type "xsd:string"}
{:jsonld/value "Q" :jsonld/type "xsd:string"}])
(dsl/rdf-list [:ex/summer :ex/winter]) ; in a dsl-scopecljdoc 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 |