meta-record 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|