Current section
Files
Jump to
Current section
Files
src/cquill@cli@args.erl
-module(cquill@cli@args).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/cquill/cli/args.gleam").
-export([format_error/1, parse_table_list/1, should_include_table/3, help_text/0, version_text/0, default_generate_options/0, parse/1]).
-export_type([command/0, generate_options/0, parse_error/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type command() :: {generate, generate_options()} | help | version.
-type generate_options() :: {generate_options,
binary(),
binary(),
binary(),
gleam@option:option(binary()),
gleam@option:option(binary()),
binary(),
boolean(),
integer(),
boolean(),
boolean(),
boolean(),
boolean()}.
-type parse_error() :: {missing_required, binary()} |
{invalid_value, binary(), binary(), binary()} |
{unknown_command, binary()} |
{missing_value, binary()} |
{unknown_option, binary()}.
-file("src/cquill/cli/args.gleam", 75).
?DOC(" Format a parse error for display\n").
-spec format_error(parse_error()) -> binary().
format_error(Error) ->
case Error of
{missing_required, Name} ->
<<<<<<"Error: Missing required argument: --"/utf8, Name/binary>>/binary,
"\n\n"/utf8>>/binary,
"Use --help for usage information."/utf8>>;
{invalid_value, Name@1, Value, Reason} ->
<<<<<<<<<<"Error: Invalid value for --"/utf8, Name@1/binary>>/binary,
": '"/utf8>>/binary,
Value/binary>>/binary,
"'\n"/utf8>>/binary,
Reason/binary>>;
{unknown_command, Name@2} ->
<<<<<<<<"Error: Unknown command: "/utf8, Name@2/binary>>/binary,
"\n\n"/utf8>>/binary,
"Available commands: generate\n"/utf8>>/binary,
"Use --help for usage information."/utf8>>;
{missing_value, Name@3} ->
<<<<"Error: Option --"/utf8, Name@3/binary>>/binary,
" requires a value"/utf8>>;
{unknown_option, Name@4} ->
<<<<<<"Error: Unknown option: "/utf8, Name@4/binary>>/binary,
"\n\n"/utf8>>/binary,
"Use --help for usage information."/utf8>>
end.
-file("src/cquill/cli/args.gleam", 170).
?DOC(" Parse generate command arguments recursively\n").
-spec parse_generate_args(list(binary()), generate_options()) -> {ok,
generate_options()} |
{error, parse_error()}.
parse_generate_args(Args, Opts) ->
case Args of
[] ->
{ok, Opts};
[<<"--database-url"/utf8>>, Value | Rest] ->
parse_generate_args(
Rest,
{generate_options,
Value,
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--output"/utf8>>, Value@1 | Rest@1] ->
parse_generate_args(
Rest@1,
{generate_options,
erlang:element(2, Opts),
Value@1,
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-o"/utf8>>, Value@1 | Rest@1] ->
parse_generate_args(
Rest@1,
{generate_options,
erlang:element(2, Opts),
Value@1,
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--schema"/utf8>>, Value@2 | Rest@2] ->
parse_generate_args(
Rest@2,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
Value@2,
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-s"/utf8>>, Value@2 | Rest@2] ->
parse_generate_args(
Rest@2,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
Value@2,
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--tables"/utf8>>, Value@3 | Rest@3] ->
parse_generate_args(
Rest@3,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
{some, Value@3},
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-t"/utf8>>, Value@3 | Rest@3] ->
parse_generate_args(
Rest@3,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
{some, Value@3},
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--exclude"/utf8>>, Value@4 | Rest@4] ->
parse_generate_args(
Rest@4,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
{some, Value@4},
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-e"/utf8>>, Value@4 | Rest@4] ->
parse_generate_args(
Rest@4,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
{some, Value@4},
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--prefix"/utf8>>, Value@5 | Rest@5] ->
parse_generate_args(
Rest@5,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
Value@5,
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-p"/utf8>>, Value@5 | Rest@5] ->
parse_generate_args(
Rest@5,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
Value@5,
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--watch"/utf8>> | Rest@6] ->
parse_generate_args(
Rest@6,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
true,
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-w"/utf8>> | Rest@6] ->
parse_generate_args(
Rest@6,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
true,
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--poll-interval"/utf8>>, Value@6 | Rest@7] ->
case gleam_stdlib:parse_int(Value@6) of
{ok, Ms} when Ms > 0 ->
parse_generate_args(
Rest@7,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
Ms,
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
{ok, _} ->
{error,
{invalid_value,
<<"poll-interval"/utf8>>,
Value@6,
<<"Must be a positive integer (milliseconds)"/utf8>>}};
{error, _} ->
{error,
{invalid_value,
<<"poll-interval"/utf8>>,
Value@6,
<<"Must be a valid integer (milliseconds)"/utf8>>}}
end;
[<<"--format"/utf8>> | Rest@8] ->
parse_generate_args(
Rest@8,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
true,
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-f"/utf8>> | Rest@8] ->
parse_generate_args(
Rest@8,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
true,
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--no-format"/utf8>> | Rest@9] ->
parse_generate_args(
Rest@9,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
false,
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--dry-run"/utf8>> | Rest@10] ->
parse_generate_args(
Rest@10,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
true,
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"-n"/utf8>> | Rest@10] ->
parse_generate_args(
Rest@10,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
true,
erlang:element(12, Opts),
erlang:element(13, Opts)}
);
[<<"--verbose"/utf8>> | Rest@11] ->
parse_generate_args(
Rest@11,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
true,
erlang:element(13, Opts)}
);
[<<"-v"/utf8>> | Rest@11] ->
parse_generate_args(
Rest@11,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
true,
erlang:element(13, Opts)}
);
[<<"--typed"/utf8>> | Rest@12] ->
parse_generate_args(
Rest@12,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
true}
);
[<<"--no-typed"/utf8>> | Rest@13] ->
parse_generate_args(
Rest@13,
{generate_options,
erlang:element(2, Opts),
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
false}
);
[<<"--database-url"/utf8>>] ->
{error, {missing_value, <<"database-url"/utf8>>}};
[<<"--output"/utf8>>] ->
{error, {missing_value, <<"output"/utf8>>}};
[<<"-o"/utf8>>] ->
{error, {missing_value, <<"output"/utf8>>}};
[<<"--schema"/utf8>>] ->
{error, {missing_value, <<"schema"/utf8>>}};
[<<"-s"/utf8>>] ->
{error, {missing_value, <<"schema"/utf8>>}};
[<<"--tables"/utf8>>] ->
{error, {missing_value, <<"tables"/utf8>>}};
[<<"-t"/utf8>>] ->
{error, {missing_value, <<"tables"/utf8>>}};
[<<"--exclude"/utf8>>] ->
{error, {missing_value, <<"exclude"/utf8>>}};
[<<"-e"/utf8>>] ->
{error, {missing_value, <<"exclude"/utf8>>}};
[<<"--prefix"/utf8>>] ->
{error, {missing_value, <<"prefix"/utf8>>}};
[<<"-p"/utf8>>] ->
{error, {missing_value, <<"prefix"/utf8>>}};
[<<"--poll-interval"/utf8>>] ->
{error, {missing_value, <<"poll-interval"/utf8>>}};
[Opt | _] ->
case gleam_stdlib:string_starts_with(Opt, <<"-"/utf8>>) of
true ->
{error, {unknown_option, Opt}};
false ->
{error, {unknown_option, Opt}}
end
end.
-file("src/cquill/cli/args.gleam", 265).
?DOC(" Resolve database URL from options or environment variable\n").
-spec resolve_database_url(generate_options()) -> {ok, command()} |
{error, parse_error()}.
resolve_database_url(Opts) ->
case erlang:element(2, Opts) of
<<""/utf8>> ->
case envoy_ffi:get(<<"CQUILL_DATABASE_URL"/utf8>>) of
{ok, Url} ->
{ok,
{generate,
{generate_options,
Url,
erlang:element(3, Opts),
erlang:element(4, Opts),
erlang:element(5, Opts),
erlang:element(6, Opts),
erlang:element(7, Opts),
erlang:element(8, Opts),
erlang:element(9, Opts),
erlang:element(10, Opts),
erlang:element(11, Opts),
erlang:element(12, Opts),
erlang:element(13, Opts)}}};
{error, _} ->
{error, {missing_required, <<"database-url"/utf8>>}}
end;
_ ->
{ok, {generate, Opts}}
end.
-file("src/cquill/cli/args.gleam", 283).
?DOC(" Parse a comma-separated list of table names\n").
-spec parse_table_list(gleam@option:option(binary())) -> list(binary()).
parse_table_list(Input) ->
case Input of
none ->
[];
{some, Str} ->
_pipe = Str,
_pipe@1 = gleam@string:split(_pipe, <<","/utf8>>),
_pipe@2 = gleam@list:map(_pipe@1, fun gleam@string:trim/1),
gleam@list:filter(_pipe@2, fun(S) -> S /= <<""/utf8>> end)
end.
-file("src/cquill/cli/args.gleam", 295).
?DOC(" Check if a table should be included based on include/exclude lists\n").
-spec should_include_table(binary(), list(binary()), list(binary())) -> boolean().
should_include_table(Table_name, Include_tables, Exclude_tables) ->
Included = case Include_tables of
[] ->
true;
Tables ->
gleam@list:contains(Tables, Table_name)
end,
Excluded = gleam@list:contains(Exclude_tables, Table_name),
Included andalso not Excluded.
-file("src/cquill/cli/args.gleam", 315).
?DOC(" Generate the main help text\n").
-spec help_text() -> binary().
help_text() ->
<<"cquill - A compile-time safe database library for Gleam
USAGE:
cquill <COMMAND> [OPTIONS]
COMMANDS:
generate Generate Gleam code from database schema
help Show this help message
version Show version information
GENERATE OPTIONS:
--database-url <URL> Database connection URL (required)
Can also use CQUILL_DATABASE_URL env var
-o, --output <PATH> Output directory for generated files
Default: src/db
-s, --schema <NAME> Database schema to introspect
Default: public
-t, --tables <LIST> Comma-separated list of tables to include
Default: all tables
-e, --exclude <LIST> Comma-separated list of tables to exclude
-p, --prefix <MODULE> Module prefix for generated code
Default: db
-w, --watch Watch for schema changes and regenerate
--poll-interval <MS> Polling interval in milliseconds for watch mode
Default: 5000 (5 seconds)
-f, --format Run gleam format after generation
Default: true
--no-format Skip running gleam format
-n, --dry-run Show what would be generated without writing
-v, --verbose Enable verbose output
--typed Generate typed columns for type-safe queries
Default: true
--no-typed Skip typed column generation
EXAMPLES:
# Basic usage
cquill generate --database-url postgres://user:pass@localhost/mydb
# Specify output location
cquill generate --database-url $DATABASE_URL --output src/myapp/db
# Only specific tables
cquill generate --database-url $DATABASE_URL --tables users,posts,comments
# Exclude migration tables
cquill generate --database-url $DATABASE_URL --exclude schema_migrations
# Dry run to preview
cquill generate --database-url $DATABASE_URL --dry-run
# Watch mode - regenerate on schema changes
cquill generate --database-url $DATABASE_URL --watch
# Watch with custom poll interval (2 seconds)
cquill generate --database-url $DATABASE_URL --watch --poll-interval 2000
For more information, visit: https://hexdocs.pm/cquill"/utf8>>.
-file("src/cquill/cli/args.gleam", 387).
?DOC(" Get version string\n").
-spec version_text() -> binary().
version_text() ->
<<"cquill v0.1.0"/utf8>>.
-file("src/cquill/cli/args.gleam", 120).
?DOC(" Create default generate options\n").
-spec default_generate_options() -> generate_options().
default_generate_options() ->
{generate_options,
<<""/utf8>>,
<<"src/db"/utf8>>,
<<"public"/utf8>>,
none,
none,
<<"db"/utf8>>,
false,
5000,
true,
false,
false,
true}.
-file("src/cquill/cli/args.gleam", 155).
?DOC(" Parse generate command arguments\n").
-spec parse_generate(list(binary())) -> {ok, command()} | {error, parse_error()}.
parse_generate(Args) ->
case gleam@list:contains(Args, <<"--help"/utf8>>) orelse gleam@list:contains(
Args,
<<"-h"/utf8>>
) of
true ->
{ok, help};
false ->
Opts = default_generate_options(),
case parse_generate_args(Args, Opts) of
{ok, Parsed_opts} ->
resolve_database_url(Parsed_opts);
{error, Err} ->
{error, Err}
end
end.
-file("src/cquill/cli/args.gleam", 142).
?DOC(" Parse command line arguments into a Command\n").
-spec parse(list(binary())) -> {ok, command()} | {error, parse_error()}.
parse(Args) ->
case Args of
[<<"--help"/utf8>>] ->
{ok, help};
[<<"-h"/utf8>>] ->
{ok, help};
[<<"help"/utf8>>] ->
{ok, help};
[<<"--version"/utf8>>] ->
{ok, version};
[<<"-V"/utf8>>] ->
{ok, version};
[<<"version"/utf8>>] ->
{ok, version};
[<<"generate"/utf8>> | Rest] ->
parse_generate(Rest);
[<<"generate"/utf8>>] ->
parse_generate([]);
[] ->
{ok, help};
[Cmd | _] ->
{error, {unknown_command, Cmd}}
end.