activerecord-bixformer 0.1.1 → 0.2.0

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.
@@ -1,40 +0,0 @@
1
- module ActiveRecord
2
- module Bixformer
3
- module Generator
4
- class CsvRow < ::ActiveRecord::Bixformer::Generator::Base
5
- private
6
-
7
- def association_generator
8
- :new_as_association_for_export
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
- model.generate_export_value_map.map do |attribute_name, attribute_value|
17
- [model.csv_title(attribute_name), attribute_value]
18
- end.to_h
19
- end
20
-
21
- def generate_association_value(parent_model)
22
- parent_model.association_map.values.inject({}) do |association_value, model_or_models|
23
- models = model_or_models.is_a?(::Array) ? model_or_models : [model_or_models]
24
-
25
- # 全関連レコードの生成結果を単一ハッシュにマージ
26
- association_value.merge(
27
- models.inject({}) do |current_association_value, model|
28
- # 関連レコードの全生成結果を単一ハッシュにマージ
29
- current_association_value.merge(
30
- # キーをCSVカラム名に置き換えたハッシュを作成
31
- generate_model_value(model)
32
- )
33
- end
34
- )
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,160 +0,0 @@
1
- module ActiveRecord
2
- module Bixformer
3
- module Modeler
4
- class Base
5
- attr_reader :format
6
-
7
- def initialize(format)
8
- @format = format
9
- @module_load_namespaces_of = {}
10
- @module_constant_of = {}
11
- end
12
-
13
- def model_name
14
- end
15
-
16
- def entry_definition
17
- {}
18
- end
19
-
20
- def optional_attributes
21
- []
22
- end
23
-
24
- def required_attributes
25
- []
26
- end
27
-
28
- def unique_indexes
29
- []
30
- end
31
-
32
- def required_condition
33
- {}
34
- end
35
-
36
- def default_values
37
- {}
38
- end
39
-
40
- def translation_config
41
- {
42
- scope: :bixformer,
43
- extend_scopes: []
44
- }
45
- end
46
-
47
- def module_load_namespaces(module_type)
48
- [
49
- "::ActiveRecord::Bixformer::#{module_type.to_s.camelize}::#{format.to_s.camelize}",
50
- "::ActiveRecord::Bixformer::#{module_type.to_s.camelize}",
51
- ]
52
- end
53
-
54
- def config_value_for(model, config_name, default_value = nil)
55
- model_names_without_root = (model.parents.map(&:name) + [model.name]).drop(1)
56
-
57
- # 指定された設定の全設定値を取得
58
- entire_config_value = __send__(config_name)
59
-
60
- if entire_config_value.is_a?(::Hash)
61
- # Hashなら、with_indifferent_accessしておく
62
- entire_config_value = entire_config_value.with_indifferent_access
63
- elsif entire_config_value.is_a?(::Array) && entire_config_value.last.is_a?(::Hash)
64
- # Arrayで最後の要素がHashなら、with_indifferent_accessしておく
65
- config_value = entire_config_value.pop
66
-
67
- entire_config_value.push config_value.with_indifferent_access
68
- end
69
-
70
- # その中から、指定のmodelに対応する設定部分を抽出
71
- config_value = if config_name == :entry_definition
72
- find_entry_definition(entire_config_value, model_names_without_root)
73
- else
74
- find_nested_config_value(entire_config_value, model_names_without_root)
75
- end
76
-
77
- if config_value.is_a?(::Array)
78
- # Arrayで最後の要素がHashの場合、それは子要素の設定値なので、結果に含めない
79
- config_value.pop if config_value.last.is_a?(::Hash)
80
-
81
- # Arrayなら、要素は文字列化しておく
82
- config_value = config_value.map { |v| v.to_s }
83
- end
84
-
85
- config_value || default_value
86
- end
87
-
88
- def new_module_instance(module_type, name_or_instance, *initializers)
89
- name_or_instance = :base unless name_or_instance
90
-
91
- name_or_instance = name_or_instance.to_s if name_or_instance.is_a?(::Symbol)
92
-
93
- return name_or_instance unless name_or_instance.is_a?(::String)
94
-
95
- if initializers.size > 0
96
- find_module_constant(module_type, name_or_instance).new(*initializers)
97
- else
98
- find_module_constant(module_type, name_or_instance).new
99
- end
100
- end
101
-
102
- def find_module_constant(module_type, name)
103
- name = :base unless name
104
-
105
- module_constant = @module_constant_of["#{module_type}/#{name}"]
106
-
107
- return module_constant if module_constant
108
-
109
- namespaces = @module_load_namespaces_of[module_type] ||= module_load_namespaces(module_type)
110
-
111
- namespaces.each do |namespace|
112
- constant = "#{namespace}::#{name.to_s.camelize}".safe_constantize
113
-
114
- return @module_constant_of["#{module_type}/#{name}"] = constant if constant
115
- end
116
-
117
- raise ::ArgumentError.new "Not found module named #{name.to_s.camelize} in module_load_namespaces('#{module_type}')"
118
- end
119
-
120
- def parse_to_type_and_options(value)
121
- value = value.dup if value.is_a?(::Array) || value.is_a?(::Hash)
122
- type = value.is_a?(::Array) ? value.shift : value
123
-
124
- arguments = if value.is_a?(::Array) && value.size == 1 && value.first.is_a?(::Hash)
125
- value.first
126
- elsif value.is_a?(::Array)
127
- value
128
- else
129
- nil
130
- end
131
-
132
- [type, arguments]
133
- end
134
-
135
- private
136
-
137
- def find_nested_config_value(config, keys)
138
- return config ? config.dup : nil if keys.empty?
139
-
140
- key = keys.shift
141
-
142
- # config が Array なら、子要素は最後の要素にハッシュで定義してあるはず
143
- config_map = config.is_a?(::Array) ? config.last : config
144
-
145
- return nil unless config_map.is_a?(::Hash)
146
-
147
- find_nested_config_value(config_map[key], keys)
148
- end
149
-
150
- def find_entry_definition(config, keys)
151
- return config ? config.dup : nil if keys.empty?
152
-
153
- key = keys.shift
154
-
155
- find_entry_definition(config[:associations][key], keys)
156
- end
157
- end
158
- end
159
- end
160
- end
@@ -1,11 +0,0 @@
1
- module ActiveRecord
2
- module Bixformer
3
- module Modeler
4
- class Csv < ::ActiveRecord::Bixformer::Modeler::Base
5
- def initialize
6
- super(:csv)
7
- end
8
- end
9
- end
10
- end
11
- end
@@ -1,47 +0,0 @@
1
- require 'active_record'
2
-
3
- module ActiveRecord
4
- module Bixformer
5
- module Runner
6
- class Base
7
- attr_reader :errors
8
-
9
- def initialize(format)
10
- @format = format
11
- @modelers = []
12
- @errors = []
13
- end
14
-
15
- def add_modeler(*modelers)
16
- modelers.each do |modeler|
17
- unless modeler.format.to_s == @format.to_s
18
- raise ArgumentError.new "modeler format unmatches to #{@format} as runner format : #{modeler.format}"
19
- end
20
-
21
- @modelers.push modeler
22
- end
23
- end
24
-
25
- private
26
-
27
- def available_modelers
28
- if @modelers.empty?
29
- raise ArgumentError.new "Not exist any available modelers. You have to regist modeler by add_modeler."
30
- end
31
-
32
- @modelers
33
- end
34
-
35
- def active_modeler(force_detect = nil)
36
- return @active_modeler if ! force_detect && @active_modeler
37
-
38
- @active_modeler = detect_modeler
39
- end
40
-
41
- def detect_modeler
42
- available_modelers.first
43
- end
44
- end
45
- end
46
- end
47
- end
@@ -1,123 +0,0 @@
1
- require 'csv'
2
-
3
- module ActiveRecord
4
- module Bixformer
5
- module Runner
6
- class Csv < ::ActiveRecord::Bixformer::Runner::Base
7
- def initialize
8
- super(:csv)
9
- end
10
-
11
- def import(csv_data, options = {})
12
- modeler = active_modeler(true)
13
- model_constant = modeler.model_name.to_s.camelize.constantize
14
-
15
- @errors = []
16
- options[:headers] = true
17
-
18
- model_attributes_list = parse_csv_rows(::CSV.parse(csv_data, options))
19
-
20
- model_constant.transaction do
21
- model_attributes_list.each.with_index(1) do |model_attributes, index|
22
- next unless model_attributes&.present?
23
-
24
- identified_value = model_attributes[model_constant.primary_key]
25
-
26
- activerecord = if identified_value
27
- find_activerecord(model_constant, identified_value)
28
- else
29
- build_activerecord(model_constant, model_attributes)
30
- end
31
-
32
- unless save_activerecord(activerecord, model_attributes)
33
- @errors += make_error_messages(activerecord, index)
34
- end
35
- end
36
-
37
- raise ::ActiveRecord::Rollback unless @errors.empty?
38
- end
39
-
40
- @errors.empty? ? true : false
41
- end
42
-
43
- def export(active_records_or_relation, options = {})
44
- modeler = active_modeler(true)
45
- generator = modeler.new_module_instance(:generator, :csv_row, modeler, active_records_or_relation.first)
46
- csv_titles = make_csv_titles(generator)
47
-
48
- ::CSV.generate(options) do |csv|
49
- csv << csv_titles
50
-
51
- active_records_or_relation.each do |activerecord|
52
- generator = modeler.new_module_instance(:generator, :csv_row, modeler, activerecord)
53
-
54
- csv << make_csv_row(generator, csv_titles)
55
- end
56
- end
57
- end
58
-
59
- private
60
-
61
- def make_csv_titles(generator)
62
- generator.compile.available_csv_titles
63
- end
64
-
65
- def make_csv_row(generator, csv_titles)
66
- model_attributes = generator.generate
67
-
68
- csv_titles.map { |title| model_attributes[title] }
69
- end
70
-
71
- def parse_csv_rows(csv_rows)
72
- modeler = active_modeler
73
-
74
- csv_rows.map do |csv_row|
75
- generator = modeler.new_module_instance(:generator, :active_record, modeler, csv_row)
76
-
77
- parse_csv_row(generator)
78
- end
79
- end
80
-
81
- def parse_csv_row(generator)
82
- generator.generate
83
- end
84
-
85
- def find_activerecord(model_class, id)
86
- model_class.find(id)
87
- end
88
-
89
- def build_activerecord(model_class, attributes)
90
- model_class.new(attributes)
91
- end
92
-
93
- def save_activerecord(activerecord, assigned_attributes)
94
- # CSVで削除が可能だが、削除フラグは _destroy というattributesに入っており、こんなcolumnは存在しないので、このままだとエラーになる
95
- # そのため、ここで要素から削除しておく
96
- is_destroy = assigned_attributes.delete(:_destroy)
97
-
98
- if activerecord.persisted?
99
- if is_destroy
100
- activerecord.destroy
101
- else
102
- activerecord.update(assigned_attributes)
103
- end
104
- else
105
- activerecord.save
106
- end
107
- end
108
-
109
- def make_error_messages(activerecord, csv_row_index)
110
- activerecord.errors.full_messages.map do |msg|
111
- I18n.t(
112
- :"bixformer.csv.errors.format", {
113
- default: "Entry(%{csv_row_index}): %{message}",
114
- csv_row_index: csv_row_index,
115
- message: msg
116
- }
117
- )
118
- end
119
- end
120
- end
121
- end
122
- end
123
- end