Added EUnit tests
This commit is contained in:
@@ -485,9 +485,13 @@ handle_call({table_info, Tbl}, _From, #state{port = Port} = State) ->
|
||||
SQL = io_lib:format("select sql from sqlite_master where tbl_name = '~p' and type='table';", [Tbl]),
|
||||
Data = exec(Port, {sql_exec, SQL}),
|
||||
TableSql = proplists:get_value(rows, Data),
|
||||
[{Info}] = TableSql,
|
||||
case TableSql of
|
||||
[{Info}] ->
|
||||
ColumnList = parse_table_info(binary_to_list(Info)),
|
||||
{reply, ColumnList, State};
|
||||
[] ->
|
||||
{reply, table_does_not_exist, State}
|
||||
end;
|
||||
handle_call({create_function, FunctionName, Function}, _From, #state{port = Port} = State) ->
|
||||
% make sure we only get table info.
|
||||
% SQL Injection warning
|
||||
@@ -630,15 +634,29 @@ build_table_info([[ColName, ColType | Constraints] | Tl], Acc) ->
|
||||
|
||||
%% TODO conflict-clause parsing
|
||||
build_constraints([]) -> [];
|
||||
build_constraints(["PRIMARY", "KEY", "ASC" | Tail]) -> [primary_key | build_constraints(Tail)];
|
||||
build_constraints(["PRIMARY", "KEY", "DESC" | Tail]) -> [{primary_key, desc} | build_constraints(Tail)];
|
||||
build_constraints(["PRIMARY", "KEY" | Tail]) -> [primary_key | build_constraints(Tail)];
|
||||
build_constraints(["PRIMARY", "KEY" | Tail]) ->
|
||||
{Constraint, Rest} = build_primary_key_constraint(Tail),
|
||||
[Constraint | build_constraints(Rest)];
|
||||
build_constraints(["UNIQUE" | Tail]) -> [unique | build_constraints(Tail)];
|
||||
build_constraints(["NOT", "NULL" | Tail]) -> [not_null | build_constraints(Tail)];
|
||||
build_constraints(["DEFAULT", DefaultValue | Tail]) -> [{default, sqlite3_lib:sql_to_value(DefaultValue)} | build_constraints(Tail)].
|
||||
% build_constraints(["CHECK", Check | Tail]) -> ...
|
||||
% build_constraints(["REFERENCES", Check | Tail]) -> ...
|
||||
|
||||
build_primary_key_constraint(Tokens) -> build_primary_key_constraint(Tokens, []).
|
||||
|
||||
build_primary_key_constraint(["ASC" | Rest], Acc) ->
|
||||
build_primary_key_constraint(Rest, [asc | Acc]);
|
||||
build_primary_key_constraint(["DESC" | Rest], Acc) ->
|
||||
build_primary_key_constraint(Rest, [desc | Acc]);
|
||||
build_primary_key_constraint(["AUTOINCREMENT" | Rest], Acc) ->
|
||||
build_primary_key_constraint(Rest, [autoincrement | Acc]);
|
||||
build_primary_key_constraint(Tail, []) ->
|
||||
{primary_key, Tail};
|
||||
build_primary_key_constraint(Tail, Acc) ->
|
||||
{{primary_key, lists:reverse(Acc)}, Tail}.
|
||||
|
||||
|
||||
conflict_clause(["ON", "CONFLICT", ResolutionString | Tail]) ->
|
||||
Resolution = case ResolutionString of
|
||||
"ROLLBACK" -> rollback;
|
||||
@@ -658,3 +676,11 @@ conflict_clause(NoOnConflictClause) ->
|
||||
%% and io:iolist().
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Tests
|
||||
%%--------------------------------------------------------------------
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-endif.
|
||||
|
||||
@@ -116,12 +116,12 @@ sql_to_value(String) ->
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% @spec write_value_sql(Value :: [term()]) -> iolist()
|
||||
%% @spec write_value_sql(Value :: [sql_value()]) -> iolist()
|
||||
%% @doc
|
||||
%% Creates the values portion of the sql stmt.
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
-spec write_value_sql(any()) -> iolist().
|
||||
-spec write_value_sql(sql_value()) -> iolist().
|
||||
write_value_sql(Values) ->
|
||||
map_intersperse(fun value_to_sql/1, Values, ", ").
|
||||
|
||||
@@ -355,3 +355,18 @@ indexed_column_sql(ColumnName) -> atom_to_list(ColumnName).
|
||||
%% and io:iolist().
|
||||
%% @end
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Tests
|
||||
%%--------------------------------------------------------------------
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(FLAT(X), iolist_to_binary(X)).
|
||||
|
||||
quote_test() ->
|
||||
?assertEqual(<<"'abc'">>, ?FLAT(value_to_sql("abc"))),
|
||||
?assertEqual(<<"'a''b''''c'">>, ?FLAT(value_to_sql("a'b''c"))).
|
||||
|
||||
|
||||
-endif.
|
||||
|
||||
@@ -17,25 +17,89 @@
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
create_table_test() ->
|
||||
file:delete("ct.db"),
|
||||
sqlite3:open(ct),
|
||||
sqlite3:create_table(ct, user, [{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}]),
|
||||
[user] = sqlite3:list_tables(ct),
|
||||
[{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}] = sqlite3:table_info(ct, user),
|
||||
{id, Id1} = sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}]),
|
||||
Id1 = 1,
|
||||
{id, Id2} = sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}]),
|
||||
Id2 = 2,
|
||||
[{columns, Columns}, {rows, Rows1}] = sqlite3:sql_exec(ct, "select * from user;"),
|
||||
drop_all_tables(Db) ->
|
||||
Tables = sqlite3:list_tables(Db),
|
||||
[sqlite3:drop_table(Db, Table) || Table <- Tables],
|
||||
Tables.
|
||||
|
||||
drop_table_if_exists(Db, Table) ->
|
||||
case lists:member(Table, sqlite3:list_tables(Db)) of
|
||||
true -> sqlite3:drop_table(Db, Table);
|
||||
false -> ok
|
||||
end.
|
||||
|
||||
rows(SqlExecReply) ->
|
||||
[{columns, _Columns}, {rows, Rows}] = SqlExecReply,
|
||||
Rows.
|
||||
|
||||
basic_functionality_test() ->
|
||||
Columns = ["id", "name", "age", "wage"],
|
||||
Rows1 = [{1, <<"abby">>, 20, 2000}, {2, <<"marge">>, 30, 2000}],
|
||||
[{columns, Columns}, {rows, Rows2}] = sqlite3:read(ct, user, {name, "abby"}),
|
||||
Rows2 = [{1, <<"abby">>, 20, 2000}],
|
||||
[{columns, Columns}, {rows, Rows1}] = sqlite3:read(ct, user, {wage, 2000}),
|
||||
sqlite3:delete(ct, user, {name, "abby"}),
|
||||
sqlite3:drop_table(ct, user),
|
||||
%sqlite3:delete_db(ct)
|
||||
AllRows = [{1, <<"abby">>, 20, 2000}, {2, <<"marge">>, 30, 2000}],
|
||||
AbbyOnly = [{1, <<"abby">>, 20, 2000}],
|
||||
sqlite3:open(ct),
|
||||
drop_all_tables(ct),
|
||||
?assertEqual(
|
||||
[],
|
||||
sqlite3:list_tables(ct)),
|
||||
{ok, TableId} = sqlite3:create_table(ct, user, [{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}]),
|
||||
?assertEqual(
|
||||
[user],
|
||||
sqlite3:list_tables(ct)),
|
||||
?assertEqual(
|
||||
[{id, integer, [primary_key]}, {name, text}, {age, integer}, {wage, integer}],
|
||||
sqlite3:table_info(ct, user)),
|
||||
?assertEqual(
|
||||
{id, 1},
|
||||
sqlite3:write(ct, user, [{name, "abby"}, {age, 20}, {wage, 2000}])),
|
||||
?assertEqual(
|
||||
{id, 2},
|
||||
sqlite3:write(ct, user, [{name, "marge"}, {age, 30}, {wage, 2000}])),
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, AllRows}],
|
||||
sqlite3:sql_exec(ct, "select * from user;")),
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, AbbyOnly}],
|
||||
sqlite3:read(ct, user, {name, "abby"})),
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, AllRows}],
|
||||
sqlite3:read(ct, user, {wage, 2000})),
|
||||
?assertEqual(
|
||||
{ok, TableId},
|
||||
sqlite3:delete(ct, user, {name, "marge"})),
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, AbbyOnly}],
|
||||
sqlite3:sql_exec(ct, "select * from user;")),
|
||||
?assertEqual(
|
||||
{ok, TableId},
|
||||
sqlite3:drop_table(ct, user)),
|
||||
sqlite3:close(ct).
|
||||
|
||||
select_many_records_test() ->
|
||||
sqlite3:open(ct),
|
||||
drop_table_if_exists(ct, many_records),
|
||||
sqlite3:create_table(ct, many_records, [{id, integer}, {name, text}]),
|
||||
lists:foreach(fun(X) -> sqlite3:write(ct, many_records, [{id, X}, {name, "bar"}]) end, lists:seq(1, 1024)),
|
||||
Columns = ["id", "name"],
|
||||
?assertEqual(
|
||||
[{columns, Columns}, {rows, [{1, <<"bar">>}]}],
|
||||
sqlite3:read(ct, many_records, {id, 1})),
|
||||
?assertEqual(
|
||||
10,
|
||||
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 10;")))),
|
||||
?assertEqual(
|
||||
100,
|
||||
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 100;")))),
|
||||
?assertEqual(
|
||||
1000,
|
||||
length(rows(sqlite3:sql_exec(ct, "select * from many_records limit 1000;")))),
|
||||
?assertEqual(
|
||||
1024,
|
||||
length(rows(sqlite3:sql_exec(ct, "select * from many_records;")))),
|
||||
sqlite3:close(ct).
|
||||
|
||||
nonexistent_table_info_test() ->
|
||||
sqlite3:open(ct),
|
||||
?assertEqual(table_does_not_exist, sqlite3:table_info(ct, nonexistent)),
|
||||
sqlite3:close(ct).
|
||||
|
||||
-endif.
|
||||
|
||||
Reference in New Issue
Block a user