meta-record 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/metarecord-make +53 -0
- data/lib/guard/metarecord.rb +22 -0
- data/lib/metarecord/generator_base.rb +197 -0
- data/lib/metarecord/generators/aurelia_generator.rb +150 -0
- data/lib/metarecord/generators/comet/archive_generator.rb +108 -0
- data/lib/metarecord/generators/comet/data_generator.rb +77 -0
- data/lib/metarecord/generators/comet/edit_generator.rb +153 -0
- data/lib/metarecord/generators/crails/data_generator.rb +289 -0
- data/lib/metarecord/generators/crails/destroy_generator.rb +178 -0
- data/lib/metarecord/generators/crails/edit_generator.rb +364 -0
- data/lib/metarecord/generators/crails/helpers/validations.rb +77 -0
- data/lib/metarecord/generators/crails/query_generator.rb +88 -0
- data/lib/metarecord/generators/crails/view_generator.rb +80 -0
- data/lib/metarecord/generators/rails/data_generator.rb +143 -0
- data/lib/metarecord/generators/rails/migration_generator.rb +89 -0
- data/lib/metarecord/generators/rails/migrations/table_helpers.rb +67 -0
- data/lib/metarecord/generators/rails/migrations/type_helpers.rb +45 -0
- data/lib/metarecord/manifest_generator.rb +42 -0
- data/lib/metarecord/model.rb +66 -0
- data/lib/metarecord/runner.rb +56 -0
- metadata +68 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'metarecord/generators/crails/edit_generator'
|
2
|
+
|
3
|
+
class CometEditGenerator < CrailsEditGenerator
|
4
|
+
def _append_macro str
|
5
|
+
@src ||= ""
|
6
|
+
@src += str + "\n"
|
7
|
+
end
|
8
|
+
|
9
|
+
def generate_json_methods object
|
10
|
+
super
|
11
|
+
@rendering_from_json = true
|
12
|
+
_append_macro "#ifdef #{CometDataGenerator.client_define}"
|
13
|
+
_append "void #{@klassname}::from_json(Data data)"
|
14
|
+
_append "{"
|
15
|
+
@indent += 1
|
16
|
+
_append "id = data[\"id\"].defaults_to<#{id_type}>(#{null_id});"
|
17
|
+
_append "edit(data);"
|
18
|
+
@indent -= 1
|
19
|
+
_append "}"
|
20
|
+
_append_macro "#endif"
|
21
|
+
@rendering_from_json = false
|
22
|
+
end
|
23
|
+
|
24
|
+
def validation type, name, data
|
25
|
+
if data[:uniqueness] == true
|
26
|
+
_append_macro "#ifndef #{CometDataGenerator.client_define}"
|
27
|
+
_append validate_uniqueness type, name
|
28
|
+
_append_macro "#endif"
|
29
|
+
data[:uniqueness] = false
|
30
|
+
end
|
31
|
+
super type, name, data
|
32
|
+
end
|
33
|
+
|
34
|
+
def has_one_getter type, name, options
|
35
|
+
type = get_type type
|
36
|
+
tptr = ptr_type type
|
37
|
+
_append_macro "#ifndef #{CometDataGenerator.client_define}"
|
38
|
+
super
|
39
|
+
_append_macro "#else"
|
40
|
+
_append "#{tptr} #{@klassname}::get_#{name}() const"
|
41
|
+
_append "{"
|
42
|
+
_append " #{tptr} model = std::make_shared<#{type}>();"
|
43
|
+
_append " model->set_id(get_#{name}_id());"
|
44
|
+
_append " model->fetch();"
|
45
|
+
_append " return model;"
|
46
|
+
_append "}"
|
47
|
+
_append_macro "#endif"
|
48
|
+
end
|
49
|
+
|
50
|
+
def joined_has_one_edit type, name, options
|
51
|
+
data_id = "data[\"#{name}_id\"]"
|
52
|
+
inline_data = "data[\"#{name}\"]"
|
53
|
+
_append_macro "#ifndef #{CometDataGenerator.client_define}"
|
54
|
+
super
|
55
|
+
_append_macro "#else"
|
56
|
+
_append "{"
|
57
|
+
_append " if (#{data_id} == 0)"
|
58
|
+
_append " set_#{name}(nullptr);"
|
59
|
+
_append " else if (!get_#{name}() || #{data_id} != get_#{name}()->get_id())"
|
60
|
+
_append " {"
|
61
|
+
_append " auto linked_resource = std::make_shared<#{type}>();"
|
62
|
+
_append " linked_resource->set_id(#{data_id}.as<#{id_type}>());"
|
63
|
+
_append " set_#{name}(linked_resource);"
|
64
|
+
_append " }"
|
65
|
+
_append "}"
|
66
|
+
_append "else if (#{inline_data}.exists())"
|
67
|
+
_append "{"
|
68
|
+
_append " auto linked_resource = std::make_shared<#{type}>();"
|
69
|
+
_append " linked_resource->from_json(#{inline_data});"
|
70
|
+
_append " set_#{name}(linked_resource);"
|
71
|
+
_append "}"
|
72
|
+
_append_macro "#endif"
|
73
|
+
end
|
74
|
+
|
75
|
+
def has_many_fetch type, name, options
|
76
|
+
tptr = ptr_type type
|
77
|
+
singular_name = get_singular_name name
|
78
|
+
|
79
|
+
_append_macro "#ifndef #{CometDataGenerator.client_define}"
|
80
|
+
super type, name, options
|
81
|
+
_append_macro "#else"
|
82
|
+
_append "Comet::Promise #{@klassname}::fetch_#{name}()"
|
83
|
+
_append "{"
|
84
|
+
@indent += 1
|
85
|
+
_append "std::vector<Comet::Promise> promises;\n"
|
86
|
+
_append "for (auto id : #{singular_name}_ids)"
|
87
|
+
_append "{"
|
88
|
+
@indent += 1
|
89
|
+
_append "#{tptr} model;\n"
|
90
|
+
_append "model->set_id(id);"
|
91
|
+
_append "promises.push_back(model->fetch());"
|
92
|
+
_append "#{name}.push_back(model);"
|
93
|
+
_append "#{name}_fetched = true;"
|
94
|
+
@indent -= 1
|
95
|
+
_append "}"
|
96
|
+
_append "return Comet::Promise::all(promises);"
|
97
|
+
@indent -= 1
|
98
|
+
_append "}"
|
99
|
+
_append_macro "#endif"
|
100
|
+
end
|
101
|
+
|
102
|
+
def property type, name, options = {}
|
103
|
+
if options[:ready_only] == true && rendering_edit?
|
104
|
+
options[:read_only] = false
|
105
|
+
_append_macro "#ifdef #{CometDataGenerator.client_define}"
|
106
|
+
super
|
107
|
+
_append_macro "#endif"
|
108
|
+
else
|
109
|
+
super
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def has_many type, name, options = {}
|
114
|
+
if options[:read_only] == true && rendering_edit?
|
115
|
+
options[:read_only] = false
|
116
|
+
_append_macro "#ifdef #{CometDataGenerator.client_define}"
|
117
|
+
super
|
118
|
+
_append_macro "#endif"
|
119
|
+
else
|
120
|
+
super
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def has_one type, name, options = {}
|
125
|
+
if options[:read_only] == true && rendering_edit?
|
126
|
+
options[:read_only] = false
|
127
|
+
_append_macro "#ifdef #{CometDataGenerator.client_define}"
|
128
|
+
super
|
129
|
+
_append_macro "#endif"
|
130
|
+
else
|
131
|
+
super
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class << self
|
136
|
+
def generate_includes
|
137
|
+
<<CPP
|
138
|
+
#ifndef #{CometDataGenerator.client_define}
|
139
|
+
#{super}
|
140
|
+
#else
|
141
|
+
# include <crails/comet/mvc/helpers.hpp>
|
142
|
+
#endif
|
143
|
+
CPP
|
144
|
+
end
|
145
|
+
|
146
|
+
def sourcefile_to_destfile sourcefile
|
147
|
+
base = super sourcefile
|
148
|
+
basepath = Pathname.new base
|
149
|
+
parentdir = basepath.dirname.to_s + "/shared"
|
150
|
+
"#{parentdir}/#{basepath.basename}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,289 @@
|
|
1
|
+
require 'metarecord/model'
|
2
|
+
require 'metarecord/generator_base'
|
3
|
+
|
4
|
+
class CrailsDataGenerator < GeneratorBase
|
5
|
+
attr_accessor :forward_declarations
|
6
|
+
|
7
|
+
def reset
|
8
|
+
super
|
9
|
+
@forward_declarations = []
|
10
|
+
@src = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def _append str, opts = {}
|
14
|
+
@src[@current_visibility] ||= ""
|
15
|
+
@src[@current_visibility] += " " * (@indent * @tab_size)
|
16
|
+
@src[@current_visibility] += str + "\n" unless opts[:no_line_return]
|
17
|
+
end
|
18
|
+
|
19
|
+
def _append_macro str
|
20
|
+
@src[@current_visibility] ||= ""
|
21
|
+
@src[@current_visibility] += str + "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_headers
|
25
|
+
forward_source = ""
|
26
|
+
@forward_declarations.each do |type|
|
27
|
+
parts = type.split('::').reject {|part| part.empty?}
|
28
|
+
last_part = parts.last
|
29
|
+
if parts.length > 1
|
30
|
+
parts[0...parts.size-1].each do |part|
|
31
|
+
forward_source += "namespace #{part} { "
|
32
|
+
end
|
33
|
+
forward_source += "class #{last_part};"
|
34
|
+
(parts.size - 1).times do forward_source += " } " end
|
35
|
+
forward_source += "\n"
|
36
|
+
else
|
37
|
+
forward_source += "class #{last_part};\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
forward_source
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_class_head object
|
44
|
+
_append "#pragma db object abstract"
|
45
|
+
_append "struct #{object[:name]}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def generate_for object
|
49
|
+
reset
|
50
|
+
@forward_declarations << object[:classname] unless object[:classname].nil?
|
51
|
+
@current_visibility = :_preblock
|
52
|
+
@indent += 1
|
53
|
+
generate_class_head object
|
54
|
+
_append "{"
|
55
|
+
@indent += 1
|
56
|
+
_append "friend class odb::access;"
|
57
|
+
_append "#pragma db transient"
|
58
|
+
_append "DataTree errors;"
|
59
|
+
@current_visibility = :public
|
60
|
+
edit_resource_declaration
|
61
|
+
prepare_order_by
|
62
|
+
self.instance_eval &object[:block]
|
63
|
+
@current_visibility = :_postblock
|
64
|
+
@indent -= 1
|
65
|
+
_append "};"
|
66
|
+
@indent -= 1
|
67
|
+
render
|
68
|
+
end
|
69
|
+
|
70
|
+
def edit_resource_declaration
|
71
|
+
_append "virtual std::vector<std::string> find_missing_parameters(Data) const;"
|
72
|
+
_append "virtual void edit(Data);"
|
73
|
+
_append "virtual std::string to_json() const;"
|
74
|
+
_append "virtual bool is_valid();"
|
75
|
+
_append "virtual void on_dependent_destroy(#{id_type});"
|
76
|
+
_append ""
|
77
|
+
end
|
78
|
+
|
79
|
+
def prepare_order_by
|
80
|
+
_append "template<typename QUERY>"
|
81
|
+
_append "static QUERY default_order_by(QUERY query)"
|
82
|
+
_append "{"
|
83
|
+
_append " return query; // order_by"
|
84
|
+
_append "}\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
def render
|
88
|
+
@current_visibility = :_result
|
89
|
+
result = @src[:_preblock]
|
90
|
+
[:public, :protected, :private].each do |key|
|
91
|
+
unless @src[key].nil?
|
92
|
+
result += " #{key}:\n"
|
93
|
+
result += @src[key]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
result += @src[:_postblock]
|
97
|
+
result
|
98
|
+
end
|
99
|
+
|
100
|
+
def visibility value
|
101
|
+
@current_visibility = value
|
102
|
+
end
|
103
|
+
|
104
|
+
def with_visibility value, &block
|
105
|
+
old_visibility = @current_visibility
|
106
|
+
visibility value
|
107
|
+
self.instance_eval &block
|
108
|
+
visibility old_visibility
|
109
|
+
end
|
110
|
+
|
111
|
+
def resource_name name
|
112
|
+
visibility :public
|
113
|
+
_append "static const std::string scope;"
|
114
|
+
_append "static const std::string plural_scope;"
|
115
|
+
_append "static const std::string view;"
|
116
|
+
end
|
117
|
+
|
118
|
+
def order_by name, flow = nil
|
119
|
+
src = "return query + \"ORDER BY\" + QUERY::#{name}"
|
120
|
+
src += " + \"#{flow.to_s.upcase}\"" unless flow.nil?
|
121
|
+
src += ";"
|
122
|
+
@src[:public] = @src[:public].gsub /^(\s*).*\/\/ order_by$/, '\1' + src
|
123
|
+
end
|
124
|
+
|
125
|
+
def datatree_property name, options
|
126
|
+
with_visibility :public do
|
127
|
+
virt = if options[:allow_override] == true then "virtual " else "" end
|
128
|
+
_append "#{virt}DataTree& get_#{name}() { return #{name}; }"
|
129
|
+
_append "#{virt}const DataTree& get_#{name}() const { return #{name}; }"
|
130
|
+
_append "#{virt}void set_#{name}(Data value) { this->#{name}.clear(); this->#{name}.as_data().merge(value); }"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def property type, name, options = {}
|
135
|
+
if type == 'DataTree'
|
136
|
+
datatree_property name, options
|
137
|
+
else
|
138
|
+
with_visibility :public do
|
139
|
+
virt = if options[:allow_override] == true then "virtual " else "" end
|
140
|
+
_append "#{virt}#{type} get_#{name}() const { return #{name}; }"
|
141
|
+
_append "#{virt}void set_#{name}(#{type} value) { this->#{name} = value; }"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
make_pragma_db options[:db] unless options[:db].nil?
|
145
|
+
if options[:default].nil?
|
146
|
+
_append "#{type} #{name};"
|
147
|
+
else
|
148
|
+
_append "#{type} #{name} = #{get_value options[:default]};"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def make_pragma_db options, authorized_options = []
|
153
|
+
is_option_available = lambda {|a|
|
154
|
+
(not options[a].nil?) && (authorized_options.size == 0 || authorized_options.include?(a))
|
155
|
+
}
|
156
|
+
src = ""
|
157
|
+
src += "transient " if is_option_available.call(:transient) && options[:transient] == true
|
158
|
+
src += "type(\"#{options[:type]}\") " if is_option_available.call :type
|
159
|
+
src += "column(\"#{options[:column]}\") " if is_option_available.call :column
|
160
|
+
src += "default(#{get_value options[:default]}) " if is_option_available.call :default
|
161
|
+
src += "null " if is_option_available.call(:null) && options[:null] == true
|
162
|
+
_append "#pragma db #{src}" if src.size > 0
|
163
|
+
end
|
164
|
+
|
165
|
+
def has_one type, name, options = {}
|
166
|
+
@forward_declarations << type
|
167
|
+
type = get_type type
|
168
|
+
tptr = ptr_type type
|
169
|
+
virt = if options[:allow_override] == true then "virtual " else "" end
|
170
|
+
if options[:joined] != false
|
171
|
+
with_visibility :public do
|
172
|
+
_append "#{virt}#{tptr} get_#{name}() const { return #{name}; }"
|
173
|
+
_append "#{virt}void set_#{name}(#{tptr} v) { this->#{name} = v; }"
|
174
|
+
_append "#{virt}#{id_type} get_#{name}_id() const;"
|
175
|
+
end
|
176
|
+
_append "#{tptr} #{name};"
|
177
|
+
else
|
178
|
+
with_visibility :public do
|
179
|
+
_append "#{virt}#{tptr} get_#{name}() const;"
|
180
|
+
_append "#{virt}void set_#{name}(#{tptr} v);"
|
181
|
+
_append "#{id_type} get_#{name}_id() const { return #{name}_id; }"
|
182
|
+
_append "void set_#{name}_id(#{id_type} v) { #{name}_id = v; }"
|
183
|
+
end
|
184
|
+
make_pragma_db options[:db] unless options[:db].nil?
|
185
|
+
_append "#{id_type} #{name}_id = #{null_id};"
|
186
|
+
end
|
187
|
+
with_visibility :public do
|
188
|
+
_append <<CPP
|
189
|
+
|
190
|
+
template<typename ARRAY>
|
191
|
+
static void collect_#{name}(ARRAY& array, std::map<#{id_type}, #{tptr} >& results)
|
192
|
+
{
|
193
|
+
for (auto model : array)
|
194
|
+
{
|
195
|
+
if (results.find(model.get_#{name}_id()) == results.end())
|
196
|
+
results[model.get_#{name}_id()] = model.get_#{name}();
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
CPP
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def has_many type, name, options = {}
|
205
|
+
@forward_declarations << type
|
206
|
+
type = get_type type
|
207
|
+
tptr = ptr_type type
|
208
|
+
list_type = "std::list<#{tptr} >"
|
209
|
+
singular_name = get_singular_name name
|
210
|
+
with_visibility :public do
|
211
|
+
virt = if options[:allow_override] == true then "virtual " else "" end
|
212
|
+
_append "#{virt}bool update_#{name}(Data);"
|
213
|
+
_append "#{virt}void add_#{singular_name}(#{tptr});"
|
214
|
+
_append "#{virt}void remove_#{singular_name}(const #{type}&);"
|
215
|
+
_append "#{virt}void collect_#{name}(std::map<#{id_type}, #{tptr} >&);"
|
216
|
+
end
|
217
|
+
if options[:joined] != false
|
218
|
+
_join_based_has_many list_type, name, options
|
219
|
+
else
|
220
|
+
_id_based_has_many list_type, name, options
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def _join_based_has_many list_type, name, options
|
225
|
+
singular_name = get_singular_name name
|
226
|
+
with_visibility :public do
|
227
|
+
_append "const #{list_type}& get_#{name}() const { return #{name}; }"
|
228
|
+
_append "std::vector<#{id_type}> get_#{singular_name}_ids() const;"
|
229
|
+
end
|
230
|
+
_append "#{list_type} #{name};"
|
231
|
+
end
|
232
|
+
|
233
|
+
def has_many_fetch list_type, name, options
|
234
|
+
with_visibility :public do
|
235
|
+
_append "void fetch_#{name}();"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def _id_based_has_many list_type, name, options
|
240
|
+
singular_name = get_singular_name name
|
241
|
+
store_type = "std::vector<#{id_type}>"
|
242
|
+
with_visibility :public do
|
243
|
+
_append "const #{store_type}& get_#{singular_name}_ids() const { return #{singular_name}_ids; }"
|
244
|
+
_append "const #{list_type}& get_#{name}();"
|
245
|
+
_append "void set_#{singular_name}_ids(const #{store_type}& val) { #{singular_name}_ids = val; #{name}_fetched = false; }"
|
246
|
+
end
|
247
|
+
has_many_fetch list_type, name, options
|
248
|
+
options[:db] ||= {}
|
249
|
+
options[:db][:type] ||= "INTEGER[]"
|
250
|
+
make_pragma_db options[:db], [:type, :column, :null]
|
251
|
+
_append "#{store_type} #{singular_name}_ids;"
|
252
|
+
make_pragma_db transient: true
|
253
|
+
_append "#{list_type} #{name};"
|
254
|
+
make_pragma_db transient: true
|
255
|
+
_append "bool #{name}_fetched = false;"
|
256
|
+
end
|
257
|
+
|
258
|
+
class << self
|
259
|
+
def extension ; ".hpp" ; end
|
260
|
+
|
261
|
+
def generate_includes
|
262
|
+
<<CPP
|
263
|
+
# include <vector>
|
264
|
+
# include <list>
|
265
|
+
# include <map>
|
266
|
+
# include <string>
|
267
|
+
# include <crails/datatree.hpp>
|
268
|
+
# include <crails/odb/id_type.hpp>
|
269
|
+
CPP
|
270
|
+
end
|
271
|
+
|
272
|
+
def make_file filename, data
|
273
|
+
file_define = "_#{filename[0...-3].upcase.gsub "/", "_"}_HPP"
|
274
|
+
source = <<CPP
|
275
|
+
#ifndef #{file_define}
|
276
|
+
# define #{file_define}
|
277
|
+
#{generate_includes}
|
278
|
+
#{collect_includes_for(filename, true).join "\n"}
|
279
|
+
namespace odb { class access; }
|
280
|
+
#{data[:headers].join ""}
|
281
|
+
namespace #{METARECORD_NAMESPACE}
|
282
|
+
{
|
283
|
+
#{data[:bodies].join "\n"}}
|
284
|
+
|
285
|
+
#endif
|
286
|
+
CPP
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
require 'metarecord/model'
|
3
|
+
require 'metarecord/generator_base'
|
4
|
+
|
5
|
+
class CrailsDestroyPreparator < GeneratorBase
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
def prepare
|
9
|
+
@data = {}
|
10
|
+
Model.list.each do |model|
|
11
|
+
@model = model
|
12
|
+
self.instance_eval &model[:block]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_many type, name, options = {}
|
17
|
+
unless options[:dependent].nil?
|
18
|
+
@data[type] ||= []
|
19
|
+
@data[type] << ({
|
20
|
+
type: "has_many", class: @model[:classname],
|
21
|
+
field: name, options: options
|
22
|
+
})
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_one type, name, options = {}
|
27
|
+
unless options[:dependent].nil?
|
28
|
+
@data[type] ||= []
|
29
|
+
@data[type] << ({
|
30
|
+
type: "has_one", class: @model[:classname],
|
31
|
+
field: name, options: options
|
32
|
+
})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class CrailsDestroyGenerator < GeneratorBase
|
38
|
+
class << self
|
39
|
+
attr_accessor :destroy_data
|
40
|
+
|
41
|
+
def my_prepare
|
42
|
+
destroy_preparator = CrailsDestroyPreparator.new
|
43
|
+
destroy_preparator.prepare
|
44
|
+
@destroy_data = destroy_preparator.data
|
45
|
+
end
|
46
|
+
|
47
|
+
def extension ; ".destroy.cpp" ; end
|
48
|
+
|
49
|
+
def make_file filename, data
|
50
|
+
include = "lib/" + filename[0...-2] + "hpp"
|
51
|
+
source = "#include \"#{include}\"\n"
|
52
|
+
source += "#include \"lib/#{filename[0...-2]}queries.hpp\"\n"
|
53
|
+
source += "#include <crails/odb/helpers.hpp>\n"
|
54
|
+
source += "#include <crails/odb/any.hpp>\n"
|
55
|
+
source += "#include <#{GeneratorBase.odb_connection[:include]}>\n"
|
56
|
+
source += "#include \"lib/odb/application-odb.hxx\"\n"
|
57
|
+
source += (collect_includes_for filename).join "\n"
|
58
|
+
source += "\n" + (data[:bodies].join "\n")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate_for object
|
63
|
+
reset
|
64
|
+
CrailsDestroyGenerator.my_prepare if CrailsDestroyGenerator.destroy_data.nil?
|
65
|
+
@finalclass = object[:classname]
|
66
|
+
@klassname = get_classname(object)
|
67
|
+
_append "void #{@klassname}::on_dependent_destroy(#{id_type} self_id)"
|
68
|
+
_append "{"
|
69
|
+
unless object[:classname].nil?
|
70
|
+
@indent += 1
|
71
|
+
depended_by = CrailsDestroyGenerator.destroy_data[object[:classname]]
|
72
|
+
if depended_by.class == Array
|
73
|
+
_append "auto& database = *#{GeneratorBase.odb_connection[:object]}::instance;"
|
74
|
+
depended_by.each do |relation|
|
75
|
+
_append "// #{relation[:class]}"
|
76
|
+
_append "{"
|
77
|
+
@indent += 1
|
78
|
+
if relation[:type] == "has_one"
|
79
|
+
one_to_many relation
|
80
|
+
elsif relation[:type] == "has_many"
|
81
|
+
many_to_many relation
|
82
|
+
end
|
83
|
+
@indent -= 1
|
84
|
+
_append "}\n"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
@indent -= 1
|
88
|
+
end
|
89
|
+
_append "}"
|
90
|
+
@src
|
91
|
+
end
|
92
|
+
|
93
|
+
def one_to_many relation
|
94
|
+
_append "typedef odb::query<::#{relation[:class]}> Query;"
|
95
|
+
_append "odb::result<::#{relation[:class]}> models;"
|
96
|
+
_append "Query query;\n"
|
97
|
+
|
98
|
+
if relation[:options][:joined] != false
|
99
|
+
_append "query = Query::#{relation[:field]}->id == self_id;"
|
100
|
+
else
|
101
|
+
_append "query = Query::#{relation[:field]}_id == self_id;"
|
102
|
+
end
|
103
|
+
_append "database.find<::#{relation[:class]}>(models, query);"
|
104
|
+
_append "for (auto model : odb::to_vector<::#{relation[:class]}>(models))"
|
105
|
+
if relation[:options][:dependent] == :destroy
|
106
|
+
_append " database.destroy(model);"
|
107
|
+
elsif relation[:options][:dependent] == :unlink
|
108
|
+
_append "{"
|
109
|
+
if relation[:options][:joined] != false
|
110
|
+
_append " model.set_#{relation[:field]}(nullptr);"
|
111
|
+
else
|
112
|
+
_append " model.set_#{relation[:field]}_id(0);"
|
113
|
+
end
|
114
|
+
_append " database.save(model);"
|
115
|
+
_append "}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def many_to_many relation
|
120
|
+
if relation[:options][:joined] != false
|
121
|
+
outer_name = (relation[:field].split(/-|_|\s/).each do |i| i.capitalize! end).join
|
122
|
+
view_klass = "#{relation[:class].split("::").join}By#{outer_name}"
|
123
|
+
klassname = @klassname.split("::").last
|
124
|
+
singular_name = get_singular_name relation[:field]
|
125
|
+
_append "typedef odb::query<#{view_klass}> Query;"
|
126
|
+
_append "odb::result<#{view_klass}> models;"
|
127
|
+
_append "Query query;\n"
|
128
|
+
_append "query = Query::#{klassname}::id == self_id;"
|
129
|
+
_append "database.find<#{view_klass}>(models, query);"
|
130
|
+
_append "for (auto model : odb::to_vector<#{relation[:class]}, #{view_klass}>(models))"
|
131
|
+
_append "{"
|
132
|
+
@indent += 1
|
133
|
+
if relation[:options][:dependent] == :destroy
|
134
|
+
_append "if (model.get_#{relation[:field]}().size() == 1)"
|
135
|
+
_append " database.destroy(model);"
|
136
|
+
_append "else"
|
137
|
+
_append "{"
|
138
|
+
_append " model.remove_#{singular_name}(*static_cast<#{@finalclass}*>(this));"
|
139
|
+
_append " database.save(model);"
|
140
|
+
_append "}"
|
141
|
+
else relation[:options][:dependent] == :unlink
|
142
|
+
_append "model.remove_#{singular_name}(*static_cast<#{@finalclass}*>(this));"
|
143
|
+
_append "database.save(model);"
|
144
|
+
end
|
145
|
+
@indent -= 1
|
146
|
+
_append "}"
|
147
|
+
else
|
148
|
+
_append "typedef odb::query<#{relation[:class]}> Query;"
|
149
|
+
_append "std::vector<#{id_type}> ids = { self_id };"
|
150
|
+
_append "odb::result<#{relation[:class]}> models;"
|
151
|
+
_append "Query query;\n"
|
152
|
+
id_field = "#{get_singular_name relation[:field]}_ids"
|
153
|
+
_append "query = Query::#{id_field} + \"@>\" + ODB::array_to_string(ids, \"int\");"
|
154
|
+
_append "database.find<#{relation[:class]}>(models, query);"
|
155
|
+
_append "for (auto model : odb::to_vector<#{relation[:class]}>(models))"
|
156
|
+
_append "{"
|
157
|
+
@indent += 1
|
158
|
+
if relation[:options][:dependent] == :destroy
|
159
|
+
_append "auto id_list = model.get_#{id_field}();\n"
|
160
|
+
_append "if (id_list.size() == 1)"
|
161
|
+
_append " database.destroy(model);"
|
162
|
+
_append "else"
|
163
|
+
_append "{"
|
164
|
+
_append " id_list.erase(std::find(id_list.begin(), id_list.end(), self_id));"
|
165
|
+
_append " model.set_#{id_field}(id_list);"
|
166
|
+
_append " database.save(model);"
|
167
|
+
_append "}"
|
168
|
+
elsif relation[:options][:dependent] == :unlink
|
169
|
+
_append "auto id_list = model.get_#{id_field}();\n"
|
170
|
+
_append "id_list.erase(std::find(id_list.begin(), id_list.end(), self_id));"
|
171
|
+
_append "model.set_#{id_field}(id_list);"
|
172
|
+
_append "database.save(model);"
|
173
|
+
end
|
174
|
+
@indent -= 1
|
175
|
+
_append "}"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|