This is a work in progress. There's also an article about sumo_db. This articles might be a little outdated by now, but can still provide some basic information on how to get started.
sumo_db aims to ease db access for erlang applications. It offers a very simple persistance layer capable of interacting with different db's, while offering a consistent api to your code.
If you find any bugs or have a problem while using this library, please open an issue in this repo (or a pull request :)).
-
sumo_db gives you a standard way to define your db schema, regardless of the db implementation (mongo, mysql, redis, elasticsearch, etc.).
-
Your entities encapsulate behavior in code (i.e. functions in a module) and state in a
sumo:doc()implementation. -
sumois the main module. It translates to and from sumo internal records into your own state. -
Each store is managed by a worker pool of processes, each one using a module that implements
sumo_storeand calls the actual db driver (e.g:sumo_store_mnesia). -
Some native domain events are supported, that are dispatched through a
gen_event:notify/2automatically when an entity is created, updated, deleted. Also when a schema is created and when all entities of a given type are deleted. Events are described in this article. -
Full conditional logic support when using
find_by/2anddelete_by/2function. You can find more information about the syntax of this conditional logic operators here. -
Support for sorting (
ascordesc) based on multiple fields unsingfind_by/5andfind_all/4functions. For example this[{age, desc}, {name, asc}]]will sort descendently byageand ascendently byname. -
Support for docs/models validations through
sumo_changeset(check out the Changeset section).
These three concepts have a specific meaning in the context of sumo_db.
-
Backend: establishes and holds a single Database instance connection.
-
Store: implements the specific operations that modify the contents of the backend and retrieves the information it holds.
-
Repository: the application that uses
sumo_dbshould implement one repository for each entity that's defined in it. The repository is the module that bridges the model and the store.
- Mnesia – built-in with
sumo - Riak
- PostgreSQL
- MySQL
- MongoDB
- ElasticSearch
To implement an adapter, you must implement two specific behaviours:
- sumo_backend – DB connection
- sumo_store – implements the Sumo API
You can check the implemented adapters mentioned above in order to have a better idea about how to build a custom adapter from scratch.
Sumo dispatches events when things happen. An Event has this structure:
{EventId, Model, Event, Args}EventIdis areference()which identifies the eventModelis the model where the event happend, for example, if we are creating a new entitiy in the modelpeoplethe value ofModelwould bepeople.Eventis the type of the event.Argsextra data sent.
Supported types of events:
pre_persistedjust before persisting some entity. This event has the entity we want to persist asArgs. It is dispatched on this function:sumo:persist/2
persistedjust after persisting some entity. This event has the persisted entity asArgs. This Event has the sameEventIdas itspre_persistedevent. It is dispatched on this function:sumo:persist/2
pre_delete_alljust before deleting all entities for a model. This event has noArgs. It is dispatched on this function:sumo:delete_all/1
deleted_alljust after deleting all entities for a model. This event has noArgs. This Event has the sameEventIdas itspre_delete_allevent. It is dispatched on this function:sumo:delete_all/1
pre_deletedjust before deleting an entity. This event has the entity id asArgs. It is dispatched on this function:sumo:delete/2
deletedjust after deleting an entity. This event has the entity id asArgs. This Event has the sameEventIdas itspre_deletedevent. It is dispatched on this function:sumo:delete/2
pre_deleted_totaljust before deleting by some delete conditions. This event has the sumo conditions asArgs. It is dispatched on this function:sumo:delete_by/2
deleted_totaljust after deleting by some delete conditions. This event has a list with the number of entities deleted and the delete conditions asArgs. This Event has the sameEventIdas itspre_deleted_totalevent. It is dispatched on this function:sumo:delete_by/2
pre_schema_createdjust before creating a sumo schema. This event has noArgs. It is dispatched on this function:sumo:create_schema/2
schema_createdjust after creating a sumo schema. This event has noArgs. This Event has the sameEventIdas itspre_schema_createdevent. It is dispatched on this function:sumo:create_schema/2
Sumo requires users to add their own gen_event's in order to handle those events. In order to add them Users have to configure sumo properly. In the config file we can add them like this under sumo_db configuration:
{events, [
{'_', sumo_test_people_events_manager},
{people, sumo_test_people_events_manager}
]}Sumo allows us to add a gen_event to one type of model (i.e. people) or for all ('_').
This feature is inspired by Elixir Ecto.Changeset, and the module that implements this feature is sumo_changeset.
NOTE: This example uses FancyFlow in order to pipe changeset functions in a nicer way.
%% suppose you have a model/doc `person`, and that module provides a function
%% to encapsulate model/doc creation
Person = person:new(<<"John">>, <<"Doe">>),
%% create the set of params/changes
Params = #{age => 33, id => 1, <<"last_name">> => <<"other">>},
%% run the changeset
Changeset = [pipe](people,
sumo_changeset:cast(_, Person, Params, [id, first_name, last_name, age, status]),
sumo_changeset:validate_required(_, [id, last_name, status]),
sumo_changeset:validate_inclusion(_, status, [<<"active">>, <<"blocked">>]),
sumo_changeset:validate_number(_, age, [{less_than_or_equal_to, 18}]),
sumo_changeset:validate_length(_, last_name, [{min, 3}]),
sumo_changeset:validate_format(_, last_name, <<"^[a-zA-Z]">>)),See: examples/blog for a full example. To run it, while being in the top level directory:
make all blog
See: examples/custom_store for creating your own Store. To run it, follow the instructions in this README
$ rebar3 dialyzer
$ rebar3 ct
All notable changes to this project will be documented in the CHANGELOG.md.
We want to thank all of our contributors for their hard work :muscle:.