calculable_attrs 0.0.8 → 0.0.9
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/calculable_attrs/active_record/querying.rb +1 -1
- data/lib/calculable_attrs/active_record/relation.rb +103 -34
- data/lib/calculable_attrs/calculator.rb +20 -4
- data/lib/calculable_attrs/model_calculable_attrs_scope.rb +18 -8
- data/lib/calculable_attrs/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57c06a0f4f9704dd33c80b66e571b32df767ad3d
|
4
|
+
data.tar.gz: 77a6b0903406d4f36c197fa0db1ae1f7fedfadf4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ebbfb7711a299a2b597a9ef419ee4af4bf2c1592636e30a7734063eb3811d6c20421a0137170c758f04fcb910cfff344e2c68c6b215ca247b01a4a2910a1721f
|
7
|
+
data.tar.gz: 6e6df74cae0281b0ed8d8d9d9e92a262106b3d813c63bce4faac7bec583fbd33d75bb38b369519c1b398fdd18753d9f3e2d1300c39c815661b4ccdcceca1b602
|
@@ -1,25 +1,48 @@
|
|
1
1
|
module CalculableAttrs::ActiveRecord::Relation
|
2
|
-
|
3
|
-
spawn.calculate_attrs!(*attrs)
|
4
|
-
end
|
2
|
+
JOINED_RELATION_NAME = 'calculated_attrs'
|
5
3
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attrs = [true] if attrs.empty?
|
4
|
+
def includes_calculable_attrs(*attrs)
|
5
|
+
spawn.includes_calculable_attrs!(*attrs)
|
6
|
+
end
|
7
|
+
alias_method :calculate_attrs, :includes_calculable_attrs
|
11
8
|
|
12
|
-
|
9
|
+
def includes_calculable_attrs!(*attrs)
|
10
|
+
set_calculable_attrs_included(refine_calculable_attrs(attrs))
|
13
11
|
self
|
14
12
|
end
|
13
|
+
alias_method :calculate_attrs!, :includes_calculable_attrs!
|
15
14
|
|
16
|
-
def
|
17
|
-
|
15
|
+
def joins_calculable_attrs(*attrs)
|
16
|
+
spawn.joins_calculable_attrs!(*attrs)
|
18
17
|
end
|
19
18
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
19
|
+
def joins_calculable_attrs!(*attrs)
|
20
|
+
set_calculable_attrs_joined(refine_calculable_attrs(attrs))
|
21
|
+
|
22
|
+
scope = CalculableAttrs::ModelCalculableAttrsScope.new(klass)
|
23
|
+
scope.add_attrs(calculable_attrs_joined)
|
24
|
+
_select!("#{ klass.table_name }.*")
|
25
|
+
scope.calculators_to_use.each_with_index do |calcualtor, index|
|
26
|
+
joined_relation_name = '__' + JOINED_RELATION_NAME + '_' + index.to_s + '__'
|
27
|
+
|
28
|
+
attrs_to_calculate = scope.attrs && calcualtor.attrs
|
29
|
+
left_join_sql =
|
30
|
+
<<-sql
|
31
|
+
LEFT JOIN ( #{ calcualtor.query_with_grouping(attrs_to_calculate, nil).to_sql })
|
32
|
+
AS #{ joined_relation_name }
|
33
|
+
ON #{ joined_relation_name }.#{ calcualtor.calculable_foreign_key } = #{ klass.table_name }.id
|
34
|
+
sql
|
35
|
+
|
36
|
+
calculable_values_sql = attrs_to_calculate.map do |attr|
|
37
|
+
attr_name = "#{ klass.name.underscore }_#{ attr }"
|
38
|
+
left_join_sql.sub!(" AS #{ attr }", " AS #{ attr_name }")
|
39
|
+
klass.send(:sanitize_sql, ["COALESCE(#{ joined_relation_name }.#{ attr_name }, ?) AS #{ attr_name }", calcualtor.default(attr)])
|
40
|
+
end.join(',')
|
41
|
+
|
42
|
+
joins!(left_join_sql)
|
43
|
+
_select!(calculable_values_sql)
|
44
|
+
end
|
45
|
+
self
|
23
46
|
end
|
24
47
|
|
25
48
|
|
@@ -36,36 +59,68 @@ module CalculableAttrs::ActiveRecord::Relation
|
|
36
59
|
|
37
60
|
private
|
38
61
|
|
62
|
+
def refine_calculable_attrs(attrs)
|
63
|
+
attrs.reject!(&:blank?)
|
64
|
+
attrs.flatten!
|
65
|
+
attrs = [true] if attrs.empty?
|
66
|
+
attrs
|
67
|
+
end
|
68
|
+
|
69
|
+
def calculable_attrs_joined
|
70
|
+
@values[:calculable_attrs_joined] || []
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_calculable_attrs_joined(values)
|
74
|
+
raise ImmutableRelation if @loaded
|
75
|
+
@values[:calculable_attrs_joined] = [] unless @values[:calculable_attrs_joined]
|
76
|
+
@values[:calculable_attrs_joined] |= values
|
77
|
+
end
|
78
|
+
|
79
|
+
def calculable_attrs_included
|
80
|
+
@values[:calculable_attrs_included] || []
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_calculable_attrs_included(values)
|
84
|
+
raise ImmutableRelation if @loaded
|
85
|
+
@values[:calculable_attrs_included] = [] unless @values[:calculable_attrs_included]
|
86
|
+
@values[:calculable_attrs_included] |= values
|
87
|
+
end
|
88
|
+
|
39
89
|
def append_calculable_attrs
|
40
|
-
unless
|
41
|
-
|
42
|
-
|
43
|
-
models_calculable_scopes
|
44
|
-
|
45
|
-
models_calculable_scopes
|
46
|
-
|
90
|
+
unless calculable_attrs_included.empty?
|
91
|
+
attrs = calculable_attrs_included - calculable_attrs_joined
|
92
|
+
models_calculable_scopes = collect_calculable_scopes(attrs)
|
93
|
+
collect_models_ids(models_calculable_scopes, @records, attrs)
|
94
|
+
models_calculable_scopes.values.each { |scope| scope.calculate }
|
95
|
+
put_calculated_values(models_calculable_scopes, @records, attrs)
|
96
|
+
put_joined_calculated_values(@records)
|
47
97
|
end
|
48
98
|
|
49
99
|
@records
|
50
100
|
end
|
51
101
|
|
102
|
+
def collect_calculable_scopes(attrs)
|
103
|
+
models_calculable_scopes= {}
|
104
|
+
collect_models_calculable_attrs(models_calculable_scopes, klass, attrs)
|
105
|
+
models_calculable_scopes.select { |model, scope| scope.has_attrs }
|
106
|
+
end
|
107
|
+
|
52
108
|
def collect_models_calculable_attrs(models_calculable_scopes, klass, attrs_to_calculate)
|
53
109
|
attrs_to_calculate = [attrs_to_calculate] unless attrs_to_calculate.is_a?(Array)
|
54
110
|
scope = (models_calculable_scopes[klass] ||= CalculableAttrs::ModelCalculableAttrsScope.new(klass))
|
55
111
|
attrs_to_calculate.each do |attrs_to_calculate_item|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
collect_association_calculable_attrs(models_calculable_scopes, klass, association_name, association_attrs_to_calculate)
|
112
|
+
case attrs_to_calculate_item
|
113
|
+
when Symbol
|
114
|
+
if klass.reflect_on_association(attrs_to_calculate_item)
|
115
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, attrs_to_calculate_item, true)
|
116
|
+
else
|
117
|
+
scope.add_attr(attrs_to_calculate_item)
|
118
|
+
end
|
119
|
+
when true
|
120
|
+
scope.add_all_attrs
|
121
|
+
when Hash
|
122
|
+
attrs_to_calculate_item.each do |association_name, association_attrs_to_calculate|
|
123
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, association_name, association_attrs_to_calculate)
|
69
124
|
end
|
70
125
|
end
|
71
126
|
end
|
@@ -93,6 +148,20 @@ module CalculableAttrs::ActiveRecord::Relation
|
|
93
148
|
end
|
94
149
|
end
|
95
150
|
|
151
|
+
def put_joined_calculated_values(records)
|
152
|
+
joined_attrs = calculable_attrs_joined
|
153
|
+
joined_attrs = klass.calculable_attrs if joined_attrs == [true]
|
154
|
+
unless joined_attrs.empty?
|
155
|
+
names_hash = joined_attrs.map {|attr| [attr, "#{ klass.name.underscore }_#{ attr }"]}.to_h
|
156
|
+
records.each do |record|
|
157
|
+
names_hash.each do |attr_name, attr_full_name|
|
158
|
+
value = record.send(attr_full_name)
|
159
|
+
record.set_calculable_attr_value(attr_name, value)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
96
165
|
def iterate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate, &block)
|
97
166
|
iterate_records_recursively(records, attrs_to_calculate) do |record|
|
98
167
|
scope = models_calculable_scopes[record.class]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
class CalculableAttrs::Calculator
|
2
2
|
CALCULABLE_FOREIGN_KEY = '__calculable_id__'
|
3
|
-
attr_reader :attrs, :relation, :foreign_key
|
3
|
+
attr_reader :attrs, :relation, :foreign_key, :defaults
|
4
4
|
|
5
5
|
def initialize(relation: nil, foreign_key: nil, attributes: nil)
|
6
6
|
@relation = relation
|
@@ -25,12 +25,20 @@ class CalculableAttrs::Calculator
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
def calculable_foreign_key
|
29
|
+
CALCULABLE_FOREIGN_KEY
|
30
|
+
end
|
31
|
+
|
28
32
|
def calculate_many(attrs, ids)
|
29
|
-
query =
|
33
|
+
query = query_with_grouping(attrs, ids)
|
30
34
|
records = query.load
|
31
35
|
normalize_many_records_result(ids, attrs, records)
|
32
36
|
end
|
33
37
|
|
38
|
+
def query_with_grouping(attrs, ids)
|
39
|
+
base_query(attrs, ids).select("#{ @foreign_key } AS #{ calculable_foreign_key }").group(@foreign_key)
|
40
|
+
end
|
41
|
+
|
34
42
|
def calculate_one(attrs, id)
|
35
43
|
record = base_query(attrs, id).load.first
|
36
44
|
normalize_one_record_result(attrs, record)
|
@@ -45,7 +53,15 @@ class CalculableAttrs::Calculator
|
|
45
53
|
end
|
46
54
|
|
47
55
|
def scoped_relation(id)
|
48
|
-
|
56
|
+
if id
|
57
|
+
@relation.call.where( @foreign_key => id)
|
58
|
+
else
|
59
|
+
@relation.call
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def default(attr)
|
64
|
+
@defaults.key?(attr) ? @defaults[attr] : 0
|
49
65
|
end
|
50
66
|
|
51
67
|
private
|
@@ -80,7 +96,7 @@ class CalculableAttrs::Calculator
|
|
80
96
|
end
|
81
97
|
|
82
98
|
def normalize_one_record_result(attrs, record)
|
83
|
-
attrs.map { |a| [a, record.try(a) || (
|
99
|
+
attrs.map { |a| [a, record.try(a) || default(a)] }.to_h
|
84
100
|
end
|
85
101
|
|
86
102
|
|
@@ -7,6 +7,14 @@ class CalculableAttrs::ModelCalculableAttrsScope
|
|
7
7
|
@ids = []
|
8
8
|
end
|
9
9
|
|
10
|
+
def add_attrs(attrs)
|
11
|
+
if attrs == true || attrs == [ true ]
|
12
|
+
add_all_attrs
|
13
|
+
else
|
14
|
+
attrs.each { |attr| add_attr(attr) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
def add_attr(attribute)
|
11
19
|
attribute = attribute.to_sym
|
12
20
|
@attrs.push(attribute) unless @attrs.include?(attribute)
|
@@ -37,6 +45,15 @@ class CalculableAttrs::ModelCalculableAttrsScope
|
|
37
45
|
end
|
38
46
|
|
39
47
|
|
48
|
+
def calculators_to_use
|
49
|
+
calculators_to_use = []
|
50
|
+
@attrs.each do |attribute|
|
51
|
+
calculator = @model.calculable_attrs_calculators[attribute]
|
52
|
+
calculators_to_use.push(calculator) unless calculators_to_use.include?(calculator)
|
53
|
+
end
|
54
|
+
calculators_to_use
|
55
|
+
end
|
56
|
+
|
40
57
|
private
|
41
58
|
|
42
59
|
def merge_calculated_values(calculated_values)
|
@@ -47,12 +64,5 @@ class CalculableAttrs::ModelCalculableAttrsScope
|
|
47
64
|
end
|
48
65
|
end
|
49
66
|
|
50
|
-
|
51
|
-
calculators_to_use = []
|
52
|
-
@attrs.each do |attribute|
|
53
|
-
calculator = @model.calculable_attrs_calculators[attribute]
|
54
|
-
calculators_to_use.push(calculator) unless calculators_to_use.include?(calculator)
|
55
|
-
end
|
56
|
-
calculators_to_use
|
57
|
-
end
|
67
|
+
|
58
68
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: calculable_attrs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Sharkov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.2'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: pg
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|