Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 482 lines (440 sloc) 25.351 kb
d036073 BossDB is now its own project
Evan Miller authored
1 -module(boss_record_compiler).
2 -author('emmiller@gmail.com').
3 -define(DATABASE_MODULE, boss_db).
4 -define(PREFIX, "BOSSRECORDINTERNAL").
5
69caf5b New attribute_types function
Evan Miller authored
6 -export([compile/1, compile/2, edoc_module/1, edoc_module/2, process_tokens/1, trick_out_forms/2]).
d036073 BossDB is now its own project
Evan Miller authored
7
8 %% @spec compile( File::string() ) -> {ok, Module} | {error, Reason}
9 %% @equiv compile(File, [])
10 compile(File) ->
11 compile(File, []).
12
13 compile(File, Options) ->
14 boss_compiler:compile(File,
69caf5b New attribute_types function
Evan Miller authored
15 [{pre_revert_transform, fun ?MODULE:trick_out_forms/2},
16 {token_transform, fun ?MODULE:process_tokens/1}|Options]).
d036073 BossDB is now its own project
Evan Miller authored
17
18 %% @spec edoc_module( File::string() ) -> {Module::atom(), EDoc}
19 %% @equiv edoc_module(File, [])
20 edoc_module(File) ->
21 edoc_module(File, []).
22
23 %% @spec edoc_module( File::string(), Options ) -> {Module::atom(), EDoc}
24 %% @doc Return an `edoc_module()' for the given Erlang source file when
25 %% compiled as a BossRecord.
26 edoc_module(File, Options) ->
9abb6d4 Really fix Edoc
Evan Miller authored
27 {ok, Forms, TokenInfo} = boss_compiler:parse(File, fun ?MODULE:process_tokens/1, []),
69caf5b New attribute_types function
Evan Miller authored
28 edoc_extract:source(trick_out_forms(Forms, TokenInfo), edoc:read_comments(File),
d036073 BossDB is now its own project
Evan Miller authored
29 File, edoc_lib:get_doc_env([]), Options).
30
69caf5b New attribute_types function
Evan Miller authored
31 process_tokens(Tokens) ->
32 process_tokens(Tokens, [], []).
33
34 process_tokens([{']',_},{')',_},{dot,_}|_]=Tokens, TokenAcc, Acc) ->
35 {lists:reverse(TokenAcc, Tokens), Acc};
36 process_tokens([{'-',N}=T1,{atom,N,module}=T2,{'(',_}=T3,{atom,_,_ModuleName}=T4,{',',_}=T5,
37 {'[',_}=T6,{var,_,'Id'}=T7|Rest], TokenAcc, []) ->
38 process_tokens(Rest, lists:reverse([T1, T2, T3, T4, T5, T6, T7], TokenAcc), []);
093d9f0 @kevinmontuori ::uuid() is now a valid Id type
kevinmontuori authored
39 process_tokens([{'-',_N}=T1,{atom,_,module}=T2,{'(',_}=T3,{atom,_,_ModuleName}=T4,{',',_}=T5,
40 {'[',_}=T6,{var,_,'Id'}=T7,{'::',_},{atom,_,VarType},{'(',_},{')',_}|Rest], TokenAcc, []) ->
41 process_tokens(Rest, lists:reverse([T1, T2, T3, T4, T5, T6, T7], TokenAcc), [{'Id', VarType}]);
69caf5b New attribute_types function
Evan Miller authored
42 process_tokens([{',',_}=T1,{var,_,VarName}=T2,{'::',_},{atom,_,VarType},{'(',_},{')',_}|Rest], TokenAcc, Acc) ->
43 process_tokens(Rest, lists:reverse([T1, T2], TokenAcc), [{VarName, VarType}|Acc]);
44 process_tokens([H|T], TokenAcc, Acc) ->
45 process_tokens(T, [H|TokenAcc], Acc).
46
47 trick_out_forms(Forms, TokenInfo) ->
48 trick_out_forms(Forms, [], TokenInfo).
d036073 BossDB is now its own project
Evan Miller authored
49
50 trick_out_forms([
51 {attribute, _Pos, module, {ModuleName, Parameters}} = H
69caf5b New attribute_types function
Evan Miller authored
52 | Forms], LeadingForms, TokenInfo) ->
53 trick_out_forms(lists:reverse([H|LeadingForms]), Forms, ModuleName, Parameters, TokenInfo);
54 trick_out_forms([H|T], LeadingForms, TokenInfo) ->
55 trick_out_forms(T, [H|LeadingForms], TokenInfo).
d036073 BossDB is now its own project
Evan Miller authored
56
69caf5b New attribute_types function
Evan Miller authored
57 trick_out_forms(LeadingForms, Forms, ModuleName, Parameters, TokenInfo) ->
d036073 BossDB is now its own project
Evan Miller authored
58 Attributes = proplists:get_value(attributes, erl_syntax_lib:analyze_forms(LeadingForms ++ Forms), []),
59 [{eof, _Line}|ReversedOtherForms] = lists:reverse(Forms),
60 UserForms = lists:reverse(ReversedOtherForms),
61 Counters = lists:foldl(
62 fun
63 ({counter, Counter}, Acc) -> [Counter|Acc];
64 (_, Acc) -> Acc
65 end, [], Attributes),
66
67 GeneratedForms =
69caf5b New attribute_types function
Evan Miller authored
68 attribute_names_forms(ModuleName, Parameters) ++
69 attribute_types_forms(ModuleName, TokenInfo) ++
eeb78f0 Validate model parameter types
Evan Miller authored
70 validate_types_forms(ModuleName) ++
d036073 BossDB is now its own project
Evan Miller authored
71 validate_forms(ModuleName) ++
69caf5b New attribute_types function
Evan Miller authored
72 save_forms(ModuleName) ++
d036073 BossDB is now its own project
Evan Miller authored
73 set_attributes_forms(ModuleName, Parameters) ++
74 get_attributes_forms(ModuleName, Parameters) ++
75 counter_getter_forms(Counters) ++
76 counter_reset_forms(Counters) ++
77 counter_incr_forms(Counters) ++
78 association_forms(ModuleName, Attributes) ++
79 parameter_getter_forms(Parameters),
80
81 UserFunctionList = list_functions(UserForms),
82 GeneratedFunctionList = list_functions(GeneratedForms),
83
84 GeneratedExportForms = export_forms(GeneratedFunctionList),
85
86 LeadingForms ++ GeneratedExportForms ++ UserForms ++
87 override_functions(GeneratedForms, UserFunctionList).
88
89 list_functions(Forms) ->
90 list_functions(Forms, []).
91
92 list_functions([], DefinedFunctions) ->
93 lists:reverse(DefinedFunctions);
94 list_functions([{'function', _, Name, Arity, _}|Rest], DefinedFunctions) ->
95 list_functions(Rest, [{Name, Arity}|DefinedFunctions]);
96 list_functions([{tree, 'function', _, {'function', {tree, 'atom', _, Name},
97 [{tree, 'clause', _, {'clause', Args, _, _}}|_]}}|Rest],
98 DefinedFunctions) ->
99 Arity = length(Args),
100 list_functions(Rest, [{Name, Arity}|DefinedFunctions]);
101 list_functions([_H|T], DefinedFunctions) ->
102 list_functions(T, DefinedFunctions).
103
104 override_functions(Forms, DefinedFunctions) ->
105 override_functions(Forms, [], DefinedFunctions).
106
107 override_functions([{'function', _, Name, Arity, _} = Function|Rest], Acc, DefinedFunctions) ->
108 case lists:member({Name, Arity}, DefinedFunctions) of
109 true -> override_functions(Rest, Acc, DefinedFunctions);
110 false -> override_functions(Rest, [Function|Acc], [{Name, Arity}|DefinedFunctions])
111 end;
112 override_functions([{tree, 'function', _, {'function', {tree, 'atom', _, Name},
113 [{tree, 'clause', _, {'clause', Args, _, _}}|_]
114 }} = Function|Rest],
115 Acc, DefinedFunctions) ->
116 Arity = length(Args),
117 case lists:member({Name, Arity}, DefinedFunctions) of
118 true -> override_functions(Rest, Acc, DefinedFunctions);
119 false -> override_functions(Rest, [Function|Acc], [{Name, Arity}|DefinedFunctions])
120 end;
121 override_functions([H|T], Acc, DefinedFunctions) ->
122 override_functions(T, [H|Acc], DefinedFunctions);
123 override_functions([], Acc, _) ->
124 lists:reverse(Acc).
125
126 export_forms(FunctionList) ->
127 export_forms(FunctionList, []).
128
129 export_forms([], Acc) ->
130 lists:reverse(Acc);
131 export_forms([{Name, Arity}|Rest], Acc) ->
132 export_forms(Rest, [erl_syntax:attribute(erl_syntax:atom(export), [erl_syntax:list([erl_syntax:arity_qualifier(erl_syntax:atom(Name), erl_syntax:integer(Arity))])])|Acc]).
133
69caf5b New attribute_types function
Evan Miller authored
134 attribute_types_forms(ModuleName, TypeInfo) ->
135 [erl_syntax:add_precomments([erl_syntax:comment(
136 ["% @spec attribute_types() -> [{atom(), atom()}]",
137 lists:concat(["% @doc A proplist of the types of each `", ModuleName, "' parameter, if specified."])])],
138 erl_syntax:function(
139 erl_syntax:atom(attribute_types),
140 [erl_syntax:clause([], none, [erl_syntax:list(lists:map(
141 fun({P, T}) -> erl_syntax:tuple([erl_syntax:atom(parameter_to_colname(P)), erl_syntax:atom(T)]) end,
142 TypeInfo))])]))].
143
eeb78f0 Validate model parameter types
Evan Miller authored
144 validate_types_forms(ModuleName) ->
145 [erl_syntax:add_precomments([erl_syntax:comment(
146 ["% @spec validate_types() -> ok | {error, [ErrorMessages]}",
147 lists:concat(["% @doc Validates the parameter types of `", ModuleName, "' without saving to the database."])
148 ])],
149 erl_syntax:function(
150 erl_syntax:atom(validate_types),
151 [erl_syntax:clause([], none,
152 [erl_syntax:application(
153 erl_syntax:atom(?DATABASE_MODULE),
154 erl_syntax:atom(validate_record_types),
155 [erl_syntax:variable("THIS")]
156 )])]))].
157
d036073 BossDB is now its own project
Evan Miller authored
158 validate_forms(ModuleName) ->
159 [erl_syntax:add_precomments([erl_syntax:comment(
160 ["% @spec validate() -> ok | {error, [ErrorMessages]}",
161 lists:concat(["% @doc Validates this `", ModuleName, "' without saving to the database."]),
162 "% Errors are generated from this model's `validation_tests/0' function (if defined), ",
163 "% which should return a list of `{TestFunction, ErrorMessage}' tuples. For each test, ",
164 "% `TestFunction' should be a fun of arity 0 that returns `true' if the record is valid ",
165 "% or `false' if it is invalid. `ErrorMessage' should be a (constant) string that will be ",
166 "% included in `ErrorMessages' if the associated `TestFunction' returns `false' on this ",
167 lists:concat(["% particular `", ModuleName, "'."])
168 ])],
169 erl_syntax:function(
170 erl_syntax:atom(validate),
171 [erl_syntax:clause([], none,
172 [erl_syntax:application(
173 erl_syntax:atom(?DATABASE_MODULE),
174 erl_syntax:atom(validate_record),
175 [erl_syntax:variable("THIS")]
176 )])]))].
177
178 save_forms(ModuleName) ->
179 [erl_syntax:add_precomments([erl_syntax:comment(
180 [lists:concat(["% @spec save() -> {ok, Saved", inflector:camelize(atom_to_list(ModuleName)), "} | {error, [ErrorMessages]}"]),
181 lists:concat(["% @doc Saves this `", ModuleName, "' record to the database. The returned record"]),
182 "% will have an auto-generated ID if the record's ID was set to 'id'.",
183 "% Performs validation first, returning `ErrorMessages' if validation fails. See `validate/0'."])],
184 erl_syntax:function(
185 erl_syntax:atom(save),
186 [erl_syntax:clause([], none,
187 [erl_syntax:application(
188 erl_syntax:atom(?DATABASE_MODULE),
189 erl_syntax:atom(save_record),
190 [erl_syntax:variable("THIS")]
191 )])]))].
192 parameter_getter_forms(Parameters) ->
193 lists:map(fun(P) ->
194 erl_syntax:add_precomments([erl_syntax:comment(
195 [lists:concat(["% @spec ", parameter_to_colname(P), "() -> ", P]),
196 lists:concat(["% @doc Returns the value of `", P, "'"])])],
197 erl_syntax:function(
198 erl_syntax:atom(parameter_to_colname(P)),
199 [erl_syntax:clause([], none, [erl_syntax:variable(P)])]))
200 end, Parameters).
201
202 get_attributes_forms(ModuleName, Parameters) ->
203 [erl_syntax:add_precomments([erl_syntax:comment(
204 ["% @spec attributes() -> [{Attribute::atom(), Value::string() | undefined}]",
205 lists:concat(["% @doc A proplist of the `", ModuleName, "' parameters and their values."])])],
206 erl_syntax:function(
207 erl_syntax:atom(attributes),
208 [erl_syntax:clause([], none,
209 [erl_syntax:list(lists:map(fun(P) ->
210 erl_syntax:tuple([
211 erl_syntax:atom(parameter_to_colname(P)),
212 erl_syntax:variable(P)])
213 end, Parameters))])]))].
214
215 set_attributes_forms(ModuleName, Parameters) ->
216 [erl_syntax:add_precomments([erl_syntax:comment(
217 ["% @spec set([{Attribute::atom(), Value}]) -> "++inflector:camelize(atom_to_list(ModuleName)),
218 "% @doc Set multiple record attributes at once. Does not save the record."])],
219 erl_syntax:function(
220 erl_syntax:atom(set),
221 [erl_syntax:clause([erl_syntax:variable("AttributeProplist")], none,
222 [erl_syntax:application(
223 erl_syntax:atom(ModuleName),
224 erl_syntax:atom(new),
225 lists:map(fun(P) ->
226 erl_syntax:application(
227 erl_syntax:atom(proplists),
228 erl_syntax:atom(get_value),
229 [erl_syntax:atom(parameter_to_colname(P)),
230 erl_syntax:variable("AttributeProplist"),
231 erl_syntax:variable(P)])
232 end, Parameters))])])),
233 erl_syntax:add_precomments([erl_syntax:comment(
1303558 @evanmiller Avoid variable name conflicts in set/2
evanmiller authored
234 ["% @spec set(Attribute::atom(), NewValue::any()) -> "++inflector:camelize(atom_to_list(ModuleName)),
d036073 BossDB is now its own project
Evan Miller authored
235 "% @doc Set the value of a particular attribute. Does not save the record."])],
236 erl_syntax:function(
237 erl_syntax:atom(set),
1303558 @evanmiller Avoid variable name conflicts in set/2
evanmiller authored
238 [erl_syntax:clause([erl_syntax:variable(?PREFIX++"Attribute"), erl_syntax:variable(?PREFIX++"NewValue")], none,
d036073 BossDB is now its own project
Evan Miller authored
239 [
240 erl_syntax:application(
241 erl_syntax:atom(set),
1303558 @evanmiller Avoid variable name conflicts in set/2
evanmiller authored
242 [erl_syntax:list([erl_syntax:tuple([erl_syntax:variable(?PREFIX++"Attribute"), erl_syntax:variable(?PREFIX++"NewValue")])])])
d036073 BossDB is now its own project
Evan Miller authored
243 ])]))
244 ].
245
246 association_forms(ModuleName, Attributes) ->
247 {Forms, BelongsToList} = lists:foldl(
248 fun
249 ({has, {HasOne, 1}}, {Acc, BT}) ->
250 {has_one_forms(HasOne, ModuleName, []) ++ Acc, BT};
251 ({has, {HasOne, 1, Opts}}, {Acc, BT}) ->
252 {has_one_forms(HasOne, ModuleName, Opts) ++ Acc, BT};
253 ({has, {HasMany, Limit}}, {Acc, BT}) ->
254 {has_many_forms(HasMany, ModuleName, Limit, []) ++ Acc, BT};
255 ({has, {HasMany, Limit, Opts}}, {Acc, BT}) ->
256 {has_many_forms(HasMany, ModuleName, Limit, Opts) ++ Acc, BT};
257 ({belongs_to, BelongsTo}, {Acc, BT}) ->
258 {[belongs_to_forms(BelongsTo, BelongsTo, ModuleName)|Acc], [BelongsTo|BT]};
259 ({OtherAttr, BelongsTo}, {Acc, BT}) ->
260 case atom_to_list(OtherAttr) of
261 "belongs_to_"++Type ->
262 {[belongs_to_forms(Type, BelongsTo, ModuleName)|Acc], [BelongsTo|BT]};
263 _ ->
264 {Acc, BT}
265 end;
266 (_, Acc) ->
267 Acc
268 end, {[], []}, Attributes),
269 Forms ++ belongs_to_list_forms(BelongsToList).
270
271
272 belongs_to_list_forms(BelongsToList) ->
273 [ erl_syntax:add_precomments([erl_syntax:comment(
274 ["% @spec belongs_to_names() -> [{atom()}]",
275 lists:concat(["% @doc Retrieve a list of the names of `belongs_to' associations."])])],
276 erl_syntax:function(
277 erl_syntax:atom(belongs_to_names),
278 [erl_syntax:clause([], none, [erl_syntax:list(lists:map(
279 fun(P) -> erl_syntax:atom(P) end, BelongsToList))])])),
280
281 erl_syntax:add_precomments([erl_syntax:comment(
282 ["% @spec belongs_to() -> [{atom(), BossRecord}]",
283 lists:concat(["% @doc Retrieve all of the `belongs_to' associations at once."])])],
284 erl_syntax:function(
285 erl_syntax:atom(belongs_to),
286 [erl_syntax:clause([], none, [erl_syntax:list(lists:map(
287 fun(P) -> erl_syntax:tuple([
288 erl_syntax:atom(P),
289 erl_syntax:application(none, erl_syntax:atom(P), [])]) end, BelongsToList))])]))
290 ].
291
292 attribute_names_forms(ModuleName, Parameters) ->
293 [ erl_syntax:add_precomments([erl_syntax:comment(
294 ["% @spec attribute_names() -> [atom()]",
295 lists:concat(["% @doc A list of the lower-case `", ModuleName, "' parameters."])])],
296 erl_syntax:function(
297 erl_syntax:atom(attribute_names),
298 [erl_syntax:clause([], none, [erl_syntax:list(lists:map(
299 fun(P) -> erl_syntax:atom(parameter_to_colname(P)) end,
300 Parameters))])]))].
301
302 has_one_forms(HasOne, ModuleName, Opts) ->
303 Type = proplists:get_value(module, Opts, HasOne),
304 ForeignKey = proplists:get_value(foreign_key, Opts, atom_to_list(ModuleName) ++ "_id"),
305 [erl_syntax:add_precomments([erl_syntax:comment(
306 [lists:concat(["% @spec ", HasOne, "() -> ", Type, " | undefined"]),
307 lists:concat(["% @doc Retrieves the `", Type, "' with `", ForeignKey, "' ",
308 "set to the `Id' of this `", ModuleName, "'"])])],
309 erl_syntax:function(erl_syntax:atom(HasOne),
310 [erl_syntax:clause([], none, [
311 first_or_undefined_forms(
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
312 has_many_application_forms(Type, ForeignKey, 1, id, false)
d036073 BossDB is now its own project
Evan Miller authored
313 )
314 ])]))
315 ].
316
317 has_many_forms(HasMany, ModuleName, many, Opts) ->
318 has_many_forms(HasMany, ModuleName, all, Opts);
319 has_many_forms(HasMany, ModuleName, Limit, Opts) ->
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
320 Sort = proplists:get_value(order_by, Opts, 'id'),
321 IsDescending = proplists:get_value(descending, Opts, false),
d036073 BossDB is now its own project
Evan Miller authored
322 Singular = inflector:singularize(atom_to_list(HasMany)),
323 Type = proplists:get_value(module, Opts, Singular),
324 ForeignKey = proplists:get_value(foreign_key, Opts, atom_to_list(ModuleName) ++ "_id"),
325 [erl_syntax:add_precomments([erl_syntax:comment(
326 [
327 lists:concat(["% @spec ", HasMany, "() -> [ ", Type, " ]"]),
328 lists:concat(["% @doc Retrieves `", Type, "' records with `", ForeignKey, "' ",
329 "set to the `Id' of this `", ModuleName, "'"])])],
330 erl_syntax:function(erl_syntax:atom(HasMany),
331 [erl_syntax:clause([], none, [
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
332 has_many_application_forms(Type, ForeignKey, Limit, Sort, IsDescending)
d036073 BossDB is now its own project
Evan Miller authored
333 ])])),
334 erl_syntax:add_precomments([erl_syntax:comment(
335 [
336 lists:concat(["% @spec first_", Singular, "() -> ", Type, " | undefined"]),
337 lists:concat(["% @doc Retrieves the first `", Type,
338 "' that would be returned by `", HasMany, "()'"])])],
339 erl_syntax:function(erl_syntax:atom("first_"++Singular),
340 [erl_syntax:clause([], none, [
341 first_or_undefined_forms(
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
342 has_many_application_forms(Type, ForeignKey, 1, Sort, IsDescending)
d036073 BossDB is now its own project
Evan Miller authored
343 )
344 ])])),
345 erl_syntax:add_precomments([erl_syntax:comment(
346 [
347 lists:concat(["% @spec last_", Singular, "() -> ", Type, " | undefined"]),
348 lists:concat(["% @doc Retrieves the last `", Type,
349 "' that would be returned by `", HasMany, "()'"])])],
350 erl_syntax:function(erl_syntax:atom("last_"++Singular),
351 [erl_syntax:clause([], none, [
352 first_or_undefined_forms(
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
353 has_many_application_forms(Type, ForeignKey, 1, Sort, not IsDescending)
d036073 BossDB is now its own project
Evan Miller authored
354 )
355 ])]))
356 ].
357
358 first_or_undefined_forms(Forms) ->
359 erl_syntax:case_expr(Forms,
360 [erl_syntax:clause([erl_syntax:list([erl_syntax:variable(?PREFIX++"Record")])], none,
361 [erl_syntax:variable(?PREFIX++"Record")]),
362 erl_syntax:clause([erl_syntax:underscore()], none, [erl_syntax:atom(undefined)])]).
363
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
364 has_many_application_forms(Type, ForeignKey, Limit, Sort, IsDescending) ->
d036073 BossDB is now its own project
Evan Miller authored
365 erl_syntax:application(
366 erl_syntax:atom(?DATABASE_MODULE),
367 erl_syntax:atom(find),
368 [erl_syntax:atom(Type),
369 erl_syntax:list([
370 erl_syntax:tuple([
371 erl_syntax:atom(ForeignKey),
372 erl_syntax:variable("Id")])
373 ]),
9943a4d @evanmiller Revamp the boss_db:find/N API
evanmiller authored
374 erl_syntax:list([
375 erl_syntax:tuple([
376 erl_syntax:atom(limit),
377 erl_syntax:integer(Limit)]),
378 erl_syntax:tuple([
379 erl_syntax:atom(order_by),
380 erl_syntax:atom(Sort)]),
381 erl_syntax:tuple([
382 erl_syntax:atom(descending),
383 erl_syntax:atom(IsDescending)])
384 ])
d036073 BossDB is now its own project
Evan Miller authored
385 ]).
386
387 belongs_to_forms(Type, BelongsTo, ModuleName) ->
388 erl_syntax:add_precomments([erl_syntax:comment(
389 [lists:concat(["% @spec ", BelongsTo, "() -> ",
390 inflector:camelize(atom_to_list(BelongsTo))]),
391 lists:concat(["% @doc Retrieves the ", Type,
392 " with `Id' equal to the `",
393 inflector:camelize(atom_to_list(BelongsTo)), "Id'",
394 " of this ", ModuleName])])],
395 erl_syntax:function(erl_syntax:atom(BelongsTo),
396 [erl_syntax:clause([], none, [
397 erl_syntax:application(
398 erl_syntax:atom(?DATABASE_MODULE),
399 erl_syntax:atom(find),
400 [erl_syntax:variable(inflector:camelize(atom_to_list(BelongsTo)) ++ "Id")]
401 )])])).
402
403 counter_getter_forms(Counters) ->
404 lists:map(
405 fun(Counter) ->
406 erl_syntax:add_precomments([erl_syntax:comment(
407 [
408 lists:concat(["% @spec ", Counter, "() -> integer()"]),
409 lists:concat(["% @doc Retrieve the value of the `", Counter, "' counter"])])],
410 erl_syntax:function(erl_syntax:atom(Counter),
411 [erl_syntax:clause([], none, [
412 erl_syntax:application(
413 erl_syntax:atom(?DATABASE_MODULE),
414 erl_syntax:atom(counter),
415 [erl_syntax:infix_expr(
416 erl_syntax:variable("Id"),
417 erl_syntax:operator("++"),
418 erl_syntax:string("-counter-" ++ atom_to_list(Counter))
419 )])])])) end, Counters).
420
421 counter_reset_forms([]) ->
422 [];
423 counter_reset_forms(Counters) ->
424 [erl_syntax:add_precomments([erl_syntax:comment(
425 ["% @spec reset( Counter::atom() ) -> ok | {error, Reason}",
426 "% @doc Reset a counter to zero"])],
427 erl_syntax:function(erl_syntax:atom(reset),
428 lists:map(
429 fun(Counter) ->
430 erl_syntax:clause([erl_syntax:atom(Counter)], none, [
431 erl_syntax:application(
432 erl_syntax:atom(?DATABASE_MODULE),
433 erl_syntax:atom(delete),
434 [counter_name_forms(Counter)])])
435 end, Counters)))].
436
437 counter_incr_forms([]) ->
438 [];
439 counter_incr_forms(Counters) ->
440 [ erl_syntax:add_precomments([erl_syntax:comment(
441 ["% @spec incr( Counter::atom() ) -> integer()",
442 "@doc Atomically increment a counter by 1."])],
443 erl_syntax:function(erl_syntax:atom(incr),
444 lists:map(
445 fun(Counter) ->
446 erl_syntax:clause([erl_syntax:atom(Counter)], none, [
447 erl_syntax:application(
448 erl_syntax:atom(?DATABASE_MODULE),
449 erl_syntax:atom(incr),
450 [counter_name_forms(Counter)])])
451 end, Counters))),
452 erl_syntax:add_precomments([erl_syntax:comment(
453 ["% @spec incr( Counter::atom(), Increment::integer() ) ->"++
454 " integer()",
455 "% @doc Atomically increment a counter by the specified increment"])],
456 erl_syntax:function(erl_syntax:atom(incr),
457 lists:map(
458 fun(Counter) ->
459 erl_syntax:clause([erl_syntax:atom(Counter),
460 erl_syntax:variable("Amount")], none, [
461 erl_syntax:application(
462 erl_syntax:atom(?DATABASE_MODULE),
463 erl_syntax:atom(incr),
464 [counter_name_forms(Counter),
465 erl_syntax:variable("Amount")])])
466 end, Counters)))].
467
468 counter_name_forms(CounterVariable) ->
469 erl_syntax:infix_expr(
470 erl_syntax:infix_expr(
471 erl_syntax:variable("Id"),
472 erl_syntax:operator("++"),
473 erl_syntax:string("-counter-")),
474 erl_syntax:operator("++"),
475 erl_syntax:application(
476 erl_syntax:atom('erlang'),
477 erl_syntax:atom('atom_to_list'),
478 [erl_syntax:atom(CounterVariable)])).
479
480 parameter_to_colname(Parameter) when is_atom(Parameter) ->
481 string:to_lower(inflector:underscore(atom_to_list(Parameter))).
Something went wrong with that request. Please try again.