engine2 1.0.4 → 1.0.5

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