%%% @doc Main **internal** module for sumo. %%% Use this one from your own applications. %%% %%% Copyright 2012 Inaka <hello@inaka.net> %%% %%% Licensed under the Apache License, Version 2.0 (the "License"); %%% you may not use this file except in compliance with the License. %%% You may obtain a copy of the License at %%% %%% http://www.apache.org/licenses/LICENSE-2.0 %%% %%% Unless required by applicable law or agreed to in writing, software %%% distributed under the License is distributed on an "AS IS" BASIS, %%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %%% See the License for the specific language governing permissions and %%% limitations under the License. %%% @end %%% @copyright Inaka %%% -module(sumo_internal). -author("Marcelo Gornstein "). -author("Brujo Benavides "). -github("https://github.com/inaka"). -license("Apache License 2.0"). %%% API for doc/schema manipulation. -export([new_schema/2, new_field/3]). %%% API for opaqueness -export([ schema_name/1, schema_fields/1, doc_name/1, doc_fields/1, wakeup/1, new_doc/1, new_doc/2 ]). %%% API for schema fields manipulation. -export([ get_schema/1, field_name/1, field_type/1, field_attrs/1, field_is/2, get_field/2, set_field/3, id_field_name/1, id_field_type/1 ]). %%% API for conditional logic. -export([check_operator/1]). -export([report_overrun/1]). %%%=================================================================== %%% Types definitions %%%=================================================================== -opaque schema() :: #{ name => atom(), fields => [field()] }. -opaque doc() :: #{ name => atom(), module => module(), fields => sumo:model() }. -opaque field() :: #{ name => atom(), type => atom(), attrs => sumo:field_attrs() }. -export_type([schema/0, doc/0, field/0]). %%%=================================================================== %%% API %%%=================================================================== %% @doc Returns a new schema. -spec new_schema(sumo:schema_name(), [field()]) -> schema(). new_schema(Name, Fields) -> #{name => Name, fields => Fields}. %% @doc Returns a new field of the given type and attributes. -spec new_field( sumo:field_name(), sumo:field_type(), sumo:field_attrs() ) -> field(). new_field(Name, Type, Attributes) -> #{name => Name, type => Type, attrs => Attributes}. %% @doc Returns the name of the schema -spec schema_name(schema()) -> sumo:schema_name(). schema_name(Schema) -> maps:get(name, Schema, undefined). %% @doc Returns the fields of the schema -spec schema_fields(schema()) -> [field()]. schema_fields(Schema) -> maps:get(fields, Schema, []). %% @doc Returns the doc name -spec doc_name(doc()) -> atom(). doc_name(Doc) -> maps:get(name, Doc, undefined). -spec doc_fields(doc()) -> sumo:model(). doc_fields(Doc) -> maps:get(fields, Doc, []). %% @doc Wakes up the document -spec wakeup(doc()) -> sumo:user_doc(). wakeup(Doc) -> Module = sumo_config:get_prop_value(doc_name(Doc), module), Fields = maps:get(fields, Doc, []), Module:sumo_wakeup(Fields). %% @doc Returns a new doc. -spec new_doc(sumo:schema_name()) -> doc(). new_doc(Name) -> new_doc(Name, #{}). %% @doc Returns a new doc. -spec new_doc(sumo:schema_name(), sumo:model()) -> doc(). new_doc(Name, Fields) -> Module = sumo_config:get_prop_value(Name, module), #{name => Name, module => Module, fields => Fields}. %% @doc Returns the schema for a given DocName. -spec get_schema(sumo:schema_name()) -> schema(). get_schema(DocName) -> Module = sumo_config:get_prop_value(DocName, module), Module:sumo_schema(). %% @doc Returns the name of the given field. -spec field_name(field()) -> sumo:field_name(). field_name(#{name := Name}) -> Name. %% @doc Returns the type of the given field. -spec field_type(field()) -> sumo:field_type(). field_type(#{type := Type}) -> Type. %% @doc Returns all attributes of the given field. -spec field_attrs(field()) -> sumo:field_attrs(). field_attrs(_Field = #{attrs := Attributes}) -> Attributes. %% @doc True if the field has a given attribute. -spec field_is(atom(), field()) -> boolean(). field_is(What, #{attrs := Attributes}) -> proplists:is_defined(What, Attributes). %% @doc Returns the value of a field from a sumo_doc. -spec get_field(sumo:field_name(), doc()) -> sumo:field_value(). get_field(Name, Doc) -> maps:get(Name, doc_fields(Doc), undefined). %% @doc Sets a value in an sumo_doc. -spec set_field(sumo:field_name(), sumo:field_value(), doc()) -> doc(). set_field(FieldName, Value, _Doc = #{fields := Fields, name := Name}) -> new_doc(Name, maps:put(FieldName, Value, Fields)). %% @doc Returns name of field marked as ID for the given schema or doc name. -spec id_field_name(sumo:schema_name()) -> sumo:field_name(). id_field_name(DocName) -> field_name(get_id_field(get_schema(DocName))). %% @doc Returns type of field marked as ID for the given schema or doc name. -spec id_field_type(sumo:schema_name()) -> sumo:field_type(). id_field_type(DocName) -> field_type(get_id_field(get_schema(DocName))). %% @doc Checks the operator is known, throws otherwise. -spec check_operator(sumo:operator()) -> ok. check_operator('<') -> ok; check_operator('=<') -> ok; check_operator('>') -> ok; check_operator('>=') -> ok; check_operator('==') -> ok; check_operator('/=') -> ok; check_operator('like') -> ok; check_operator(Op) -> throw({unknown_operator, Op}). -spec report_overrun(term()) -> ok. report_overrun(Report) -> lager:error("~p", [Report]). %%%=================================================================== %%% Internal functions %%%=================================================================== %% @doc Returns field marked as ID for the given schema or doc name. %% @private get_id_field(_Schema = #{fields := Fields}) -> hd(lists:filter(fun(_Field = #{attrs := Attributes}) -> length(lists:filter(fun(T) -> T =:= id end, Attributes)) > 0 end, Fields)).