0.1.0 • Published 11 months ago

@orbit-utils/zod-to-model-definition v0.1.0

Weekly downloads
-
License
MIT
Repository
github
Last release
11 months ago

@orbit-utils/zod-to-model-definition

Define your RecordSchema using Zod.

Before:

const planetModelDefinition = {
    attributes: {
        name: {type: "string"},
        classification: {type: "string"},
        atmosphere: {type: "boolean"},
        mass: {type: "number"},
    },
    relationships: {
        solarSystem: {kind: "hasOne", type: "solarSystem", inverse: "planets"},
        moons: {kind: "hasMany", type: "moon", inverse: "planet"},
    },
};

After:

import {m, zodToModelDefinition} from "@orbit-utils/zod-to-model-definition";
import {z} from "zod";

const planetZodSchema = z.object({
    type: z.literal("planet"),
    id: z.string().optional(),
    attributes: z.object({
        name: z.string(),
        classification: z.enum(["terrestrial", "gaseous"]),
        atmosphere: z.boolean(),
        mass: z.number().positive().finite(),
    }),
    relationships: z.object({
        solarSystem: m.relationship("hasOne", "solarSystem").inverse("planets"),
        moons: m.relationship("hasMany", "moon").inverse("planet"),
    }),
});
const planetModelDefinition = zodToModelDefinition(planetZodSchema);

Usage

Install using your preferred Node.js package manager. For example:

pnpm add @orbit-utils/zod-to-model-definition

Import and enjoy!

import {zodToModelDefinition} from "@orbit-utils/zod-to-model-definition";

For facilitating special model definition attributes (such as inverse, dependent: "delete" and meta) in your Zod schema, the library provides custom ZodTypes through m:

import {m} from "@orbit-utils/zod-to-model-definition";

m.relationship("hasOne", "solarSystem").inverse("planets");
m.relationship("hasMany", "moon").inverse("planet");
m.attribute(z.number().positive().finite()).definitionMeta({unit: "kg"});

Advantages of using Zod to define your RecordSchema

  • You can infer TypeScript types from your Zod schema.
    type Planet = z.infer<typeof planetZodSchema>;
    // same as…
    interface Planet extends UninitializedRecord {
        type: "planet";
        ...
    }
    // …except you don't have to maintain separate interface definitions
  • Zod allows for a more granular schema definition (more granular types, more granular validation).
    classification: {
        type: "string";
    }
    vs.z.enum(["terrestrial", "gaseous"]);
    mass: {
        type: "number";
    }
    vs.z.number().positive().finite();
    • You can configure Orbit to use Zod's validation instead of its own with validateFor.

Additional features

API reference

zodToModelDefinition

import type {ModelDefinition} from "@orbit/records";
import type {AnyZodObject} from "zod";

export function zodToModelDefinition(zodSchema: AnyZodObject): ModelDefinition;

ZodKey

Extends ZodType.

Zod schema counterpart for KeyDefinition.

Can be created by calling m.key.

import type {ZodType} from "zod";

export function key(zodType?: ZodType<string>): ZodKey;

.definitionMeta

ZodKey.definitionMeta: (definitionMeta: {[key: string]: unknown}) => ZodKey

ZodAttribute

Extends ZodType.

Zod schema counterpart for AttributeDefinition.

Can be created by calling m.attribute.

import type {ZodTypeAny} from "zod";

export function attribute(zodType?: ZodTypeAny): ZodAttribute;

.definitionMeta

ZodAttribute.definitionMeta: (definitionMeta: {[key: string]: unknown}) => ZodAttribute

.serialization

ZodAttribute.serialization: (serialization: {[key: string]: unknown}) => ZodAttribute

.deserialization

ZodAttribute.deserialization: (deserialization: {[key: string]: unknown}) => ZodAttribute

ZodRelationship

Extends ZodType.

Zod schema counterpart for RelationshipDefinition.

Can be created by calling m.relationship.

import type {ZodTypeAny} from "zod";

export function relationship(
    kind: "hasOne" | "hasMany",
    type?: string | string[],
): ZodRelationship;

.definitionMeta

ZodRelationship.definitionMeta: (definitionMeta: {[key: string]: unknown}) => ZodRelationship

.inverse

ZodRelationship.inverse: (relationshipName: string) => ZodRelationship

.dependentRemove

ZodRelationship.dependentRemove: () => ZodRelationship

.links

Schema for the links object that can appear on your record. (See RecordRelationship.)

import type {Link} from "@orbit/records";
import type {ZodType} from "zod";

ZodRelationship.links: (schema: ZodType<{[key: string]: Link} | undefined>) => ZodRelationship

.meta

Schema for the meta object that can appear on your record. (See RecordRelationship.)

import type {ZodType} from "zod";

ZodRelationship.meta: (schema: ZodType<{[key: string]: unknown} | undefined>) => ZodRelationship