mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-22 17:28:25 +01:00
Use yconf validator for custom Mnesia schemas
This commit is contained in:
parent
39cf8d86d6
commit
6011135d24
@ -45,8 +45,15 @@
|
|||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("ejabberd_stacktrace.hrl").
|
-include("ejabberd_stacktrace.hrl").
|
||||||
|
|
||||||
-record(state, {tables = #{} :: map(),
|
-record(state, {tables = #{} :: tables(),
|
||||||
schema = [] :: [{atom(), [{atom(), any()}]}]}).
|
schema = [] :: [{atom(), custom_schema()}]}).
|
||||||
|
|
||||||
|
-type tables() :: #{atom() => {[{atom(), term()}], term()}}.
|
||||||
|
-type custom_schema() :: [{ram_copies | disc_copies | disc_only_copies, [node()]} |
|
||||||
|
{local_content, boolean()} |
|
||||||
|
{type, set | ordered_set | bag} |
|
||||||
|
{attributes, [atom()]} |
|
||||||
|
{index, [atom()]}].
|
||||||
|
|
||||||
start() ->
|
start() ->
|
||||||
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
|
||||||
@ -201,79 +208,51 @@ schema(Name, Default, Schema) ->
|
|||||||
[Name, TabDefs]),
|
[Name, TabDefs]),
|
||||||
TabDefs;
|
TabDefs;
|
||||||
false ->
|
false ->
|
||||||
?DEBUG("No custom Mnesia schema for table '~s' found",
|
|
||||||
[Name]),
|
|
||||||
Default
|
Default
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec read_schema_file() -> [{atom(), custom_schema()}].
|
||||||
read_schema_file() ->
|
read_schema_file() ->
|
||||||
File = schema_path(),
|
File = schema_path(),
|
||||||
case fast_yaml:decode_from_file(File, [plain_as_atom]) of
|
case fast_yaml:decode_from_file(File, [plain_as_atom]) of
|
||||||
{ok, [Defs|_]} ->
|
{ok, Y} ->
|
||||||
?INFO_MSG("Using custom Mnesia schema from ~s", [File]),
|
case econf:validate(validator(), lists:flatten(Y)) of
|
||||||
lists:flatmap(
|
{ok, []} ->
|
||||||
fun({Tab, Opts}) ->
|
?WARNING_MSG("Mnesia schema file ~s is empty", [File]),
|
||||||
case validate_schema_opts(File, Opts) of
|
[];
|
||||||
{ok, NewOpts} ->
|
{ok, Config} ->
|
||||||
[{Tab, lists:ukeysort(1, NewOpts)}];
|
lists:map(
|
||||||
error ->
|
fun({Tab, Opts}) ->
|
||||||
[]
|
{Tab, lists:map(
|
||||||
end
|
fun({storage_type, T}) -> {T, [node()]};
|
||||||
end, Defs);
|
(Other) -> Other
|
||||||
{ok, []} ->
|
end, Opts)}
|
||||||
?WARNING_MSG("Mnesia schema file ~s is empty", [File]),
|
end, Config);
|
||||||
[];
|
{error, Reason, Ctx} ->
|
||||||
|
?ERROR_MSG("Failed to read Mnesia schema from ~s: ~s",
|
||||||
|
[File, econf:format_error(Reason, Ctx)]),
|
||||||
|
[]
|
||||||
|
end;
|
||||||
{error, enoent} ->
|
{error, enoent} ->
|
||||||
?DEBUG("No custom Mnesia schema file found", []),
|
?DEBUG("No custom Mnesia schema file found at ~s", [File]),
|
||||||
[];
|
[];
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?ERROR_MSG("Failed to read Mnesia schema file ~s: ~s",
|
?ERROR_MSG("Failed to read Mnesia schema file ~s: ~s",
|
||||||
[File, fast_yaml:format_error(Reason)]),
|
[File, fast_yaml:format_error(Reason)])
|
||||||
[]
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
validate_schema_opts(File, Opts) ->
|
-spec validator() -> econf:validator().
|
||||||
try {ok, lists:map(
|
validator() ->
|
||||||
fun({storage_type, Type}) when Type == ram_copies;
|
econf:map(
|
||||||
Type == disc_copies;
|
econf:atom(),
|
||||||
Type == disc_only_copies ->
|
econf:options(
|
||||||
{Type, [node()]};
|
#{storage_type => econf:enum([ram_copies, disc_copies, disc_only_copies]),
|
||||||
({storage_type, _} = Opt) ->
|
local_content => econf:bool(),
|
||||||
erlang:error({invalid_value, Opt});
|
type => econf:enum([set, ordered_set, bag]),
|
||||||
({local_content, Bool}) when is_boolean(Bool) ->
|
attributes => econf:list(econf:atom()),
|
||||||
{local_content, Bool};
|
index => econf:list(econf:atom())},
|
||||||
({local_content, _} = Opt) ->
|
[{return, orddict}, unique]),
|
||||||
erlang:error({invalid_value, Opt});
|
[unique]).
|
||||||
({type, Type}) when Type == set;
|
|
||||||
Type == ordered_set;
|
|
||||||
Type == bag ->
|
|
||||||
{type, Type};
|
|
||||||
({type, _} = Opt) ->
|
|
||||||
erlang:error({invalid_value, Opt});
|
|
||||||
({attributes, Attrs} = Opt) ->
|
|
||||||
try lists:all(fun is_atom/1, Attrs) of
|
|
||||||
true -> {attributes, Attrs};
|
|
||||||
false -> erlang:error({invalid_value, Opt})
|
|
||||||
catch _:_ -> erlang:error({invalid_value, Opt})
|
|
||||||
end;
|
|
||||||
({index, Indexes} = Opt) ->
|
|
||||||
try lists:all(fun is_atom/1, Indexes) of
|
|
||||||
true -> {index, Indexes};
|
|
||||||
false -> erlang:error({invalid_value, Opt})
|
|
||||||
catch _:_ -> erlang:error({invalid_value, Opt})
|
|
||||||
end;
|
|
||||||
(Opt) ->
|
|
||||||
erlang:error({unknown_option, Opt})
|
|
||||||
end, Opts)}
|
|
||||||
catch _:{invalid_value, {Opt, Val}} ->
|
|
||||||
?ERROR_MSG("Mnesia schema ~s is incorrect: invalid value ~p of "
|
|
||||||
"option '~s'", [File, Val, Opt]),
|
|
||||||
error;
|
|
||||||
_:{unknown_option, Opt} ->
|
|
||||||
?ERROR_MSG("Mnesia schema ~s is incorrect: unknown option ~p",
|
|
||||||
[File, Opt]),
|
|
||||||
error
|
|
||||||
end.
|
|
||||||
|
|
||||||
create(Name, TabDef) ->
|
create(Name, TabDef) ->
|
||||||
?INFO_MSG("Creating Mnesia table '~s'", [Name]),
|
?INFO_MSG("Creating Mnesia table '~s'", [Name]),
|
||||||
|
Loading…
Reference in New Issue
Block a user