Home

Awesome

EctoShortcuts 🚅

Lightweight Elixir extension to simplify common use cases in Ecto.

Installation

  1. Get Hex

  2. Add ecto_shortcuts to your list of dependencies in mix.exs:

  def deps do
    [{:ecto_shortcuts, "~> 0.1.6"}]
  end

Configuration

Add it to your Ecto Models like:

defmodule MyApp.User do
  ...
  use EctoShortcuts, repo: MyApp.Repo
  ...
end  

or (to closely mirror Phoenix model standards):

defmodule MyApp.RepoAUsers do
  ...
  use EctoShortcuts, repo: MyApp.RepoA, model: MyApp.User
  ...
end

defmodule MyApp.RepoBUsers do
  ...
  use EctoShortcuts, repo: MyApp.RepoB, model: MyApp.User
  ...
end  

Usage

insert

  # create a new user named Bob
  MyApp.User.insert name: "Bob"
  MyApp.User.insert %{name: "Bob"}

  # create a new user named Alice without validation
  MyApp.User.insert name: "Alice", validate: false
  MyApp.User.insert %{name: "Alice"}, %{validate: false}

insert!

  MyApp.User.insert! name: "Bob"
  MyApp.User.insert! %{name: "Bob"}

  MyApp.User.insert! name: "Alice", validate: false
  MyApp.User.insert! %{name: "Alice"}, %{validate: false}

-- note: If your model defines a changeset, insert, insert! & any validations will by default use that changeset. To disable validation, use the validate: false option shown below. If your model lacks a changeset, then your model will be inserted without any validation.

--

update_all

  # set status_id to 3 on all users
  MyApp.User.update_all set: [status_id: 3]
  MyApp.User.update_all %{set: [status_id: 3]}

update_by

  # set status_id to 4 where mode is 3
  MyApp.User.update_by [mode: 3], set: [status_id: 4]
  MyApp.User.update_by %{mode: 3}, %{set: [status_id: 4]}

update_by_returning

  # set status_id to 4 where mode is 3
  updated_users = MyApp.User.update_by_returning [mode: 3], set: [status_id: 4]

  # set status_id to 3 for user 1 and return updated user with posts association preloaded
  [updated_user] = MyApp.User.update_by_returning [id: 1], [set: [status_id: 3]], preload: [:posts]

  # same as above but using maps
  [updated_user] = MyApp.User.update_by_returning %{id: 1}, %{set: [status_id: 3]}, preload: [:posts]

delete_all

  # delete all users
  MyApp.User.delete_all

delete_by

  # delete all users where mode is 3
  MyApp.User.delete_by mode: 3
  MyApp.User.delete_by %{mode: 3}

get

  # get user with id 3
  MyApp.User.get 3

  # get user with id 3 and preload posts association
  MyApp.User.get 3, preload: [:posts]

  # get user with id 3 and preload posts associations in addition to posts.post_type association
  MyApp.User.get 3, preload: [{:posts, :post_type}]

get!

  MyApp.User.get! 3
  MyApp.User.get! 3, preload: [:posts]
  MyApp.User.get! 3, preload: [{:posts, :post_type}]

get_by

  # fetch a single user where name is Sally and age is 30
  MyApp.User.get_by name: "Sally", age: 30

  # fetch a single user where name is Sally and preload the posts association
  MyApp.User.get_by [name: "Sally"],  preload: [:posts]

  # same as above but using maps
  MyApp.User.get_by %{name: "Sally"},  preload: [:posts]

get_by!

  MyApp.User.get_by! name: "Sally", age: 30
  MyApp.User.get_by! [name: "Sally", age: 30],  preload: [:posts]

where

  # get all users where status is 3
  MyApp.User.where status: 3

  # get all users where status is 3 and limit to 10 ordering by created_at
  MyApp.User.where [status: 3], limit: 10, order_by: [desc: :created_at]

  # same as above but using maps
  MyApp.User.where %{status: 3}, %{limit: 10, order_by: [desc: :created_at]}

  # same as above but preload the posts association
  MyApp.User.where [status: 3],  limit: 10, order_by: [desc: :inserted_at], preload: [:posts]

get_or_insert

  # get user with name John Smith or insert if user does not exist
  MyApp.User.get_or_insert first_name: "John", last_name: "Smith"

  MyApp.User.get_or_insert %{first_name: "John", last_name: "Smith"}

get_or_insert!

  MyApp.User.get_or_insert! first_name: "John", last_name: "Smith"

first

  # get first user
  MyApp.User.first

  # get first user preloading the posts association
  MyApp.User.first preload: [:posts]

all

  # get all users
  MyApp.User.all

  # get all users preloading the posts association
  MyApp.User.all preload: [:posts]

count

  # get count of all users
  MyApp.User.count

count_where

  # get count of all users where status is 4
  MyApp.User.count_where status_id: 4

  MyApp.User.count_where %{status_id: 4}

Wilcard Preloads

You can preload all associations via a wildcard, do

  MyApp.User.get 3, preload: "*"

or

  MyApp.User.get 3, preload: :*

Default Preloads

You can set a default set of preloads.

defmodule MyApp.Users do
  ...
  use EctoShortcuts, repo: MyApp.Repo,
                     model: MyApp.User,
                     default_preload: [:friends, :user_status, :posts]
  ...
end

or using wildcards

defmodule MyApp.Users do
  ...
  use EctoShortcuts, repo: MyApp.Repo,
                     model: MyApp.User,
                     default_preload: "*"
  ...
end

If you want to override defaults, pass in specific preloads.

Running Tests

To run tests:

Coming Soon:

NOTE: Ecto's DSL is rich & flexible. It should be deferred to for anything complex. 🙌