Current section
Files
Jump to
Current section
Files
src/glsql@internal@parser.erl
-module(glsql@internal@parser).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glsql/internal/parser.gleam").
-export([parse/1]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/glsql/internal/parser.gleam", 105).
?DOC(false).
-spec skip_statement(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()).
skip_statement(Tokens) ->
case Tokens of
[] ->
[];
[{positioned, semicolon, _, _} | Rest] ->
Rest;
[_ | Rest@1] ->
skip_statement(Rest@1)
end.
-file("src/glsql/internal/parser.gleam", 639).
?DOC(false).
-spec expect(
list(glsql@internal@token:positioned()),
glsql@internal@token:token(),
binary()
) -> {ok, {integer(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
expect(Tokens, Want, Label) ->
case Tokens of
[{positioned, T, Pos, _} | Rest] when T =:= Want ->
{ok, {Pos, Rest}};
[{positioned, T@1, Pos@1, _} | _] ->
{error,
{parse_error,
<<<<<<<<"Expected `"/utf8, Label/binary>>/binary,
"`, found `"/utf8>>/binary,
(glsql@internal@token:to_string(T@1))/binary>>/binary,
"`"/utf8>>,
Pos@1,
none}};
[] ->
{error,
{parse_error,
<<<<"Unexpected end of file, expected `"/utf8,
Label/binary>>/binary,
"`"/utf8>>,
0,
none}}
end.
-file("src/glsql/internal/parser.gleam", 598).
?DOC(false).
-spec identifier(list(glsql@internal@token:positioned())) -> {ok,
{binary(), integer(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
identifier(Tokens) ->
case Tokens of
[{positioned, {word, W}, Pos, _} | Rest] ->
{ok, {W, Pos, Rest}};
[{positioned, {quoted_ident, W@1}, Pos@1, _} | Rest@1] ->
{ok, {W@1, Pos@1, Rest@1}};
[{positioned, T, Pos@2, _} | _] ->
{error,
{parse_error,
<<<<"Expected a name, found `"/utf8,
(glsql@internal@token:to_string(T))/binary>>/binary,
"`"/utf8>>,
Pos@2,
none}};
[] ->
{error,
{parse_error,
<<"Unexpected end of file, expected a name"/utf8>>,
0,
none}}
end.
-file("src/glsql/internal/parser.gleam", 402).
?DOC(false).
-spec skip_words(list(glsql@internal@token:positioned()), list(binary())) -> list(glsql@internal@token:positioned()).
skip_words(Tokens, Words) ->
case Tokens of
[{positioned, {word, W}, _, _} | Rest] ->
case gleam@list:contains(Words, string:lowercase(W)) of
true ->
skip_words(Rest, Words);
false ->
Tokens
end;
_ ->
Tokens
end.
-file("src/glsql/internal/parser.gleam", 445).
?DOC(false).
-spec join(binary(), binary()) -> binary().
join(Acc, Word) ->
case (Acc =:= <<""/utf8>>) orelse gleam_stdlib:string_ends_with(
Acc,
<<"("/utf8>>
) of
true ->
<<Acc/binary, Word/binary>>;
false ->
<<<<Acc/binary, " "/utf8>>/binary, Word/binary>>
end.
-file("src/glsql/internal/parser.gleam", 413).
?DOC(false).
-spec take_expression(
list(glsql@internal@token:positioned()),
binary(),
integer()
) -> {binary(), list(glsql@internal@token:positioned())}.
take_expression(Tokens, Acc, Depth) ->
case Tokens of
[] ->
{gleam@string:trim(Acc), []};
[{positioned, comma, _, _} | _] when Depth =:= 0 ->
{gleam@string:trim(Acc), Tokens};
[{positioned, r_paren, _, _} | _] when Depth =:= 0 ->
{gleam@string:trim(Acc), Tokens};
[{positioned, {word, W}, _, _} | Rest] when Depth =:= 0 ->
case gleam@list:contains(
[<<"not"/utf8>>,
<<"null"/utf8>>,
<<"primary"/utf8>>,
<<"unique"/utf8>>,
<<"default"/utf8>>,
<<"references"/utf8>>,
<<"check"/utf8>>,
<<"constraint"/utf8>>,
<<"foreign"/utf8>>,
<<"generated"/utf8>>,
<<"collate"/utf8>>],
string:lowercase(W)
) of
true ->
{gleam@string:trim(Acc), Tokens};
false ->
take_expression(Rest, join(Acc, W), Depth)
end;
[{positioned, l_paren, _, _} | Rest@1] ->
take_expression(Rest@1, <<Acc/binary, "("/utf8>>, Depth + 1);
[{positioned, r_paren, _, _} | Rest@2] ->
take_expression(Rest@2, <<Acc/binary, ")"/utf8>>, Depth - 1);
[{positioned, {word, W@1}, _, _} | Rest@3] ->
take_expression(Rest@3, join(Acc, W@1), Depth);
[{positioned, T, _, _} | Rest@4] ->
take_expression(
Rest@4,
<<Acc/binary, (glsql@internal@token:to_string(T))/binary>>,
Depth
)
end.
-file("src/glsql/internal/parser.gleam", 378).
?DOC(false).
-spec take_parens(list(glsql@internal@token:positioned())) -> {binary(),
list(glsql@internal@token:positioned())}.
take_parens(Tokens) ->
case Tokens of
[{positioned, l_paren, _, _} | Rest] ->
{Expr, Rest@1} = take_expression(Rest, <<""/utf8>>, 0),
case Rest@1 of
[{positioned, r_paren, _, _} | Rest@2] ->
{Expr, Rest@2};
_ ->
{Expr, Rest@1}
end;
_ ->
take_expression(Tokens, <<""/utf8>>, 0)
end.
-file("src/glsql/internal/parser.gleam", 391).
?DOC(false).
-spec discard_parens(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()).
discard_parens(Tokens) ->
case Tokens of
[{positioned, l_paren, _, _} | _] ->
{_, Rest} = take_parens(Tokens),
Rest;
_ ->
Tokens
end.
-file("src/glsql/internal/parser.gleam", 363).
?DOC(false).
-spec generated_value(list(glsql@internal@token:positioned())) -> {binary(),
list(glsql@internal@token:positioned())}.
generated_value(Tokens) ->
Identity = case Tokens of
[{positioned, {word, W}, _, _} | _] ->
string:lowercase(W) =:= <<"identity"/utf8>>;
_ ->
false
end,
case {Identity, Tokens} of
{true, [_ | Rest]} ->
{<<"identity"/utf8>>, discard_parens(Rest)};
{_, _} ->
{Expr, Rest@1} = take_parens(Tokens),
{Expr, skip_words(Rest@1, [<<"stored"/utf8>>, <<"virtual"/utf8>>])}
end.
-file("src/glsql/internal/parser.gleam", 612).
?DOC(false).
-spec keyword(list(glsql@internal@token:positioned()), binary()) -> {ok,
{integer(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
keyword(Tokens, Want) ->
case Tokens of
[{positioned, {word, W}, Pos, _} | Rest] ->
case string:lowercase(W) =:= Want of
true ->
{ok, {Pos, Rest}};
false ->
{error,
{parse_error,
<<<<<<<<"Expected `"/utf8, Want/binary>>/binary,
"`, found `"/utf8>>/binary,
W/binary>>/binary,
"`"/utf8>>,
Pos,
none}}
end;
[{positioned, T, Pos@1, _} | _] ->
{error,
{parse_error,
<<<<<<<<"Expected `"/utf8, Want/binary>>/binary,
"`, found `"/utf8>>/binary,
(glsql@internal@token:to_string(T))/binary>>/binary,
"`"/utf8>>,
Pos@1,
none}};
[] ->
{error,
{parse_error,
<<<<"Unexpected end of file, expected `"/utf8, Want/binary>>/binary,
"`"/utf8>>,
0,
none}}
end.
-file("src/glsql/internal/parser.gleam", 338).
?DOC(false).
-spec collect_names(list(glsql@internal@token:positioned()), list(binary())) -> {ok,
{list(binary()), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
collect_names(Tokens, Acc) ->
gleam@result:'try'(
identifier(Tokens),
fun(_use0) ->
{Name, _, Rest} = _use0,
case Rest of
[{positioned, comma, _, _} | Rest@1] ->
collect_names(Rest@1, [Name | Acc]);
[{positioned, r_paren, _, _} | Rest@2] ->
{ok, {lists:reverse([Name | Acc]), Rest@2}};
[{positioned, T, Pos, _} | _] ->
{error,
{parse_error,
<<<<"Expected `,` or `)`, found `"/utf8,
(glsql@internal@token:to_string(T))/binary>>/binary,
"`"/utf8>>,
Pos,
none}};
[] ->
{error,
{parse_error,
<<"Unexpected end of file in column list"/utf8>>,
0,
none}}
end
end
).
-file("src/glsql/internal/parser.gleam", 329).
?DOC(false).
-spec optional_column_list(list(glsql@internal@token:positioned())) -> {ok,
{list(binary()), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
optional_column_list(Tokens) ->
case Tokens of
[{positioned, l_paren, _, _} | Rest] ->
collect_names(Rest, []);
_ ->
{ok, {[], Tokens}}
end.
-file("src/glsql/internal/parser.gleam", 585).
?DOC(false).
-spec qualified_name(list(glsql@internal@token:positioned())) -> {ok,
{gleam@option:option(binary()),
binary(),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
qualified_name(Tokens) ->
gleam@result:'try'(
identifier(Tokens),
fun(_use0) ->
{First, _, Rest} = _use0,
case Rest of
[{positioned, dot, _, _} | Rest@1] ->
gleam@result:'try'(
identifier(Rest@1),
fun(_use0@1) ->
{Second, _, Rest@2} = _use0@1,
{ok, {{some, First}, Second, Rest@2}}
end
);
_ ->
{ok, {none, First, Rest}}
end
end
).
-file("src/glsql/internal/parser.gleam", 185).
?DOC(false).
-spec parse_column_constraints(
list(glsql@internal@token:positioned()),
list(glsql@internal@ast:column_constraint())
) -> {ok,
{list(glsql@internal@ast:column_constraint()),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_column_constraints(Tokens, Acc) ->
case Tokens of
[{positioned, comma, _, _} | _] ->
{ok, {Acc, Tokens}};
[{positioned, r_paren, _, _} | _] ->
{ok, {Acc, Tokens}};
[] ->
{ok, {Acc, Tokens}};
[{positioned, {word, W}, Pos, _} | Rest] ->
case string:lowercase(W) of
<<"not"/utf8>> ->
gleam@result:'try'(
keyword(Rest, <<"null"/utf8>>),
fun(_use0) ->
{_, Rest@1} = _use0,
parse_column_constraints(
Rest@1,
[{not_null, Pos} | Acc]
)
end
);
<<"null"/utf8>> ->
parse_column_constraints(Rest, [{nullable, Pos} | Acc]);
<<"primary"/utf8>> ->
gleam@result:'try'(
keyword(Rest, <<"key"/utf8>>),
fun(_use0@1) ->
{_, Rest@2} = _use0@1,
parse_column_constraints(
Rest@2,
[{primary_key, Pos} | Acc]
)
end
);
<<"unique"/utf8>> ->
parse_column_constraints(Rest, [{unique, Pos} | Acc]);
<<"default"/utf8>> ->
{Expr, Rest@3} = take_expression(Rest, <<""/utf8>>, 0),
parse_column_constraints(
Rest@3,
[{default, Expr, Pos} | Acc]
);
<<"check"/utf8>> ->
{Expr@1, Rest@4} = take_expression(Rest, <<""/utf8>>, 0),
parse_column_constraints(
Rest@4,
[{check, Expr@1, Pos} | Acc]
);
<<"references"/utf8>> ->
gleam@result:'try'(
qualified_name(Rest),
fun(_use0@2) ->
{_, Tbl, Rest@5} = _use0@2,
gleam@result:'try'(
optional_column_list(Rest@5),
fun(_use0@3) ->
{Cols, Rest@6} = _use0@3,
parse_column_constraints(
Rest@6,
[{references, Tbl, Cols, Pos} | Acc]
)
end
)
end
);
<<"generated"/utf8>> ->
Rest@7 = skip_words(
Rest,
[<<"always"/utf8>>, <<"by"/utf8>>, <<"default"/utf8>>]
),
gleam@result:'try'(
keyword(Rest@7, <<"as"/utf8>>),
fun(_use0@4) ->
{_, Rest@8} = _use0@4,
{Expr@2, Rest@9} = generated_value(Rest@8),
parse_column_constraints(
Rest@9,
[{default, Expr@2, Pos} | Acc]
)
end
);
<<"collate"/utf8>> ->
gleam@result:'try'(
identifier(Rest),
fun(_use0@5) ->
{_, _, Rest@10} = _use0@5,
parse_column_constraints(Rest@10, Acc)
end
);
Other ->
{error,
{parse_error,
<<<<"Unknown column constraint `"/utf8, W/binary>>/binary,
"`"/utf8>>,
Pos,
glsql@internal@suggest:closest(
Other,
[<<"not"/utf8>>,
<<"null"/utf8>>,
<<"primary"/utf8>>,
<<"unique"/utf8>>,
<<"default"/utf8>>,
<<"references"/utf8>>,
<<"check"/utf8>>,
<<"constraint"/utf8>>,
<<"foreign"/utf8>>,
<<"generated"/utf8>>,
<<"collate"/utf8>>]
)}}
end;
[{positioned, T, Pos@1, _} | _] ->
{error,
{parse_error,
<<<<"Unexpected `"/utf8,
(glsql@internal@token:to_string(T))/binary>>/binary,
"` in column definition"/utf8>>,
Pos@1,
none}}
end.
-file("src/glsql/internal/parser.gleam", 561).
?DOC(false).
-spec parse_array_dims(list(glsql@internal@token:positioned()), integer()) -> {integer(),
list(glsql@internal@token:positioned())}.
parse_array_dims(Tokens, Count) ->
case Tokens of
[{positioned, l_bracket, _, _}, {positioned, r_bracket, _, _} | Rest] ->
parse_array_dims(Rest, Count + 1);
_ ->
{Count, Tokens}
end.
-file("src/glsql/internal/parser.gleam", 544).
?DOC(false).
-spec collect_args(list(glsql@internal@token:positioned()), list(binary())) -> {ok,
{list(binary()), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
collect_args(Tokens, Acc) ->
case Tokens of
[{positioned, {number, N}, _, _}, {positioned, comma, _, _} | Rest] ->
collect_args(Rest, [N | Acc]);
[{positioned, {number, N@1}, _, _},
{positioned, r_paren, _, _} |
Rest@1] ->
{ok, {lists:reverse([N@1 | Acc]), Rest@1}};
[{positioned, {word, W}, _, _}, {positioned, r_paren, _, _} | Rest@2] ->
{ok, {lists:reverse([W | Acc]), Rest@2}};
[{positioned, _, Pos, _} | _] ->
{error,
{parse_error, <<"Expected a type argument"/utf8>>, Pos, none}};
[] ->
{error,
{parse_error,
<<"Unexpected end of file in type arguments"/utf8>>,
0,
none}}
end.
-file("src/glsql/internal/parser.gleam", 537).
?DOC(false).
-spec parse_type_args(list(glsql@internal@token:positioned())) -> {ok,
{list(binary()), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_type_args(Tokens) ->
case Tokens of
[{positioned, l_paren, _, _} | Rest] ->
collect_args(Rest, []);
_ ->
{ok, {[], Tokens}}
end.
-file("src/glsql/internal/parser.gleam", 525).
?DOC(false).
-spec match_words(list(binary()), list(glsql@internal@token:positioned())) -> {ok,
list(glsql@internal@token:positioned())} |
{error, nil}.
match_words(Words, Tokens) ->
case {Words, Tokens} of
{[], _} ->
{ok, Tokens};
{[Want | Rest_words], [{positioned, {word, W}, _, _} | Rest]} ->
case string:lowercase(W) =:= Want of
true ->
match_words(Rest_words, Rest);
false ->
{error, nil}
end;
{_, _} ->
{error, nil}
end.
-file("src/glsql/internal/parser.gleam", 508).
?DOC(false).
-spec first_matching_name(
binary(),
list(list(binary())),
list(glsql@internal@token:positioned())
) -> {binary(), list(glsql@internal@token:positioned())}.
first_matching_name(Name, Candidates, Tokens) ->
case Candidates of
[] ->
{Name, Tokens};
[Words | Others] ->
Wanted = gleam@list:drop(Words, 1),
case match_words(Wanted, Tokens) of
{ok, Rest} ->
{gleam@string:join([Name | Wanted], <<" "/utf8>>), Rest};
{error, nil} ->
first_matching_name(Name, Others, Tokens)
end
end.
-file("src/glsql/internal/parser.gleam", 496).
?DOC(false).
-spec extend_type_name(binary(), list(glsql@internal@token:positioned())) -> {binary(),
list(glsql@internal@token:positioned())}.
extend_type_name(Name, Tokens) ->
Lowered = string:lowercase(Name),
Candidates = gleam@list:filter(
[[<<"timestamp"/utf8>>,
<<"with"/utf8>>,
<<"time"/utf8>>,
<<"zone"/utf8>>],
[<<"timestamp"/utf8>>,
<<"without"/utf8>>,
<<"time"/utf8>>,
<<"zone"/utf8>>],
[<<"time"/utf8>>, <<"with"/utf8>>, <<"time"/utf8>>, <<"zone"/utf8>>],
[<<"time"/utf8>>,
<<"without"/utf8>>,
<<"time"/utf8>>,
<<"zone"/utf8>>],
[<<"character"/utf8>>, <<"varying"/utf8>>],
[<<"bit"/utf8>>, <<"varying"/utf8>>],
[<<"double"/utf8>>, <<"precision"/utf8>>]],
fun(Words) -> case Words of
[First | _] ->
First =:= Lowered;
[] ->
false
end end
),
first_matching_name(Name, Candidates, Tokens).
-file("src/glsql/internal/parser.gleam", 482).
?DOC(false).
-spec qualified_type_name(list(glsql@internal@token:positioned())) -> {ok,
{gleam@option:option(binary()),
binary(),
integer(),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
qualified_type_name(Tokens) ->
gleam@result:'try'(
identifier(Tokens),
fun(_use0) ->
{First, Pos, Rest} = _use0,
case Rest of
[{positioned, dot, _, _} | Rest@1] ->
gleam@result:'try'(
identifier(Rest@1),
fun(_use0@1) ->
{Second, _, Rest@2} = _use0@1,
{ok, {{some, First}, Second, Pos, Rest@2}}
end
);
_ ->
{ok, {none, First, Pos, Rest}}
end
end
).
-file("src/glsql/internal/parser.gleam", 464).
?DOC(false).
-spec parse_type(list(glsql@internal@token:positioned())) -> {ok,
{glsql@internal@ast:sql_type(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_type(Tokens) ->
gleam@result:'try'(
qualified_type_name(Tokens),
fun(_use0) ->
{_, Name, Pos, Rest} = _use0,
gleam@result:'try'(
parse_type_args(Rest),
fun(_use0@1) ->
{Args, Rest@1} = _use0@1,
{Name@1, Rest@2} = extend_type_name(Name, Rest@1),
gleam@result:'try'(case Args of
[] ->
parse_type_args(Rest@2);
_ ->
{ok, {Args, Rest@2}}
end, fun(_use0@2) ->
{Args@1, Rest@3} = _use0@2,
{Dims, Rest@4} = parse_array_dims(Rest@3, 0),
{ok,
{{sql_type, Name@1, Args@1, Dims, Pos}, Rest@4}}
end)
end
)
end
).
-file("src/glsql/internal/parser.gleam", 170).
?DOC(false).
-spec parse_column(list(glsql@internal@token:positioned())) -> {ok,
{glsql@internal@ast:column(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_column(Tokens) ->
gleam@result:'try'(
identifier(Tokens),
fun(_use0) ->
{Name, Pos, Rest} = _use0,
gleam@result:'try'(
parse_type(Rest),
fun(_use0@1) ->
{Sql_type, Rest@1} = _use0@1,
gleam@result:'try'(
parse_column_constraints(Rest@1, []),
fun(_use0@2) ->
{Constraints, Rest@2} = _use0@2,
{ok,
{{column,
Name,
Sql_type,
lists:reverse(Constraints),
Pos},
Rest@2}}
end
)
end
)
end
).
-file("src/glsql/internal/parser.gleam", 313).
?DOC(false).
-spec skip_constraint_name(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()).
skip_constraint_name(Tokens) ->
case Tokens of
[{positioned, {word, W}, _, _} | Rest] ->
case string:lowercase(W) of
<<"constraint"/utf8>> ->
case Rest of
[{positioned, {word, _}, _, _} | Rest@1] ->
Rest@1;
[{positioned, {quoted_ident, _}, _, _} | Rest@2] ->
Rest@2;
_ ->
Rest
end;
_ ->
Tokens
end;
_ ->
Tokens
end.
-file("src/glsql/internal/parser.gleam", 302).
?DOC(false).
-spec continue_table_constraints(
list(glsql@internal@token:positioned()),
list(glsql@internal@ast:table_constraint())
) -> {ok,
{list(glsql@internal@ast:table_constraint()),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
continue_table_constraints(Tokens, Acc) ->
case Tokens of
[{positioned, comma, _, _} | Rest] ->
parse_table_constraints(Rest, Acc);
_ ->
{ok, {lists:reverse(Acc), Tokens}}
end.
-file("src/glsql/internal/parser.gleam", 249).
?DOC(false).
-spec parse_table_constraints(
list(glsql@internal@token:positioned()),
list(glsql@internal@ast:table_constraint())
) -> {ok,
{list(glsql@internal@ast:table_constraint()),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_table_constraints(Tokens, Acc) ->
Tokens@1 = skip_constraint_name(Tokens),
case Tokens@1 of
[{positioned, {word, W}, Pos, _} | Rest] ->
case string:lowercase(W) of
<<"primary"/utf8>> ->
gleam@result:'try'(
keyword(Rest, <<"key"/utf8>>),
fun(_use0) ->
{_, Rest@1} = _use0,
gleam@result:'try'(
optional_column_list(Rest@1),
fun(_use0@1) ->
{Cols, Rest@2} = _use0@1,
continue_table_constraints(
Rest@2,
[{table_primary_key, Cols, Pos} | Acc]
)
end
)
end
);
<<"unique"/utf8>> ->
gleam@result:'try'(
optional_column_list(Rest),
fun(_use0@2) ->
{Cols@1, Rest@3} = _use0@2,
continue_table_constraints(
Rest@3,
[{table_unique, Cols@1, Pos} | Acc]
)
end
);
<<"foreign"/utf8>> ->
gleam@result:'try'(
keyword(Rest, <<"key"/utf8>>),
fun(_use0@3) ->
{_, Rest@4} = _use0@3,
gleam@result:'try'(
optional_column_list(Rest@4),
fun(_use0@4) ->
{Cols@2, Rest@5} = _use0@4,
gleam@result:'try'(
keyword(Rest@5, <<"references"/utf8>>),
fun(_use0@5) ->
{_, Rest@6} = _use0@5,
gleam@result:'try'(
qualified_name(Rest@6),
fun(_use0@6) ->
{_, Tbl, Rest@7} = _use0@6,
gleam@result:'try'(
optional_column_list(
Rest@7
),
fun(_use0@7) ->
{Ref, Rest@8} = _use0@7,
continue_table_constraints(
Rest@8,
[{table_foreign_key,
Cols@2,
Tbl,
Ref,
Pos} |
Acc]
)
end
)
end
)
end
)
end
)
end
);
<<"check"/utf8>> ->
{Expr, Rest@9} = take_expression(Rest, <<""/utf8>>, 0),
continue_table_constraints(
Rest@9,
[{table_check, Expr, Pos} | Acc]
);
Other ->
{error,
{parse_error,
<<<<"Unknown table constraint `"/utf8, W/binary>>/binary,
"`"/utf8>>,
Pos,
glsql@internal@suggest:closest(
Other,
[<<"not"/utf8>>,
<<"null"/utf8>>,
<<"primary"/utf8>>,
<<"unique"/utf8>>,
<<"default"/utf8>>,
<<"references"/utf8>>,
<<"check"/utf8>>,
<<"constraint"/utf8>>,
<<"foreign"/utf8>>,
<<"generated"/utf8>>,
<<"collate"/utf8>>]
)}}
end;
[{positioned, T, Pos@1, _} | _] ->
{error,
{parse_error,
<<<<"Expected a table constraint, found `"/utf8,
(glsql@internal@token:to_string(T))/binary>>/binary,
"`"/utf8>>,
Pos@1,
none}};
[] ->
{error,
{parse_error,
<<"Unexpected end of file in table constraints"/utf8>>,
0,
none}}
end.
-file("src/glsql/internal/parser.gleam", 159).
?DOC(false).
-spec is_table_constraint(list(glsql@internal@token:positioned())) -> boolean().
is_table_constraint(Tokens) ->
case Tokens of
[{positioned, {word, W}, _, _} | _] ->
case string:lowercase(W) of
<<"primary"/utf8>> ->
true;
<<"unique"/utf8>> ->
true;
<<"foreign"/utf8>> ->
true;
<<"check"/utf8>> ->
true;
<<"constraint"/utf8>> ->
true;
_ ->
false
end;
_ ->
false
end.
-file("src/glsql/internal/parser.gleam", 137).
?DOC(false).
-spec parse_column_list(
list(glsql@internal@token:positioned()),
list(glsql@internal@ast:column())
) -> {ok,
{list(glsql@internal@ast:column()),
list(glsql@internal@ast:table_constraint()),
list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_column_list(Tokens, Acc) ->
case is_table_constraint(Tokens) of
true ->
gleam@result:'try'(
parse_table_constraints(Tokens, []),
fun(_use0) ->
{Constraints, Rest} = _use0,
{ok, {Acc, Constraints, Rest}}
end
);
false ->
gleam@result:'try'(
parse_column(Tokens),
fun(_use0@1) ->
{Column, Rest@1} = _use0@1,
case Rest@1 of
[{positioned, comma, _, _} | Rest@2] ->
parse_column_list(Rest@2, [Column | Acc]);
_ ->
{ok, {[Column | Acc], [], Rest@1}}
end
end
)
end.
-file("src/glsql/internal/parser.gleam", 569).
?DOC(false).
-spec skip_if_not_exists(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()).
skip_if_not_exists(Tokens) ->
case Tokens of
[{positioned, {word, A}, _, _},
{positioned, {word, B}, _, _},
{positioned, {word, C}, _, _} |
Rest] ->
case {string:lowercase(A), string:lowercase(B), string:lowercase(C)} of
{<<"if"/utf8>>, <<"not"/utf8>>, <<"exists"/utf8>>} ->
Rest;
{_, _, _} ->
Tokens
end;
_ ->
Tokens
end.
-file("src/glsql/internal/parser.gleam", 113).
?DOC(false).
-spec parse_create_table(list(glsql@internal@token:positioned())) -> {ok,
{glsql@internal@ast:table(), list(glsql@internal@token:positioned())}} |
{error, glsql@internal@error:error()}.
parse_create_table(Tokens) ->
gleam@result:'try'(
keyword(Tokens, <<"create"/utf8>>),
fun(_use0) ->
{Pos, Rest} = _use0,
gleam@result:'try'(
keyword(Rest, <<"table"/utf8>>),
fun(_use0@1) ->
{_, Rest@1} = _use0@1,
Rest@2 = skip_if_not_exists(Rest@1),
gleam@result:'try'(
qualified_name(Rest@2),
fun(_use0@2) ->
{Schema, Name, Rest@3} = _use0@2,
gleam@result:'try'(
expect(Rest@3, l_paren, <<"("/utf8>>),
fun(_use0@3) ->
{_, Rest@4} = _use0@3,
gleam@result:'try'(
parse_column_list(Rest@4, []),
fun(_use0@4) ->
{Columns, Constraints, Rest@5} = _use0@4,
gleam@result:'try'(
expect(
Rest@5,
r_paren,
<<")"/utf8>>
),
fun(_use0@5) ->
{_, Rest@6} = _use0@5,
Rest@7 = skip_statement(
Rest@6
),
{ok,
{{table,
Name,
Schema,
lists:reverse(
Columns
),
Constraints,
Pos},
Rest@7}}
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/glsql/internal/parser.gleam", 39).
?DOC(false).
-spec parse_statements(
list(glsql@internal@token:positioned()),
list(glsql@internal@ast:table())
) -> {ok, list(glsql@internal@ast:table())} |
{error, glsql@internal@error:error()}.
parse_statements(Tokens, Acc) ->
case Tokens of
[] ->
{ok, Acc};
[{positioned, semicolon, _, _} | Rest] ->
parse_statements(Rest, Acc);
[{positioned, {symbol, <<"\\"/utf8>>}, _, _} | Rest@1] ->
parse_statements(skip_statement(Rest@1), Acc);
[{positioned, {word, W}, Pos, _} | Rest@2] ->
case string:lowercase(W) of
<<"create"/utf8>> ->
case Rest@2 of
[{positioned, {word, Obj}, Obj_pos, _} | After] ->
case string:lowercase(Obj) of
<<"table"/utf8>> ->
gleam@result:'try'(
parse_create_table(Tokens),
fun(_use0) ->
{Table, Rest@3} = _use0,
parse_statements(
Rest@3,
[Table | Acc]
)
end
);
Other ->
case gleam@list:contains(
[<<"index"/utf8>>,
<<"unique"/utf8>>,
<<"extension"/utf8>>,
<<"sequence"/utf8>>,
<<"view"/utf8>>,
<<"schema"/utf8>>,
<<"function"/utf8>>,
<<"trigger"/utf8>>,
<<"type"/utf8>>,
<<"domain"/utf8>>,
<<"materialized"/utf8>>,
<<"publication"/utf8>>,
<<"policy"/utf8>>,
<<"aggregate"/utf8>>,
<<"operator"/utf8>>,
<<"role"/utf8>>,
<<"database"/utf8>>],
Other
) of
true ->
parse_statements(
skip_statement(After),
Acc
);
false ->
{error,
{unknown_statement,
Obj,
Obj_pos,
glsql@internal@suggest:closest(
Other,
[<<"table"/utf8>> |
[<<"index"/utf8>>,
<<"unique"/utf8>>,
<<"extension"/utf8>>,
<<"sequence"/utf8>>,
<<"view"/utf8>>,
<<"schema"/utf8>>,
<<"function"/utf8>>,
<<"trigger"/utf8>>,
<<"type"/utf8>>,
<<"domain"/utf8>>,
<<"materialized"/utf8>>,
<<"publication"/utf8>>,
<<"policy"/utf8>>,
<<"aggregate"/utf8>>,
<<"operator"/utf8>>,
<<"role"/utf8>>,
<<"database"/utf8>>]]
)}}
end
end;
_ ->
{error,
{parse_error,
<<"Unexpected end of file after `create`"/utf8>>,
Pos,
none}}
end;
Other@1 ->
case gleam@list:contains(
[<<"alter"/utf8>>,
<<"drop"/utf8>>,
<<"set"/utf8>>,
<<"comment"/utf8>>,
<<"grant"/utf8>>,
<<"revoke"/utf8>>,
<<"begin"/utf8>>,
<<"commit"/utf8>>,
<<"insert"/utf8>>,
<<"update"/utf8>>,
<<"delete"/utf8>>,
<<"select"/utf8>>,
<<"truncate"/utf8>>,
<<"analyze"/utf8>>,
<<"vacuum"/utf8>>,
<<"refresh"/utf8>>,
<<"reset"/utf8>>,
<<"with"/utf8>>],
Other@1
) of
true ->
parse_statements(skip_statement(Rest@2), Acc);
false ->
{error,
{unknown_statement,
W,
Pos,
glsql@internal@suggest:closest(
Other@1,
[<<"create"/utf8>>,
<<"alter"/utf8>>,
<<"drop"/utf8>>,
<<"set"/utf8>>,
<<"comment"/utf8>>]
)}}
end
end;
[{positioned, T, Pos@1, _} | _] ->
{error,
{parse_error,
<<<<"Expected a statement, found `"/utf8,
(glsql@internal@token:to_string(T))/binary>>/binary,
"`"/utf8>>,
Pos@1,
none}}
end.
-file("src/glsql/internal/parser.gleam", 34).
?DOC(false).
-spec parse(list(glsql@internal@token:positioned())) -> {ok,
glsql@internal@ast:schema_ast()} |
{error, glsql@internal@error:error()}.
parse(Tokens) ->
gleam@result:'try'(
parse_statements(Tokens, []),
fun(Tables) -> {ok, {schema_ast, lists:reverse(Tables)}} end
).