Micrate is recommended. It is used and supported by core crystal members.
Usage
First create a Repo. The Repo maps to the datastore and the database adapter and is used to run queries. You can even create multiple repos if you need to access multiple databases.
For those coming from Active Record: Repo provides a level of abstraction between database logic (Repo) and business logic (Model).
Let's create a repo for Postgres:
module Repo
extend Crecto::Repo
config do |conf|
conf.adapter = Crecto::Adapters::Postgres # or Crecto::Adapters::Mysql or Crecto::Adapters::SQLite3
conf.database = "database_name"
conf.hostname = "localhost"
conf.username = "user"
conf.password = "password"
conf.port = 5432
# you can also set initial_pool_size, max_pool_size, max_idle_pool_size,
# checkout_timeout, retry_attempts, and retry_delay
end
end
And another for SQLite:
module SqliteRepo
extend Crecto::Repo
config do |conf|
conf.adapter = Crecto::Adapters::SQLite3
conf.database = "./path/to/database.db"
end
end
Shortcut variables
Optionally you can use constants shorcuts using:
Query = Crecto::Repo::Query
Multi = Crecto::Multi
Definitions
Define table name, fields, validations, and constraints in your model. By default, Crecto assumes your table has the following columns defined id, created_at, updated_at. These are in addition to whatever columns you decide to add.
Defining a new class using Crecto::Model:
class User < Crecto::Model
schema "users" do
field :age, Int32 # or use `PkeyValue` alias: `field :age, PkeyValue`
field :name, String
field :is_admin, Bool, default: false
field :temporary_info, Float64, virtual: true
field :email, String
has_many :posts, Post, dependent: :destroy
end
validate_required [:name, :age]
validate_format :name, /^[a-zA-Z]*$/
unique_constraint :email
end
Defining another one:
class Post < Crecto::Model
schema "posts" do
belongs_to :user, User
end
end
Creating a new User:
user = User.new
user.name = "123"
user.age = 123
If your schema doesn't require the default fields (id, created_at, updated_at), you can omit them.
class UserTags < Crecto::Model
set_created_at_field nil # or you can set the name of your created_at field
set_updated_at_field nil # ditto
# primary_key: false tells the schema there's no `id` field
schema "user_tags", primary_key: false do
belongs_to :user, User
belongs_to :tag, Tag
end
end
For a schema with an ID that is custom (UUID, Random String, etc...)
class Comment < Crecto::Model
schema "comments" do
field :id, String, primary_key: true
field :content, String
end
end
You can check out the spec/spec_helper.cr for more examples.
If there are any errors in any of the transactions, the database will rollback as if none of the transactions happened
multi.errors.any?
Non-nillable attributes
If you wish to access attributes of a model without having to check for nil, in the case that you are using a NOT NULLdatabase constraint you can use the non-nillable attribute accessors. CAUTION: Mis-use of this could lead to Nil reference runtime errors.
user.name!
user.age!
JSON type
PostgreSQL only
class UserJson < Crecto::Model
schema "users_json" do
field :settings, Json
end
end
user = UserJson.new
user.settings = {"one" => "test", "two" => 123, "three" => 12321319323298}
Repo.insert(user)
query = Query.where("settings @> '{\"one\":\"test\"}'")
users = Repo.all(UserJson, query)
Array type
PostgreSQL only
class UserArray < Crecto::Model
schema "users_array" do
field :string_array, Array(String)
field :int_array, Array(Int32)
field :float_array, Array(Float64)
field :bool_array, Array(Bool)
end
end
user = UserArray.new
user.string_array = ["one", "two", "three"]
Repo.insert(user)
query = Query.where("? = ANY(string_array)", "one")
users = Repo.all(UserArray, query)
Database Logging
By default nothing is logged. To enable pass any type of IO to the logger. For STDOUT use:
Crecto::DbLogger.set_handler(STDOUT)
Write to a file:
f = File.open("database.log", "w")
f.sync = true
Crecto::DbLogger.set_handler(f)