domain-objects
Version:
A simple, convenient way to represent domain objects, leverage domain knowledge, and add runtime validation in your code base.
88 lines • 4.29 kB
JavaScript
;
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DomainObject = exports.MARK_AS_DOMAIN_OBJECT = void 0;
const getContract_1 = require("../manipulation/getContract");
const withImmute_1 = require("../manipulation/immute/withImmute");
const hydrateNestedDomainObjects_1 = require("./hydrate/hydrateNestedDomainObjects");
const markers_1 = require("./markers");
const validate_1 = require("./validate/validate");
const version_1 = require("./version");
var markers_2 = require("./markers");
Object.defineProperty(exports, "MARK_AS_DOMAIN_OBJECT", { enumerable: true, get: function () { return markers_2.MARK_AS_DOMAIN_OBJECT; } });
/**
* Domain Object
*
* Responsibilities:
* - optionally validate the properties that are passed into the constructor against the schema at runtime, if schema is supplied
* - assign all properties that are passed into constructor to self, after optional runtime validation
*/
class DomainObject {
constructor(props, options) {
// 1. validate with the schema if provided
const { schema } = this.constructor; // `this.constructor` does not get typed to DomainObject automatically by ts; https://stackoverflow.com/questions/33387318/access-to-static-properties-via-this-constructor-in-typescript
if (schema && !(options?.skip?.schema === true))
(0, validate_1.validate)({ props, schema, domainObjectName: this.constructor.name });
// 2. hydrate any nested props present; just overwrite the orig props for each "nested" key
const nested = (this.constructor.nested ??
{});
const hydratedProps = (0, hydrateNestedDomainObjects_1.hydrateNestedDomainObjects)({
domainObjectName: this.constructor.name,
props,
nested,
});
// 3. assign all properties to self if passed validation
Object.assign(this, hydratedProps);
}
/**
* DomainObject.contract
*
* returns the domain object's `schema` stamped with its identity + key metadata, as an `x-domain-object` pragma.
*
* whereas `schema` *validates* the data, `contract` *identifies* it: the contract is the schema that knows its
* own name, primary/unique keys, alias, and nested dobj names. the stamp rides through `z.toJSONSchema()` so a
* cross-service consumer can name, de-dupe, and reconstruct the dobj from the wire (no re-validation needed).
*
* requires a `static schema` that is a `Zod` schema; throws a `ConstraintError` otherwise.
*
* the returned contract also carries a `.ref(by)` method: `Seaturtle.contract.ref('primary')`
* returns the schema-level *reference* to this dobj by key (an `x-domain-object-ref` pragma) —
* a key-only slice for a field that references another dobj rather than composes it.
*
* @example
* z.object({ surfboard: SeaturtleSurfboard.contract }); // composes the whole dobj
* z.object({ rider: Seaturtle.contract.ref('primary') }); // references it by primary key
*/
static get contract() {
return (0, getContract_1.getContract)(this);
}
/**
* .what = an interface via which to construct instances w/ immute operations
*
* .why =
* - immute operations such as .clone produce more maintainable code by preventing unexpected mutations
* - these immute operations provide a safe pit of success for common operations
*
* .note =
* - you can add withImmute to any dobj yourself, even if it wasn't built via this .build procedure
* - you can override the .build to add your own domain's getters, too
*/
static build(props, options) {
const instance = new this(props, options);
return (0, withImmute_1.withImmute)(instance);
}
}
exports.DomainObject = DomainObject;
_a = DomainObject, _b = markers_1.MARK_AS_DOMAIN_OBJECT;
/**
* DomainObject marker symbol for cross-version compatibility.
*
* Uses Symbol.for() to create a global symbol that works across different versions
* of the domain-objects library. The value is the version string.
*/
DomainObject[_b] = version_1.VERSION;
/**
* .as = alias for .build
*/
DomainObject.as = _a.build;
//# sourceMappingURL=DomainObject.js.map