activerecord-bixformer 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README-ja.md +10 -10
- data/lib/activerecord-bixformer/assignable_attributes_normalizer.rb +125 -0
- data/lib/activerecord-bixformer/attribute/booletania.rb +4 -6
- data/lib/activerecord-bixformer/attribute/enumerize.rb +4 -2
- data/lib/activerecord-bixformer/autoload.rb +27 -0
- data/lib/activerecord-bixformer/compiler.rb +45 -0
- data/lib/activerecord-bixformer/format/csv.rb +20 -0
- data/lib/activerecord-bixformer/from/csv.rb +15 -0
- data/lib/activerecord-bixformer/import_value_validatable.rb +21 -0
- data/lib/activerecord-bixformer/model/base.rb +67 -81
- data/lib/activerecord-bixformer/model/csv/base.rb +31 -23
- data/lib/activerecord-bixformer/model/csv/indexed.rb +31 -24
- data/lib/activerecord-bixformer/plan.rb +56 -0
- data/lib/activerecord-bixformer/plan_accessor.rb +131 -0
- data/lib/activerecord-bixformer/to/csv.rb +56 -0
- data/lib/activerecord-bixformer/version.rb +1 -1
- data/lib/activerecord-bixformer.rb +2 -43
- metadata +11 -9
- data/lib/activerecord-bixformer/generator/active_record.rb +0 -170
- data/lib/activerecord-bixformer/generator/base.rb +0 -66
- data/lib/activerecord-bixformer/generator/csv_row.rb +0 -40
- data/lib/activerecord-bixformer/modeler/base.rb +0 -160
- data/lib/activerecord-bixformer/modeler/csv.rb +0 -11
- data/lib/activerecord-bixformer/runner/base.rb +0 -47
- data/lib/activerecord-bixformer/runner/csv.rb +0 -123
@@ -3,47 +3,54 @@ module ActiveRecord
|
|
3
3
|
module Model
|
4
4
|
module Csv
|
5
5
|
class Indexed < ::ActiveRecord::Bixformer::Model::Csv::Base
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def initialize(model_or_association_name, options)
|
7
|
+
super
|
8
|
+
|
9
|
+
@options = options.is_a?(::Hash) ? options : {}
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
@options[:size] ||= 1
|
12
|
+
end
|
13
13
|
|
14
|
-
|
14
|
+
def make_export_value(activerecord_or_activerecords)
|
15
|
+
activerecord_or_activerecords ||= []
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
# has_many でしか使わない想定なので activerecord_or_activerecords は Array のはず
|
18
|
+
(1..options[:size]).inject({}) do |values, index|
|
19
|
+
update_translator(index)
|
20
|
+
|
21
|
+
values.merge(super(activerecord_or_activerecords[index-1]))
|
18
22
|
end
|
23
|
+
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
def make_import_value(csv_row, parent_activerecord_id = nil)
|
26
|
+
# has_many でしか使わない想定なので Array を返却
|
27
|
+
(1..options[:size]).map do |index|
|
28
|
+
update_translator(index)
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
27
33
|
|
28
|
-
|
34
|
+
def csv_titles
|
35
|
+
(1..options[:size]).flat_map do |index|
|
36
|
+
update_translator(index)
|
29
37
|
|
30
|
-
|
31
|
-
end
|
38
|
+
super
|
32
39
|
end
|
33
40
|
end
|
34
41
|
|
35
|
-
|
36
|
-
super
|
42
|
+
private
|
37
43
|
|
38
|
-
|
44
|
+
def update_translator(index)
|
45
|
+
@translator.model_arguments = { index: index }
|
39
46
|
|
40
|
-
@translator.attribute_arguments_map = @
|
41
|
-
[
|
47
|
+
@translator.attribute_arguments_map = @attributes.map do |attr|
|
48
|
+
[attr.name, { index: index }]
|
42
49
|
end.to_h
|
43
50
|
end
|
44
51
|
|
45
52
|
def csv_title(attribute_name)
|
46
|
-
if parents.find { |parent| parent.is_a?(ActiveRecord::Bixformer::Model::Csv::Indexed) }
|
53
|
+
if parents.find { |parent| parent.is_a?(::ActiveRecord::Bixformer::Model::Csv::Indexed) }
|
47
54
|
parents.map { |parent| parent.translator.translate_model }.join + super
|
48
55
|
else
|
49
56
|
super
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Bixformer
|
3
|
+
module Plan
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_accessor :__bixformer_format
|
8
|
+
|
9
|
+
class_attribute :__bixformer_model
|
10
|
+
|
11
|
+
class_attribute :__bixformer_namespace
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def bixformer_for(model_name)
|
16
|
+
self.__bixformer_model = model_name
|
17
|
+
end
|
18
|
+
|
19
|
+
def bixformer_load_namespace(namespace)
|
20
|
+
self.__bixformer_namespace = namespace
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def entry
|
25
|
+
{}
|
26
|
+
end
|
27
|
+
|
28
|
+
def optional_attributes
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def required_attributes
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
36
|
+
def unique_indexes
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
def required_condition
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_values
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
|
48
|
+
def translation_config
|
49
|
+
{
|
50
|
+
scope: :bixformer,
|
51
|
+
extend_scopes: []
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Bixformer
|
3
|
+
class PlanAccessor
|
4
|
+
def initialize(plan)
|
5
|
+
@plan = plan
|
6
|
+
@module_constant_of = {}
|
7
|
+
@module_load_namespaces_of = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def raw_value
|
11
|
+
@plan
|
12
|
+
end
|
13
|
+
|
14
|
+
def value_of(config_name)
|
15
|
+
@plan.__send__(config_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pickup_value_for(model, config_name, default_value = nil)
|
19
|
+
model_names_without_root = (model.parents.map(&:name) + [model.name]).drop(1)
|
20
|
+
|
21
|
+
# 指定された設定の全設定値を取得
|
22
|
+
entire_config_value = @plan.__send__(config_name)
|
23
|
+
|
24
|
+
if entire_config_value.is_a?(::Hash)
|
25
|
+
# Hashなら、with_indifferent_accessしておく
|
26
|
+
entire_config_value = entire_config_value.with_indifferent_access
|
27
|
+
elsif entire_config_value.is_a?(::Array) && entire_config_value.last.is_a?(::Hash)
|
28
|
+
# Arrayで最後の要素がHashなら、with_indifferent_accessしておく
|
29
|
+
config_value = entire_config_value.pop
|
30
|
+
|
31
|
+
entire_config_value.push config_value.with_indifferent_access
|
32
|
+
end
|
33
|
+
|
34
|
+
# その中から、指定のmodelに対応する設定部分を抽出
|
35
|
+
config_value = if config_name == :entry
|
36
|
+
find_entry(entire_config_value, model_names_without_root)
|
37
|
+
else
|
38
|
+
find_nested_config_value(entire_config_value, model_names_without_root)
|
39
|
+
end
|
40
|
+
|
41
|
+
if config_value.is_a?(::Array)
|
42
|
+
# Arrayで最後の要素がHashの場合、それは子要素の設定値なので、結果に含めない
|
43
|
+
config_value.pop if config_value.last.is_a?(::Hash)
|
44
|
+
|
45
|
+
# Arrayなら、要素は文字列化しておく
|
46
|
+
config_value = config_value.map { |v| v.to_s }
|
47
|
+
end
|
48
|
+
|
49
|
+
config_value || default_value
|
50
|
+
end
|
51
|
+
|
52
|
+
def new_module_instance(module_type, name_or_instance, *initializers)
|
53
|
+
name_or_instance = :base unless name_or_instance
|
54
|
+
|
55
|
+
name_or_instance = name_or_instance.to_s if name_or_instance.is_a?(::Symbol)
|
56
|
+
|
57
|
+
return name_or_instance unless name_or_instance.is_a?(::String)
|
58
|
+
|
59
|
+
if initializers.size > 0
|
60
|
+
find_module_constant(module_type, name_or_instance).new(*initializers)
|
61
|
+
else
|
62
|
+
find_module_constant(module_type, name_or_instance).new
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_module_constant(module_type, name)
|
67
|
+
name = :base unless name
|
68
|
+
|
69
|
+
module_constant = @module_constant_of["#{module_type}/#{name}"]
|
70
|
+
|
71
|
+
return module_constant if module_constant
|
72
|
+
|
73
|
+
namespaces = @module_load_namespaces_of[module_type] ||= module_load_namespaces(module_type)
|
74
|
+
|
75
|
+
namespaces.each do |namespace|
|
76
|
+
constant = "#{namespace}::#{name.to_s.camelize}".safe_constantize
|
77
|
+
|
78
|
+
return @module_constant_of["#{module_type}/#{name}"] = constant if constant
|
79
|
+
end
|
80
|
+
|
81
|
+
raise ::ArgumentError.new "Not found module named #{name.to_s.camelize} in module_load_namespaces('#{module_type}')"
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_to_type_and_options(value)
|
85
|
+
value = value.dup if value.is_a?(::Array) || value.is_a?(::Hash)
|
86
|
+
type = value.is_a?(::Array) ? value.shift : value
|
87
|
+
|
88
|
+
arguments = if value.is_a?(::Array) && value.size == 1 && value.first.is_a?(::Hash)
|
89
|
+
value.first
|
90
|
+
elsif value.is_a?(::Array)
|
91
|
+
value
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
[type, arguments]
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def find_nested_config_value(config, keys)
|
102
|
+
return config ? config.dup : nil if keys.empty?
|
103
|
+
|
104
|
+
key = keys.shift
|
105
|
+
|
106
|
+
# config が Array なら、子要素は最後の要素にハッシュで定義してあるはず
|
107
|
+
config_map = config.is_a?(::Array) ? config.last : config
|
108
|
+
|
109
|
+
return nil unless config_map.is_a?(::Hash)
|
110
|
+
|
111
|
+
find_nested_config_value(config_map[key], keys)
|
112
|
+
end
|
113
|
+
|
114
|
+
def find_entry(config, keys)
|
115
|
+
return config ? config.dup : nil if keys.empty?
|
116
|
+
|
117
|
+
key = keys.shift
|
118
|
+
|
119
|
+
find_entry(config[:associations][key], keys)
|
120
|
+
end
|
121
|
+
|
122
|
+
def module_load_namespaces(module_type)
|
123
|
+
[
|
124
|
+
@plan.class.__bixformer_namespace,
|
125
|
+
"::ActiveRecord::Bixformer::#{module_type.to_s.camelize}::#{@plan.__bixformer_format.camelize}",
|
126
|
+
"::ActiveRecord::Bixformer::#{module_type.to_s.camelize}",
|
127
|
+
].compact
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Bixformer
|
3
|
+
module To
|
4
|
+
class Csv < ::ActiveRecord::Bixformer::Compiler
|
5
|
+
def initialize(plan)
|
6
|
+
super(:csv, plan)
|
7
|
+
end
|
8
|
+
|
9
|
+
def csv_title_row
|
10
|
+
compile.csv_titles
|
11
|
+
end
|
12
|
+
|
13
|
+
def csv_body_row(activerecord)
|
14
|
+
model = compile
|
15
|
+
body_map = model.make_export_value(activerecord)
|
16
|
+
|
17
|
+
model.csv_titles.map { |title| body_map[title] }
|
18
|
+
end
|
19
|
+
|
20
|
+
# private
|
21
|
+
|
22
|
+
# def csv_body_map_by_model(model, activerecord_or_activerecords)
|
23
|
+
# activerecord_or_activerecords = if activerecord_or_activerecords.is_a?(::ActiveRecord::Relation)
|
24
|
+
# activerecord_or_activerecords.to_a
|
25
|
+
# else
|
26
|
+
# activerecord_or_activerecords
|
27
|
+
# end
|
28
|
+
|
29
|
+
# model.generate_export_value(activerecord_or_activerecords).merge(
|
30
|
+
# csv_body_map_by_association(model, activerecord_or_activerecords)
|
31
|
+
# )
|
32
|
+
# end
|
33
|
+
|
34
|
+
# def csv_body_map_by_association(model, activerecord_or_activerecords)
|
35
|
+
# model.associations.inject({}) do |body_map, association_model|
|
36
|
+
# activerecords = if activerecord_or_activerecords.is_a?(::Array)
|
37
|
+
# activerecord_or_activerecords
|
38
|
+
# else
|
39
|
+
# [activerecord_or_activerecords]
|
40
|
+
# end
|
41
|
+
|
42
|
+
# body_map.merge(
|
43
|
+
# activerecords.inject({}) do |body_each_map, activerecord|
|
44
|
+
# association_value = activerecord.__send__(association_model.name)
|
45
|
+
|
46
|
+
# body_each_map.merge(
|
47
|
+
# csv_body_map_by_model(association_model, association_value)
|
48
|
+
# )
|
49
|
+
# end
|
50
|
+
# )
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -1,44 +1,3 @@
|
|
1
1
|
require 'activerecord-bixformer/version'
|
2
|
-
|
3
|
-
|
4
|
-
module Bixformer
|
5
|
-
module Attribute
|
6
|
-
autoload :Base, 'activerecord-bixformer/attribute/base'
|
7
|
-
autoload :Boolean, 'activerecord-bixformer/attribute/boolean'
|
8
|
-
autoload :Booletania, 'activerecord-bixformer/attribute/booletania'
|
9
|
-
autoload :Date, 'activerecord-bixformer/attribute/date'
|
10
|
-
autoload :Enumerize, 'activerecord-bixformer/attribute/enumerize'
|
11
|
-
autoload :Override, 'activerecord-bixformer/attribute/override'
|
12
|
-
autoload :Time, 'activerecord-bixformer/attribute/time'
|
13
|
-
end
|
14
|
-
|
15
|
-
module Generator
|
16
|
-
autoload :ActiveRecord, 'activerecord-bixformer/generator/active_record'
|
17
|
-
autoload :Base, 'activerecord-bixformer/generator/base'
|
18
|
-
autoload :CsvRow, 'activerecord-bixformer/generator/csv_row'
|
19
|
-
end
|
20
|
-
|
21
|
-
module Model
|
22
|
-
autoload :Base, 'activerecord-bixformer/model/base'
|
23
|
-
|
24
|
-
module Csv
|
25
|
-
autoload :Base, 'activerecord-bixformer/model/csv/base'
|
26
|
-
autoload :Indexed, 'activerecord-bixformer/model/csv/indexed'
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
module Modeler
|
31
|
-
autoload :Base, 'activerecord-bixformer/modeler/base'
|
32
|
-
autoload :Csv, 'activerecord-bixformer/modeler/csv'
|
33
|
-
end
|
34
|
-
|
35
|
-
module Runner
|
36
|
-
autoload :Base, 'activerecord-bixformer/runner/base'
|
37
|
-
autoload :Csv, 'activerecord-bixformer/runner/csv'
|
38
|
-
end
|
39
|
-
|
40
|
-
module Translator
|
41
|
-
autoload :I18n, 'activerecord-bixformer/translator/i18n'
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
2
|
+
require 'activerecord-bixformer/autoload'
|
3
|
+
require 'activerecord-bixformer/format/csv'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-bixformer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroaki Otsu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -222,6 +222,7 @@ files:
|
|
222
222
|
- Rakefile
|
223
223
|
- activerecord-bixformer.gemspec
|
224
224
|
- lib/activerecord-bixformer.rb
|
225
|
+
- lib/activerecord-bixformer/assignable_attributes_normalizer.rb
|
225
226
|
- lib/activerecord-bixformer/attribute/base.rb
|
226
227
|
- lib/activerecord-bixformer/attribute/boolean.rb
|
227
228
|
- lib/activerecord-bixformer/attribute/booletania.rb
|
@@ -229,16 +230,17 @@ files:
|
|
229
230
|
- lib/activerecord-bixformer/attribute/enumerize.rb
|
230
231
|
- lib/activerecord-bixformer/attribute/override.rb
|
231
232
|
- lib/activerecord-bixformer/attribute/time.rb
|
232
|
-
- lib/activerecord-bixformer/
|
233
|
-
- lib/activerecord-bixformer/
|
234
|
-
- lib/activerecord-bixformer/
|
233
|
+
- lib/activerecord-bixformer/autoload.rb
|
234
|
+
- lib/activerecord-bixformer/compiler.rb
|
235
|
+
- lib/activerecord-bixformer/format/csv.rb
|
236
|
+
- lib/activerecord-bixformer/from/csv.rb
|
237
|
+
- lib/activerecord-bixformer/import_value_validatable.rb
|
235
238
|
- lib/activerecord-bixformer/model/base.rb
|
236
239
|
- lib/activerecord-bixformer/model/csv/base.rb
|
237
240
|
- lib/activerecord-bixformer/model/csv/indexed.rb
|
238
|
-
- lib/activerecord-bixformer/
|
239
|
-
- lib/activerecord-bixformer/
|
240
|
-
- lib/activerecord-bixformer/
|
241
|
-
- lib/activerecord-bixformer/runner/csv.rb
|
241
|
+
- lib/activerecord-bixformer/plan.rb
|
242
|
+
- lib/activerecord-bixformer/plan_accessor.rb
|
243
|
+
- lib/activerecord-bixformer/to/csv.rb
|
242
244
|
- lib/activerecord-bixformer/translator/i18n.rb
|
243
245
|
- lib/activerecord-bixformer/version.rb
|
244
246
|
homepage: https://github.com/aki2o/activerecord-bixformer
|
@@ -1,170 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Bixformer
|
3
|
-
module Generator
|
4
|
-
class ActiveRecord < ::ActiveRecord::Bixformer::Generator::Base
|
5
|
-
private
|
6
|
-
|
7
|
-
def association_generator
|
8
|
-
:new_as_association_for_import
|
9
|
-
end
|
10
|
-
|
11
|
-
def generate_model_value(model)
|
12
|
-
generate_attributes_value(model).merge(generate_association_value(model))
|
13
|
-
end
|
14
|
-
|
15
|
-
def generate_attributes_value(model)
|
16
|
-
attribute_value_map = model.generate_import_value_map
|
17
|
-
required_attributes = @modeler.config_value_for(model, :required_attributes, [])
|
18
|
-
identified_column_name = identified_column_name_of(model)
|
19
|
-
|
20
|
-
# 必須な属性が渡されていない場合には、取り込みしない
|
21
|
-
return {} if required_attributes.any? { |attribute_name| ! presence_value?(attribute_value_map[attribute_name]) }
|
22
|
-
|
23
|
-
set_required_condition(model, attribute_value_map)
|
24
|
-
set_parent_key(model, attribute_value_map, identified_column_name)
|
25
|
-
set_activerecord_id(model, attribute_value_map, identified_column_name)
|
26
|
-
|
27
|
-
# 空でない要素が無いなら、空ハッシュで返す
|
28
|
-
presence_value?(attribute_value_map) ? attribute_value_map : {}
|
29
|
-
end
|
30
|
-
|
31
|
-
def generate_association_value(parent_model)
|
32
|
-
association_value_map = {}.with_indifferent_access
|
33
|
-
|
34
|
-
parent_model.association_map.each do |association_name, model_or_models|
|
35
|
-
association_value = if model_or_models.is_a?(::Array)
|
36
|
-
model_or_models.map { |m| generate_model_value(m) }.reject { |v| ! presence_value?(v) }
|
37
|
-
else
|
38
|
-
generate_model_value(model_or_models)
|
39
|
-
end
|
40
|
-
|
41
|
-
# 取り込み時は、オプショナルな関連では、空と思われる値は取り込まない
|
42
|
-
next if ! presence_value?(association_value) &&
|
43
|
-
parent_model.optional_attributes.include?(association_name.to_s)
|
44
|
-
|
45
|
-
association_value_map["#{association_name}_attributes".to_sym] = association_value
|
46
|
-
end
|
47
|
-
|
48
|
-
association_value_map
|
49
|
-
end
|
50
|
-
|
51
|
-
def set_required_condition(model, attribute_value_map)
|
52
|
-
# 結果ハッシュが空なら、取り込みしないように追加はしない
|
53
|
-
return unless presence_value?(attribute_value_map)
|
54
|
-
|
55
|
-
# 設定するのはルートの場合のみ
|
56
|
-
return if model.parent
|
57
|
-
|
58
|
-
attribute_value_map.merge!(@modeler.required_condition)
|
59
|
-
end
|
60
|
-
|
61
|
-
def set_parent_key(model, attribute_value_map, identified_column_name)
|
62
|
-
# 結果ハッシュが空なら、取り込みしないように追加はしない
|
63
|
-
return unless presence_value?(attribute_value_map)
|
64
|
-
|
65
|
-
# 設定するのは親がいる場合のみ
|
66
|
-
return unless model.parent
|
67
|
-
|
68
|
-
parent_id = model.parent&.activerecord_id
|
69
|
-
|
70
|
-
if parent_id
|
71
|
-
# 親のレコードが見つかっているなら、それも結果ハッシュに追加する
|
72
|
-
attribute_value_map[model.parent_foreign_key] = parent_id
|
73
|
-
else
|
74
|
-
# 見つかっていないなら、間違った値が指定されている可能性があるので、キー自体を削除
|
75
|
-
attribute_value_map.delete(model.parent_foreign_key)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def set_activerecord_id(model, attribute_value_map, identified_column_name)
|
80
|
-
# 更新の場合は、インポートデータを元にデータベースから対象のレコードを検索してIDを取得
|
81
|
-
model.activerecord_id = verified_activerecord_id(model, attribute_value_map, identified_column_name)
|
82
|
-
|
83
|
-
if model.activerecord_id
|
84
|
-
# 更新なら、ID属性を改めて設定
|
85
|
-
attribute_value_map[identified_column_name] = model.activerecord_id
|
86
|
-
else
|
87
|
-
# 見つかっていないなら、間違った値が指定されている可能性があるので、キー自体を削除
|
88
|
-
attribute_value_map.delete(identified_column_name)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def verified_activerecord_id(model, attribute_value_map, identified_column_name)
|
93
|
-
# 更新対象のレコードを特定できるかチェック
|
94
|
-
identified_value = attribute_value_map[identified_column_name]
|
95
|
-
|
96
|
-
uniqueness_condition = if identified_value
|
97
|
-
{ identified_column_name => identified_value }
|
98
|
-
else
|
99
|
-
find_unique_condition(model, attribute_value_map, identified_column_name)
|
100
|
-
end
|
101
|
-
|
102
|
-
# レコードが特定できないなら、更新処理ではないので終了
|
103
|
-
return nil unless uniqueness_condition
|
104
|
-
|
105
|
-
# 更新対象のレコードを正しく特定できているか確認するための検証条件を取得
|
106
|
-
required_condition = if model.parent
|
107
|
-
key = model.parent_foreign_key
|
108
|
-
|
109
|
-
{ key => attribute_value_map[key] }
|
110
|
-
else
|
111
|
-
@modeler.required_condition
|
112
|
-
end
|
113
|
-
|
114
|
-
# 検証条件は、必ず値がなければならない
|
115
|
-
return nil if required_condition.any? { |_k, v| ! presence_value?(v) }
|
116
|
-
|
117
|
-
# インポートされてきた、レコードを特定する条件が、誤った値でないかどうかを、
|
118
|
-
# 特定されるレコードが、更新すべき正しいレコードであるかチェックするための
|
119
|
-
# 検証条件とマージして、データベースに登録されているか確認する
|
120
|
-
verified_condition = uniqueness_condition.merge(required_condition)
|
121
|
-
|
122
|
-
find_verified_activerecord_by!(model.activerecord_constant, verified_condition).__send__(identified_column_name)
|
123
|
-
rescue ::ActiveRecord::RecordNotFound => e
|
124
|
-
# ID属性が指定されているのに、データベースに見つからない場合はエラーにする
|
125
|
-
raise e if identified_value
|
126
|
-
end
|
127
|
-
|
128
|
-
def find_unique_condition(model, attribute_value_map, identified_column_name)
|
129
|
-
unique_indexes = @modeler.config_value_for(model, :unique_indexes, [])
|
130
|
-
|
131
|
-
# ユニーク条件が指定されていないなら終了
|
132
|
-
return nil if unique_indexes.empty?
|
133
|
-
|
134
|
-
unique_condition = unique_indexes.map do |key|
|
135
|
-
[key, attribute_value_map[key]]
|
136
|
-
end.to_h
|
137
|
-
|
138
|
-
# ユニーク条件は、必ず値がなければならない
|
139
|
-
return nil if unique_condition.any? { |_k, v| ! presence_value?(v) }
|
140
|
-
|
141
|
-
unique_condition
|
142
|
-
end
|
143
|
-
|
144
|
-
def find_verified_activerecord_by!(klass, verified_uniqueness_condition)
|
145
|
-
klass.find_by!(verified_uniqueness_condition)
|
146
|
-
end
|
147
|
-
|
148
|
-
def identified_column_name_of(model)
|
149
|
-
model.activerecord_constant.primary_key
|
150
|
-
end
|
151
|
-
|
152
|
-
def presence_value?(value)
|
153
|
-
# 空でない要素であるか or 空でない要素を含んでいるかどうか
|
154
|
-
case value
|
155
|
-
when ::Hash
|
156
|
-
value.values.any? { |v| presence_value?(v) }
|
157
|
-
when ::Array
|
158
|
-
value.any? { |v| presence_value?(v) }
|
159
|
-
when ::String
|
160
|
-
! value.blank?
|
161
|
-
when ::TrueClass, ::FalseClass
|
162
|
-
true
|
163
|
-
else
|
164
|
-
value ? true : false
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module Bixformer
|
3
|
-
module Generator
|
4
|
-
class Base
|
5
|
-
attr_reader :data_source
|
6
|
-
|
7
|
-
def initialize(modeler, data_source)
|
8
|
-
@modeler = modeler
|
9
|
-
@data_source = data_source
|
10
|
-
end
|
11
|
-
|
12
|
-
def compile
|
13
|
-
return @model if @model
|
14
|
-
|
15
|
-
model_name = @modeler.model_name
|
16
|
-
model_type, model_options = @modeler.parse_to_type_and_options(@modeler.entry_definition[:type])
|
17
|
-
|
18
|
-
@model = @modeler.new_module_instance(:model, model_type, model_name, model_options)
|
19
|
-
|
20
|
-
@model.data_source = @data_source
|
21
|
-
|
22
|
-
compile_model(@model)
|
23
|
-
|
24
|
-
@model
|
25
|
-
end
|
26
|
-
|
27
|
-
def generate
|
28
|
-
generate_model_value(compile)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def compile_model(model)
|
34
|
-
model.setup_with_modeler(@modeler)
|
35
|
-
|
36
|
-
compile_associations(model)
|
37
|
-
end
|
38
|
-
|
39
|
-
def compile_associations(parent_model)
|
40
|
-
association_definitions = @modeler.config_value_for(parent_model, :entry_definition, {})[:associations] || {}
|
41
|
-
|
42
|
-
association_definitions.each do |association_name, association_definition|
|
43
|
-
association_type, association_options = @modeler.parse_to_type_and_options(association_definition[:type])
|
44
|
-
association_constant = @modeler.find_module_constant(:model, association_type)
|
45
|
-
|
46
|
-
model_or_models = association_constant.__send__(
|
47
|
-
association_generator, parent_model, association_name, association_options
|
48
|
-
)
|
49
|
-
|
50
|
-
parent_model.add_association(model_or_models)
|
51
|
-
|
52
|
-
if model_or_models.is_a?(::Array)
|
53
|
-
model_or_models.each { |model| compile_model(model) }
|
54
|
-
else
|
55
|
-
compile_model(model_or_models)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def association_generator
|
61
|
-
raise ::NotImplementedError.new "You must implement #{self.class}##{__method__}"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|