store_mnesia.erl 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. -module(store_mnesia).
  2. -author('Maxim Sokhatsky').
  3. -copyright('Synrc Research Center s.r.o.').
  4. -include_lib("kvs/include/config.hrl").
  5. -include_lib("kvs/include/users.hrl").
  6. -include_lib("kvs/include/groups.hrl").
  7. -include_lib("kvs/include/feeds.hrl").
  8. -include_lib("kvs/include/acls.hrl").
  9. -include_lib("kvs/include/invites.hrl").
  10. -include_lib("kvs/include/meetings.hrl").
  11. -include_lib("kvs/include/membership.hrl").
  12. -include_lib("kvs/include/payments.hrl").
  13. -include_lib("kvs/include/purchases.hrl").
  14. -include_lib("kvs/include/accounts.hrl").
  15. -include_lib("kvs/include/log.hrl").
  16. -include_lib("kvs/include/translations.hrl").
  17. -include_lib("stdlib/include/qlc.hrl").
  18. -compile(export_all).
  19. -define(CREATE_TAB(T), create_table(T, record_info(fields, T), [{storage, permanent}]) ).
  20. start() -> mnesia:start(), mnesia:change_table_copy_type(schema, node(), disc_copies).
  21. stop() -> mnesia:stop().
  22. delete() -> mnesia:delete_schema([node()]).
  23. version() -> {version,"KVS MNESIA Embedded"}.
  24. initialize() ->
  25. mnesia:create_schema([node()]),
  26. ?CREATE_TAB(payment),
  27. ?CREATE_TAB(acl),
  28. ?CREATE_TAB(acl_entry),
  29. ?CREATE_TAB(feed),
  30. ?CREATE_TAB(team),
  31. ?CREATE_TAB(entry),
  32. ?CREATE_TAB(comment),
  33. ?CREATE_TAB(user),
  34. ?CREATE_TAB(user_product),
  35. ?CREATE_TAB(user_payment),
  36. ?CREATE_TAB(user_status),
  37. ?CREATE_TAB(membership),
  38. ?CREATE_TAB(account),
  39. ?CREATE_TAB(subscription),
  40. ?CREATE_TAB(group_subscription),
  41. ?CREATE_TAB(group),
  42. ?CREATE_TAB(id_seq),
  43. ?CREATE_TAB(transaction),
  44. ?CREATE_TAB(translation),
  45. mnesia:wait_for_tables([comment,subscription,group,group_subscription,user,entry],5000),
  46. add_table_index(comment, entry_id),
  47. add_table_index(comment, author_id),
  48. add_table_index(subscription, who),
  49. add_table_index(subscription, whom),
  50. add_table_index(group_subscription, who),
  51. add_table_index(group_subscription, where),
  52. add_table_index(entry, feed_id),
  53. add_table_index(entry, entry_id),
  54. add_table_index(entry, from),
  55. add_table_index(user, facebook_id),
  56. add_table_index(user, googleplus_id),
  57. add_table_index(user, email),
  58. ok.
  59. dir() ->
  60. Tables = mnesia:system_info(local_tables),
  61. [{table,atom_to_list(T)}||T<-Tables].
  62. get(RecordName, Key) -> just_one(fun() -> mnesia:read(RecordName, Key) end).
  63. put(Records) when is_list(Records) -> void(fun() -> lists:foreach(fun mnesia:write/1, Records) end);
  64. put(Record) -> put([Record]).
  65. delete(Keys) when is_list(Keys) -> void(fun() -> lists:foreach(fun mnesia:delete_object/1, Keys) end);
  66. delete(Keys) -> delete([Keys]).
  67. delete(Tab, Key) -> mnesia:transaction(fun()-> mnesia:delete({Tab, Key}) end), ok.
  68. multi_select(RecordName, Keys) when is_list(Keys) -> flatten(fun() -> [mnesia:read({RecordName, Key}) || Key <- Keys] end).
  69. select(From, PredicateFunction) when is_function(PredicateFunction) -> exec(qlc:q([Record || Record <- mnesia:table(From), apply(PredicateFunction, [Record])]));
  70. select(From, [{where, Fn}, {order, {Idx, Order}}]) -> exec(qlc:q([R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])]));
  71. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {1, Length}}]) ->
  72. {atomic, Recs} = mnesia:transaction(fun()->
  73. QC = qlc:cursor(qlc:q(
  74. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  75. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  76. qlc:delete_cursor(QC),
  77. Ret
  78. end),
  79. Recs;
  80. select(From, [{where, Fn}, {order, {Idx, Order}}, {limit, {Offset, Length}}]) ->
  81. {atomic, Recs} = mnesia:transaction(fun()->
  82. QC = qlc:cursor(qlc:q(
  83. [R || R <- qlc:keysort(Idx, mnesia:table(From), [{order, Order}]), apply(Fn, [R])])),
  84. qlc:next_answers(QC, Offset - 1),
  85. Ret = qlc:eval(qlc:next_answers(QC, Length)),
  86. qlc:delete_cursor(QC),
  87. Ret
  88. end),
  89. Recs;
  90. select(RecordName, Key) -> many(fun() -> mnesia:read({RecordName, Key}) end).
  91. count(RecordName) -> mnesia:table_info(RecordName, size).
  92. all(RecordName) -> flatten(fun() -> Lists = mnesia:all_keys(RecordName), [ mnesia:read({RecordName, G}) || G <- Lists ] end).
  93. all_by_index(RecordName,Key,Value) -> flatten(fun() -> mnesia:index_read(RecordName,Value,Key) end).
  94. next_id(RecordName) -> next_id(RecordName, 1).
  95. next_id(RecordName, Incr) -> mnesia:dirty_update_counter({id_seq, RecordName}, Incr).
  96. just_one(Fun) ->
  97. case mnesia:transaction(Fun) of
  98. {atomic, []} -> {error, not_found};
  99. {atomic, [R]} -> {ok, R};
  100. {atomic, [_|_]} -> {error, duplicated};
  101. _ -> {error, not_found} end.
  102. flatten(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> lists:flatten(R); _ -> [] end.
  103. many(Fun) -> case mnesia:transaction(Fun) of {atomic, R} -> R; _ -> [] end.
  104. void(Fun) -> case mnesia:transaction(Fun) of {atomic, ok} -> ok; {aborted, Error} -> {error, Error} end.
  105. create_table(Record, RecordInfo, Opts0) ->
  106. Attr = [{attributes, RecordInfo}],
  107. Opts = transform_opts(Opts0),
  108. AllOpts = lists:concat([Opts, Attr]),
  109. case mnesia:create_table(Record, lists:flatten(AllOpts)) of
  110. {atomic, ok} -> ok;
  111. {aborted, {already_exists, Record}} -> ok;
  112. {aborted, Err} -> {error, Err} end.
  113. add_table_index(Record, Field) ->
  114. catch case mnesia:add_table_index(Record, Field) of
  115. {atomic, ok} -> ok;
  116. {aborted,Reason} -> {aborted,Reason};
  117. Err -> Err end.
  118. transform_opts(Opts) -> transform_opts(Opts, []).
  119. transform_opts([], Acc) -> lists:reverse(Acc);
  120. transform_opts([{storage, Value} | Rest], Acc0) ->
  121. NewOpts = storage_to_mnesia_type(Value),
  122. Acc = [NewOpts | Acc0],
  123. transform_opts(Rest, Acc);
  124. transform_opts([Other | Rest], Acc0) ->
  125. Acc = [Other | Acc0],
  126. transform_opts(Rest, Acc).
  127. storage_to_mnesia_type(permanent) -> {disc_copies, [node()]};
  128. storage_to_mnesia_type(temporary) -> {ram_copies, [node()]};
  129. storage_to_mnesia_type(ondisk) -> {disc_only_copies, [node()]}.
  130. exec(Q) -> F = fun() -> qlc:e(Q) end, {atomic, Val} = mnesia:transaction(F), Val.
  131. % index funs
  132. products(UId) -> all_by_index(user_product, #user_product.username, UId).
  133. subscriptions(UId) -> all_by_index(subsciption, #subscription.who, UId).
  134. subscribed(Who) -> all_by_index(subscription, #subscription.whom, Who).
  135. participate(UserName) -> all_by_index(group_subscription, #group_subscription.who, UserName).
  136. members(GroupName) -> all_by_index(group_subscription, #group_subscription.where, GroupName).
  137. user_tournaments(UId) -> all_by_index(play_record, #play_record.who, UId).
  138. tournament_users(TId) -> all_by_index(play_record, #play_record.tournament, TId).
  139. author_comments(Who) ->
  140. EIDs = [E || #comment{entry_id=E} <- all_by_index(comment,#comment.author_id, Who) ],
  141. lists:flatten([ all_by_index(entry, #entry.id,EID) || EID <- EIDs]).