engine2 1.0.4 → 1.0.5

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.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -0
  3. data/Rakefile +1 -1
  4. data/app/{engine2actions.coffee → actions.coffee} +192 -142
  5. data/app/app.coffee +0 -0
  6. data/app/app.css +4 -0
  7. data/app/engine2.coffee +87 -175
  8. data/app/modal.coffee +133 -0
  9. data/bower.json +2 -1
  10. data/conf/message.yaml +0 -0
  11. data/conf/message_pl.yaml +0 -0
  12. data/config.coffee +11 -2
  13. data/engine2.gemspec +2 -2
  14. data/lib/engine2.rb +12 -10
  15. data/lib/engine2/action.rb +1290 -134
  16. data/lib/engine2/{meta/array_meta.rb → action/array.rb} +4 -3
  17. data/lib/engine2/{meta/decode_meta.rb → action/decode.rb} +16 -15
  18. data/lib/engine2/action/delete.rb +65 -0
  19. data/lib/engine2/action/form.rb +16 -0
  20. data/lib/engine2/{meta/infra_meta.rb → action/infra.rb} +118 -85
  21. data/lib/engine2/action/link.rb +117 -0
  22. data/lib/engine2/{meta/list_meta.rb → action/list.rb} +61 -62
  23. data/lib/engine2/action/save.rb +30 -0
  24. data/lib/engine2/action/view.rb +8 -0
  25. data/lib/engine2/action_node.rb +221 -0
  26. data/lib/engine2/core.rb +120 -77
  27. data/lib/engine2/handler.rb +9 -10
  28. data/lib/engine2/model.rb +4 -20
  29. data/lib/engine2/models/Files.rb +2 -1
  30. data/lib/engine2/models/UserInfo.rb +6 -3
  31. data/lib/engine2/post_bootstrap.rb +3 -2
  32. data/lib/engine2/pre_bootstrap.rb +1 -0
  33. data/lib/engine2/scheme.rb +98 -47
  34. data/lib/engine2/templates.rb +1 -0
  35. data/lib/engine2/type_info.rb +6 -4
  36. data/lib/engine2/version.rb +2 -1
  37. data/package.json +12 -10
  38. data/public/favicon.ico +0 -0
  39. data/public/img/ajax-loader-dark.gif +0 -0
  40. data/public/img/ajax-loader.gif +0 -0
  41. data/views/fields/blob.slim +0 -0
  42. data/views/fields/bs_select.slim +0 -0
  43. data/views/fields/bsselect_picker.slim +0 -0
  44. data/views/fields/bsselect_picker_opt.slim +0 -0
  45. data/views/fields/checkbox.slim +0 -0
  46. data/views/fields/checkbox_buttons.slim +0 -0
  47. data/views/fields/checkbox_buttons_opt.slim +0 -0
  48. data/views/fields/currency.slim +0 -0
  49. data/views/fields/date.slim +0 -0
  50. data/views/fields/date_range.slim +0 -0
  51. data/views/fields/date_time.slim +0 -0
  52. data/views/fields/datetime.slim +0 -0
  53. data/views/fields/decimal.slim +0 -0
  54. data/views/fields/decimal_date.slim +0 -0
  55. data/views/fields/decimal_time.slim +0 -0
  56. data/views/fields/email.slim +0 -0
  57. data/views/fields/file_store.slim +7 -7
  58. data/views/fields/input_text.slim +0 -0
  59. data/views/fields/integer.slim +0 -0
  60. data/views/fields/list_bsselect.slim +0 -0
  61. data/views/fields/list_bsselect_opt.slim +0 -0
  62. data/views/fields/list_buttons.slim +0 -0
  63. data/views/fields/list_buttons_opt.slim +0 -0
  64. data/views/fields/list_select.slim +0 -0
  65. data/views/fields/list_select_opt.slim +0 -0
  66. data/views/fields/password.slim +0 -0
  67. data/views/fields/radio_checkbox.slim +0 -0
  68. data/views/fields/scaffold.slim +0 -0
  69. data/views/fields/scaffold_picker.slim +0 -0
  70. data/views/fields/select_picker.slim +0 -0
  71. data/views/fields/select_picker_opt.slim +0 -0
  72. data/views/fields/text_area.slim +1 -0
  73. data/views/fields/time.slim +0 -0
  74. data/views/fields/typeahead_picker.slim +0 -0
  75. data/views/index.slim +3 -3
  76. data/views/infra/index.slim +0 -0
  77. data/views/infra/inspect.slim +20 -0
  78. data/views/modals/close_m.slim +0 -0
  79. data/views/modals/confirm_m.slim +0 -0
  80. data/views/modals/empty_m.slim +0 -0
  81. data/views/modals/menu_m.slim +1 -1
  82. data/views/modals/yes_no_m.slim +0 -0
  83. data/views/panels/menu_m.slim +1 -1
  84. data/views/scaffold/confirm.slim +0 -0
  85. data/views/scaffold/fields.slim +0 -0
  86. data/views/scaffold/form.slim +0 -0
  87. data/views/scaffold/form_collapse.slim +0 -0
  88. data/views/scaffold/form_tabs.slim +0 -0
  89. data/views/scaffold/list.slim +0 -0
  90. data/views/scaffold/message.slim +0 -0
  91. data/views/scaffold/search.slim +0 -0
  92. data/views/scaffold/search_collapse.slim +0 -0
  93. data/views/scaffold/search_tabs.slim +0 -0
  94. data/views/scaffold/view.slim +0 -0
  95. data/views/scaffold/view_collapse.slim +0 -0
  96. data/views/scaffold/view_tabs.slim +0 -0
  97. data/views/search_fields/bsmselect_picker.slim +0 -0
  98. data/views/search_fields/bsselect_picker.slim +0 -0
  99. data/views/search_fields/checkbox.slim +0 -0
  100. data/views/search_fields/checkbox2.slim +0 -0
  101. data/views/search_fields/checkbox_buttons.slim +0 -0
  102. data/views/search_fields/date_range.slim +0 -0
  103. data/views/search_fields/decimal_date_range.slim +0 -0
  104. data/views/search_fields/input_text.slim +0 -0
  105. data/views/search_fields/integer.slim +0 -0
  106. data/views/search_fields/integer_range.slim +0 -0
  107. data/views/search_fields/list_bsmselect.slim +0 -0
  108. data/views/search_fields/list_bsselect.slim +0 -0
  109. data/views/search_fields/list_buttons.slim +0 -0
  110. data/views/search_fields/list_select.slim +0 -0
  111. data/views/search_fields/scaffold_picker.slim +0 -0
  112. data/views/search_fields/select_picker.slim +0 -0
  113. data/views/search_fields/typeahead_picker.slim +0 -0
  114. metadata +41 -42
  115. data/lib/engine2/meta.rb +0 -1216
  116. data/lib/engine2/meta/delete_meta.rb +0 -60
  117. data/lib/engine2/meta/form_meta.rb +0 -15
  118. data/lib/engine2/meta/link_meta.rb +0 -134
  119. data/lib/engine2/meta/save_meta.rb +0 -50
  120. data/lib/engine2/meta/view_meta.rb +0 -7
  121. data/public/__sinatra__/404.png +0 -0
  122. data/public/__sinatra__/500.png +0 -0
