11-module (boss_record_compiler ).
22-author ('emmiller@gmail.com' ).
3+ -author ('zkessin@gmail.com' ).
34-define (DATABASE_MODULE , boss_db ).
45-define (PREFIX , " BOSSRECORDINTERNAL" ).
56-ifdef (TEST ).
67-compile (export_all ).
78-endif .
8-
9+ - compile ( export_all ).
910% -type limit() :: pos_integer()|all.
11+ -type error (T ) :: {ok , T } | {error , string ()}.
1012-type syntaxTree () :: erl_syntax :syntaxTree ().
1113-type name () :: atom ()|[byte (),...].
12- -type fctn_n () :: {atom (), non_neg_integer ()}.
13- -type fctn () :: {function , atom (), atom (), non_neg_integer (), _ }.
14+ -type fctn_n () :: {atom (), non_neg_integer ()}.
15+ -type fctn () :: {function , atom (), atom (), non_neg_integer (), _ }.
16+ -type pair () :: {atom (),atom ()}.
17+ -type assoc () :: {has , {atom (), integer ()}} |
18+ {has , {atom (), integer (), [any ()]}} |
19+ {belongs_to , atom ()}.
1420
1521
1622-export ([compile /1 , compile /2 , edoc_module /1 , edoc_module /2 , process_tokens /1 , trick_out_forms /2 ]).
2026-spec edoc_module (string (),_ ) -> {module (),_ }.
2127-spec process_tokens (nonempty_maybe_improper_list ()) -> {nonempty_maybe_improper_list (),[{_ ,_ }]}.
2228-spec process_tokens (nonempty_maybe_improper_list (),[any ()],[{_ ,_ }]) -> {nonempty_maybe_improper_list (),[{_ ,_ }]}.
29+ -spec make_counters ([{counter , atom ()}| {atom (), any ()}]) -> [atom ()].
30+ -spec make_generated_forms (atom (),
31+ [atom (),...],
32+ [pair (),...],
33+ [pair (),...],
34+ [ atom ()],
35+ boolean ()) -> error ([syntaxTree ()]).
36+ -spec make_generated_forms (atom (),
37+ [atom (),...],
38+ [pair (),...],
39+ [pair (),...],
40+ [ atom ()]) -> error ([syntaxTree ()]).
41+ -spec has_duplicates ([any ()]) -> any ().
2342-spec trick_out_forms ([any (),...],[any ()]) -> [any (),...].
2443-spec trick_out_forms ([any (),...],[any ()],[any ()]) -> [any (),...].
2544-spec trick_out_forms ([any (),...],[any ()],atom (),[any ()],[any ()]) -> [any (),...].
2948-spec override_functions ([syntaxTree ()|fctn ()],[syntaxTree ()],[fctn_n ()]) -> [any ()].
3049-spec export_forms ([{atom (), pos_integer ()}]) -> syntaxTree ().
3150-spec export_forms ([{atom (), pos_integer ()}],[syntaxTree ()]) -> syntaxTree ().
32- -spec database_columns_forms (atom () ,[atom ()],[{ atom (), atom ()} ]) -> syntaxTree ().
33- -spec database_table_forms (atom (),[{ atom (), atom ()} ]) -> syntaxTree ().
51+ -spec database_columns_forms (atom () ,[atom ()],[pair () ]) -> syntaxTree ().
52+ -spec database_table_forms (atom (),[pair () ]) -> syntaxTree ().
3453-spec attribute_types_forms (atom () ,[{atom (), atom ()}]) -> syntaxTree ().
3554-spec validate_types_forms (atom ()) -> syntaxTree ().
3655-spec validate_forms (atom ()) -> syntaxTree ().
4160-spec deep_get_forms () -> syntaxTree ().
4261-spec get_attributes_forms (atom (),[atom ()]) -> syntaxTree ().
4362-spec set_attributes_forms (atom (),[atom ()]) -> syntaxTree ().
44- -type assoc () :: {has , {atom (), integer ()}} |
45- {has , {atom (), integer (), [any ()]}} |
46- {belongs_to , atom ()}.
4763-spec association_forms (atom (),[assoc ()]) -> [any (),...].
4864
4965-spec belongs_to_list_forms ([{atom (),any ()}]) -> syntaxTree ().
5066
51- -spec belongs_to_list_make_list ([{ atom (), atom ()} ]) -> syntaxTree ().
67+ -spec belongs_to_list_make_list ([pair () ]) -> syntaxTree ().
5268-spec attribute_names_forms (name (),[atom ()]) -> syntaxTree ().
5369-spec has_one_forms (name (),atom (),[any ()]) -> syntaxTree ().
54- -spec has_many_forms (atom (),atom (), pos_integer ()| all | many , [any ()]) -> syntaxTree ().
70+ -spec has_many_forms (atom (),atom (), pos_integer (), [any ()]) -> syntaxTree ().
5571-spec first_or_undefined_forms ( syntaxTree ()) -> syntaxTree ().
5672-spec has_many_application_forms (name (),{'tree' ,atom (),{'attr' ,_ ,[any ()],'none' | {_ ,_ ,_ }},_ } | {'wrapper' ,atom (),{'attr' ,_ ,[any ()],'none' | {_ ,_ ,_ }},_ },
5773 pos_integer (),
@@ -93,8 +109,10 @@ edoc_module(File) ->
93109
94110edoc_module (File , Options ) ->
95111 {ok , Forms , TokenInfo } = boss_compiler :parse (File , fun ? MODULE :process_tokens /1 , []),
96- edoc_extract :source (trick_out_forms (Forms , TokenInfo ), edoc :read_comments (File ),
97- File , edoc_lib :get_doc_env ([]), Options ).
112+ edoc_extract :source (trick_out_forms (Forms , TokenInfo ),
113+ edoc :read_comments (File ),
114+ File , edoc_lib :get_doc_env ([]),
115+ Options ).
98116
99117process_tokens (Tokens ) ->
100118 process_tokens (Tokens , [], []).
@@ -116,26 +134,32 @@ trick_out_forms(Forms, TokenInfo) ->
116134 trick_out_forms (Forms , [], TokenInfo ).
117135
118136trick_out_forms ([
119- {attribute , _Pos , module , {ModuleName , Parameters }} = H
120- | Forms ], LeadingForms , TokenInfo ) ->
137+ {attribute , _Pos , module , {ModuleName , Parameters }} = H
138+ | Forms ],
139+ LeadingForms ,
140+ TokenInfo ) ->
121141 trick_out_forms (lists :reverse ([H |LeadingForms ]), Forms , ModuleName , Parameters , TokenInfo );
122142trick_out_forms ([H |T ], LeadingForms , TokenInfo ) ->
123143 trick_out_forms (T , [H |LeadingForms ], TokenInfo ).
124144
145+ has_duplicates (List ) ->
146+ erlang :length (List ) =/= sets :size (sets :from_list (List )).
147+
148+
125149trick_out_forms (LeadingForms , Forms , ModuleName , Parameters , TokenInfo ) ->
126- Attributes = proplists :get_value (attributes , erl_syntax_lib :analyze_forms (LeadingForms ++ Forms ), []),
150+ Attributes = proplists :get_value (attributes , erl_syntax_lib :analyze_forms (LeadingForms ++ Forms ), []),
127151 [{eof , _Line }|ReversedOtherForms ] = lists :reverse (Forms ),
128- UserForms = lists :reverse (ReversedOtherForms ),
129- Counters = make_counters (Attributes ),
130-
131- GeneratedForms =
152+ UserForms = lists :reverse (ReversedOtherForms ),
153+ Counters = make_counters (Attributes ),
154+
155+ { ok , GeneratedForms } =
132156 make_generated_forms (ModuleName , Parameters , TokenInfo , Attributes ,
133157 Counters ),
134158
135- UserFunctionList = list_functions (UserForms ),
136- GeneratedFunctionList = list_functions (GeneratedForms ),
159+ UserFunctionList = list_functions (UserForms ),
160+ GeneratedFunctionList = list_functions (GeneratedForms ),
137161
138- GeneratedExportForms = export_forms (GeneratedFunctionList ),
162+ GeneratedExportForms = export_forms (GeneratedFunctionList ),
139163
140164 LeadingForms ++ GeneratedExportForms ++ UserForms ++
141165 override_functions (GeneratedForms , UserFunctionList ).
@@ -147,23 +171,38 @@ make_counters(Attributes) ->
147171 (_ , Acc ) -> Acc
148172 end , [], Attributes ).
149173
174+ make_generated_forms (ModuleName , Parameters , _TokenInfo , _Attributes ,
175+ _Counters ) ->
176+ make_generated_forms (ModuleName ,
177+ Parameters , _TokenInfo , _Attributes ,
178+ _Counters , has_duplicates (Parameters )).
179+
180+ make_generated_forms (ModuleName , Parameters , _TokenInfo , _Attributes ,
181+ _Counters , _Dup = true ) ->
182+ DupFields = Parameters -- sets :to_list (sets :from_list (Parameters )),
183+ lager :error (" Unable to compile module ~p due to duplicate field(s) ~p " ,
184+ [ModuleName , DupFields ]),
185+ {error , " Duplicate Fields" };
186+
150187make_generated_forms (ModuleName , Parameters , TokenInfo , Attributes ,
151- Counters ) ->
152- lists :concat ([attribute_names_forms (ModuleName , Parameters ) ,
153- attribute_types_forms (ModuleName , TokenInfo ) ,
154- database_columns_forms (ModuleName , Parameters , Attributes ) ,
155- database_table_forms (ModuleName , Attributes ) ,
156- validate_types_forms (ModuleName ) ,
157- validate_forms (ModuleName ) ,
158- save_forms (ModuleName ) ,
159- set_attributes_forms (ModuleName , Parameters ) ,
160- get_attributes_forms (ModuleName , Parameters ) ,
161- counter_getter_forms (Counters ) ,
162- counter_reset_forms (Counters ) ,
163- counter_incr_forms (Counters ) ,
164- association_forms (ModuleName , Attributes ) ,
165- parameter_getter_forms (Parameters )
166- |deep_get_forms ()]).
188+ Counters , _Dup = false ) ->
189+ lager :notice (" Module \" ~p \" Parameters ~p Attributes~p " , [ModuleName ,Parameters , Attributes ]),
190+ GF = attribute_names_forms (ModuleName , Parameters ) ++
191+ attribute_types_forms (ModuleName , TokenInfo ) ++
192+ database_columns_forms (ModuleName , Parameters , Attributes ) ++
193+ database_table_forms (ModuleName , Attributes ) ++
194+ validate_types_forms (ModuleName ) ++
195+ validate_forms (ModuleName ) ++
196+ save_forms (ModuleName ) ++
197+ set_attributes_forms (ModuleName , Parameters ) ++
198+ get_attributes_forms (ModuleName , Parameters ) ++
199+ counter_getter_forms (Counters ) ++
200+ counter_reset_forms (Counters ) ++
201+ counter_incr_forms (Counters ) ++
202+ association_forms (ModuleName , Attributes ) ++
203+ parameter_getter_forms (Parameters ) ++
204+ deep_get_forms (),
205+ {ok , GF }.
167206
168207list_functions (Forms ) ->
169208 list_functions (Forms , []).
@@ -490,8 +529,8 @@ has_one_forms(HasOne, ModuleName, Opts) ->
490529 ])]))
491530 ].
492531
493- has_many_forms (HasMany , ModuleName , many , Opts ) ->
494- has_many_forms (HasMany , ModuleName , all , Opts );
532+ % % has_many_forms(HasMany, ModuleName, many, Opts) ->
533+ % % has_many_forms(HasMany, ModuleName, all, Opts);
495534has_many_forms (HasMany , ModuleName , Limit , Opts ) ->
496535 Sort = proplists :get_value (order_by , Opts , 'id' ),
497536 IsDescending = proplists :get_value (descending , Opts , false ),
0 commit comments