Current section
Files
Jump to
Current section
Files
src/glsql@validate.erl
-module(glsql@validate).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glsql/validate.gleam").
-export([check/2]).
-file("src/glsql/validate.gleam", 211).
-spec has_column(glsql@ast:table(), binary()) -> boolean().
has_column(Table, Name) ->
gleam@list:any(
erlang:element(4, Table),
fun(C) ->
string:lowercase(erlang:element(2, C)) =:= string:lowercase(Name)
end
).
-file("src/glsql/validate.gleam", 205).
-spec find_table(glsql@ast:schema_ast(), binary()) -> {ok, glsql@ast:table()} |
{error, nil}.
find_table(Schema, Name) ->
gleam@list:find(
erlang:element(2, Schema),
fun(T) ->
string:lowercase(erlang:element(2, T)) =:= string:lowercase(Name)
end
).
-file("src/glsql/validate.gleam", 159).
-spec foreign_keys(glsql@ast:table(), glsql@ast:schema_ast()) -> list(glsql@error:error()).
foreign_keys(Table, Schema) ->
Inline = gleam@list:flat_map(
erlang:element(4, Table),
fun(C) ->
gleam@list:filter_map(erlang:element(4, C), fun(K) -> case K of
{references, T, Cols, Pos} ->
{ok, {T, Cols, Pos}};
_ ->
{error, nil}
end end)
end
),
Table_level = gleam@list:filter_map(
erlang:element(5, Table),
fun(K@1) -> case K@1 of
{table_foreign_key, _, T@1, Cols@1, Pos@1} ->
{ok, {T@1, Cols@1, Pos@1}};
_ ->
{error, nil}
end end
),
_pipe = lists:append(Inline, Table_level),
gleam@list:flat_map(
_pipe,
fun(Fk) ->
{Ref_table, Ref_cols, Pos@2} = Fk,
case find_table(Schema, Ref_table) of
{error, nil} ->
[{validation_error,
<<<<"`"/utf8, Ref_table/binary>>/binary,
"` is not a table in this schema"/utf8>>,
Pos@2,
none}];
{ok, Target} ->
gleam@list:filter_map(
Ref_cols,
fun(Col) -> case has_column(Target, Col) of
true ->
{error, nil};
false ->
{ok,
{validation_error,
<<<<<<<<"`"/utf8, Ref_table/binary>>/binary,
"` has no column `"/utf8>>/binary,
Col/binary>>/binary,
"`"/utf8>>,
Pos@2,
none}}
end end
)
end
end
).
-file("src/glsql/validate.gleam", 136).
-spec reserved_names(glsql@ast:table(), glsql@config:config()) -> list(glsql@error:error()).
reserved_names(Table, Cfg) ->
gleam@list:filter_map(
erlang:element(4, Table),
fun(C) ->
Key = <<<<(erlang:element(2, Table))/binary, "."/utf8>>/binary,
(erlang:element(2, C))/binary>>,
Renamed = gleam@dict:has_key(erlang:element(6, Cfg), Key),
case gleam@list:contains(
[<<"as"/utf8>>,
<<"assert"/utf8>>,
<<"auto"/utf8>>,
<<"case"/utf8>>,
<<"const"/utf8>>,
<<"delegate"/utf8>>,
<<"derive"/utf8>>,
<<"echo"/utf8>>,
<<"else"/utf8>>,
<<"fn"/utf8>>,
<<"if"/utf8>>,
<<"implement"/utf8>>,
<<"import"/utf8>>,
<<"let"/utf8>>,
<<"macro"/utf8>>,
<<"opaque"/utf8>>,
<<"panic"/utf8>>,
<<"pub"/utf8>>,
<<"test"/utf8>>,
<<"todo"/utf8>>,
<<"type"/utf8>>,
<<"use"/utf8>>],
string:lowercase(erlang:element(2, C))
)
andalso not Renamed of
true ->
{ok,
{validation_error,
<<<<<<<<<<<<<<"`"/utf8,
(erlang:element(2, C))/binary>>/binary,
"` is a reserved word in Gleam, so it cannot be a field name. "/utf8>>/binary,
"Add a rename to glsql.toml:\n\n [rename]\n \""/utf8>>/binary,
Key/binary>>/binary,
"\" = \""/utf8>>/binary,
(erlang:element(2, C))/binary>>/binary,
"_\""/utf8>>,
erlang:element(5, C),
none}};
false ->
{error, nil}
end
end
).
-file("src/glsql/validate.gleam", 120).
-spec empty_names(glsql@ast:table()) -> list(glsql@error:error()).
empty_names(Table) ->
Table_errors = case gleam@string:trim(erlang:element(2, Table)) =:= <<""/utf8>> of
true ->
[{validation_error,
<<"This table has an empty name"/utf8>>,
erlang:element(6, Table),
none}];
false ->
[]
end,
Column_errors = gleam@list:filter_map(
erlang:element(4, Table),
fun(C) ->
case gleam@string:trim(erlang:element(2, C)) =:= <<""/utf8>> of
true ->
{ok,
{validation_error,
<<"This column has an empty name"/utf8>>,
erlang:element(5, C),
none}};
false ->
{error, nil}
end
end
),
lists:append(Table_errors, Column_errors).
-file("src/glsql/validate.gleam", 89).
-spec multiple_primary_keys(glsql@ast:table()) -> list(glsql@error:error()).
multiple_primary_keys(Table) ->
Inline = gleam@list:filter(
erlang:element(4, Table),
fun(C) -> gleam@list:any(erlang:element(4, C), fun(K) -> case K of
{primary_key, _} ->
true;
_ ->
false
end end) end
),
Table_level = gleam@list:filter(
erlang:element(5, Table),
fun(K@1) -> case K@1 of
{table_primary_key, _, _} ->
true;
_ ->
false
end end
),
case (erlang:length(Inline) + erlang:length(Table_level)) > 1 of
true ->
[{validation_error,
<<<<"`"/utf8, (erlang:element(2, Table))/binary>>/binary,
"` declares more than one primary key"/utf8>>,
erlang:element(6, Table),
none}];
false ->
[]
end.
-file("src/glsql/validate.gleam", 66).
-spec duplicate_columns(glsql@ast:table()) -> list(glsql@error:error()).
duplicate_columns(Table) ->
{Errors@1, _} = gleam@list:fold(
erlang:element(4, Table),
{[], gleam@set:new()},
fun(State, C) ->
{Errors, Seen} = State,
Key = string:lowercase(erlang:element(2, C)),
case gleam@set:contains(Seen, Key) of
true ->
{[{validation_error,
<<<<<<<<"`"/utf8,
(erlang:element(2, Table))/binary>>/binary,
"` has two columns named `"/utf8>>/binary,
(erlang:element(2, C))/binary>>/binary,
"`"/utf8>>,
erlang:element(5, C),
none} |
Errors],
Seen};
false ->
{Errors, gleam@set:insert(Seen, Key)}
end
end
),
lists:reverse(Errors@1).
-file("src/glsql/validate.gleam", 29).
-spec check_table(
glsql@ast:table(),
glsql@ast:schema_ast(),
glsql@config:config()
) -> list(glsql@error:error()).
check_table(Table, Schema, Cfg) ->
lists:append(
[duplicate_columns(Table),
multiple_primary_keys(Table),
empty_names(Table),
reserved_names(Table, Cfg),
foreign_keys(Table, Schema)]
).
-file("src/glsql/validate.gleam", 43).
-spec duplicate_tables(list(glsql@ast:table())) -> list(glsql@error:error()).
duplicate_tables(Tables) ->
{Errors@1, _} = gleam@list:fold(
Tables,
{[], gleam@set:new()},
fun(State, T) ->
{Errors, Seen} = State,
Key = string:lowercase(erlang:element(2, T)),
case gleam@set:contains(Seen, Key) of
true ->
{[{validation_error,
<<<<"The table `"/utf8,
(erlang:element(2, T))/binary>>/binary,
"` is defined more than once"/utf8>>,
erlang:element(6, T),
none} |
Errors],
Seen};
false ->
{Errors, gleam@set:insert(Seen, Key)}
end
end
),
lists:reverse(Errors@1).
-file("src/glsql/validate.gleam", 16).
-spec check(glsql@ast:schema_ast(), glsql@config:config()) -> {ok, nil} |
{error, list(glsql@error:error())}.
check(Schema, Cfg) ->
Errors = lists:append(
[duplicate_tables(erlang:element(2, Schema)),
gleam@list:flat_map(
erlang:element(2, Schema),
fun(T) -> check_table(T, Schema, Cfg) end
)]
),
case Errors of
[] ->
{ok, nil};
_ ->
{error, Errors}
end.