BulkUpsert (Bulk Upsert v0.1.2)
View SourceEnable bulk upsert functionality when working with Ecto.
Summary
Functions
Validate a list of attrs maps (attrs_list) by passing them through an Ecto changeset,
then upsert the valid items to the database that corresponds to a given Ecto repo_module (e.g.
YourProject.Repo).
Functions
Validate a list of attrs maps (attrs_list) by passing them through an Ecto changeset,
then upsert the valid items to the database that corresponds to a given Ecto repo_module (e.g.
YourProject.Repo).
Using a changeset serves two purposes:
- The changeset can be used to validate and transform the data.
- Using a changeset allows this function to perform bulk upserts with nested associations.
For validation, each list item in the attrs_list is converted to a changeset for a given
schema_module. By default, this function expects the schema module to contain a 2-arity
function called :changeset. (See the #options section for more info.)
Basic example
iex> BulkUpsert.bulk_upsert(
...> YourProject.Repo,
...> YourProject.Persons.Person,
...> _attrs_list = [
...> %{id: 1, name: "Alice", age: 25, phone_number: "555-1234"},
...> %{id: 2, name: "Bob", age: 35, phone_number: "555-2345"},
...> ]
...> )
:okOptions
:changeset_function_atom- The name of the 2-arity changeset function to apply for the givenschema_module(Default::changeset):insert_all_function_module- Instead of using the:insert_allfunction in the givenrepo_module, you may specify the name of a custom module to use instead. (Default: Inherited from the value specified in therepo_modulefunction argument, e.g.YourProject.Repo))- Example:
YourProject.OtherRepo
- Example:
:insert_all_function_atom- Instead of using your repo module's:insert_allfunction, you may pass a compatible equivalent that accepts the same arguments. (Default::insert_all)- Example:
:insert_all_with_autogenerated_timestamps
- Example:
:insert_all_opts- Pass customoptsto theinsert_all/3function. This option consists of a map whose key is the schema module that may have items being upserted, and the value is theYourProject.Repo.insert_all/3opts that will be applied when items for that schema are being upserted. By default, this function is configured to replace all values in a given struct, except for the primary key(s) and the insert timestamp. (Default:%{})- Example:
%{YourProject.Persons.Person => [on_conflict: {:nothing}]}
- Example:
:recover_changeset_errors- If the given fields in a changeset have errors, then replace them with a custom fallback value. (Default:%{})- Example:
%{YourProject.Persons.Person => %{phone_number: "INVALID"}}
- Example:
:replace_all_except- If a row already exists, then all fields will be replaced except the primary key, and any fields specified here. (Default:[])- Example:
[:field, :other_field]
- Example:
:timeout- The maximum timeout for a transaction. (Default:15000)- Example:
60_000
- Example:
Examples
Upsert a list of Person attrs using the changeset function
YourProject.Persons.Person.upsert_changeset/2 to validate the attrs:
iex> attrs_list = [%{id: 1, name: "Alice", ...}]
iex> BulkUpsert.bulk_upsert(
...> YourProject.Repo,
...> YourProject.Persons.Person,
...> attrs_list,
...> changeset_function_atom: :upsert_changeset
...> )
:okUpsert a list of attrs, but overwrite the :name field if there is a conflict.
If using this option, you must declare each schema that will get a customized :insert_all_opts
keyword list. Any schemas that are not given custom :insert_all_opts will overwrite all fields
except the primary key:
iex> insert_all_opts = %{
...> YourProject.Persons => [on_conflict: {:replace, [:name]}]
...> }
iex> BulkUpsert.bulk_upsert(
...> YourProject.Repo,
...> YourProject.Persons.Person,
...> _attrs_list = [%{id: 1, name: "Alicia"}],
...> insert_all_opts: insert_all_opts
...> )
:okKnown limitations
- This function will not currently work with the
:placeholdersoption of Ecto'sinsert_all/3function. This is because the attrs are passed directly to the changesets for validation, so the placeholder values will not be parsed correctly. This functionality can be added later if needed.