@@ -1,4 +1,5 @@
1
- #coding: utf-8
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module PrettyJSON
4
5
  def to_json_pretty
@@ -13,9 +14,19 @@ class BigDecimal
13
14
  end
14
15
  end
15
16
 
17
+ class Sequel::SQL::QualifiedIdentifier
18
+ def to_json(*)
19
+ "\"#{table}__#{column}\""
20
+ end
21
+
22
+ def to_sym
23
+ :"#{table}__#{column}"
24
+ end
25
+ end
26
+
16
27
  class Object
17
28
  def instance_variables_hash
18
- instance_variables.inject({}) do |h, i|
29
+ instance_variables.reduce({}) do |h, i|
19
30
  h[i] = instance_variable_get(i)
20
31
  h
21
32
  end
@@ -25,16 +36,24 @@ end
25
36
  class Proc
26
37
  def to_json(*)
27
38
  loc = source_location
28
- "\"#<Proc:#{loc.first[/\w+.rb/]}:#{loc.last}>\""
39
+ loc ? "\"#<Proc:#{loc.first[/\w+.rb/]}:#{loc.last}>\"" : '"source unknown"'
29
40
  end
30
41
 
31
42
  def chain &blk
32
- proc = self
43
+ prc = self
33
44
  lambda do |obj|
34
- obj.instance_eval(&proc)
45
+ obj.instance_eval(&prc)
35
46
  obj.instance_eval(&blk)
36
47
  end
37
48
  end
49
+
50
+ def chain_args &blk
51
+ prc = self
52
+ lambda do |*args|
53
+ instance_exec(*args, &prc)
54
+ instance_exec(*args, &blk)
55
+ end
56
+ end
38
57
  end
39
58
 
40
59
  class Hash
@@ -111,11 +130,27 @@ end
111
130
 
112
131
  class Symbol
113
132
  def icon
114
- "<span class='glyphicon glyphicon-#{self}'></span>"
133
+ s = self
134
+ if s[0, 3] == 'fa_'
135
+ "<i class='fa fa-#{s[3 .. -1]}'></i>"
136
+ else
137
+ "<span class='glyphicon glyphicon-#{s}'></span>"
138
+ end
115
139
  end
116
140
 
117
- def aicon
118
- "<i class='fa fa-#{self}'></i>"
141
+ def q col
142
+ col.qualify self
143
+ end
144
+ end
145
+
146
+ module Faye
147
+ class WebSocket
148
+ module API
149
+ def send! msg
150
+ msg = msg.to_json if msg.is_a? Hash
151
+ send msg
152
+ end
153
+ end
119
154
  end
120
155
  end
121
156
 
@@ -125,13 +160,17 @@ class << Sequel
125
160
  def split_keys id
126
161
  id.split(Engine2::SETTINGS[:key_separator])
127
162
  end
163
+
164
+ def join_keys keys
165
+ keys.join(Engine2::SETTINGS[:key_separator])
166
+ end
128
167
  end
129
168
 
130
169
  class Sequel::Database
131
170
  attr_accessor :models, :default_schema
132
171
 
133
172
  def cache_file
134
- "#{Engine2::app}/#{opts[:orig_opts][:name]}.dump"
173
+ "#{Engine2::SETTINGS.path_for(:db_path)}/#{opts[:orig_opts][:name]}.dump"
135
174
  end
136
175
 
137
176
  def load_schema_cache_from_file
@@ -144,7 +183,6 @@ class Sequel::Database
144
183
  end
145
184
  end
146
185
 
147
- Sequel.quote_identifiers = false
148
186
  Sequel.extension :core_extensions
149
187
  Sequel::Inflections.clear
150
188
  Sequel.alias_columns_in_joins = true
@@ -277,7 +315,7 @@ module E2Model
277
315
 
278
316
  def primary_keys_qualified
279
317
  # cache it ?
280
- primary_keys.map{|k|k.qualify(table_name)}
318
+ primary_keys.map{|k|table_name.q(k)}
281
319
  end
282
320
 
283
321
  def primary_keys_hash id
@@ -290,9 +328,8 @@ module E2Model
290
328
  end
291
329
 
292
330
  module DatasetMethods
293
-
294
331
  def ensure_primary_key
295
- pk = @model.primary_keys
332
+ pk = model.primary_keys
296
333
  raise Engine2::E2Error.new("No primary key defined for model #{model}") unless pk && pk.all?
297
334
 
298
335
  if opts_select = @opts[:select]
@@ -300,7 +337,7 @@ module E2Model
300
337
  opts_select.each do |sel|
301
338
  name = case sel
302
339
  when Symbol
303
- sel.to_s =~ /\w+__(\w+)/ ? $1.to_sym : sel
340
+ sel
304
341
  when Sequel::SQL::QualifiedIdentifier
305
342
  sel.column
306
343
  when Sequel::SQL::AliasedExpression
@@ -314,94 +351,85 @@ module E2Model
314
351
  if pk.length == sel_pk.length
315
352
  self
316
353
  else
317
- sels = (pk - sel_pk).map{|k| k.qualify(@model.table_name)}
354
+ sels = (pk - sel_pk).map{|k| model.table_name.q(k)}
318
355
  select_more(*sels)
319
356
  end
320
357
  else
321
- select(*pk.map{|k| k.qualify(@model.table_name)})
358
+ select(*pk.map{|k| model.table_name.q(k)})
322
359
  end
323
360
 
324
361
  end
325
362
 
363
+ def extract_select sel, al = nil, &blk
364
+ case sel
365
+ when Symbol
366
+ yield nil, sel, nil
367
+ when Sequel::SQL::QualifiedIdentifier
368
+ yield sel.table, sel.column, al
369
+ when Sequel::SQL::AliasedExpression, Sequel::SQL::Function
370
+ sel
371
+ # extract_select sel.expression, sel.aliaz, &blk
372
+ # expr = sel.expression
373
+ # yield expr.table, expr.column
374
+ else
375
+ raise Engine2::E2Error.new("Unknown selection #{sel}")
376
+ end
377
+ end
378
+
326
379
  def setup! fields
327
380
  joins = {}
328
381
  type_info = model.type_info
329
382
  model_table_name = model.table_name
330
383
 
331
- @opts[:select].map! do |sel|
384
+ @opts[:select] = @opts[:select].map do |sel|
332
385
  extract_select sel do |table, name, aliaz|
333
- if table
386
+ info = if table
334
387
  if table == model_table_name
335
- m = model
388
+ model
336
389
  else
337
- a = model.many_to_one_associations[table] # || model.one_to_one_associations[table]
338
- raise Engine2::E2Error.new("Association #{table} not found for model #{model}") unless a
339
- m = a.associated_class
340
- end
341
- # raise Engine2::E2Error.new("Model not found for table #{table} in model #{model}") unless m
342
- info = m.type_info
390
+ assoc = model.many_to_one_associations[table] || model.many_to_many_associations[table]
391
+ raise Engine2::E2Error.new("Association #{table} not found for model #{model}") unless assoc
392
+ assoc.associated_class
393
+ end.type_info
343
394
  else
344
- info = type_info
395
+ type_info
345
396
  end
346
397
 
347
- f_info = info[name]
348
- raise Engine2::E2Error.new("Column #{name} not found for table #{table || model_table_name}") unless f_info
349
-
350
398
  table ||= model_table_name
351
-
352
399
  if table == model_table_name
353
400
  fields << name
354
401
  else
355
- fields << :"#{table}__#{name}"
356
- joins[table] = model.many_to_one_associations[table]
402
+ fields << table.q(name)
403
+ joins[table] ||= model.many_to_one_associations[table] || model.many_to_many_associations[table]
357
404
  end
358
405
 
406
+ f_info = info[name]
407
+ raise Engine2::E2Error.new("Column #{name} not found for table #{table || model_table_name}") unless f_info
359
408
  if f_info[:dummy]
360
409
  nil
361
- # elsif f_info[:type] == :blob_store
362
- # # (~{name => nil}).as :name
363
- # # Sequel.char_length(name).as name
364
- # nil
365
410
  else
411
+ qname = table.q(name)
366
412
  if table != model_table_name
367
- if Sequel.alias_columns_in_joins
368
- name.qualify(table).as(:"#{table}__#{name}")
369
- else
370
- name.qualify(table)
371
- end
413
+ Sequel.alias_columns_in_joins ? qname.as(:"#{table}__#{name}") : qname
372
414
  else
373
- name.qualify(table)
415
+ qname
374
416
  end
375
417
  end
376
418
  end
377
419
  end
378
420
 
379
- @opts[:select].compact!
421
+ @opts[:select].compact!.freeze
380
422
 
381
423
  joins.reduce(self) do |joined, (table, assoc)|
382
424
  m = assoc.associated_class
383
- keys = assoc[:qualified_key]
384
- joined.left_join(table, m.primary_keys.zip(keys.is_a?(Array) ? keys : [keys]))
385
- end
386
- end
387
-
388
- def extract_select sel, al = nil, &blk
389
- case sel
390
- when Symbol
391
- if sel.to_s =~ /^(\w+)__(\w+?)(?:___(\w+))?$/
392
- yield $1.to_sym, $2.to_sym, $3 ? $3.to_sym : nil
393
- else
394
- yield nil, sel, al
425
+ case assoc[:type]
426
+ when :many_to_one
427
+ keys = assoc[:qualified_key]
428
+ joined.left_join(table, m.primary_keys.zip(keys.is_a?(Array) ? keys : [keys]))
429
+ when :many_to_many
430
+ joined.left_join(assoc[:join_table], assoc[:left_keys].zip(model.primary_keys)).left_join(m.table_name, m.primary_keys.zip(assoc[:right_keys]))
431
+ else unsupported_association
395
432
  end
396
- when Sequel::SQL::QualifiedIdentifier
397
- yield sel.table, sel.column, al
398
- when Sequel::SQL::AliasedExpression, Sequel::SQL::Function
399
- sel
400
- # extract_select sel.expression, sel.aliaz, &blk
401
- # expr = sel.expression
402
- # yield expr.table, expr.column
403
- else
404
- raise Engine2::E2Error.new("Unknown selection #{sel}")
405
433
  end
406
434
  end
407
435
 
@@ -433,10 +461,21 @@ end
433
461
  module Engine2
434
462
  LOCS ||= Hash.new{|h, k| ":#{k}:"}
435
463
  PATH ||= File.expand_path('../..', File.dirname(__FILE__))
436
- SETTINGS ||= {key_separator: '|'}
464
+ SETTINGS ||= {
465
+ key_separator: '|',
466
+ app_path: 'app',
467
+ db_path: 'db',
468
+ model_path: 'models',
469
+ view_path: 'views',
470
+ asset_path: 'assets',
471
+ conf_path: 'conf'
472
+ }
473
+
474
+ def SETTINGS.path_for path
475
+ "#{self[:app_path]}/#{self[path]}"
476
+ end unless SETTINGS.frozen?
437
477
 
438
478
  class << self
439
- attr_reader :app
440
479
  attr_reader :core_loaded
441
480
 
442
481
  def database name
@@ -457,8 +496,9 @@ module Engine2
457
496
  end
458
497
 
459
498
  def bootstrap_e2db
460
- e2_db_file = (defined? JRUBY_VERSION) ? "jdbc:sqlite:#{@app}/engine2.db" : "sqlite://#{@app}/engine2.db"
461
- const_set :E2DB, connect(e2_db_file, loggers: [Logger.new($stdout)], convert_types: false, name: :engine2)
499
+ e2_db_path = "#{Engine2::SETTINGS.path_for(:db_path)}/engine2.db"
500
+ e2_db_url = (defined? JRUBY_VERSION) ? "jdbc:sqlite:#{e2_db_path}" : "sqlite://#{e2_db_path}"
501
+ const_set :E2DB, connect(e2_db_url, loggers: [Logger.new($stdout)], convert_types: false, name: :engine2)
462
502
  const_set :DUMMYDB, Sequel::Database.new(uri: 'dummy')
463
503
  def DUMMYDB.synchronize *args;end
464
504
  end
@@ -466,35 +506,38 @@ module Engine2
466
506
  def reload
467
507
  @core_loaded = true
468
508
  t = Time.now
469
- Action.count = 0
509
+ ActionNode.count = 0
470
510
  SCHEMES.user.clear
471
511
 
472
512
  Sequel::DATABASES.each do |db|
473
513
  db.models.each{|n, m| Object.send(:remove_const, n) if Object.const_defined?(n)} unless db == E2DB || db == DUMMYDB
474
514
  end
475
515
 
476
- load "#{app}/boot.rb"
516
+ load "#{Engine2::SETTINGS[:app_path]}/boot.rb"
477
517
 
478
518
  Sequel::DATABASES.each &:load_schema_cache_from_file
479
519
  @model_boot_blk.() if @model_boot_blk
480
520
  load 'engine2/models/Files.rb'
481
521
  load 'engine2/models/UserInfo.rb'
482
- Dir["#{app}/models/*"].each{|m| load m}
522
+ Dir["#{Engine2::SETTINGS.path_for(:model_path)}/*"].each{|m| load m}
483
523
  puts "MODELS: #{Sequel::DATABASES.reduce(0){|s, d|s + d.models.size}}, Time: #{Time.now - t}"
484
524
  Sequel::DATABASES.each &:dump_schema_cache_to_file
485
525
 
486
526
  send(:remove_const, :ROOT) if defined? ROOT
487
- const_set(:ROOT, Action.new(nil, :api, RootMeta, {}))
527
+ const_set(:ROOT, ActionNode.new(nil, :api, RootAction, {}))
488
528
 
489
529
  @boot_blk.(ROOT)
490
- ROOT.setup_action_tree
491
- puts "BOOTSTRAP #{app}, Time: #{Time.new - t}"
530
+ ROOT.setup_node_tree
531
+ puts "BOOTSTRAP #{Engine2::SETTINGS[:name]}, Time: #{Time.new - t}"
492
532
  end
493
533
 
494
- def bootstrap app, settings = {}
495
- @app = app
534
+ def bootstrap path, settings = {}
496
535
  SETTINGS.merge! settings
497
- SETTINGS[:name] ||= File::basename(app)
536
+ SETTINGS[:path] = path
537
+ SETTINGS[:name] ||= File::basename(path)
538
+ SETTINGS.freeze
539
+ Handler.set :public_folder, "public"
540
+ Handler.set :views, [SETTINGS.path_for(:view_path), "#{Engine2::PATH}/views"]
498
541
  bootstrap_e2db
499
542
 
500
543
  require 'engine2/pre_bootstrap'
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
5
  class Handler < Sinatra::Base
