Skip to content

dougyouch/schema

Repository files navigation

schema

Fast and easy way to transform data into models for validation and type safety.

Build Status Maintainability Test Coverage

Attributes of a model have a name and type. Any value passed in goes through a parser method. If the value can not be parsed successfully the error is added to parsing_errors.

Associations are nested schema models. Each association can have its own set of attributes.

Dynamic associations are useful when creating custom logic around schema validation.

Example that show cases multiple features

spec/examples/company_schema.rb
# frozen_string_literal: true

# Example that show cases multiple features
class CompanySchema
  # includes model, associations, parsers and active model validations
  include Schema::All

  # add common attributes
  # attributes support additional names through the alias(es) option
  attribute :name, :string, alias: 'CompanyName'
  attribute :industry_type, :string, aliases: %w[IndustryType industry]

  # will take a string split on the separator and use the parse_<data_type> method on every element
  # basically take a list of comma separated numbers and create an array of integers
  # code snippet: str.split(',').map { |v| parse_integer(field_name, parsing_errors, v) }
  attribute :number_list, :array, separator: ',', data_type: :integer

  # creates a nested dynamic schema based on the industry_type which is part of the main company data
  industry_schema = has_one(:industry, external_type_field: :industry_type) do
    attribute :name, :string

    validates :name, presence: true

    add_type('tech') do
      attribute :custom_description, :string
    end

    add_type('qsr') do
      attribute :number_of_locations, :integer

      # custom validation
      validates :number_of_locations, presence: true
    end
  end

  # create multiple dynamic location schemas based on the type field in the location data
  has_many(:locations, type_field: :type) do
    attribute :type, :string
    attribute :address, :string
    attribute :city, :string
    attribute :state, :string
    attribute :zip, :string

    add_type('headquarters') do
      attribute :main_floor, :integer

      validates :city, presence: true
      validates :main_floor, presence: true
    end

    add_type('store_front') do
      attribute :main_entrance, :string

      validates :address, presence: true
      validates :main_entrance, presence: true
    end
  end

  # create multiple dynamic employee schemas based on the type field in the employee data
  has_many(:employees, type_field: :type) do
    attribute :type, :integer
    attribute :name, :string
    attribute :start_date, :date
    add_type(1) do # worker
      attribute :manager_name, :string
    end
    add_type(2) do # manager
      attribute :rank, :float
    end
    # if no or an invalid type is specified, create a default employee schema object
    # useful for communicating errors in an API
    default_type

    # dynamic_type_names returns all the types used, except for :default
    validates :type, inclusion: { in: dynamic_type_names }
  end

  has_many(:admins, from: :hash, hash_key_field: :username) do
    attribute :username, :string
    attribute :email, :string
    attribute :name, :string

    validates :username, presence: true
    validates :email, presence: true
  end

  validates :name, presence: true
  validates :industry_type, inclusion: { in: industry_schema.dynamic_type_names }

  # use the schema validator
  validates :industry, presence: true, schema: true
  validates :locations, presence: true, schema: true
  validates :employees, presence: true, schema: true
  validates :admins, presence: true, schema: true
end
spec/examples/company_schema.json
{
  "CompanyName": "Good Burger",
  "IndustryType": "qsr",
  "industry": {
    "name": "Food & Beverage",
    "number_of_locations": 2
  },
  "locations": [
    {
      "type": "headquarters",
      "city": "Boston",
      "main_floor": 5
    },
    {
      "type": "store_front",
      "address": "1st Ave",
      "zip": "02211",
      "main_entrance": "side door"
    }
  ],
  "employees": [
    {
      "type": 2,
      "name": "Queen Bee",
      "start_date": "2016-01-09",
      "rank": "0.9"
    },
    {
      "type": 1,
      "name": "Worker Bee",
      "start_date": "2018-05-10",
      "manager_name": "Queen Bee"
    }
  ],
  "admins": {
    "captain": {
      "email": "captain@example.com",
      "name": "Captain Kurk"
    },
    "joe": {
      "email": "joe.smith@example.com",
      "name": "Joe Smith"
    }
  }
}

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published