change

An early, in-progress implementation of Changesets in Crystal. Inspired by Elixir's Ecto Changesets.

Changesets are a powerful way of implementing validations and coercions in a composable, non-destructive way. Changes can be applied and validations can be enforced without ever modifying the underlying instance, making it easy to trust that data manipulation is always done correctly and safely.

What works:

Initial goals for this implementation include:

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      changeset:
        github: faultyserver/change
  2. Run shards install

Usage

This library is too early to have a documented API. In the meantime, check example.cr for an example usage. A short sample is also given here:

require "change"

class User
  Change.schema User,
    name : String,
    age : Int32,
    bio : String

  # Standard pattern for working with changesets. Define a static method
  # that performs casts and validations to abstract that from the callsite.
  def self.changeset(instance, changes={} of String => String)
    Changeset.new(instance)
      .cast(changes, [:name, :age, :bio])
      .validate_required(["name", "age"])
  end
end


user = User.new
changeset = User.changeset(user, {
  name: "Jon",
  age: 23,
})

# Changesets abstract validation to a single place, so clients can just query
# their validity before continuing.
changeset.valid? #=> true

# Changesets don't modify the backing instance until explicitly applied.
user #=> #<User @name=nil, @age=nil, @bio=nil>
user = changeset.apply_changes
user #=> #<User @name="Jon, @age=23, @bio=nil>

SQL querying

In addition to changesets, this library also includes an optional SQL querying interface. This lives in src/change/sql and must be included separately from the changeset module. Change::SQL is built on top of Changesets, so using them is required to be able to use this. Part of this is due to Crystal's current lack of support for copying instance vars effectively at compile time, but also to provide a cleaner, more powerful interface with validations, constraints, and more.

See example-sql.cr for an example of what the SQL interface currently looks like.