Liking cljdoc? Tell your friends :D

urpx.coerce

Coerce raw URPX parser output into typed Clojure values.

The parser (urpx.core/load-rate-plan) produces a Clojure map with namespaced keys but all-string leaf values. This namespace applies the :decode/urpx-jsonld decoders attached to urpx.schema schemas to convert those strings into BigDecimals, LocalDates, LocalTimes, LocalDateTimes, Durations, and integer month numbers — and to normalize fields that URPX permits as either a single map or a vector of maps.

Coerce raw URPX parser output into typed Clojure values.

The parser (`urpx.core/load-rate-plan`) produces a Clojure map with
namespaced keys but all-string leaf values. This namespace applies the
`:decode/urpx-jsonld` decoders attached to `urpx.schema` schemas to convert
those strings into BigDecimals, LocalDates, LocalTimes, LocalDateTimes,
Durations, and integer month numbers — and to normalize fields that URPX
permits as either a single map or a vector of maps.
raw docstring

urpx.core

URPX rate plan loading and price resolution.

Parses URPX JSON-LD rate plan documents into Clojure data structures and resolves prices for any given timestamp and timezone.

URPX rate plan loading and price resolution.

Parses URPX JSON-LD rate plan documents into Clojure data structures
and resolves prices for any given timestamp and timezone.
raw docstring

urpx.dsl

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 ::summer :name "Summer" :month [5 6 7 8 9 10]) (dsl/season ::winter :name "Winter" :month [11 12 1 2 3 4]) (dsl/price-definition ::pd-summer :name "Commodity Summer" :applies-in-season ::summer :references-ledger ::ledger-commodity))

Public API

  • dsl-scope macro establishing a local-symbol-ref scope
  • make-builder generator: schema → constructor function
  • entity-type introspect a schema for its @type literal
  • 37 named builders one per entity-type schema in urpx.schema (season, metric-input, price-definition, rate-plan, urpx-document, …)

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: number → BigDecimal, ISO string → LocalDate / LocalDateTime / LocalTime, --MM xsd:gMonth → int month-of-year, ISO 8601 string → Duration / Period.
  • 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 additionally:

  • Accept an optional leading qualified-keyword arg as the entity's local @id (e.g. (season ::summer …) registers ::summer in the scope and sets :jsonld/id "summer").
  • Resolve qualified-keyword kwarg values against the scope's registry to produce {:jsonld/id …} Ref maps. Vector-typed kwargs walk element-wise.

Resolution is eager (declare-before-reference): an unknown ref or a duplicate declaration throws. Each dsl-scope has its own registry — scopes don't leak.

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 ::summer :name "Summer" :month [5 6 7 8 9 10])
    (dsl/season ::winter :name "Winter" :month [11 12 1 2 3 4])
    (dsl/price-definition ::pd-summer
                          :name "Commodity Summer"
                          :applies-in-season ::summer
                          :references-ledger ::ledger-commodity))

## Public API

  - `dsl-scope`             macro establishing a local-symbol-ref scope
  - `make-builder`          generator: schema → constructor function
  - `entity-type`           introspect a schema for its @type literal
  - 37 named builders       one per entity-type schema in `urpx.schema`
                            (`season`, `metric-input`, `price-definition`,
                            `rate-plan`, `urpx-document`, …)

## 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: number → `BigDecimal`, ISO string → `LocalDate` /
    `LocalDateTime` / `LocalTime`, `--MM` xsd:gMonth → int month-of-year,
    ISO 8601 string → `Duration` / `Period`.
  - 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 additionally:

  - Accept an optional leading qualified-keyword arg as the entity's
    local `@id` (e.g. `(season ::summer …)` registers `::summer` in the
    scope and sets `:jsonld/id "summer"`).
  - Resolve qualified-keyword kwarg values against the scope's registry
    to produce `{:jsonld/id …}` Ref maps. Vector-typed kwargs walk
    element-wise.

