From 2583ec83ee31606c9481e63a9df259fabf083f75 Mon Sep 17 00:00:00 2001 From: sergey-miryanov Date: Wed, 20 Jan 2010 14:13:27 +0500 Subject: [PATCH] Add update operation --- src/sqlite3.erl | 34 +++++++++++++++++++++ src/sqlite3_lib.erl | 73 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/src/sqlite3.erl b/src/sqlite3.erl index 573cb47..d192bce 100644 --- a/src/sqlite3.erl +++ b/src/sqlite3.erl @@ -19,6 +19,7 @@ -export([create_table/2, create_table/3]). -export([list_tables/0, list_tables/1, table_info/1, table_info/2]). -export([write/2, write/3]). +-export([update/4, update/5]). -export([read/2, read/3]). -export([delete/2, delete/3]). -export([drop_table/1, drop_table/2]). @@ -240,6 +241,36 @@ write(Tbl, Data) -> write(Db, Tbl, Data) -> gen_server:call(Db, {write, Tbl, Data}). +%%-------------------------------------------------------------------- +%% @spec update (Tbl::atom (), Key::atom (), Value, Data) -> Result +%% Value = any () +%% Data = [{Column::atom (), Value::string () | integer () | float ()}] +%% Result = {ok, ID} | Unknown +%% Unknown = term () +%% @doc +%% Updates rows into Tbl table such that the Value matches the +%% value in Key with Data. Returns ID of the first updated +%% record. +%% @end +%%-------------------------------------------------------------------- +update (Tbl, Key, Value, Data) -> + ?MODULE:update (?MODULE, Tbl, Key, Value, Data). + +%%-------------------------------------------------------------------- +%% @spec update (Db::atom (), Tbl::atom (), Key::atom (), Value, Data) -> Result +%% Value = any () +%% Data = [{Column::atom (), Value::string () | integer () | float ()}] +%% Result = {ok, ID} | Unknown +%% Unknown = term () +%% @doc +%% Updates rows into Tbl table in Db dbase such that the Value +%% matches the value in Key with Data. Returns ID of the first +%% updated record. +%% @end +%%-------------------------------------------------------------------- +update (Db, Tbl, Key, Value, Data) -> + gen_server:call (Db, {update, Tbl, Key, Value, Data}). + %%-------------------------------------------------------------------- %% @spec read(Tbl::atom(), Key) -> [term()] %% Key = {ColName::atom(), ColValue::term()} @@ -397,6 +428,9 @@ handle_call({create_table, Tbl, Options}, _From, #state{port = Port} = State) -> Cmd = {sql_exec, SQL}, Reply = exec(Port, Cmd), {reply, Reply, State}; +handle_call ({update, Tbl, Key, Value, Data}, _From, #state{port = Port} = State)-> + Reply = exec (Port, {sql_exec, sqlite3_lib:update_sql (Tbl, Key, Value, Data)}), + {reply, Reply, State}; handle_call({write, Tbl, Data}, _From, #state{port = Port} = State) -> % insert into t1 (data,num) values ('This is sample data',3); Reply = exec(Port, {sql_exec, sqlite3_lib:write_sql(Tbl, Data)}), diff --git a/src/sqlite3_lib.erl b/src/sqlite3_lib.erl index a7ee4b0..b3e8484 100644 --- a/src/sqlite3_lib.erl +++ b/src/sqlite3_lib.erl @@ -12,6 +12,7 @@ -export([col_type/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 ([update_sql/4, update_set_sql/1, replace/1]). %%==================================================================== %% API @@ -19,6 +20,7 @@ %%-------------------------------------------------------------------- %% @spec col_type(Type :: term()) -> term() %% @doc Maps sqlite3 column type. +%% @end %%-------------------------------------------------------------------- -spec(col_type/1::(atom() | string()) -> atom() | string()). col_type(integer) -> @@ -59,6 +61,7 @@ write_value_sql(Values) -> %%-------------------------------------------------------------------- %% @spec write_col_sql([atom()]) -> string() %% @doc Creates the column/data stmt for SQL. +%% @end %%-------------------------------------------------------------------- -spec(write_col_sql/1::([atom()]) -> string()). write_col_sql(Cols) -> @@ -67,12 +70,58 @@ write_col_sql(Cols) -> end, Cols), string:join(StrCols, ","). +%%-------------------------------------------------------------------- +%% @spec replace (String) -> string () +%% String = string () +%% @doc Returns copy of String for which \" replaced with ' +%% @end +%%-------------------------------------------------------------------- +-spec (replace/1::(string ()) -> string ()). +replace ([34 | T]) -> + replace (T, ["'"]); +replace ([H | T]) -> + replace (T, [binary_to_list (<>)]). +replace ([], L) -> + lists:flatten (lists:reverse (L)); +replace ([34 | T], L) -> + replace (T, ["'" | L]); +replace ([H | T], L) -> + replace (T, [binary_to_list (<>) | L]). + +%%-------------------------------------------------------------------- +%% @spec update_set_sql ([{Col, Value}]) -> string () +%% Col = atom () +%% Value = integer () | float () | string () +%% @doc +%% Creates update set stmt. +%% Currently only supports integer, double/float and strings. +%% For strings \" replaced with '. +%% @end +%%-------------------------------------------------------------------- +-spec (update_set_sql/1::(any ()) -> string ()). +update_set_sql (Data) -> + Set = lists:map (fun + ({Col, Value}) when is_integer (Value) -> + string:join ( + [atom_to_list (Col), integer_to_list (Value)], " = "); + ({Col, Value}) when is_float (Value) -> + string:join ( + [atom_to_list (Col), integer_to_list (Value)], " = "); + ({Col, Value}) -> + string:join ( + [atom_to_list (Col), + io_lib:format ("\"~s\"", [replace (Value)])], " = ") + end, + Data), + string:join (Set, ", "). + %%-------------------------------------------------------------------- %% @spec create_table_sql(Tbl, [{ColName, Type}]) -> string() %% Tbl = atom() %% ColName = atom() %% Type = string() %% @doc Generates a table create stmt in SQL. +%% @end %%-------------------------------------------------------------------- -spec(create_table_sql/2::(atom(), [{atom(), string()}]) -> string()). create_table_sql(Tbl, [{ColName, Type} | Tl]) -> @@ -84,6 +133,29 @@ create_table_sql(Tbl, [{ColName, Type} | Tl]) -> end, Tl), ", ") ++ ");", lists:flatten(CT ++ Start ++ End). +%%-------------------------------------------------------------------- +%% @spec update_sql (Tbl, Key, Value, Data) -> string () +%% Tbl = atom () +%% Key = atom () +%% Value = atom () +%% Data = [{ColName :: atom (), Value :: string () | integer () | float ()}] +%% @doc +%% Using Key as the column name and Data as list of column names +%% and values pairs it creates the proper update SQL stmt for the +%% record with matching Value. +%% @end +%%-------------------------------------------------------------------- +-type(sql_value() :: string() | integer() | float()). +-spec (update_sql/4::(atom (), atom (), atom (), [{atom (), sql_value ()}]) -> string ()). +update_sql (Tbl, Key, Value, Data) -> + lists:flatten ( + io_lib:format ("UPDATE ~p SET ~s WHERE ~p = ~p;", + [Tbl, + sqlite3_lib:update_set_sql (Data), + Key, + Value + ])). + %%-------------------------------------------------------------------- %% @spec write_sql(Tbl, Data) -> string() %% Tbl = atom() @@ -92,7 +164,6 @@ create_table_sql(Tbl, [{ColName, Type} | Tl]) -> %% proper insertion SQL stmt. %% @end %%-------------------------------------------------------------------- --type(sql_value() :: string() | integer() | float()). -spec(write_sql/2::(atom(), [{atom(), sql_value()}]) -> string()). write_sql(Tbl, Data) -> {Cols, Values} = lists:unzip(Data),