diff --git a/include/sqlite3.hrl b/include/sqlite3.hrl index f0e03a4..0ca0c30 100644 --- a/include/sqlite3.hrl +++ b/include/sqlite3.hrl @@ -20,9 +20,19 @@ -endif. -define(NULL_ATOM, null). --type(sql_value() :: number() | ?NULL_ATOM | iodata() | {blob, binary()}). +-type sql_value() :: number() | ?NULL_ATOM | iodata() | {blob, binary()}. +-type sql_type() :: integer | text | double | real | blob | string(). --type(sqlite_error() :: {error, integer(), string()}). --type(sql_params() :: [sql_value() | {atom() | string() | integer(), sql_value()}]). --type(sql_non_query_result() :: ok | sqlite_error() | {rowid, integer()}). --type(sql_result() :: sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]}]). +-type pk_constraint() :: autoincrement | desc | asc. +-type pk_constraints() :: pk_constraint() | [pk_constraint()]. +-type column_constraint() :: non_null | primary_key | {primary_key, pk_constraints()} + | unique | {default, sql_value()}. +-type column_constraints() :: column_constraint() | [column_constraint()]. +-type table_constraint() :: {primary_key, [atom()]} | {unique, [atom()]}. +-type table_constraints() :: table_constraint() | [table_constraint()]. +-type table_info() :: [{atom(), sql_type()} | {atom(), sql_type(), column_constraints()}]. + +-type sqlite_error() :: {error, integer(), string()}. +-type sql_params() :: [sql_value() | {atom() | string() | integer(), sql_value()}]. +-type sql_non_query_result() :: ok | sqlite_error() | {rowid, integer()}. +-type sql_result() :: sql_non_query_result() | [{columns, [string()]} | {rows, [tuple()]}]. diff --git a/src/sqlite3.erl b/src/sqlite3.erl index adb3300..c68d8d5 100644 --- a/src/sqlite3.erl +++ b/src/sqlite3.erl @@ -297,7 +297,7 @@ columns_timeout(Db, Ref, Timeout) -> gen_server:call(Db, {columns, Ref}, Timeout). %%-------------------------------------------------------------------- -%% @spec create_table(Tbl :: atom(), TblInfo :: [{atom(), atom()}]) -> sql_non_query_result() +%% @spec create_table(Tbl :: atom(), TblInfo :: table_info()) -> sql_non_query_result() %% @doc %% Creates the Tbl table using TblInfo as the table structure. The %% table structure is a list of {column name, column type} pairs. @@ -306,13 +306,13 @@ columns_timeout(Db, Ref, Timeout) -> %% Returns the result of the create table call. %% @end %%-------------------------------------------------------------------- --spec create_table(atom(), [{atom(), atom()}]) -> sql_non_query_result(). +-spec create_table(atom(), table_info()) -> sql_non_query_result(). create_table(Tbl, Columns) -> create_table(?MODULE, Tbl, Columns). %%-------------------------------------------------------------------- %% @spec create_table(Db :: atom(), Tbl :: atom(), Columns) -> sql_non_query_result() -%% Columns = [{atom(), atom()}] +%% Columns = table_info() %% @doc %% Creates the Tbl table in Db using Columns as the table structure. %% The table structure is a list of {column name, column type} pairs. @@ -321,13 +321,13 @@ create_table(Tbl, Columns) -> %% Returns the result of the create table call. %% @end %%-------------------------------------------------------------------- --spec create_table(atom(), atom(), [{atom(), atom()}]) -> sql_non_query_result(). +-spec create_table(atom(), atom(), table_info()) -> sql_non_query_result(). create_table(Db, Tbl, Columns) -> gen_server:call(Db, {create_table, Tbl, Columns}). %%-------------------------------------------------------------------- %% @spec create_table_timeout(Db :: atom(), Tbl :: atom(), Columns, Timeout :: timeout()) -> sql_non_query_result() -%% Columns = [{atom(), atom()}] +%% Columns = table_info() %% @doc %% Creates the Tbl table in Db using Columns as the table structure. %% The table structure is a list of {column name, column type} pairs. @@ -336,13 +336,13 @@ create_table(Db, Tbl, Columns) -> %% Returns the result of the create table call. %% @end %%-------------------------------------------------------------------- --spec create_table_timeout(atom(), atom(), [{atom(), atom()}], timeout()) -> sql_non_query_result(). +-spec create_table_timeout(atom(), atom(), table_info(), timeout()) -> sql_non_query_result(). create_table_timeout(Db, Tbl, Columns, Timeout) -> gen_server:call(Db, {create_table, Tbl, Columns}, Timeout). %%-------------------------------------------------------------------- %% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo, Constraints) -> sql_non_query_result() -%% Columns = [{atom(), atom()}] +%% Columns = table_info() %% Constraints = [term()] %% @doc %% Creates the Tbl table in Db using Columns as the table structure and @@ -353,13 +353,14 @@ create_table_timeout(Db, Tbl, Columns, Timeout) -> %% Returns the result of the create table call. %% @end %%-------------------------------------------------------------------- --spec create_table(atom(), atom(), [{atom(), atom()}], [any()]) -> sql_non_query_result(). +-spec create_table(atom(), atom(), table_info(), table_constraints()) -> + sql_non_query_result(). create_table(Db, Tbl, Columns, Constraints) -> gen_server:call(Db, {create_table, Tbl, Columns, Constraints}). %%-------------------------------------------------------------------- %% @spec create_table_timeout(Db :: atom(), Tbl :: atom(), TblInfo, Constraints, Timeout) -> sql_non_query_result() -%% Columns = [{atom(), atom()}] +%% Columns = table_info() %% Constraints = [term()] %% @doc %% Creates the Tbl table in Db using Columns as the table structure and @@ -370,7 +371,8 @@ create_table(Db, Tbl, Columns, Constraints) -> %% Returns the result of the create table call. %% @end %%-------------------------------------------------------------------- --spec create_table_timeout(atom(), atom(), [{atom(), atom()}], [any()], timeout()) -> sql_non_query_result(). +-spec create_table_timeout(atom(), atom(), table_info(), table_constraints(), timeout()) -> + sql_non_query_result(). create_table_timeout(Db, Tbl, Columns, Constraints, Timeout) -> gen_server:call(Db, {create_table, Tbl, Columns, Constraints}, Timeout). @@ -405,32 +407,32 @@ list_tables_timeout(Db, Timeout) -> gen_server:call(Db, list_tables, Timeout). %%-------------------------------------------------------------------- -%% @spec table_info(Tbl :: atom()) -> [any()] +%% @spec table_info(Tbl :: atom()) -> table_info() %% @doc %% Returns table schema for Tbl. %% @end %%-------------------------------------------------------------------- --spec table_info(atom()) -> [any()]. +-spec table_info(atom()) -> table_info(). table_info(Tbl) -> table_info(?MODULE, Tbl). %%-------------------------------------------------------------------- -%% @spec table_info(Db :: atom(), Tbl :: atom()) -> [any()] +%% @spec table_info(Db :: atom(), Tbl :: atom()) -> table_info() %% @doc %% Returns table schema for Tbl in Db. %% @end %%-------------------------------------------------------------------- --spec table_info(atom(), atom()) -> [any()]. +-spec table_info(atom(), atom()) -> table_info(). table_info(Db, Tbl) -> gen_server:call(Db, {table_info, Tbl}). %%-------------------------------------------------------------------- -%% @spec table_info_timeout(Db :: atom(), Tbl :: atom()) -> [any()] +%% @spec table_info_timeout(Db :: atom(), Tbl :: atom()) -> table_info() %% @doc %% Returns table schema for Tbl in Db. %% @end %%-------------------------------------------------------------------- --spec table_info_timeout(atom(), atom(), timeout()) -> [any()]. +-spec table_info_timeout(atom(), atom(), timeout()) -> table_info(). table_info_timeout(Db, Tbl, Timeout) -> gen_server:call(Db, {table_info, Tbl}, Timeout). diff --git a/src/sqlite3_lib.erl b/src/sqlite3_lib.erl index 9b704c8..ded64d7 100644 --- a/src/sqlite3_lib.erl +++ b/src/sqlite3_lib.erl @@ -25,7 +25,7 @@ %% @doc Maps sqlite3 column type. %% @end %%-------------------------------------------------------------------- --spec col_type_to_string(atom() | string()) -> string(). +-spec col_type_to_string(sql_type()) -> string(). col_type_to_string(integer) -> "INTEGER"; col_type_to_string(text) -> @@ -36,6 +36,8 @@ col_type_to_string(real) -> "REAL"; col_type_to_string(blob) -> "BLOB"; +col_type_to_string(Atom) when is_atom(Atom) -> + string:to_upper(atom_to_list(Atom)); col_type_to_string(String) when is_list(String) -> String. @@ -196,7 +198,7 @@ read_cols_sql(Columns) -> %% @doc Generates a table create stmt in SQL. %% @end %%-------------------------------------------------------------------- --spec create_table_sql(atom(), [{atom(), atom()} | {atom(), atom(), [any()]}]) -> iolist(). +-spec create_table_sql(atom(), table_info()) -> iolist(). create_table_sql(Tbl, Columns) -> ["CREATE TABLE ", atom_to_list(Tbl), " (", map_intersperse(fun column_sql_for_create_table/1, Columns, ", "), ");"]. @@ -212,11 +214,11 @@ create_table_sql(Tbl, Columns) -> %% @doc Generates a table create stmt in SQL. %% @end %%-------------------------------------------------------------------- --spec create_table_sql(atom(), [{atom(), atom()} | {atom(), atom(), [any()]}], [any()]) -> iolist(). +-spec create_table_sql(atom(), table_info(), table_constraints()) -> iolist(). create_table_sql(Tbl, Columns, TblConstraints) -> ["CREATE TABLE ", atom_to_list(Tbl), " (", map_intersperse(fun column_sql_for_create_table/1, Columns, ", "), ", ", - map_intersperse(fun table_constraint_sql/1, TblConstraints, ", "), + table_constraint_sql(TblConstraints), ");"]. %%-------------------------------------------------------------------- @@ -334,7 +336,7 @@ drop_table_sql(Tbl) -> %% @doc Works like string:join for iolists --spec map_intersperse(fun((X) -> iolist()), [X], [iolist() | integer()]) -> iolist(). +-spec map_intersperse(fun((X) -> iolist()), [X], iolist()) -> iolist(). map_intersperse(_Fun, [], _Sep) -> []; map_intersperse(Fun, [Elem], _Sep) -> [Fun(Elem)]; map_intersperse(Fun, [Head | Tail], Sep) -> [Fun(Head), Sep | map_intersperse(Fun, Tail, Sep)]. @@ -375,16 +377,16 @@ column_sql_for_create_table({Name, Type}) -> column_sql_for_create_table({Name, Type, Constraints}) -> [atom_to_list(Name), " ", col_type_to_string(Type), " ", constraint_sql(Constraints)]. --spec pk_constraint_sql(any()) -> iolist(). +-spec pk_constraint_sql(pk_constraints()) -> iolist(). pk_constraint_sql(Constraint) -> case Constraint of desc -> "DESC"; asc -> "ASC"; autoincrement -> "AUTOINCREMENT"; - List -> map_intersperse(fun pk_constraint_sql/1, List, " ") + _ when is_list(Constraint) -> map_intersperse(fun pk_constraint_sql/1, Constraint, " ") end. --spec constraint_sql(any()) -> iolist(). +-spec constraint_sql(column_constraints()) -> iolist(). constraint_sql(Constraint) -> case Constraint of primary_key -> "PRIMARY KEY"; @@ -392,10 +394,10 @@ constraint_sql(Constraint) -> unique -> "UNIQUE"; not_null -> "NOT NULL"; {default, DefaultValue} -> ["DEFAULT ", value_to_sql(DefaultValue)]; - List -> map_intersperse(fun constraint_sql/1, List, " ") + _ when is_list(Constraint) -> map_intersperse(fun constraint_sql/1, Constraint, " ") end. --spec table_constraint_sql(any()) -> iolist(). +-spec table_constraint_sql(table_constraints()) -> iolist(). table_constraint_sql(TableConstraint) -> case TableConstraint of {primary_key, Columns} -> @@ -403,8 +405,10 @@ table_constraint_sql(TableConstraint) -> map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"]; {unique, Columns} -> ["UNIQUE(", - map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"] + map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"]; %% TODO: foreign key + _ when is_list(TableConstraint) -> + map_intersperse(fun table_constraint_sql/1, TableConstraint, ", ") end. indexed_column_sql({ColumnName, asc}) -> [atom_to_list(ColumnName), " ASC"];