Resolution is eager (declare-before-reference): an unknown ref or a
duplicate declaration throws. Each `dsl-scope` has its own registry —
scopes don't leak.
raw docstring

urpx.emit

Write-side: emit URPX JSON-LD from coerced Clojure entities.

Symmetric to the existing parse + coerce path. Given a coerced urpx:RatePlan / urpx:RatePlanModifier / urpx:URPXDocument (or an EDN map shaped like one with namespaced-keyword keys + already-string values), emit a SHACL-valid JSON-LD string ready to write to disk or send to a consumer.

Pipeline (per call):

  1. urpx.coerce/encode runs the schema's :encode/urpx-jsonld transformer — turns BigDecimal / LocalDate / LocalDateTime / LocalTime / Duration / int-month back into the JSON-LD string forms (xsd:decimal, xsd:date, xsd:dateTime, xsd:time, xsd:duration, xsd:gMonth). Already-string values pass through unchanged.
  2. urpx.core/keys->jsonld walks the result, converting namespaced keyword keys back to their CURIE / @-reserved JSON-LD forms.
  3. clojure.data.json/write-str serializes to JSON.

Round-trip success bar: logical/RDF-graph equivalence (parse → coerce → write → re-parse → re-coerce yields a structurally equal entity). Byte-for-byte equality with the input is NOT a goal — key ordering, single-vs-vector property emission, and @context recreation may differ from the source document. The vendored-fixture round-trip suite in urpx.emit-test pins the =-equality contract over every PG&E filing in test/resources/urpx-fixtures/ plus a URPXDocument- wrapped E-ELEC test case from the URPX upstream.

