calculable_attrs 0.0.9 → 0.0.10

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: 57c06a0f4f9704dd33c80b66e571b32df767ad3d
4
- data.tar.gz: 77a6b0903406d4f36c197fa0db1ae1f7fedfadf4
3
+ metadata.gz: bc9300a7e0499492982a09b34c989978fed6c09b
4
+ data.tar.gz: c635f7b8e3db6594bcbd1a780c1a96738ee281f3
5
5
  SHA512:
6
- metadata.gz: ebbfb7711a299a2b597a9ef419ee4af4bf2c1592636e30a7734063eb3811d6c20421a0137170c758f04fcb910cfff344e2c68c6b215ca247b01a4a2910a1721f
7
- data.tar.gz: 6e6df74cae0281b0ed8d8d9d9e92a262106b3d813c63bce4faac7bec583fbd33d75bb38b369519c1b398fdd18753d9f3e2d1300c39c815661b4ccdcceca1b602
6
+ metadata.gz: 3405f74980918e7621336cb67c3f4d01e12dae5b9579113a3874caeb75e47871dc672502f1a351ce27a673e612dfe792cda00628cf98761b135026a91c4cffcd
7
+ data.tar.gz: 5aed3a55144e62bca6a0500a1de8f5f61f69aaa2096059a0911478dddc0ff7c3d97a32449169f8c9cd603a54c677ff930f1d0c273183e4f1fe7d67454d9f78a8
@@ -18,30 +18,6 @@ module CalculableAttrs::ActiveRecord::Relation
18
18
 
19
19
  def joins_calculable_attrs!(*attrs)
20
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
21
  self
46
22
  end
47
23
 
@@ -50,8 +26,12 @@ sql
50
26
  base.class_eval do
51
27
  alias_method :calculable_orig_exec_queries, :exec_queries
52
28
  def exec_queries
53
- calculable_orig_exec_queries
54
- append_calculable_attrs
29
+ if calculable_attrs_joined.empty?
30
+ calculable_orig_exec_queries
31
+ else
32
+ wrap_with_left_joins_and_exec_queries
33
+ end
34
+ apped_calculable_attrs
55
35
  @records
56
36
  end
57
37
  end
@@ -59,6 +39,14 @@ sql
59
39
 
60
40
  private
61
41
 
42
+
43
+
44
+ def wrap_with_left_joins_and_exec_queries
45
+ relation = wrap_with_calculable_joins(spawn)
46
+ @records = relation.send(:calculable_orig_exec_queries)
47
+ @loaded = true
48
+ end
49
+
62
50
  def refine_calculable_attrs(attrs)
63
51
  attrs.reject!(&:blank?)
64
52
  attrs.flatten!
@@ -86,19 +74,86 @@ sql
86
74
  @values[:calculable_attrs_included] |= values
87
75
  end
88
76
 
89
- def append_calculable_attrs
77
+ def wrap_with_calculable_joins(relation)
78
+ scope = CalculableAttrs::ModelCalculableAttrsScope.new(klass)
79
+ scope.add_attrs(calculable_attrs_joined)
80
+
81
+ original_sql = relation.to_sql
82
+
83
+ sql_parser = CalculableAttrs::Utils::SqlParser.new(original_sql)
84
+ select_sql_snippets = [sql_parser.first_select_snippet]
85
+ where_sql_snippet = sql_parser.last_where_snippet
86
+ relation.reset
87
+
88
+
89
+ scope.calculators_to_use.each_with_index do |calcualtor, index|
90
+ joined_relation_name = '__' + JOINED_RELATION_NAME + '_' + index.to_s + '__'
91
+
92
+ attrs_to_calculate = scope.attrs && calcualtor.attrs
93
+ left_join_sql = "LEFT JOIN ( #{ calcualtor.query_with_grouping(attrs_to_calculate, nil).to_sql })" +
94
+ " AS #{ joined_relation_name }" +
95
+ " ON #{ joined_relation_name }.#{ calcualtor.calculable_foreign_key } = #{ klass.table_name }.id"
96
+
97
+ calculable_values_sql = attrs_to_calculate.map do |attr|
98
+ attr_name = "#{ klass.name.underscore }_#{ attr }"
99
+ left_join_sql.sub!(" AS #{ attr }", " AS #{ attr_name }")
100
+ klass.send(:sanitize_sql, ["COALESCE(#{ joined_relation_name }.#{ attr_name }, ?) AS #{ attr_name }", calcualtor.default(attr)])
101
+ end.join(',')
102
+ select_sql_snippets << calculable_values_sql
103
+
104
+ if where_sql_snippet
105
+ attrs_to_calculate.each do |attr|
106
+ original_names = [
107
+ "#{ klass.table_name.underscore }.#{ attr }",
108
+ "\"#{ klass.table_name.underscore }\".#{ attr }",
109
+ "#{ klass.table_name.underscore }.\"#{ attr }\"",
110
+ "\"#{ klass.table_name.underscore }\".\"#{ attr }\"",
111
+ ]
112
+ replacement_name = "#{ joined_relation_name }.#{ klass.name.underscore }_#{ attr }"
113
+ replacement = klass.send(:sanitize_sql, ["COALESCE(#{ replacement_name }, ?)", calcualtor.default(attr)])
114
+ original_names.each { |original_name| where_sql_snippet.gsub!(original_name, replacement) }
115
+ end
116
+ end
117
+
118
+ relation.joins!(left_join_sql)
119
+
120
+ end
121
+ sql_select = select_sql_snippets.join(',')
122
+ #relation.rewhere(where_sql_snippet) if where_sql_snippet
123
+ if where_sql_snippet
124
+ relation.where_values = nil
125
+ relation.where!(where_sql_snippet)
126
+ end
127
+ relation._select!(sql_select)
128
+ relation
129
+ end
130
+
131
+
132
+
133
+ def apped_calculable_attrs
134
+ append_included_calculable_attrs
135
+ append_joinded_calculable_attrs
136
+ end
137
+
138
+ def append_included_calculable_attrs
90
139
  unless calculable_attrs_included.empty?
