From 3999e736bee4b75504e13bde409d6b1a06e7f707 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard <jdbernard@gmail.com> Date: Wed, 15 Jun 2011 07:34:41 -0500 Subject: [PATCH] Bug fixes and implementation refinement around ``ts_ext_data``. * Transformed the test database to match the new data model. Added ``ts_ext_data`` table and moved ``ts_user.ext_data`` values to it. * Added D0022: cascade delete ``ts_ext_data`` when ``ts_entry`` record is deleted. * Completed refactor of ``ts_api`` functions to account for extended data: * ``post_entry/3`` * ``put_entry/3`` * Created ``ts_entry:write/2`` to write extended data atomically with the entry. * Fixed copy/paste bug in ``ts_ext_data:create_table/1``. * Fixed implementation of ``ts_ext_data:set_property/3`` to be explicit about taking a record, not a reference. It then extracts the reference and passes it to the underlying implementation in ``ts_ext_data:do_set_property/3``. * Refactored ``ts_ext_data:do_set_property/3`` to take a record *reference*, not the record itself. * Refactored the ``ts_ext_data:get_property/2`` and ``ts_ext_data:get_properties/1`` functions to return key value tuple pairs, not ``ts_ext_data{}`` records. --- db/test/DECISION_TAB.LOG | Bin 156 -> 156 bytes db/test/LATEST.LOG | Bin 92 -> 92 bytes db/test/schema.DAT | Bin 8323 -> 8745 bytes db/test/ts_ext_data.DCD | Bin 0 -> 304 bytes db/test/ts_ext_data.DCL | Bin 0 -> 224 bytes db/test/ts_user.DCD | Bin 258 -> 257 bytes doc/issues/desktop/0022bn5.rst | 10 ++++++++++ src/ts_api.erl | 9 ++++----- src/ts_entry.erl | 11 +++++++++-- src/ts_ext_data.erl | 27 +++++++++++++++------------ 10 files changed, 38 insertions(+), 19 deletions(-) create mode 100644 db/test/ts_ext_data.DCD create mode 100644 db/test/ts_ext_data.DCL create mode 100644 doc/issues/desktop/0022bn5.rst diff --git a/db/test/DECISION_TAB.LOG b/db/test/DECISION_TAB.LOG index c41385d58f11381a7db61f90c6a38d35d7bfc444..c329c24fc948a2e9ca6445005adcfd51b00385f3 100644 GIT binary patch delta 20 ccmbQkIEQgU1p7<xBnIx~8z#nEGd;-y08B{-od5s; delta 20 bcmbQkIEQgU1iMIY5(9IL_r!Q>rsG)vKJx}O diff --git a/db/test/LATEST.LOG b/db/test/LATEST.LOG index 761214661f0567a51a86cf6d6a8330757ac7f78c..c403a32f8bbfa94ca1373b9595972823ebcbd0d8 100644 GIT binary patch delta 12 Tcma!vnGnkU(mRQPd&XP<9UcUG delta 12 Tcma!vnGnh@(woG<{G$c{8D0b* diff --git a/db/test/schema.DAT b/db/test/schema.DAT index 0816fbdc60def99024f3c066ed5173c949baba3e..169aefd5cbda75eb7fd76aa644fe99cb0666a205 100644 GIT binary patch delta 294 zcmZp6T<N00z@YGwVfESf3=9m6P|S&7GB5$f*g$xqhB_nL#Dft6?K(H)uIioD@7*hU zhqbhD{$xkSrp;E29Q<sI8yOhnEj9!BjGIphGBUD$U|^61@r9T+KN5-L;QSzD5>^2; z{KaM$S!qT_w#f-{=9AOK949}P(`00s%quSyCzHg$`1o2912<z$RuThCAUlx%tt|`a z0uW%_2sL44a|Uw?16y%&Mrv+i3IlgZaeQh;NqkCTNn#FAoj?Xt3Ij`CVs0v`+~g|p uYwS>klO4pw*_n${(^42%Cl|;#bAzpBN@C#Gc{_Q7nC50Td22={B~1W{*G$s@ delta 210 zcmZ4K((I_gz#wnTu=?zK1_lO3DCR^k8JK`#tROs5L!FUz;=u@k*r>oSt=y-2Iv4)D z?GaecJ=u}5X|ok02mj^(#tz2Krvw=pS${Jy$XaZ6WE5iB{758{gY&nLNmvEY)X$q; zWThDy*(WE+nRBNwaHLk0#HS>dBu=hUu$z2UPRE=%ks*UAg@HFOKQBKe)gdoGBfq#L ogE<N40Er|9mO%C-2F7n~SwIH~Fhd;81@wT$=9da~j7$p60Oqwd(f|Me diff --git a/db/test/ts_ext_data.DCD b/db/test/ts_ext_data.DCD new file mode 100644 index 0000000000000000000000000000000000000000..3e52c5681e65e5a4ee3a3a2f6fedcf02a97c26c0 GIT binary patch literal 304 zcma*hO-chX7{>9ZGqtu310KMICm3ug-3hu<{8+hAC^aPWzBFT|c_oRcYY*X7Jc(!U z7zT9VLc#6BpC8YlD2MIMWd-2OTwff&*b!l;m$kC2i34GqT2gs%D5uSV!)V^jo9T>D zd+|bi<i$!%wlu)jp26Vb)u4KN&*J%)SQ4rf6+b0KI%!+j!eMephJ)9E9EOh)9ATGz z3eUM~`-j+xj}G;Tbbh_RJhdy?a3&A`Ab*0tO5@w*Ra_;x&&c9mNZsq0RO&X|cb>mr FegZ%LUX}m= literal 0 HcmV?d00001 diff --git a/db/test/ts_ext_data.DCL b/db/test/ts_ext_data.DCL new file mode 100644 index 0000000000000000000000000000000000000000..9ea29b70d9d1910f34e9974f81bdfa7d3847d0d7 GIT binary patch literal 224 zcmb7-OA5j;6h&_v>#qndz%>*rU4Tygj2tM4hNdr=en=#Vs1qmd!~MAn3$DQFJ)Coc zkaddvCI+w+yY=Fwx`bh4&Rofyq$TvIXm~r+U}-X~(an-9NoRzSHrkM!Yom<wiU}Z^ z2n3&%K>X%y@%bw<6%u0axV(E#xzANtV^EQhR_B%oW2wD;w76)lt~A;y_NUOaZ$XXz Q>9BQ2Z!Q%fy4ljpFV=rU^8f$< literal 0 HcmV?d00001 diff --git a/db/test/ts_user.DCD b/db/test/ts_user.DCD index 05cef8295eba6515ed9ce6547b1a8ba8a91733ab..72c0ed1ab890ca538f7cce159c14fd615f2406d1 100644 GIT binary patch delta 32 ncmZo-YGj(=FD8@3!1&xCiGjP+i-Cb*ep0xPV{-=k#MC(eiqQ!u delta 34 pcmZo<YGRt;FD8-1z!J%r#K6VBjDdk+K~lJnV{-<_#MC*ASpbWR2+RNg diff --git a/doc/issues/desktop/0022bn5.rst b/doc/issues/desktop/0022bn5.rst new file mode 100644 index 0000000..cecafa7 --- /dev/null +++ b/doc/issues/desktop/0022bn5.rst @@ -0,0 +1,10 @@ +Deleting an entry should cascade delete extended data. +====================================================== + +Currently the data remains in the database. It should not cause any +problems, but it is wasting space. + +========= ========== +Created: 2011-06-15 +Resolved: YYYY-MM-DD +========= ========== \ No newline at end of file diff --git a/src/ts_api.erl b/src/ts_api.erl index 122f015..42abb31 100644 --- a/src/ts_api.erl +++ b/src/ts_api.erl @@ -418,11 +418,10 @@ post_entry(YArg, Username, TimelineId) -> #ts_entry{ref = {Username, TimelineId, undefined}}, EJSON) catch _:InputError -> error_logger:error_report("Bad input: ~p", [InputError]), - throw(make_json_400(YArg)) + throw(make_json_400(YArg, {request_error, InputError})) end, - %% TODO; should entries and their properties be created atomically? - case ts_entry:new(ER) of + case ts_entry:new(ER, ExtData) of % record created {ok, CreatedRecord} -> @@ -445,14 +444,14 @@ put_entry(YArg, Username, TimelineId, EntryId) -> EJSON = parse_json_body(YArg), % parse into ts_entry record - ER = try ts_json:ejson_to_record_strict( + {ER, ExtData} = try ts_json:ejson_to_record_strict( #ts_entry{ref={Username, TimelineId, EntryId}}, EJSON) catch _:InputError -> error_logger:error_report("Bad input: ~p", [InputError]), throw(make_json_400(YArg)) end, - ts_entry:write(ER), + ts_entry:write(ER, ExtData), make_json_200(YArg, ER). delete_entry(YArg, Username, TimelineId, EntryId) -> diff --git a/src/ts_entry.erl b/src/ts_entry.erl index 3662f08..266db8a 100644 --- a/src/ts_entry.erl +++ b/src/ts_entry.erl @@ -1,6 +1,6 @@ -module(ts_entry). --export([create_table/1, new/1, new/2, update/1, update/2, write/1, delete/1, - lookup/3, list_asc/3, list_desc/3]). +-export([create_table/1, new/1, new/2, update/1, update/2, write/1, write/2, + delete/1, lookup/3, list_asc/3, list_desc/3]). -include("ts_db_records.hrl"). -include_lib("stdlib/include/qlc.hrl"). @@ -35,6 +35,13 @@ update(ER = #ts_entry{}, ExtData) when is_list(ExtData) -> write(ER = #ts_entry{}) -> mnesia:dirty_write(ER). +write(ER = #ts_entry{}, ExtData) -> + {atomic, Result} = mnesia:transcation(fun() -> + ok = mnesia:write(ER), + ok = ts_common:do_set_ext_data(ER, ExtData) + end), + Result. + lookup(Username, TimelineId, EntryId) -> case mnesia:dirty_read(ts_entry, {Username, TimelineId, EntryId}) of [] -> no_record; diff --git a/src/ts_ext_data.erl b/src/ts_ext_data.erl index c6406ef..2cb8fcd 100644 --- a/src/ts_ext_data.erl +++ b/src/ts_ext_data.erl @@ -4,41 +4,44 @@ -include("ts_db_records.hrl"). create_table(TableOpts) -> - mnesia:create_table(ts_entry, + mnesia:create_table(ts_ext_data, TableOpts ++ [{attributes, record_info(fields, ts_ext_data)}, {type, ordered_set}]). % set last timeline -set_property(Ref=#ts_user{}, last_timeline, LastTimelineId) -> - do_set_property(Ref, last_timeline, LastTimelineId); +set_property(Rec=#ts_user{}, last_timeline, LastTimelineId) -> + do_set_property(Rec#ts_user.username, last_timeline, LastTimelineId); % Set exclusion_list for a User account -set_property(Ref=#ts_user{}, entry_exclusions, ExclusionList) -> - do_set_property(Ref, entry_exclusions, string:join(ExclusionList, "|")); +set_property(Rec=#ts_user{}, entry_exclusions, ExclusionList) -> + do_set_property(Rec#ts_user.username, entry_exclusions, ExclusionList); % Set exclusion_list for a Timeline entry -set_property(Ref=#ts_timeline{}, entry_exclusions, ExclusionList) -> - do_set_property(Ref, entry_exclusions, string:join(ExclusionList, "|")); +set_property(Rec=#ts_timeline{}, entry_exclusions, ExclusionList) -> + do_set_property(Rec#ts_timeline.ref, entry_exclusions, ExclusionList); -set_property(Ref, Key, Value) -> +set_property(Rec, Key, _Value) -> throw(io_lib:format("Property '~s' not available for a ~s record.", - [Key, element(1, Ref)])). + [Key, element(1, Rec)])). get_property(Ref, PropKey) -> {atomic, Result} = mnesia:transaction(fun() -> case mnesia:read(ts_ext_data, {Ref, PropKey}) of [] -> not_set; - [Property] -> Property + [Property] -> Property#ts_ext_data.value end end), Result. -get_properties(Ref) -> +get_properties(Rec) -> + Ref = element(2, Rec), {atomic, Result} = mnesia:transaction(fun() -> MatchHead = #ts_ext_data{ref = {Ref, '_'}, _='_'}, mnesia:select(ts_ext_data, [{MatchHead, [], ['$_']}]) end), - Result. + lists:map(fun(ExtData = #ts_ext_data{}) -> + {Ref, Key} = ExtData#ts_ext_data.ref, + {Key, ExtData#ts_ext_data.value} end, Result). do_set_property(Ref, PropKey, Val) -> {atomic, Result} = mnesia:transaction(fun() ->