Skip to content

Instantly share code, notes, and snippets.

@izelnakri
Last active December 3, 2020 03:11
Show Gist options
  • Select an option

  • Save izelnakri/f65e6807ed233e60efa074c276b48b45 to your computer and use it in GitHub Desktop.

Select an option

Save izelnakri/f65e6807ed233e60efa074c276b48b45 to your computer and use it in GitHub Desktop.
Without pipes(|>) certain APIs will not get built or used. Application code below is very easy to read/follow/maintain and write.
// Ecto composable queries:
// iex> Movie \
// ...> |> where([m], m.id < 2) \
// ...> |> select([m], {m.title}) \
// ...> |> Repo.all
// [{"Pirates of Silicon Valley"}]
// In JavaScript with |> most likely would be:
Movie
|> where('m', 'm.id < 2') // 'm' because there could be multiple model references on |> sql joins()
|> select('m', 'm.title')
|> Repo.all
// returns: ['Pirates of Silicon Valley'] or Promise to await, or elixir like error handling with tuple: [boolean, returnValue]
// Today without |>:
Repo.all(select(where(Movie, 'm', 'm.id < 2'), 'm', 'm.title')))
# Ecto composable changesets/validations:
defmodule Email do
def changeset(struct, params \\ %{}) do
struct
|> cast(params, [:address])
|> validate_required([:address])
|> validate_format(:address, ~r/@/)
|> validate_length(:address, max: 75)
|> unique_constraint(:address)
|> foreign_key_constraint(:person_id)
end
def user_registration_changeset(struct, params \\ %{}) do
struct
|> cast(params, [:person_id])
|> changeset(params)
|> validate_required([:person_id])
|> generate_confirmation_token()
end
# ....
end
# in Elixir following would return a special Changeset object(struct) that has error, misses "person_id":
Email.user_registration_changeset(%Email{}, %{"adress" => "someone@example.com"})
Email.changeset(%Email{}, %{"address" => "someone@example.com"}) # returns a valid Changeset with no errors.
Email.user_registration_changeset(%Email{}, %{}) # returns a Changeset with all "address" and "person_id" errors
# For example, to insert or update a record to DB:
case Email.changeset(%Email{}, %{"address" => "someone@example.com"}) |> Repo.insert do
{:ok, email} -> serialize(email) |> to_json
{:error, changeset} -> format_error_to_json(changeset)
end
// Ecto composable changesets/validations
// without pipes(|>) this very nice API below is near impossible to use effectively:
import {
cast, validateRequired, validateFormat, validateLength, uniqueConstraint, foreignKeyConstraint
} from 'ecto';
interface ChangesetError {
[anyProperty: string]: string[]; // string of error messages
}
interface Changeset {
valid: boolean;
action: void | string; // more likely set after Repo.insert() / Repo.update() / Repo.delete() call
changes: object; // more like js object, holds only the changed properties with previous values of the model.
errors: ChangesetError[];
data: void | object; // data to insert/update/delete
}
export default class Email {
static changeset(oldInstance: Email, paramsToCastValidate: object): Changeset {
return oldInstance
|> cast(paramsToCastValidate, ['address'])
|> validateRequired(['address'])
|> validateFormat('address', /@/)
|> validateLength('address', { min: 3, max: 75 })
|> uniqueConstraint('address')
|> foreignKeyConstraint('person_id')
}
static userRegistrationChangeset(oldInstance: Email, paramsToCastValidate: object): Changeset {
return oldInstance
|> cast(paramsToCastValidate, ['person_id'])
|> changeset(paramsToCastValidate)
|> validateRequired(['person_id'])
|> this.generateConfirmationToken()
}
// ... with static generateConfirmationToken() {} uses cast(changeset, ['confirmation_token'], generatedToken) inside
}
Email.userRegistrationChangeset(new Email(), { adress: 'someone@example.com' })
// -> Changeset{ valid: false, action: null, changes: { address: null }, errors: [{ person_id: ['is required'] }], data: { address: 'someone@example.com' } }
Email.changeset(new Email(), { address: 'someone@example.com' }) // returns a valid Changeset with no errors.
// -> Changeset{ valid: true, action: null, changes: { address: null }, errors: [], data: { address: 'someone@example.com' } }
Email.userRegistrationChangeset(new Email(), {}) // returns a Changeset with all "address" and "person_id" errors
// -> Changeset{ valid: false, action: null, changes: { address: null },
// errors: [{ address: ['is required', 'should have correct format', 'should be min. 3 characters', 'already exists'] }, { person_id: ['is_required] }],
// data: { address: 'someone@example.com' } }
// For example, to insert or update a record to DB:
try {
Email.changeset(new Email(), { address: 'someone@example.com' })
|> Repo.insert // or maybe with await, Repo can find the table from the email.constructor.name
} catch(error: Changeset) {
// do smt with the Changeset
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment