engine2 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/Rakefile +138 -0
  4. data/conf/message.yaml +93 -0
  5. data/conf/message_pl.yaml +93 -0
  6. data/engine2.gemspec +34 -0
  7. data/lib/engine2.rb +34 -0
  8. data/lib/engine2/action.rb +217 -0
  9. data/lib/engine2/core.rb +572 -0
  10. data/lib/engine2/handler.rb +134 -0
  11. data/lib/engine2/meta.rb +969 -0
  12. data/lib/engine2/meta/decode_meta.rb +110 -0
  13. data/lib/engine2/meta/delete_meta.rb +73 -0
  14. data/lib/engine2/meta/form_meta.rb +144 -0
  15. data/lib/engine2/meta/infra_meta.rb +292 -0
  16. data/lib/engine2/meta/link_meta.rb +133 -0
  17. data/lib/engine2/meta/list_meta.rb +284 -0
  18. data/lib/engine2/meta/save_meta.rb +63 -0
  19. data/lib/engine2/meta/view_meta.rb +22 -0
  20. data/lib/engine2/model.rb +390 -0
  21. data/lib/engine2/models/Files.rb +38 -0
  22. data/lib/engine2/models/UserInfo.rb +24 -0
  23. data/lib/engine2/post_bootstrap.rb +83 -0
  24. data/lib/engine2/pre_bootstrap.rb +27 -0
  25. data/lib/engine2/scheme.rb +202 -0
  26. data/lib/engine2/templates.rb +229 -0
  27. data/lib/engine2/type_info.rb +342 -0
  28. data/lib/engine2/version.rb +9 -0
  29. data/public/assets/javascripts.js +13 -0
  30. data/public/assets/styles.css +4 -0
  31. data/public/css/angular-motion.css +1022 -0
  32. data/public/css/angular-ui-tree.min.css +1 -0
  33. data/public/css/app.css +196 -0
  34. data/public/css/bootstrap-additions.css +1560 -0
  35. data/public/css/bootstrap.min.css +11 -0
  36. data/public/css/font-awesome.min.css +4 -0
  37. data/public/favicon.ico +0 -0
  38. data/public/fonts/FontAwesome.otf +0 -0
  39. data/public/fonts/fontawesome-webfont.eot +0 -0
  40. data/public/fonts/fontawesome-webfont.svg +655 -0
  41. data/public/fonts/fontawesome-webfont.ttf +0 -0
  42. data/public/fonts/fontawesome-webfont.woff +0 -0
  43. data/public/fonts/fontawesome-webfont.woff2 +0 -0
  44. data/public/fonts/glyphicons-halflings-regular.eot +0 -0
  45. data/public/fonts/glyphicons-halflings-regular.svg +288 -0
  46. data/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  47. data/public/fonts/glyphicons-halflings-regular.woff +0 -0
  48. data/public/fonts/glyphicons-halflings-regular.woff2 +0 -0
  49. data/public/images/file.png +0 -0
  50. data/public/images/folder-closed.png +0 -0
  51. data/public/images/folder.png +0 -0
  52. data/public/images/node-closed-2.png +0 -0
  53. data/public/images/node-closed-light.png +0 -0
  54. data/public/images/node-closed.png +0 -0
  55. data/public/images/node-opened-2.png +0 -0
  56. data/public/images/node-opened-light.png +0 -0
  57. data/public/images/node-opened.png +0 -0
  58. data/public/img/ajax-loader-dark.gif +0 -0
  59. data/public/img/ajax-loader-light.gif +0 -0
  60. data/public/img/ajax-loader.gif +0 -0
  61. data/public/js/angular-animate.js +4115 -0
  62. data/public/js/angular-cookies.js +322 -0
  63. data/public/js/angular-local-storage.js +455 -0
  64. data/public/js/angular-route.js +1022 -0
  65. data/public/js/angular-sanitize.js +717 -0
  66. data/public/js/angular-strap.js +4339 -0
  67. data/public/js/angular-strap.tpl.js +43 -0
  68. data/public/js/angular-ui-tree.js +1569 -0
  69. data/public/js/angular.js +30714 -0
  70. data/public/js/i18n/angular-locale_pl.js +115 -0
  71. data/public/js/lodash.custom.min.js +97 -0
  72. data/public/js/ng-file-upload-shim.min.js +2 -0
  73. data/public/js/ng-file-upload.min.js +3 -0
  74. data/views/app.coffee +3 -0
  75. data/views/engine2.coffee +557 -0
  76. data/views/engine2actions.coffee +849 -0
  77. data/views/engine2templates.coffee +0 -0
  78. data/views/fields/blob.slim +22 -0
  79. data/views/fields/bs_select.slim +10 -0
  80. data/views/fields/bsselect_picker.slim +18 -0
  81. data/views/fields/bsselect_picker_opt.slim +22 -0
  82. data/views/fields/checkbox.slim +11 -0
  83. data/views/fields/checkbox_buttons.slim +6 -0
  84. data/views/fields/checkbox_buttons_opt.slim +8 -0
  85. data/views/fields/currency.slim +10 -0
  86. data/views/fields/date.slim +21 -0
  87. data/views/fields/date_range.slim +44 -0
  88. data/views/fields/date_time.slim +42 -0
  89. data/views/fields/datetime.slim +42 -0
  90. data/views/fields/decimal.slim +11 -0
  91. data/views/fields/decimal_date.slim +22 -0
  92. data/views/fields/decimal_time.slim +26 -0
  93. data/views/fields/email.slim +13 -0
  94. data/views/fields/file_store.slim +61 -0
  95. data/views/fields/input_text.slim +14 -0
  96. data/views/fields/integer.slim +11 -0
  97. data/views/fields/list_bsselect.slim +18 -0
  98. data/views/fields/list_bsselect_opt.slim +21 -0
  99. data/views/fields/list_buttons.slim +3 -0
  100. data/views/fields/list_buttons_opt.slim +5 -0
  101. data/views/fields/list_select.slim +11 -0
  102. data/views/fields/list_select_opt.slim +15 -0
  103. data/views/fields/password.slim +14 -0
  104. data/views/fields/radio_checkbox.slim +10 -0
  105. data/views/fields/scaffold.slim +2 -0
  106. data/views/fields/scaffold_picker.slim +20 -0
  107. data/views/fields/select_picker.slim +12 -0
  108. data/views/fields/select_picker_opt.slim +16 -0
  109. data/views/fields/text_area.slim +10 -0
  110. data/views/fields/time.slim +22 -0
  111. data/views/fields/typeahead_picker.slim +25 -0
  112. data/views/index.slim +44 -0
  113. data/views/infra/index.slim +5 -0
  114. data/views/infra/inspect.slim +81 -0
  115. data/views/modals/close_m.slim +15 -0
  116. data/views/modals/confirm_m.slim +19 -0
  117. data/views/modals/empty_m.slim +12 -0
  118. data/views/modals/menu_m.slim +13 -0
  119. data/views/modals/yes_no_m.slim +19 -0
  120. data/views/panels/menu_m.slim +9 -0
  121. data/views/scaffold/confirm.slim +3 -0
  122. data/views/scaffold/fields.slim +10 -0
  123. data/views/scaffold/form.slim +11 -0
  124. data/views/scaffold/list.slim +42 -0
  125. data/views/scaffold/message.slim +3 -0
  126. data/views/scaffold/search.slim +20 -0
  127. data/views/scaffold/view.slim +18 -0
  128. data/views/search_fields/bsmselect_picker.slim +25 -0
  129. data/views/search_fields/bsselect_picker.slim +24 -0
  130. data/views/search_fields/checkbox.slim +11 -0
  131. data/views/search_fields/checkbox2.slim +14 -0
  132. data/views/search_fields/checkbox_buttons.slim +10 -0
  133. data/views/search_fields/date_range.slim +46 -0
  134. data/views/search_fields/decimal_date_range.slim +47 -0
  135. data/views/search_fields/input_text.slim +18 -0
  136. data/views/search_fields/integer.slim +18 -0
  137. data/views/search_fields/integer_range.slim +27 -0
  138. data/views/search_fields/list_bsmselect.slim +24 -0
  139. data/views/search_fields/list_bsselect.slim +22 -0
  140. data/views/search_fields/list_buttons.slim +8 -0
  141. data/views/search_fields/list_select.slim +17 -0
  142. data/views/search_fields/scaffold_picker.slim +19 -0
  143. data/views/search_fields/select_picker.slim +17 -0
  144. data/views/search_fields/typeahead_picker.slim +25 -0
  145. metadata +327 -0
