Functions to create tables with constraints

This commit is contained in:
Alexey Romanov
2010-10-12 14:23:05 +04:00
parent d4272f423e
commit a8d0290407
2 changed files with 77 additions and 23 deletions

View File

@@ -17,7 +17,7 @@
-export([stop/0, close/1]). -export([stop/0, close/1]).
-export([sql_exec/1, sql_exec/2]). -export([sql_exec/1, sql_exec/2]).
-export([create_table/2, create_table/3]). -export([create_table/2, create_table/3, create_table/4]).
-export([list_tables/0, list_tables/1, table_info/1, table_info/2]). -export([list_tables/0, list_tables/1, table_info/1, table_info/2]).
-export([write/2, write/3]). -export([write/2, write/3]).
-export([update/4, update/5]). -export([update/4, update/5]).
@@ -167,9 +167,10 @@ create_table(Tbl, Options) ->
?MODULE:create_table(?MODULE, Tbl, Options). ?MODULE:create_table(?MODULE, Tbl, Options).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo :: [{atom(), atom()}]) -> any() %% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo) -> any()
%% TblInfo = [{atom(), atom()}]
%% @doc %% @doc
%% Creates the Tbl table in Db using TblInfo as the table structure. %% Creates the Tbl table in Db using Columns as the table structure.
%% The table structure is a list of {column name, column type} pairs. %% The table structure is a list of {column name, column type} pairs.
%% e.g. [{name, text}, {age, integer}] %% e.g. [{name, text}, {age, integer}]
%% %%
@@ -177,8 +178,25 @@ create_table(Tbl, Options) ->
%% @end %% @end
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec create_table(atom(), atom(), [{atom(), atom()}]) -> any(). -spec create_table(atom(), atom(), [{atom(), atom()}]) -> any().
create_table(Db, Tbl, Options) -> create_table(Db, Tbl, Columns) ->
gen_server:call(Db, {create_table, Tbl, Options}). gen_server:call(Db, {create_table, Tbl, Columns}).
%%--------------------------------------------------------------------
%% @spec create_table(Db :: atom(), Tbl :: atom(), TblInfo, Constraints) -> any()
%% Columns = [{atom(), atom()}]
%% Constraints = [term()]
%% @doc
%% Creates the Tbl table in Db using Columns as the table structure and
%% Constraints as table constraints.
%% The table structure is a list of {column name, column type} pairs.
%% e.g. [{name, text}, {age, integer}]
%%
%% Returns the result of the create table call.
%% @end
%%--------------------------------------------------------------------
-spec create_table(atom(), atom(), [{atom(), atom()}], [any()]) -> any().
create_table(Db, Tbl, Columns, Constraints) ->
gen_server:call(Db, {create_table, Tbl, Columns, Constraints}).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec list_tables() -> [atom()] %% @spec list_tables() -> [atom()]
@@ -475,8 +493,13 @@ handle_call({create_function, FunctionName, Function}, _From, #state{port = Port
% SQL Injection warning % SQL Injection warning
Reply = exec(Port, {create_function, FunctionName, Function}), Reply = exec(Port, {create_function, FunctionName, Function}),
{reply, Reply, State}; {reply, Reply, State};
handle_call({create_table, Tbl, Options}, _From, #state{port = Port} = State) -> handle_call({create_table, Tbl, Columns}, _From, #state{port = Port} = State) ->
SQL = sqlite3_lib:create_table_sql(Tbl, Options), SQL = sqlite3_lib:create_table_sql(Tbl, Columns),
Cmd = {sql_exec, SQL},
Reply = exec(Port, Cmd),
{reply, Reply, State};
handle_call({create_table, Tbl, Columns, Constraints}, _From, #state{port = Port} = State) ->
SQL = sqlite3_lib:create_table_sql(Tbl, Columns, Constraints),
Cmd = {sql_exec, SQL}, Cmd = {sql_exec, SQL},
Reply = exec(Port, Cmd), Reply = exec(Port, Cmd),
{reply, Reply, State}; {reply, Reply, State};

View File

@@ -13,19 +13,19 @@
-export([col_type_to_atom/1]). -export([col_type_to_atom/1]).
-export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/1]). -export([value_to_sql/1, value_to_sql_unsafe/1, sql_to_value/1, escape/1]).
-export([write_value_sql/1, write_col_sql/1]). -export([write_value_sql/1, write_col_sql/1]).
-export([create_table_sql/2, write_sql/2, read_sql/3, delete_sql/3, drop_table/1]). -export([create_table_sql/2, create_table_sql/3, drop_table/1]).
-export([update_sql/4, update_set_sql/1]). -export([write_sql/2, update_sql/4, update_set_sql/1, delete_sql/3]).
-export([read_sql/4, read_cols_sql/1]). -export([read_sql/3, read_sql/4, read_cols_sql/1]).
%%==================================================================== %%====================================================================
%% API %% API
%%==================================================================== %%====================================================================
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec col_type_to_string(Type :: atom()) -> string() %% @spec col_type_to_string(Type :: atom() | string()) -> string()
%% @doc Maps sqlite3 column type. %% @doc Maps sqlite3 column type.
%% @end %% @end
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec col_type_to_string(atom()) -> string(). -spec col_type_to_string(atom() | string()) -> string().
col_type_to_string(integer) -> col_type_to_string(integer) ->
"INTEGER"; "INTEGER";
col_type_to_string(text) -> col_type_to_string(text) ->
@@ -33,7 +33,9 @@ col_type_to_string(text) ->
col_type_to_string(double) -> col_type_to_string(double) ->
"REAL"; "REAL";
col_type_to_string(real) -> col_type_to_string(real) ->
"REAL". "REAL";
col_type_to_string(String) when is_list(String) ->
String.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec col_type_to_atom(Type :: string()) -> atom() %% @spec col_type_to_atom(Type :: string()) -> atom()
@@ -168,7 +170,7 @@ read_cols_sql(Columns) ->
map_intersperse(fun atom_to_list/1, Columns, ", "). map_intersperse(fun atom_to_list/1, Columns, ", ").
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec create_table_sql(Tbl :: atom(), [{Column, Type}]) -> iolist() %% @spec create_table_sql(Tbl :: atom(), ColumnData) -> iolist()
%% Tbl = atom() %% Tbl = atom()
%% ColumnData = {Column, Type} | {Column, Type, Constraints} %% ColumnData = {Column, Type} | {Column, Type, Constraints}
%% Column = atom() %% Column = atom()
@@ -179,15 +181,26 @@ read_cols_sql(Columns) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec create_table_sql(atom(), [{atom(), atom()} | {atom(), atom(), [any()]}]) -> iolist(). -spec create_table_sql(atom(), [{atom(), atom()} | {atom(), atom(), [any()]}]) -> iolist().
create_table_sql(Tbl, Columns) -> create_table_sql(Tbl, Columns) ->
ColumnNameTypeFun =
fun({Name0, Type0}) ->
[atom_to_list(Name0), " ", col_type_to_string(Type0)];
({Name0, Type0, Constraints}) ->
[atom_to_list(Name0), " ", col_type_to_string(Type0),
" " | map_intersperse(fun constraint_sql/1, Constraints, " ")]
end,
["CREATE TABLE ", atom_to_list(Tbl), " (", ["CREATE TABLE ", atom_to_list(Tbl), " (",
map_intersperse(ColumnNameTypeFun, Columns, ", "), ");"]. map_intersperse(fun column_sql_for_create_table/1, Columns, ", "), ");"].
%%--------------------------------------------------------------------
%% @spec create_table_sql(Tbl :: atom(), ColumnData, TableConstraints) -> iolist()
%% Tbl = atom()
%% ColumnData = {Column, Type} | {Column, Type, Constraints}
%% Column = atom()
%% Type = atom()
%% Constraints = [any()]
%% TableConstraints = [any()]
%% @doc Generates a table create stmt in SQL.
%% @end
%%--------------------------------------------------------------------
-spec create_table_sql(atom(), [{atom(), atom()} | {atom(), atom(), [any()]}], [any()]) -> 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, ", "),
");"].
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @spec update_sql(Tbl, Key, Value, Data) -> iolist() %% @spec update_sql(Tbl, Key, Value, Data) -> iolist()
@@ -307,7 +320,13 @@ sql_string(StringWithEscapedQuotes) ->
-spec sql_blob(string()) -> string(). -spec sql_blob(string()) -> string().
sql_blob(Blob) -> Blob. sql_blob(Blob) -> Blob.
-spec constraint_sql([any()]) -> iolist(). column_sql_for_create_table({Name, Type}) ->
[atom_to_list(Name), " ", col_type_to_string(Type)];
column_sql_for_create_table({Name, Type, Constraints}) ->
[atom_to_list(Name), " ", col_type_to_string(Type),
" " | map_intersperse(fun constraint_sql/1, Constraints, " ")].
-spec constraint_sql(any()) -> iolist().
constraint_sql(Constraint) -> constraint_sql(Constraint) ->
case Constraint of case Constraint of
primary_key -> "PRIMARY KEY"; primary_key -> "PRIMARY KEY";
@@ -317,6 +336,18 @@ constraint_sql(Constraint) ->
{default, DefaultValue} -> ["DEFAULT ", value_to_sql(DefaultValue)] {default, DefaultValue} -> ["DEFAULT ", value_to_sql(DefaultValue)]
end. end.
-spec table_constraint_sql(any()) -> iolist().
table_constraint_sql(TableConstraint) ->
case TableConstraint of
{primary_key, Columns} -> ["PRIMARY KEY(", map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"];
{unique, Columns} -> ["UNIQUE(", map_intersperse(fun indexed_column_sql/1, Columns, ", "), ")"]
%% TODO: foreign key
end.
indexed_column_sql({ColumnName, asc}) -> [atom_to_list(ColumnName), " ASC"];
indexed_column_sql({ColumnName, desc}) -> [atom_to_list(ColumnName), " DESC"];
indexed_column_sql(ColumnName) -> atom_to_list(ColumnName).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% @type sql_value() = number() | 'null' | iodata(). %% @type sql_value() = number() | 'null' | iodata().
%% %%