flatten_record 1.0.2 → 1.0.3
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.
- checksums.yaml +4 -4
- data/lib/flatten_record/definition.rb +16 -11
- data/lib/flatten_record/meta/id_column.rb +1 -2
- data/lib/flatten_record/meta/normalized_attr.rb +52 -35
- data/lib/flatten_record/version.rb +1 -1
- data/lib/generators/flatten_record/migration/migration_generator.rb +76 -62
- data/spec/dummy/log/test.log +14730 -0
- data/spec/lib/flatten_record/flattener/denormalize_spec.rb +61 -0
- data/spec/support/flattener.rb +2 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3f760e4ba28e47a8cb7e46621300db8c99d36c9
|
4
|
+
data.tar.gz: 4129c16a709afbd09567ee9ce888257651f20a19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5713c428677377b05b1feb93bc50fa821c173e6ccc33a52c6c571e1731c495d372b4f9006920d4ef811686b8d990ee6ef2f513f3efa3a9861e1d88fc71f851ba
|
7
|
+
data.tar.gz: 3ea39337ec9243801d6883bf1831267e3bbb28f70f6bf6af543dd8684e19ea7a4456e9c3c4029e2c507901d43900ba149525f9c94fa2c72e27148c8951a5cf2f
|
@@ -45,21 +45,13 @@ module FlattenRecord
|
|
45
45
|
|
46
46
|
protected
|
47
47
|
def validate_except(attrs)
|
48
|
-
attrs
|
49
|
-
error = "unknown attribute '#{attr}' in #{@target_model.name.to_s}"
|
50
|
-
@errors << error unless target_method?(attr)
|
51
|
-
@except << attr
|
52
|
-
end
|
48
|
+
validate_attrs(:except, attrs)
|
53
49
|
end
|
54
50
|
|
55
51
|
def validate_only(attrs)
|
56
|
-
attrs
|
57
|
-
error = "unknown attribute '#{attr}' in #{@target_model.name.to_s}"
|
58
|
-
@errors << error unless target_method?(attr)
|
59
|
-
@only << attr
|
60
|
-
end
|
52
|
+
validate_attrs(:only, attrs)
|
61
53
|
end
|
62
|
-
|
54
|
+
|
63
55
|
def validate_methods(methods)
|
64
56
|
methods.each do |method, type|
|
65
57
|
error = "undefined method '#{method}' in #{@target_model.name}"
|
@@ -92,6 +84,19 @@ module FlattenRecord
|
|
92
84
|
end
|
93
85
|
|
94
86
|
private
|
87
|
+
def validate_attrs(name, attrs)
|
88
|
+
attrs.each do |attr|
|
89
|
+
error = "unknown attribute '#{attr}' in #{@target_model.name.to_s}"
|
90
|
+
@errors << error unless target_method?(attr)
|
91
|
+
case name
|
92
|
+
when :only
|
93
|
+
@only << attr
|
94
|
+
when :except
|
95
|
+
@except << attr
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
95
100
|
def model_method?(method)
|
96
101
|
@model.attribute_method?(method) ||
|
97
102
|
@model.method_defined?(method)
|
@@ -7,12 +7,8 @@ module FlattenRecord
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def all_columns
|
10
|
-
|
11
|
-
|
12
|
-
n[:columns] + n[:methods] + n[:compute]
|
13
|
-
end
|
14
|
-
child_columns.flatten!
|
15
|
-
@columns = @base_columns + @methods + @compute + child_columns
|
10
|
+
child_columns = @include.values.collect(&:all_columns)
|
11
|
+
@base_columns + @methods + @compute + child_columns.flatten
|
16
12
|
end
|
17
13
|
|
18
14
|
def associated_models
|
@@ -59,22 +55,27 @@ module FlattenRecord
|
|
59
55
|
|
60
56
|
def build(definition)
|
61
57
|
super(definition)
|
62
|
-
|
58
|
+
|
59
|
+
@foreign_keys = []
|
63
60
|
primary_key = target_columns.select(&:primary).first
|
64
61
|
@id_column = IdColumn.new(self, primary_key, target_model, model)
|
65
|
-
|
66
|
-
@excluded_columns = []
|
62
|
+
|
67
63
|
@compute = build_compute(definition) || []
|
68
64
|
@methods = build_methods(definition) || []
|
69
65
|
@include = build_children(definition) || {}
|
70
66
|
@base_columns = build_columns(definition) || []
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
raise "#{@excluded_columns.inspect}Duplicate columns found: #{dups.join(", ")}"
|
75
|
-
end
|
68
|
+
validate_columns(all_columns)
|
69
|
+
|
76
70
|
self
|
77
71
|
end
|
72
|
+
|
73
|
+
def validate_columns(columns)
|
74
|
+
dups = find_dup_columns(columns)
|
75
|
+
if dups.present?
|
76
|
+
raise "Duplicate columns found: #{dups.join(", ")}"
|
77
|
+
end
|
78
|
+
end
|
78
79
|
|
79
80
|
def children
|
80
81
|
(@base_columns + @compute + @methods + @include.values)
|
@@ -130,38 +131,54 @@ module FlattenRecord
|
|
130
131
|
end
|
131
132
|
|
132
133
|
private
|
133
|
-
def find_dup_columns
|
134
|
+
def find_dup_columns(columns)
|
134
135
|
dups = []
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
dups << "#{column.name} was from #{parent_target}'s #{original_name}"
|
141
|
-
end
|
136
|
+
columns.each do |column|
|
137
|
+
if match_columns?(columns, column)
|
138
|
+
parent_target = column.parent.target_model
|
139
|
+
original_name = column.column.name
|
140
|
+
dups << "#{column.name} was from #{parent_target}'s #{original_name}"
|
142
141
|
end
|
143
142
|
end
|
144
143
|
dups
|
145
144
|
end
|
146
145
|
|
147
|
-
def
|
148
|
-
|
146
|
+
def match_columns?(columns, column)
|
147
|
+
columns.each do |c|
|
148
|
+
if c.parent != column.parent && c.name == column.name
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
false
|
153
|
+
end
|
149
154
|
|
155
|
+
def associated_node_factory(parent, child, class_name)
|
150
156
|
association = target_model.reflect_on_association(child)
|
151
|
-
|
152
|
-
|
153
|
-
class_name ||= association.klass
|
154
|
-
node = nil
|
157
|
+
|
158
|
+
raise_missing_macro(child, target_model) unless association.macro
|
155
159
|
|
156
|
-
if
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
160
|
+
if association_node?(association.macro)
|
161
|
+
class_name ||= association.klass
|
162
|
+
type = "#{association.macro}"
|
163
|
+
klass = Meta.const_get(type.camelize)
|
164
|
+
|
165
|
+
@foreign_keys << association.foreign_key.to_s
|
166
|
+
klass.new(parent, association, class_name, model)
|
161
167
|
else
|
162
|
-
|
168
|
+
raise_unsupported_type(association.macro, target_model)
|
163
169
|
end
|
164
|
-
|
170
|
+
end
|
171
|
+
|
172
|
+
def association_node?(type)
|
173
|
+
[:has_many, :belongs_to, :has_one].include?(type)
|
174
|
+
end
|
175
|
+
|
176
|
+
def raise_unsupported_type(type, model)
|
177
|
+
raise "association type '#{type}' with '#{model}' is not supported"
|
178
|
+
end
|
179
|
+
|
180
|
+
def raise_missing_macro(child, model)
|
181
|
+
raise "association with '#{child}' on #{model} is not found"
|
165
182
|
end
|
166
183
|
|
167
184
|
def columns_from_definition(definition)
|
@@ -176,7 +193,7 @@ module FlattenRecord
|
|
176
193
|
|
177
194
|
def allow_column?(col, definition)
|
178
195
|
return false if col.primary
|
179
|
-
return false if @
|
196
|
+
return false if @foreign_keys.include?(col.name.to_s)
|
180
197
|
|
181
198
|
if definition[:only].present?
|
182
199
|
definition[:only].include?(col.name.to_sym)
|
@@ -8,49 +8,51 @@ module FlattenRecord
|
|
8
8
|
@source_root ||= File.join(File.dirname(__FILE__), 'templates')
|
9
9
|
end
|
10
10
|
|
11
|
-
argument :name, :description => '
|
11
|
+
argument :name, :description => 'model'
|
12
12
|
|
13
13
|
def generate_files
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@table_columns = denormalized_columns
|
22
|
-
|
23
|
-
case
|
24
|
-
when @klass.table_exists?
|
25
|
-
puts yellow("Warning. Table already exists: #{@table_name}")
|
26
|
-
diff_and_generate if meta
|
27
|
-
|
28
|
-
when meta
|
29
|
-
migration_template('migration.erb', "db/migrate/create_table_#{@table_name}.rb")
|
30
|
-
|
31
|
-
else
|
32
|
-
puts red("Error. No denormalization definition found in #{@table_name}")
|
33
|
-
end
|
14
|
+
return unless valid?
|
15
|
+
|
16
|
+
@table_name = klass.table_name
|
17
|
+
if klass.table_exists?
|
18
|
+
puts "Table already exists: #{@table_name}"
|
19
|
+
diff_and_generate
|
20
|
+
else
|
21
|
+
@table_columns = denormalized_columns
|
22
|
+
migration_template('migration.erb', "db/migrate/create_table_#{@table_name}.rb")
|
34
23
|
end
|
35
24
|
end
|
36
25
|
|
37
26
|
private
|
38
27
|
def meta
|
39
|
-
|
28
|
+
klass.flattener_meta
|
40
29
|
end
|
41
|
-
|
30
|
+
|
42
31
|
def denormalized_columns
|
43
|
-
|
32
|
+
meta.all_columns
|
44
33
|
end
|
45
|
-
|
34
|
+
|
35
|
+
def klass_name
|
36
|
+
name.camelize
|
37
|
+
end
|
38
|
+
|
39
|
+
def klass
|
40
|
+
klass_name.constantize
|
41
|
+
end
|
42
|
+
|
43
|
+
def table_name
|
44
|
+
klass.table_name
|
45
|
+
end
|
46
|
+
|
47
|
+
def flatten_klass_names
|
48
|
+
FlattenRecord::Config.included_models
|
49
|
+
end
|
50
|
+
|
46
51
|
def diff_and_generate
|
47
52
|
if any_diff?
|
48
|
-
puts
|
49
|
-
puts ""
|
50
|
-
puts "
|
51
|
-
puts ""
|
52
|
-
puts " #{red('Drop columns:')} #{drop_columns_names}" unless drop_columns.empty?
|
53
|
-
puts ""
|
53
|
+
puts "Generating migration based on the difference.."
|
54
|
+
puts " #{green('Add columns:')} #{add_columns_names}" unless add_columns.empty?
|
55
|
+
puts " #{red('Drop columns:')} #{drop_columns_names}" unless drop_columns.empty?
|
54
56
|
|
55
57
|
@migration = add_columns.empty? ?
|
56
58
|
"drop_#{drop_columns.first.name}_etc_from" :
|
@@ -60,15 +62,6 @@ module FlattenRecord
|
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
63
|
-
def colorize(text, color_code)
|
64
|
-
"\e[#{color_code}m#{text}\e[0m"
|
65
|
-
end
|
66
|
-
|
67
|
-
def red(text); colorize(text, 31); end
|
68
|
-
def green(text); colorize(text, 32); end
|
69
|
-
def yellow(text); colorize(text, 33); end
|
70
|
-
def blue(text); colorize(text, 34); end
|
71
|
-
|
72
65
|
def any_diff?
|
73
66
|
!add_columns.empty? || !drop_columns.empty?
|
74
67
|
end
|
@@ -81,38 +74,59 @@ module FlattenRecord
|
|
81
74
|
drop_columns.collect(&:name).join(', ')
|
82
75
|
end
|
83
76
|
|
84
|
-
def
|
85
|
-
|
86
|
-
cols ||= []
|
87
|
-
@klass.columns.collect(&:name).include?(col.name) ?
|
88
|
-
cols : cols << col
|
89
|
-
end
|
77
|
+
def columns
|
78
|
+
klass.columns
|
90
79
|
end
|
91
|
-
|
92
|
-
def
|
93
|
-
|
94
|
-
next if col.name == 'id'
|
95
|
-
cols ||= []
|
96
|
-
denormalized_columns.collect(&:name).include?(col.name) ?
|
97
|
-
cols : cols << col
|
98
|
-
end
|
80
|
+
|
81
|
+
def denormalized_column_names
|
82
|
+
denormalized_columns.map(&:name)
|
99
83
|
end
|
100
84
|
|
101
|
-
def
|
102
|
-
|
85
|
+
def column_names
|
86
|
+
columns.map(&:name)
|
103
87
|
end
|
104
88
|
|
105
|
-
def
|
106
|
-
@
|
107
|
-
|
89
|
+
def add_columns
|
90
|
+
@add_columns ||=
|
91
|
+
denormalized_columns.inject([]) do |cols, col|
|
92
|
+
if !column_names.include?(col.name)
|
93
|
+
cols << col
|
94
|
+
puts "#{col.name}"
|
95
|
+
end
|
96
|
+
cols
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def drop_columns
|
101
|
+
@drop_columns ||=
|
102
|
+
columns.inject([]) do |cols, col|
|
103
|
+
if col.name != 'id' && !denormalized_column_names.include?(col.name)
|
104
|
+
cols << col
|
105
|
+
end
|
106
|
+
cols
|
107
|
+
end
|
108
108
|
end
|
109
109
|
|
110
110
|
def valid?
|
111
111
|
Rails.application.eager_load!
|
112
|
-
|
113
|
-
|
114
|
-
|
112
|
+
|
113
|
+
begin
|
114
|
+
klass && meta
|
115
|
+
rescue Exception => e
|
116
|
+
puts red(e.message)
|
117
|
+
false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def colorize(text, color_code)
|
122
|
+
"\e[#{color_code}m#{text}\e[0m"
|
115
123
|
end
|
124
|
+
|
125
|
+
def red(text); colorize(text, 31); end
|
126
|
+
def green(text); colorize(text, 32); end
|
127
|
+
def yellow(text); colorize(text, 33); end
|
128
|
+
def blue(text); colorize(text, 34); end
|
129
|
+
|
116
130
|
end
|
117
131
|
end
|
118
132
|
end
|