91
140
  attrs = calculable_attrs_included - calculable_attrs_joined
92
141
  models_calculable_scopes = collect_calculable_scopes(attrs)
93
142
  collect_models_ids(models_calculable_scopes, @records, attrs)
94
143
  models_calculable_scopes.values.each { |scope| scope.calculate }
95
144
  put_calculated_values(models_calculable_scopes, @records, attrs)
96
- put_joined_calculated_values(@records)
97
145
  end
98
146
 
99
147
  @records
100
148
  end
101
149
 
150
+ def append_joinded_calculable_attrs
151
+ unless calculable_attrs_joined.empty?
152
+ put_joined_calculated_values(@records)
153
+ end
154
+ @records
155
+ end
156
+
102
157
  def collect_calculable_scopes(attrs)
103
158
  models_calculable_scopes= {}
104
159
  collect_models_calculable_attrs(models_calculable_scopes, klass, attrs)
@@ -0,0 +1,91 @@
1
+ class CalculableAttrs::Utils::SqlParser
2
+ def initialize(sql)
3
+ @sql = sql
4
+ @masked_sql = mask_sql(sql)
5
+ end
6
+
7
+ def first_select_snippet
8
+ match = @masked_sql.match(/SELECT (?<select>.*?) FROM/)
9
+ from, to = *match.offset(:select)
10
+ @sql[from..to-1]
11
+ end
12
+
13
+ def last_where_snippet
14
+ last_where_start_at = @masked_sql.rindex('WHERE')
15
+ return unless last_where_start_at
16
+ masted_sql_starting_with_last_where = @masked_sql[last_where_start_at..-1]
17
+ match = masted_sql_starting_with_last_where.match(/WHERE (?<where>.*?)( GROUP| ORDER| LIMIT| OFFSET|$)/)
18
+ from, to = *match.offset(:where)
19
+ @sql[last_where_start_at + from..last_where_start_at+to-1]
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def mask_sql(sql)
26
+ sql = mask_strings(sql)
27
+ sql = mask_brackets(sql)
28
+ sql
29
+ end
30
+
31
+ def mask_strings(sql, mask='x')
32
+ idx = 0
33
+ len = sql.size
34
+ masked_sql = ''
35
+ inside_string = false
36
+ while idx < len
37
+ ch = sql[idx]
38
+ if ch == '\''
39
+ if inside_string
40
+ next_not_apostroph_index = sql.index(/[^']/,idx)
41
+ next_not_apostroph_index = len unless next_not_apostroph_index
42
+ apostrophs_length = next_not_apostroph_index - idx
43
+ idx = next_not_apostroph_index
44
+ masked_sql << mask * apostrophs_length
45
+ inside_string = !(apostrophs_length % 2 == 1)
46
+ else
47
+ inside_string = true
48
+ masked_sql << mask
49
+ idx += 1
50
+ end
51
+ else
52
+ if inside_string
53
+ masked_sql << mask
54
+ else
55
+ masked_sql << ch
56
+ end
57
+ idx += 1
58
+ end
59
+ end
60
+
61
+ masked_sql
62
+ end
63
+
64
+
65
+ def mask_brackets(sql, mask='y')
66
+ idx = 0
67
+ len = sql.size
68
+ masked_sql = ''
69
+ stack_size = 0
70
+ while idx < len
71
+ ch = sql[idx]
72
+ case ch
73
+ when '('
74
+ stack_size += 1
75
+ masked_sql << mask
76
+ when ')'
77
+ stack_size -= 1
78
+ masked_sql << mask
79
+ else
80
+ if stack_size > 0
81
+ masked_sql << mask
82
+ else
83
+ masked_sql << ch
84
+ end
85
+ end
86
+ idx += 1
87
+ end
88
+
89
+ masked_sql
90
+ end
91
+ end
@@ -1,3 +1,3 @@
1
1
  module CalculableAttrs
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -1,8 +1,11 @@
1
- module CalculableAttrs; end
1
+ module CalculableAttrs
2
+ module Utils; end
3
+ end
2
4
 
3
5
  require 'calculable_attrs/active_record'
4
6
  require 'calculable_attrs/calculator'
5
7
  require 'calculable_attrs/model_calculable_attrs_scope'
8
+ require 'calculable_attrs/utils/sql_parser'
6
9
 
7
10
  ::ActiveRecord::Base.include(CalculableAttrs::ActiveRecord::Base)
8
11
  ::ActiveRecord::Relation.include(CalculableAttrs::ActiveRecord::Relation)
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.9
4
+ version: 0.0.10
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-09-03 00:00:00.000000000 Z
11
+ date: 2014-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -113,6 +113,7 @@ files:
113
113
  - lib/calculable_attrs/active_record/relation.rb
114
114
  - lib/calculable_attrs/calculator.rb
115
115
  - lib/calculable_attrs/model_calculable_attrs_scope.rb
116
+ - lib/calculable_attrs/utils/sql_parser.rb
116
117
  - lib/calculable_attrs/version.rb
117
118
  - lib/tasks/calculable_tasks.rake
118
119
  homepage: https://github.com/dmitrysharkov/calculable_attrs