calculable_attrs 0.0.1 → 0.0.2
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 29b013d46b1eda78f5b0032bb59662a40ea920fc
|
4
|
+
data.tar.gz: 4410bf96fc63ce202ecfb1e40084078adddc9565
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3c8a9d3e4893577e94cdd16157f92b7ec841da83eff1f773fb7e661412ea18a44a7238c281f4000cd54cb16f068f9c29f04635a5129a68ceb91ca25bf2d350e
|
7
|
+
data.tar.gz: 50e135f1ce8bbfff3171781e038987b265b90623e6d97602ffd0b505f0182e65cfab67094b517217ec876e689531f72d02867a25f4b0044eb46901b46b7f38d7
|
@@ -42,80 +42,79 @@ module CalculableAttrs::ActiveRecord::Relation
|
|
42
42
|
collect_models_calculable_attrs(models_calculable_scopes, klass, calculate_attrs_values)
|
43
43
|
models_calculable_scopes = models_calculable_scopes.select { |model, scope| scope.has_attrs }
|
44
44
|
collect_models_ids(models_calculable_scopes, @records, calculate_attrs_values)
|
45
|
-
models_calculable_scopes.each { |model,
|
46
|
-
|
45
|
+
models_calculable_scopes.each { |model, scope| scope.calculate }
|
46
|
+
put_calculated_values(models_calculable_scopes, @records, calculate_attrs_values)
|
47
47
|
end
|
48
48
|
|
49
49
|
@records
|
50
50
|
end
|
51
51
|
|
52
|
-
def collect_models_calculable_attrs(models_calculable_scopes, klass,
|
53
|
-
|
52
|
+
def collect_models_calculable_attrs(models_calculable_scopes, klass, attrs_to_calculate)
|
53
|
+
attrs_to_calculate = [attrs_to_calculate] unless attrs_to_calculate.is_a?(Array)
|
54
54
|
scope = (models_calculable_scopes[klass] ||= CalculableAttrs::ModelCalculableAttrsScope.new(klass))
|
55
|
-
|
55
|
+
attrs_to_calculate.each do |attrs_to_calculate_item|
|
56
56
|
|
57
|
-
case
|
57
|
+
case attrs_to_calculate_item
|
58
58
|
when Symbol
|
59
|
-
if klass.reflect_on_association(
|
60
|
-
collect_association_calculable_attrs(models_calculable_scopes, klass,
|
59
|
+
if klass.reflect_on_association(attrs_to_calculate_item)
|
60
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, attrs_to_calculate_item, true)
|
61
61
|
else
|
62
|
-
scope.add_attr(
|
62
|
+
scope.add_attr(attrs_to_calculate_item)
|
63
63
|
end
|
64
64
|
when true
|
65
65
|
scope.add_all_attrs
|
66
66
|
when Hash
|
67
|
-
|
68
|
-
collect_association_calculable_attrs(models_calculable_scopes, klass, association_name,
|
67
|
+
attrs_to_calculate_item.each do |association_name, association_attrs_to_calculate|
|
68
|
+
collect_association_calculable_attrs(models_calculable_scopes, klass, association_name, association_attrs_to_calculate)
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
def collect_association_calculable_attrs(models_calculable_scopes, klass,
|
75
|
-
|
76
|
-
if
|
77
|
-
collect_models_calculable_attrs(models_calculable_scopes,
|
74
|
+
def collect_association_calculable_attrs(models_calculable_scopes, klass, association_name, association_attrs_to_calculate)
|
75
|
+
association = klass.reflect_on_association(association_name)
|
76
|
+
if association
|
77
|
+
collect_models_calculable_attrs(models_calculable_scopes, association.klass, association_attrs_to_calculate)
|
78
78
|
else
|
79
|
-
p "
|
79
|
+
p "CALCULABLE_ATTRS: WAINING: Model #{ klass.name } doesn't have association attribute #{ association_name }."
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
83
|
def collect_models_ids(models_calculable_scopes, records, attrs_to_calculate)
|
84
|
-
|
84
|
+
iterate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate) do |scope, record|
|
85
85
|
scope.add_id(record.id)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
89
|
|
90
|
-
def
|
91
|
-
|
92
|
-
record.calculable_attrs_values = scope.
|
90
|
+
def put_calculated_values(models_calculable_scopes, records, attrs_to_calculate)
|
91
|
+
iterate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate) do |scope, record|
|
92
|
+
record.calculable_attrs_values = scope.calculated_attrs_values(record.id)
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
def
|
97
|
-
|
96
|
+
def iterate_scoped_records_recursively(models_calculable_scopes, records, attrs_to_calculate, &block)
|
97
|
+
iterate_records_recursively(records, attrs_to_calculate) do |record|
|
98
98
|
scope = models_calculable_scopes[record.class]
|
99
99
|
block.call(scope, record) if scope
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
def
|
104
|
-
attrs_to_calcualte = [attrs_to_calcualte] unless attrs_to_calcualte.is_a?(Array)
|
103
|
+
def iterate_records_recursively(records, attrs_to_calculate, &block)
|
105
104
|
records = [records] unless records.is_a?(Array)
|
106
105
|
|
107
106
|
records.each do |record|
|
108
107
|
block.call(record)
|
109
108
|
|
110
109
|
attrs_to_calculate.select {|item| item.is_a?(Hash)}.each do |hash|
|
111
|
-
hash.each do |
|
112
|
-
if record.respond_to?(
|
113
|
-
associated_records = record.send(
|
110
|
+
hash.each do |association_name, association_attributes|
|
111
|
+
if record.respond_to?(association_name)
|
112
|
+
associated_records = record.send(association_name)
|
114
113
|
associated_records = associated_records.respond_to?(:to_a) ? associated_records.to_a : associated_records
|
115
|
-
|
114
|
+
iterate_records_recursively(associated_records, attrs_to_calculate, &block)
|
116
115
|
end
|
117
116
|
end
|
118
117
|
end
|
119
118
|
end
|
120
119
|
end
|
121
|
-
end
|
120
|
+
end
|
@@ -18,7 +18,7 @@ class CalculableAttrs::Calculator
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def calculate(attrs, id)
|
21
|
-
if
|
21
|
+
if id.is_a?(Array)
|
22
22
|
calculate_many(attrs, id)
|
23
23
|
else
|
24
24
|
calculate_one(attrs, id)
|
@@ -28,12 +28,12 @@ class CalculableAttrs::Calculator
|
|
28
28
|
def calculate_many(attrs, ids)
|
29
29
|
query = base_query(attrs, ids).select("#{ @foreign_key } AS #{ CALCULABLE_FOREIGN_KEY }").group(@foreign_key)
|
30
30
|
records = query.load
|
31
|
-
|
31
|
+
normalize_many_records_result(ids, attrs, records)
|
32
32
|
end
|
33
33
|
|
34
34
|
def calculate_one(attrs, id)
|
35
35
|
record = base_query(attrs, id).load.first
|
36
|
-
|
36
|
+
normalize_one_record_result(attrs, record)
|
37
37
|
end
|
38
38
|
|
39
39
|
def calculate_all(id)
|
@@ -51,10 +51,10 @@ class CalculableAttrs::Calculator
|
|
51
51
|
@formulas[name] = value[0]
|
52
52
|
@defaults[name] = value[1]
|
53
53
|
else
|
54
|
-
raise "
|
54
|
+
raise "CALCULABLE_ATTRS: Invalid attribute array for #{ name }. Expected ['formula', default_value]"
|
55
55
|
end
|
56
56
|
else
|
57
|
-
raise "
|
57
|
+
raise "CALCULABLE_ATTRS: Invalid attribute value for #{ name }"
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -62,19 +62,19 @@ class CalculableAttrs::Calculator
|
|
62
62
|
@relation.call.select(build_select(attrs)).where( @foreign_key => id)
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
65
|
+
def normalize_many_records_result(ids, attrs, records)
|
66
66
|
normalized = {}
|
67
67
|
records.each do |row|
|
68
68
|
id = row[CALCULABLE_FOREIGN_KEY].to_i
|
69
|
-
normalized[id] =
|
69
|
+
normalized[id] = normalize_one_record_result(attrs, row)
|
70
70
|
end
|
71
71
|
ids.each do |id|
|
72
|
-
normalized[id] ||=
|
72
|
+
normalized[id] ||= normalize_one_record_result(attrs, nil)
|
73
73
|
end
|
74
74
|
normalized
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
77
|
+
def normalize_one_record_result(attrs, record)
|
78
78
|
attrs.map { |a| [a, record.try(a) || ( @defaults.key?(a) ? @defaults[a] : 0)] }.to_h
|
79
79
|
end
|
80
80
|
|
@@ -82,4 +82,4 @@ class CalculableAttrs::Calculator
|
|
82
82
|
def build_select(attrs)
|
83
83
|
attrs.map { |a| "#{ @formulas[a] } AS #{ a }" }.join(', ')
|
84
84
|
end
|
85
|
-
end
|
85
|
+
end
|
@@ -7,9 +7,9 @@ class CalculableAttrs::ModelCalculableAttrsScope
|
|
7
7
|
@ids = []
|
8
8
|
end
|
9
9
|
|
10
|
-
def add_attr(
|
11
|
-
|
12
|
-
@attrs.push(
|
10
|
+
def add_attr(attribute)
|
11
|
+
attribute = attribute.to_sym
|
12
|
+
@attrs.push(attribute) unless @attrs.include?(attribute)
|
13
13
|
end
|
14
14
|
|
15
15
|
def add_all_attrs
|
@@ -26,33 +26,33 @@ class CalculableAttrs::ModelCalculableAttrsScope
|
|
26
26
|
|
27
27
|
def calculate
|
28
28
|
@calculable_attrs_values = nil
|
29
|
-
calculators_to_use.each do |
|
30
|
-
|
31
|
-
merge_calculated_values(
|
29
|
+
calculators_to_use.each do |calculator|
|
30
|
+
calculated_values = calculator.calculate_many(attrs | @attrs, ids)
|
31
|
+
merge_calculated_values(calculated_values)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def calculated_attrs_values(id)
|
36
36
|
@calculable_attrs_values[id.to_i]
|
37
37
|
end
|
38
38
|
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
-
def merge_calculated_values(
|
42
|
+
def merge_calculated_values(calculated_values)
|
43
43
|
if @calculable_attrs_values
|
44
|
-
|
44
|
+
calculated_values.each {|id, values| @calculable_attrs_values[id].merge!(calculated_values[id]) }
|
45
45
|
else
|
46
|
-
@calculable_attrs_values =
|
46
|
+
@calculable_attrs_values = calculated_values
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
def calculators_to_use
|
51
51
|
calculators_to_use = []
|
52
52
|
@attrs.each do |attribute|
|
53
|
-
|
54
|
-
calculators_to_use.push(
|
53
|
+
calculator = @model.calculable_attrs_calculators[attribute]
|
54
|
+
calculators_to_use.push(calculator) unless calculators_to_use.include?(calculator)
|
55
55
|
end
|
56
56
|
calculators_to_use
|
57
57
|
end
|
58
|
-
end
|
58
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Sharkov
|
@@ -28,14 +28,14 @@ dependencies:
|
|
28
28
|
name: sqlite3
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
@@ -70,19 +70,19 @@ dependencies:
|
|
70
70
|
name: database_cleaner
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
description: |2
|
84
84
|
Imagine you an Account model which has many transactions.
|
85
|
-
calculable_attrs gem allows you to define
|
85
|
+
calculable_attrs gem allows you to define Account#blalace and SUM(transactions.amount) directly in your Account model.
|
86
86
|
And solves n+1 problem for you in an elegant way.
|
87
87
|
email:
|
88
88
|
- dmitry.sharkov@gmail.com
|