@context emission: every write-* function accepts an optional opts map with :context. Three states:

  • opts omits :context (or doesn't pass opts) → emit default-context (URPX prefix declarations + typed-property declarations matching what vendored fixtures carry).
  • opts has :context map → emit that map verbatim as @context.
  • opts has :context nil → emit no @context (used by round-trip tests where the input doesn't carry one and =-equality would mismatch).

An @context already on the input entity (:jsonld/context, e.g. from a parsed document) is preserved untouched — the default never clobbers a context the consumer already supplied.

Write-side: emit URPX JSON-LD from coerced Clojure entities.

Symmetric to the existing parse + coerce path. Given a coerced
urpx:RatePlan / urpx:RatePlanModifier / urpx:URPXDocument (or an EDN
map shaped like one with namespaced-keyword keys + already-string values),
emit a SHACL-valid JSON-LD string ready to write to disk or send to a
consumer.

Pipeline (per call):

  1. urpx.coerce/encode runs the schema's :encode/urpx-jsonld transformer
     — turns BigDecimal / LocalDate / LocalDateTime / LocalTime / Duration
     / int-month back into the JSON-LD string forms (xsd:decimal,
     xsd:date, xsd:dateTime, xsd:time, xsd:duration, xsd:gMonth).
     Already-string values pass through unchanged.
  2. urpx.core/keys->jsonld walks the result, converting namespaced
     keyword keys back to their CURIE / @-reserved JSON-LD forms.
  3. clojure.data.json/write-str serializes to JSON.

Round-trip success bar: logical/RDF-graph equivalence
(parse → coerce → write → re-parse → re-coerce yields a structurally
equal entity). Byte-for-byte equality with the input is NOT a goal —
key ordering, single-vs-vector property emission, and @context
recreation may differ from the source document. The vendored-fixture
round-trip suite in urpx.emit-test pins the `=`-equality contract over
every PG&E filing in test/resources/urpx-fixtures/ plus a URPXDocument-
wrapped E-ELEC test case from the URPX upstream.

@context emission: every write-* function accepts an optional opts map
with `:context`. Three states:

  - opts omits :context (or doesn't pass opts) → emit `default-context`
    (URPX prefix declarations + typed-property declarations matching what
    vendored fixtures carry).
  - opts has `:context map` → emit that map verbatim as @context.
  - opts has `:context nil` → emit no @context (used by round-trip tests
    where the input doesn't carry one and `=`-equality would mismatch).

An @context already on the input entity (`:jsonld/context`, e.g. from
a parsed document) is preserved untouched — the default never clobbers
a context the consumer already supplied.
raw docstring

urpx.holidays

Derive a holiday-date predicate from a rate plan's embedded urpx:HolidayCalendar.

URPX rate plans may embed a HolidayCalendar at :urpx/hasRatePlanVersion → :urpx/hasPlanElements → :urpx/hasHolidayCalendar listing each Holiday with a urpx:holidayName plus either:

  • urpx:holidayDate — literal xsd:date for one specific instance, OR
  • urpx:holidayRule — free-form string like 'Third Monday in February' or 'January 1 (legally observed)'.

derive-predicate returns a (java.time.LocalDate -> bool) predicate, or nil when the plan has no embedded calendar. The predicate covers any year on demand; per-year date sets are computed once and cached internally so driving price-schedule across thousands of timestamps doesn't repeat work.

Recognized urpx:holidayRule patterns:

  • 'First|Second|Third|Fourth|Fifth <Weekday> in <Month>'
  • 'Last <Weekday> in <Month>'
  • '<Month> <Day>' — observed on the actual date
  • '<Month> <Day> (legally observed)' — observed on the nearest weekday when the actual date falls on a weekend (Sat → Fri, Sun → Mon)

When a Holiday carries an explicit urpx:observanceRule (Ref to one of urpx:actualDateObservance / urpx:nearestWeekdayObservance / urpx:mondayIfWeekendObservance / urpx:fridayIfWeekendObservance) it overrides the implicit observance derived from the rule string.

Unrecognized rules throw ex-info — pass an explicit :holiday? predicate in urpx.price/resolve-prices opts to override the derived calendar.

Derive a holiday-date predicate from a rate plan's embedded
urpx:HolidayCalendar.

URPX rate plans may embed a HolidayCalendar at
  :urpx/hasRatePlanVersion → :urpx/hasPlanElements → :urpx/hasHolidayCalendar
listing each Holiday with a urpx:holidayName plus either:
  - urpx:holidayDate    — literal xsd:date for one specific instance, OR
  - urpx:holidayRule    — free-form string like 'Third Monday in February'
                          or 'January 1 (legally observed)'.

`derive-predicate` returns a `(java.time.LocalDate -> bool)` predicate, or
nil when the plan has no embedded calendar. The predicate covers any year
on demand; per-year date sets are computed once and cached internally so
driving `price-schedule` across thousands of timestamps doesn't repeat work.

Recognized urpx:holidayRule patterns:
  - 'First|Second|Third|Fourth|Fifth <Weekday> in <Month>'
  - 'Last <Weekday> in <Month>'
  - '<Month> <Day>'                       — observed on the actual date
  - '<Month> <Day> (legally observed)'    — observed on the nearest weekday
                                            when the actual date falls on
                                            a weekend (Sat → Fri, Sun → Mon)

When a Holiday carries an explicit urpx:observanceRule (Ref to one of
urpx:actualDateObservance / urpx:nearestWeekdayObservance /
urpx:mondayIfWeekendObservance / urpx:fridayIfWeekendObservance) it
overrides the implicit observance derived from the rule string.

Unrecognized rules throw ex-info — pass an explicit `:holiday?` predicate
in `urpx.price/resolve-prices` opts to override the derived calendar.
raw docstring

urpx.index

Build and query an entity index for URPX documents.

URPX JSON-LD documents are graphs: most entities carry a :jsonld/id and refer to other entities by reference shape {:jsonld/id "urpx:foo"}. Coercion leaves these references intact; consumers dereference them on demand against an index keyed by id string.

Note: many references point to vocabulary IRIs in the URPX ontology (e.g. urpx:peakTier, urpx:allDays, urpx:bundledLedger) rather than entities defined in the document. Those lookups return nil — callers distinguish internal refs (resolve to a node) from vocabulary terms (do not).

Build and query an entity index for URPX documents.

URPX JSON-LD documents are graphs: most entities carry a :jsonld/id and refer
to other entities by reference shape `{:jsonld/id "urpx:foo"}`. Coercion
leaves these references intact; consumers dereference them on demand against
an index keyed by id string.

Note: many references point to vocabulary IRIs in the URPX ontology
(e.g. urpx:peakTier, urpx:allDays, urpx:bundledLedger) rather than entities
defined in the document. Those lookups return nil — callers distinguish
internal refs (resolve to a node) from vocabulary terms (do not).
raw docstring

urpx.price

Resolve applicable per-energy prices for a URPX rate plan at a given instant.

Given a coerced rate plan (urpx.coerce/coerce-rate-plan) and a ZonedDateTime, resolve-prices returns the season, the matched TOU period (if any), and one entry per active per-energy ledger (commodity, distribution, public benefits, etc.). Each ledger entry carries a :tiers vector — for block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is surfaced so the caller can pick the active one based on cumulative usage; for non-tiered ledgers the vector has a single entry.

Skipped:

  • PriceDefinitions whose own :urpx/hasCalculationMethod is set (recurring fixed charges like a monthly customer charge — these are subscription-style and don't apply to instantaneous lookup).

Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays, urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays booleans (both default to true when omitted). Holiday detection sources, in priority order:

  1. Explicit :holiday? predicate in opts (highest precedence — overrides).
  2. The plan's embedded urpx:HolidayCalendar, derived via urpx.holidays/derive-predicate.
  3. Fallback: every date treated as a non-holiday.

Plans without a HolidayCalendar and called without :holiday? retain the pre-existing 'every date is a non-holiday' fallback — so brackets that opt out of non-holidays (urpx:includeNonHolidays = false) will never match.

Resolve applicable per-energy prices for a URPX rate plan at a given instant.

Given a coerced rate plan (`urpx.coerce/coerce-rate-plan`) and a
ZonedDateTime, `resolve-prices` returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a `:tiers` vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.

Skipped:
  - PriceDefinitions whose own `:urpx/hasCalculationMethod` is set
    (recurring fixed charges like a monthly customer charge — these are
    subscription-style and don't apply to instantaneous lookup).

Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays,
urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the
TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays
booleans (both default to true when omitted). Holiday detection sources,
in priority order:

  1. Explicit `:holiday?` predicate in opts (highest precedence — overrides).
  2. The plan's embedded urpx:HolidayCalendar, derived via
     `urpx.holidays/derive-predicate`.
  3. Fallback: every date treated as a non-holiday.

Plans without a HolidayCalendar and called without `:holiday?` retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.
raw docstring

urpx.schedule

Generate contiguous price-interval schedules from a coerced URPX rate plan.

price-schedule walks a [start, end) instant window in the rate plan's local timezone, calls urpx.price/resolve-prices at each step, and merges adjacent steps whose ledger resolutions are identical.

Output is a vector of interval maps each carrying :tick/beginning and :tick/end (java.time.ZonedDateTime in the resolved zone — DST-correct end-to-end) plus the full urpx.price resolved structure under :urpx.interval/resolved. Callers that want plain java.time.Instant values invoke .toInstant themselves at the call site.

Default step is 1 hour, anchored to the start-of-hour of start. Pass {:step (Duration/ofMinutes 15)} etc. for finer granularity when a rate plan defines sub-hour TOU bracket transitions.

Generate contiguous price-interval schedules from a coerced URPX rate plan.

`price-schedule` walks a [start, end) instant window in the rate plan's
local timezone, calls `urpx.price/resolve-prices` at each step, and
merges adjacent steps whose ledger resolutions are identical.

Output is a vector of interval maps each carrying `:tick/beginning` and
`:tick/end` (java.time.ZonedDateTime in the resolved zone — DST-correct
end-to-end) plus the full `urpx.price` resolved structure under
`:urpx.interval/resolved`. Callers that want plain `java.time.Instant`
values invoke `.toInstant` themselves at the call site.

Default step is 1 hour, anchored to the start-of-hour of `start`. Pass
`{:step (Duration/ofMinutes 15)}` etc. for finer granularity when a rate
plan defines sub-hour TOU bracket transitions.
raw docstring

urpx.schema

Malli schemas for URPX v0.2.0 entities, describing the coerced shape.

Two-layer model (mirroring the clj-oa3 pattern):

  • urpx.core — raw parse: JSON-LD with namespaced keys, all string values.
  • urpx.schema — coerced shape: typed Clojure values (BigDecimal, LocalDate, LocalTime, LocalDateTime, Duration, integer month numbers).

Schemas carry :decode/urpx-jsonld decoders that turn the raw parser output (strings) into the typed shape described here. The transformer is built and applied in urpx.coerce. Reference resolution keeps :jsonld/id references intact; consumers dereference via an entity index.

Schemas are bare def vars referenced by symbol — there is no central registry except inside ConditionExpression, where the recursive Comparison/Boolean operand tree uses a local Malli registry.

Malli schemas for URPX v0.2.0 entities, describing the coerced shape.

Two-layer model (mirroring the clj-oa3 pattern):
  - urpx.core      — raw parse: JSON-LD with namespaced keys, all string values.
  - urpx.schema    — coerced shape: typed Clojure values (BigDecimal, LocalDate,
                     LocalTime, LocalDateTime, Duration, integer month numbers).

Schemas carry `:decode/urpx-jsonld` decoders that turn the raw parser output
(strings) into the typed shape described here. The transformer is built and
applied in `urpx.coerce`. Reference resolution keeps :jsonld/id references
intact; consumers dereference via an entity index.

Schemas are bare def vars referenced by symbol — there is no central registry
except inside ConditionExpression, where the recursive Comparison/Boolean
operand tree uses a local Malli registry.
raw docstring

urpx.tz-inference

Best-effort timezone inference for URPX rate plans whose urpx:timezoneIdentifier is absent.

This namespace is opt-inurpx.schedule does not call it automatically. Callers that want plug-and-play timezone resolution compose inference with the declared field at the call site:

(or (some-> plan :urpx/timezoneIdentifier ZoneId/of)
    (:zone (urpx.tz-inference/infer-zone plan)))

Inference uses utility-identifying fields on the publishing Organization: urpx:eiaId (preferred — official US energy reporting code) and urpx:legalName (fallback). When the utility is unknown to the lookup tables, or known to operate across more than one IANA zone, infer-zone returns nil so the caller can fail loudly rather than silently pick one.

The shipped tables only cover utilities used by the clj-urpx test suite; production deployments are expected to supply their own table (e.g. derived from EIA Form 861).

Best-effort timezone inference for URPX rate plans whose
`urpx:timezoneIdentifier` is absent.

This namespace is **opt-in** — `urpx.schedule` does not call it
automatically. Callers that want plug-and-play timezone resolution
compose inference with the declared field at the call site:

    (or (some-> plan :urpx/timezoneIdentifier ZoneId/of)
        (:zone (urpx.tz-inference/infer-zone plan)))

Inference uses utility-identifying fields on the publishing
Organization: `urpx:eiaId` (preferred — official US energy reporting
code) and `urpx:legalName` (fallback). When the utility is unknown to
the lookup tables, or known to operate across more than one IANA
zone, `infer-zone` returns `nil` so the caller can fail loudly rather
than silently pick one.

The shipped tables only cover utilities used by the clj-urpx test
suite; production deployments are expected to supply their own table
(e.g. derived from EIA Form 861).
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close