Skip to main content
This guide covers advanced aspects of working with Orionjs schemas, including composition, inheritance, and complex validation.

Schema Composition

You can compose schemas together to create more complex structures:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'

// Base schemas
export const AddressSchema = schemaWithName('AddressSchema', {
  street: {type: String},
  city: {type: String},
  zipCode: {type: String}
})

export const NameSchema = schemaWithName('NameSchema', {
  firstName: {type: String},
  lastName: {type: String}
})

// Composed schema
export const UserSchema = schemaWithName('UserSchema', {
  _id: {type: String},
  
  // Embed the name schema
  name: {type: NameSchema},
  
  // Embed the address schema
  address: {type: AddressSchema, optional: true},
  
  email: {type: String}
})

export type UserType = InferSchemaType<typeof UserSchema>

Arrays of Complex Types

Working with arrays of objects:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'

export const TagSchema = schemaWithName('TagSchema', {
  name: {type: String},
  color: {type: String, optional: true}
})

export const PostSchema = schemaWithName('PostSchema', {
  _id: {type: String},
  title: {type: String},
  
  // Array of primitive values
  categories: {type: [String]},
  
  // Array of complex objects
  tags: {type: [TagSchema], minLength: 1, maxLength: 10}
})

export type PostType = InferSchemaType<typeof PostSchema>

Conditional Validation

You can implement conditional validation based on other field values:
import {schemaWithName, InferSchemaType} from '@orion-js/schema'

export const PaymentSchema = schemaWithName('PaymentSchema', {
  method: {
    type: String,
    allowedValues: ['credit_card', 'bank_transfer', 'paypal']
  },
  
  // Credit card details, required only when method is 'credit_card'
  cardNumber: {
    type: String,
    optional: true,
    validate: (value, {doc}) => {
      if (doc.method === 'credit_card' && !value) {
        return 'required-for-credit-card'
      }
      if (value && !/^\d{16}$/.test(value)) {
        return 'invalid-card-number'
      }
    }
  },
  
  // PayPal email, required only when method is 'paypal'
  paypalEmail: {
    type: String,
    optional: true,
    validate: (value, {doc}) => {
      if (doc.method === 'paypal' && !value) {
        return 'required-for-paypal'
      }
    }
  }
})

export type PaymentType = InferSchemaType<typeof PaymentSchema>

Custom Types with Transformation

Creating a custom type with validation and transformation:
import {schemaWithName, InferSchemaType, createType} from '@orion-js/schema'

// Custom type for phone numbers
const PhoneNumberType = createType({
  name: 'phoneNumber',
  validate(value) {
    if (!/^\+?[0-9\s-()]+$/.test(value)) {
      return 'invalid-phone-format'
    }
  },
  clean(value) {
    // Remove non-digit characters
    return value.replace(/[^0-9+]/g, '')
  }
})

export const ContactSchema = schemaWithName('ContactSchema', {
  name: {type: String},
  phone: {type: PhoneNumberType}
})

export type ContactType = InferSchemaType<typeof ContactSchema>