UNPKG

domain-objects

Version:

A simple, convenient way to represent domain objects, leverage domain knowledge, and add runtime validation in your code base.

116 lines (115 loc) 5.77 kB
/** * .what = the kind of a domain object — which base class it extends * .why = * - the pragma stamps the true subclass so a consumer can pick the right base class to rebuild * - replaces the fragile `primary`-non-empty heuristic (a literal may declare `primary`; an * entity may omit it) with the class's own marker-symbol truth * .note = `object` is the fallback for a plain `DomainObject` with a schema but no subclass marker */ export type DomainObjectKind = 'entity' | 'literal' | 'event' | 'object'; /** * .what = the type of a domain object's `x-domain-object` **pragma** — the static declarations * stamped onto its `.contract` schema so a cross-service consumer can reconstruct the class. * * .why = * a domain object splits into two halves on the wire: * - **instance** data (a Job's `uuid`, `status` values) → already carried by the schema/contract * - **static** declarations (the Job class's `primary`, `unique`, `kind`) → the schema cannot * carry class statics, so the pragma exists to carry them * the *only* reason to read this type is to **rebuild the class** (codegen turns it back into * `class Job extends DomainEntity { static primary = [...] }`). a consumer who does not care * about the class does not need these fields. * * .note = the term **pragma**, from Greek `prâgma` ("a deed, a matter of fact"; cf. C's `#pragma`): * a stated fact stamped alongside a payload that declares how to interpret it. the domain-object * pragma family states a schema node's domain-object semantics: * * | pragma (json keyword) | states | type | * |-----------------------|---------------------------|-------------------------------------| * | `x-domain-object` | this node **IS** dobj X | `DomainObjectPragma` (this type) | * | `x-domain-object-ref` | this node **REFERENCES** X | `DomainObjectPragmaRef` | * * the base + `Ref` partner mirrors the runtime pair `DomainObject : Ref`. both ship today: * `DomainObjectPragma` (the full body, via `.contract`) and `DomainObjectPragmaRef` (a key-only * reference, via `.contract.ref(by)`). * * .note = fields are **optional** where the stamp omits them: `getContract` writes `primary`/ * `unique`/`alias`/`nested` only when the dobj declares them, so a consumer reads e.g. * `pragma.primary` as `string[] | undefined`. field names mirror the class statics exactly. * * @example * // the `x-domain-object` node comes off an untyped json-schema blob, so the cast is a * // boundary read — domain-objects ships the type, the consumer owns the node access * const pragma = jsonSchema['x-domain-object'] as DomainObjectPragma; * pragma.kind; // 'entity' | 'literal' | 'event' | 'object' * pragma.primary; // string[] | undefined */ export type DomainObjectPragma = { /** * the domain object's class name (`constructor.name`) — names the reconstructed type */ name: string; /** * which base class the domain object extends — picks `DomainEntity` / `DomainLiteral` / * `DomainEvent` (or a plain `DomainObject`) when the consumer rebuilds the class */ kind: DomainObjectKind; /** * the surrogate key (`DomainEntity.primary` / `DomainLiteral.primary`), when declared */ primary?: string[]; /** * the natural key (`DomainEntity.unique`), when declared */ unique?: string[]; /** * the colloquial alias (`DomainObject.alias`), when declared */ alias?: string | { singular?: string; plural?: string; }; /** * the nested dobj names by key (`DomainObject.nested`), when declared — a single name, or an * array of names for polymorphic nested choices */ nested?: Record<string, string | string[]>; }; /** * .what = which key(s) a domain-object reference carries over the wire * .why = a reference points at a dobj *by* one of its keys — the surrogate (`primary`), the * natural key (`unique`), or either (`ref`, a union of the two). mirrors the runtime `Ref` family. */ export type DomainObjectRefBy = 'primary' | 'unique' | 'ref'; /** * .what = the type of a domain object's `x-domain-object-ref` **pragma** — stamped onto a schema * node that *references* a dobj by key (rather than *is* the dobj, which `x-domain-object` states). * * .why = * a contract field often references another dobj by its key, not by its whole body: * `class SurfTrophy { rider: Seaturtle.contract.ref('primary') }` → the wire carries just * `{ uuid }`, and this pragma states "that `{ uuid }` **references** a Seaturtle by primary". * a consumer reads it to emit a typed `RefByPrimary<typeof Seaturtle>` instead of an anonymous * `{ uuid: string }`. deliberately smaller than `DomainObjectPragma`: a reference needs only * *which dobj* + *which key*, not the full body nor `kind` — the target's own `.contract` * (bound elsewhere) already states those. * * .note = the schema-level partner of the runtime `refByPrimary` / `refByUnique` ops and the * `RefByPrimary` / `RefByUnique` types. it is to `DomainObjectPragma` what a reference is to a * composition — see the table on `DomainObjectPragma`. * * @example * const pragma = jsonSchema.properties.rider['x-domain-object-ref'] as DomainObjectPragmaRef; * pragma.of; // 'Seaturtle' * pragma.by; // 'primary' */ export type DomainObjectPragmaRef = { /** * the referenced dobj's class name (`constructor.name`) — names the reconstructed reference type */ of: string; /** * which key(s) the reference carries — `primary` / `unique` / `ref` (a union of both) */ by: DomainObjectRefBy; };