@@ -66,20 +67,20 @@ module Engine2
66
67
  def serve_api_resource verb, path
67
68
  path = path.split('/') # -1 ?
68
69
  is_meta = path.pop if path.last == 'meta'
69
- action = ROOT
70
+ node = ROOT
70
71
  path.each do |pat|
71
- action = action[pat.to_sym]
72
- halt_not_found unless action
73
- halt_unauthorized unless action.check_access!(self)
72
+ node = node[pat.to_sym]
73
+ halt_not_found unless node
74
+ halt_unauthorized unless node.check_access!(self)
74
75
  end
75
76
 
76
- meta = action.*
77
+ action = node.*
77
78
  response = if is_meta
78
- params[:access] ? action.access_info(self) : {meta: meta.get, actions: action.actions_info(self)}
79
+ params[:access] ? node.access_info(self) : {meta: action.meta, actions: node.nodes_info(self)}
79
80
  else
80
- if meta.http_method == verb && meta.invokable
81
+ if action.http_method == verb && action.invokable
81
82
  begin
82
- meta.invoke!(self)
83
+ action.invoke!(self)
83
84
  rescue => error
84
85
  attachment nil, nil
85
86
  # content_type :json
@@ -119,8 +120,6 @@ module Engine2
119
120
  end
120
121
 
121
122
  set :slim, pretty: true, sort_attrs: false
122
- set :views, ["views", "#{PATH}/views"]
123
- set :public_folder, "#{PATH}/public"
124
123
  set :sessions, expire_after: 3600 # , :httponly => true, :secure => production?
125
124
 
126
125
  helpers do
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
5
  module Model
@@ -74,6 +75,8 @@ module Engine2
74
75
  decimal_field name, size, scale
75
76
  when :blob
76
77
  blob_field name, 100000
78
+ when :boolean
79
+ boolean_field name
77
80
  when nil
78
81
  # ignore nil type
79
82
  else
@@ -284,7 +287,7 @@ module Engine2
284
287
  with_errors = with.map{|w|record.errors[w]}
285
288
  if with_errors.compact.empty?
286
289
  all_fields = [field] + with
287
- query = record.model.dataset.where(*all_fields.map{|f|{f => record[f]}})
290
+ query = all_fields.reduce(record.model.dataset){|ds, f|ds.where f => record[f]}
288
291
  query = query.exclude(record.model.primary_keys_hash(record.primary_key_values)) unless record.new?
289
292
  unless query.empty?
290
293
  msg = LOCS[:required_unique_value]
@@ -327,25 +330,6 @@ module Engine2
327
330
  )
328
331
 
329
332
  (AfterSaveProcessors ||= {}).merge!(
330
- star_to_many_field: lambda{|record, field, info|
331
- value = record.values[field]
332
- if value && value.is_a?(Hash)
333
- assoc = record.model.association_reflections[info[:assoc_name]]
334
- other_model = assoc.associated_class
335
- unlinked = value[:unlinked]
336
- linked = value[:linked]
337
- parent_key = record.primary_key_values
338
- case assoc[:type]
339
- when :one_to_many
340
- StarToManyUnlinkMetaBase.one_to_many_unlink_db(other_model, assoc, unlinked) if unlinked
341
- StarToManyLinkMeta.one_to_many_link_db(other_model, assoc, parent_key, linked) if linked
342
- when :many_to_many
343
- StarToManyUnlinkMetaBase.many_to_many_unlink_db(other_model, assoc, parent_key, unlinked) if unlinked
344
- StarToManyLinkMeta.many_to_many_link_db(other_model, assoc, parent_key, linked) if linked
345
- else unsupported_association
346
- end
347
- end
348
- },
349
333
  file_store: lambda{|m, v, info|
350
334
  value = m.values[v]
351
335
  files = E2Files.db[:files]
@@ -1,4 +1,5 @@
1
1
  # coding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Engine2
4
5
  E2DB.create_table :files do
@@ -28,7 +29,7 @@ module Engine2
28
29
  search_live
29
30
 
30
31
  on_change :model do |req, value|
31
- # action.parent.*.assets[:model].select(:field).where(model: value).all.map{|rec|f = rec.values[:field]; [f, f]}
32
+ # node.parent.*.assets[:model].select(:field).where(model: value).all.map{|rec|f = rec.values[:field]; [f, f]}
32
33
  # render :field, list: {a: 1, b: 2}.to_a
33
34
  end
34
35