@@ -0,0 +1,133 @@
1
+ # coding: utf-8
2
+
3
+ module Engine2
4
+ class StarToManyLinkMeta < Meta
5
+ include MetaModelSupport
6
+ http_method :post
7
+ meta_type :star_to_many_link
8
+
9
+ def invoke handler
10
+ json = handler.post_to_json
11
+ parent = json[:parent_id]
12
+ ids = json[:ids]
13
+ handler.permit parent && ids
14
+ model = assets[:model]
15
+ assoc = assets[:assoc]
16
+ case assoc[:type]
17
+ when :one_to_many
18
+ model.db.transaction do
19
+ self.class.one_to_many_link_db model, assoc, split_keys(parent), ids
20
+ end
21
+ {}
22
+ when :many_to_many
23
+ self.class.many_to_many_link_db model, assoc, split_keys(parent), ids
24
+ {}
25
+ else unsupported_association
26
+ end
27
+ end
28
+
29
+ def self.one_to_many_link_db model, assoc, parent, ids
30
+ pk = Hash[assoc[:keys].zip(parent)]
31
+ ids.each do |id|
32
+ model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(pk)
33
+ end
34
+ end
35
+
36
+ def self.many_to_many_link_db model, assoc, parent, ids
37
+ p_pk = Hash[assoc[:left_keys].zip(parent)]
38
+ values = ids.map do |id|
39
+ p_pk.merge Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]
40
+ end
41
+ model.db[assoc[:join_table]].multi_insert values
42
+ end
43
+ end
44
+
45
+ class StarToManyUnlinkMetaBase < Meta
46
+ include MetaModelSupport
47
+ http_method :delete
48
+
49
+ def one_to_many_unlink_db handler, ids
50
+ model = assets[:model]
51
+ assoc = assets[:assoc]
52
+ keys = assoc[:keys]
53
+ if keys.all?{|k|model.db_schema[k][:allow_null] == true}
54
+ model.db.transaction do
55
+ self.class.one_to_many_unlink_db model, assoc, ids
56
+ end
57
+ {}
58
+ else
59
+ handler.halt_method_not_allowed LOCS[:"non_nullable"]
60
+ end
61
+ end
62
+
63
+ def self.one_to_many_unlink_db model, assoc, ids
64
+ keys = assoc[:keys]
65
+ ids.each do |id|
66
+ model.where(model.primary_keys_hash(Sequel::split_keys(id))).update(Hash[keys.zip([nil])])
67
+ end
68
+ end
69
+
70
+ def many_to_many_unlink_db parent, ids
71
+ model = assets[:model]
72
+ assoc = assets[:assoc]
73
+
74
+ model.db.transaction do
75
+ self.class.many_to_many_unlink_db model, assoc, Sequel::split_keys(parent), ids
76
+ end
77
+ {}
78
+ end
79
+
80
+ def self.many_to_many_unlink_db model, assoc, parent, ids
81
+ p_pk = Hash[assoc[:left_keys].zip(parent)]
82
+ ds = model.db[assoc[:join_table]]
83
+ ids.each do |id|
84
+ ds.where(p_pk, Hash[assoc[:right_keys].zip(Sequel::split_keys(id))]).delete
85
+ end
86
+ end
87
+ end
88
+
89
+ class StarToManyUnlinkMeta < StarToManyUnlinkMetaBase
90
+ meta_type :star_to_many_unlink
91
+
92
+ def pre_run
93
+ super
94
+ action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
95
+ end
96
+
97
+ def invoke handler
98
+ handler.permit id = handler.params[:id]
99
+ assoc = assets[:assoc]
100
+ case assoc[:type]
101
+ when :one_to_many
102
+ one_to_many_unlink_db(handler, [id])
103
+ when :many_to_many
104
+ handler.permit parent = handler.params[:parent_id]
105
+ many_to_many_unlink_db(parent, [id])
106
+ else unsupported_association
107
+ end
108
+ end
109
+ end
110
+
111
+ class StarToManyBulkUnlinkMeta < StarToManyUnlinkMetaBase
112
+ meta_type :star_to_many_bulk_unlink
113
+
114
+ def pre_run
115
+ super
116
+ action.parent.parent.*.menu(:menu).option_after :default_order, :confirm_bulk_unlink, icon: "minus", show: "action.selected_size() > 0", button_loc: false
117
+ end
118
+
119
+ def invoke handler
120
+ ids = handler.param_to_json(:ids)
121
+ handler.permit ids.is_a?(Array)
122
+ assoc = assets[:assoc]
123
+ case assoc[:type]
124
+ when :one_to_many
125
+ one_to_many_unlink_db(handler, ids)
126
+ when :many_to_many
127
+ handler.permit parent = handler.params[:parent_id]
128
+ many_to_many_unlink_db(parent, ids)
129
+ else unsupported_association
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,284 @@
1
+ # coding: utf-8
2
+
3
+ module Engine2
4
+ class ListMeta < Meta
5
+ meta_type :list
6
+ include MetaListSupport, MetaQuerySupport
7
+
8
+ (DefaultFilters ||= {}).merge!(
9
+ string: lambda{|query, name, value, type_info, hash|
10
+ case type_info[:type]
11
+ when :many_to_one
12
+ query.where(name => value)
13
+ else
14
+ query.where(name.like("%#{value}%"))
15
+ end
16
+ },
17
+ date: lambda{|query, name, value, type_info, hash|
18
+ if value.is_a? Hash
19
+ from, to = value[:from], value[:to]
20
+ if from && to
21
+ query.where(name => from .. to)
22
+ elsif from
23
+ query.where(name >= Sequel.string_to_date(from))
24
+ elsif to
25
+ query.where(name <= Sequel.string_to_date(to))
26
+ else
27
+ query # ?
28
+ end
29
+ else
30
+ query.where(name => Sequel.string_to_date(value))
31
+ end
32
+ },
33
+ integer: lambda{|query, name, value, type_info, hash|
34
+ if value.is_a? Hash
35
+ from, to = value[:from], value[:to]
36
+ if from && to
37
+ query.where(name => from .. to)
38
+ else
39
+ query.where(from ? name >= from.to_i : name <= to.to_i)
40
+ end
41
+ elsif value.is_a? Integer
42
+ query.where(name => value)
43
+ elsif value.is_a? Array
44
+ if !value.empty?
45
+ case type_info[:type]
46
+ when :many_to_one
47
+ keys = type_info[:keys]
48
+ if keys.length == 1
49
+ query.where(name => value)
50
+ else
51
+ query.where(keys.map{|k| hash[k]}.transpose.map{|vals| Hash[keys.zip(vals)]}.inject{|q, c| q | c
52
+ })
53
+ end
54
+ when :list_select
55
+ query.where(name => value) # decode in sql query ?
56
+ when :integer
57
+ query
58
+ else
59
+ nil
60
+ end
61
+ else
62
+ nil
63
+ end
64
+ else
65
+ nil
66
+ end
67
+ }
68
+ )
69
+
70
+ def post_run
71
+ query select(*assets[:model].columns.reject{|col| assets[:model].type_info[col][:length].to_i > 20}.take(10)) unless @query
72
+ super
73
+ end
74
+
75
+ def invoke handler
76
+ params = handler.params
77
+ model = assets[:model]
78
+ query = list_context(get_query, handler)
79
+
80
+ if search = params[:search]
81
+ query = list_search(query, handler, search)
82
+ end
83
+
84
+ count = query.count if lookup(:config, :use_count)
85
+
86
+ if order_str = params[:order]
87
+ order = order_str.to_sym
88
+ handler.permit lookup(:info, order, :sort)
89
+
90
+ if order_blk = (@orders && @orders[order]) || (dynamic? && (static.orders && static.orders[order]))
91
+ query = order_blk.(query, handler)
92
+ else
93
+ order = order.qualify(model.table_name) if model.type_info[order]
94
+ query = query.order(order)
95
+ end
96
+
97
+ query = query.reverse if params[:asc] == "true"
98
+ end
99
+
100
+ per_page = lookup(:config, :per_page)
101
+ page = params[:page].to_i
102
+ handler.permit page >= 0 && page < 1000
103
+
104
+ query = query.limit(per_page, page)
105
+
106
+ res = {entries: query.all}
107
+ res[:count] = count if count
108
+ res
109
+ end
110
+
111
+ def list_search query, handler, search
112
+ hash = JSON.parse(search, symbolize_names: true) rescue handler.halt_forbidden
113
+ model = assets[:model]
114
+ sfields = lookup(:search_fields)
115
+ handler.permit sfields
116
+ hash.each_pair do |name, value|
117
+ handler.permit sfields.include?(name)
118
+
119
+ type_info = get_type_info(name)
120
+ query = if filter = (@filters && @filters[name]) || (dynamic? && (static.filters && static.filters[name]))
121
+ filter.(query, hash, handler)
122
+ elsif filter = DefaultFilters[type_info[:otype]]
123
+ name = model.type_info[name] ? name.qualify(model.table_name) : Sequel.expr(name)
124
+ filter.(query, name, value, type_info, hash)
125
+ else
126
+ raise E2Error.new("Filter not found for field #{name} in model #{model}") unless filter
127
+ end
128
+
129
+ handler.permit query
130
+ end
131
+ query
132
+ end
133
+
134
+ def list_context query, handler
135
+ query
136
+ end
137
+ end
138
+
139
+ #
140
+ # Many to One
141
+ #
142
+ class ManyToOneListMeta < ListMeta
143
+ meta_type :many_to_one_list
144
+
145
+ def pre_run
146
+ super
147
+ config.merge!(selectable: false)
148
+ end
149
+ end
150
+
151
+ #
152
+ # * to Many
153
+ #
154
+ class StarToManyListMeta < ListMeta
155
+ meta_type :star_to_many_list
156
+ def pre_run
157
+ super
158
+ panel_title "#{glyphicon('list')} #{LOCS[assets[:assoc][:name]]}"
159
+ end
160
+
161
+ # def decode_panel_title handler
162
+ # if handler.initial?
163
+ # # Hash[assets[:model].primary_keys.zip(split_keys(id))]]
164
+ # p action.parent.decode_entry.*.invoke_decode([[handler.params[:parent_id]]])
165
+ # panel_title "ADFASDF"
166
+ # end
167
+ # end
168
+
169
+ # def post_run
170
+ # super
171
+ # unless @request_meta_proc
172
+ # request{|h| decode_panel_title h}
173
+ # end
174
+ # end
175
+
176
+ def list_context query, handler
177
+ handler.permit parent = handler.params[:parent_id]
178
+ model = assets[:model]
179
+ assoc = assets[:assoc]
180
+ case assoc[:type]
181
+ when :one_to_many
182
+ keys = assoc[:keys]
183
+ condition = parent.empty? ? false : Hash[keys.map{|k| k.qualify(model.table_name)}.zip(split_keys(parent))]
184
+ if handler.params[:negate]
185
+ query = query.exclude(condition)
186
+ query = query.or(Hash[keys.zip([nil])]) if keys.all?{|k|model.db_schema[k][:allow_null] == true} # type_info[:required] ?
187
+ query
188
+ else
189
+ query.where(condition)
190
+ end
191
+ when :many_to_many
192
+ q_pk = model.primary_keys_qualified
193
+ j_table = assoc[:join_table]
194
+ l_keys = assoc[:left_keys].map{|k| k.qualify(j_table)}
195
+ r_keys = assoc[:right_keys].map{|k| k.qualify(j_table)}
196
+ r_keys_vals = Hash[r_keys.zip(q_pk)]
197
+ l_keys_vals = parent.empty? ? false : Hash[l_keys.zip(split_keys(parent))]
198
+
199
+ if handler.params[:negate]
200
+ query.exclude(model.db[j_table].select(nil).where(r_keys_vals, l_keys_vals).exists)
201
+ else
202
+ # query.qualify.join(j_table, [r_keys_vals, l_keys_vals])
203
+ query.qualify.left_join(j_table, r_keys_vals).filter(l_keys_vals)
204
+ end
205
+ else unsupported_association
206
+ end
207
+ end
208
+ end
209
+
210
+ class StarToManyLinkListMeta < StarToManyListMeta
211
+ meta_type :star_to_many_link_list
212
+ def pre_run
213
+ super
214
+ config.merge!(selectable: false)
215
+ panel_title LOCS[:link_title]
216
+ menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
217
+ action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
218
+ end
219
+ end
220
+
221
+ # *_to_many_field
222
+ class StarToManyFieldMeta < StarToManyListMeta
223
+ meta_type :star_to_many_field
224
+
225
+ def pre_run
226
+ super
227
+ modal_action false
228
+ panel_panel_template false
229
+ # panel_template nil
230
+ end
231
+
232
+ def list_context query, handler
233
+ unlinked = handler.param_to_json(:unlinked)
234
+ linked = handler.param_to_json(:linked)
235
+ query = super(query, handler)
236
+ model = assets[:model]
237
+ pks = model.primary_keys_qualified
238
+
239
+ if handler.params[:negate]
240
+ query = unlinked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
241
+ # query = query.or *unlinked.map{|unl| Hash[model.primary_keys.zip(split_keys(unl))]}.inject{|q, c| q | c}
242
+ query = query.where *linked.map{|ln| pks.zip(split_keys(ln)).sql_negate}
243
+
244
+ else
245
+ query = query.where *unlinked.map{|unl| pks.zip(split_keys(unl)).sql_negate}
246
+ # query = query.or *linked.map{|ln| model.primary_keys.zip(split_keys(ln))}
247
+ # query = query.or *linked.map{|ln| Hash[model.primary_keys.zip(split_keys(ln))]}.inject{|q, c| q | c}
248
+ case assets[:assoc][:type]
249
+ when :one_to_many
250
+ query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}
251
+ when :many_to_many
252
+ query = linked.map{|ln| pks.zip(split_keys(ln))}.inject(query){|q, c| q.or c}.distinct
253
+ else unsupported_association
254
+ end unless linked.empty?
255
+ end
256
+
257
+ query
258
+ end
259
+ end
260
+
261
+ class StarToManyFieldUnlinkMeta < Meta
262
+ meta_type :star_to_many_field_unlink
263
+
264
+ def pre_run
265
+ super
266
+ action.parent.parent.*.menu(:item_menu).option :confirm_unlink, icon: "minus", show: "action.selected_size() == 0", button_loc: false
267
+ end
268
+ end
269
+
270
+ class StarToManyFieldLinkListMeta < StarToManyFieldMeta
271
+ meta_type :star_to_many_field_link_list
272
+
273
+ def pre_run
274
+ super
275
+ config.merge!(selectable: false)
276
+ modal_action true
277
+ panel_panel_template 'scaffold/list'
278
+ panel_title LOCS[:link_title]
279
+ menu(:panel_menu).option_at 0, :link, icon: "ok", enabled: "action.selected_size() > 0"
280
+ action.parent.*.menu(:menu).option_at 0, :link_list, icon: "paperclip", button_loc: false
281
+ end
282
+ end
283
+ end
284
+
@@ -0,0 +1,63 @@
1
+ # coding: utf-8
2
+
3
+ module Engine2
4
+
5
+ class SaveMeta < Meta
6
+ include MetaApproveSupport
7
+ http_method :post
8
+
9
+ def validate_and_approve handler, record, json
10
+ record.skip_save_refresh = true
11
+ record.raise_on_save_failure = false
12
+ model = assets[:model]
13
+ assoc = assets[:assoc]
14
+ mtm_insert = record.new? && assoc && assoc[:type] == :many_to_many
15
+
16
+ save = lambda do|c|
17
+ if super(handler, record, json)
18
+ result = record.save(transaction: false, validate: false)
19
+ if result && mtm_insert
20
+ handler.permit parent_id = json[:parent_id]
21
+ model.db[assoc[:join_table]].insert(assoc[:left_keys] + assoc[:right_keys], split_keys(parent_id) + record.primary_key_values)
22
+ end
23
+ result
24
+ end
25
+ end
26
+ (model.validation_in_transaction || mtm_insert) ? model.db.transaction(&save) : save.(nil)
27
+ end
28
+ end
29
+
30
+ class InsertMeta < SaveMeta
31
+ meta_type :save
32
+ def allocate_record handler, json
33
+ record = super(handler, json)
34
+ record.instance_variable_set(:"@new", true)
35
+ model = assets[:model]
36
+ model.primary_keys.each{|k|record.values.delete k} unless model.natural_key
37
+ handler.permit !record.has_primary_key? unless model.natural_key
38
+ record
39
+ end
40
+ end
41
+
42
+ class UpdateMeta < SaveMeta
43
+ meta_type :save
44
+ def allocate_record handler, json
45
+ record = super(handler, json)
46
+ model = assets[:model]
47
+ handler.permit record.has_primary_key? unless model.natural_key
48
+ record
49
+ end
50
+ end
51
+
52
+ module TimeStampMeta
53
+ def before_approve handler, record
54
+ super
55
+ puts "before approve"
56
+ end
57
+
58
+ def after_approve handler, record
59
+ super
60
+ puts "after approve"
61
+ end
62
+ end
63
+ end