rails_select_on_includes 0.4.8 → 0.4.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/README.md +13 -5
- data/lib/rails_select_on_includes.rb +89 -96
- data/lib/rails_select_on_includes/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b57b9f8c06e67c99cf4719b7bb192778e4da854
|
4
|
+
data.tar.gz: f551cd5aac2d88d2eb159e64002194cf892cc3b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dd172b53816e4ddd23c827827f51a27811739496c4b446eed27d860e3dfb61e023e24b550a6a8cdcaa5c4df88f179bf566a6cf7642177ed9f37dd1f75752fc6
|
7
|
+
data.tar.gz: f45c2992a8f78bb673946ae334764b986cdcea5a8c90aae2c1d5438f8647a0358c105bfc6e2a5b14948f76ffe738342ca38a5e8e62822ac11fe8bf8d96d0de80
|
data/README.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
#Rails version
|
2
|
+
|
3
|
+
Supports rails 4.x and rails 5 now!
|
4
|
+
|
1
5
|
# RailsSelectOnIncludes
|
2
6
|
|
3
|
-
This gem solves issue in rails: https://github.com/rails/rails/issues/15185 for base_class.
|
7
|
+
This gem solves issue in rails: https://github.com/rails/rails/issues/15185 for base_class.
|
4
8
|
|
5
9
|
It was impossible to select virtual attributes to object from its relations or any other way
|
6
|
-
when using includes and where.
|
10
|
+
when using includes and where ( actually when includes becomes eager_load, i.e. when you add not SOME_CONDITION, but SOME_CONDITION_ON_INCLUDES, http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html ).
|
7
11
|
|
8
12
|
Example from upper rails issue:
|
9
13
|
|
@@ -30,7 +34,7 @@ post.comments.first.testval # Undefined method!
|
|
30
34
|
|
31
35
|
Данный gem решает проблему в рельсах с виртуальными аттрибутами при использовании includes,
|
32
36
|
когда рельсы собирают в запрос в joins с алиасами на все аттрибуты. В настоящий момент в модель не собираются
|
33
|
-
никаким боком виртуальные
|
37
|
+
никаким боком виртуальные аттрибуты ( имеется ввиду когда includes ведет себя как eager_load и создает сложный одинарный запрос, подробнее: http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html ).
|
34
38
|
|
35
39
|
В частности проблема описана здесь: https://github.com/rails/rails/issues/15185
|
36
40
|
|
@@ -56,12 +60,16 @@ post.comments.first.testval # Undefined method!
|
|
56
60
|
```
|
57
61
|
|
58
62
|
|
59
|
-
## Installation
|
63
|
+
## Installation
|
60
64
|
|
61
65
|
Add this line to your application's Gemfile:
|
62
66
|
|
63
67
|
```ruby
|
64
|
-
|
68
|
+
#rails 4
|
69
|
+
gem 'rails_select_on_includes', '~> 0.4.3'
|
70
|
+
|
71
|
+
#rails 5
|
72
|
+
gem 'rails_select_on_includes', '~> 0.5.0'
|
65
73
|
```
|
66
74
|
|
67
75
|
And then execute:
|
@@ -1,112 +1,106 @@
|
|
1
1
|
require 'active_support/deprecation'
|
2
2
|
require 'active_support/core_ext/string/filters'
|
3
3
|
|
4
|
-
module ActiveRecord
|
5
|
-
module Associations
|
6
|
-
class JoinDependency # :nodoc:
|
7
|
-
|
8
|
-
class Aliases # :nodoc:
|
9
|
-
def initialize(tables)
|
10
|
-
@tables = tables
|
11
|
-
@alias_cache = tables.each_with_object({}) { |table,h|
|
12
|
-
h[table.node] = table.columns.each_with_object({}) { |column,i|
|
13
|
-
i[column.name] = column.alias
|
14
|
-
}
|
15
|
-
}
|
16
|
-
@name_and_alias_cache = tables.each_with_object({}) { |table,h|
|
17
|
-
h[table.node] = table.columns.map { |column|
|
18
|
-
[column.name, column.alias]
|
19
|
-
}
|
20
|
-
@base_class_node_aliases ||= h[table.node] if table.node.is_a?(ActiveRecord::Associations::JoinDependency::JoinBase)
|
21
|
-
}
|
22
|
-
|
23
|
-
@virtual_attributes_names = []
|
24
|
-
end
|
25
|
-
# valid formats are:
|
26
|
-
# 1 'table_name.column' or 'table_name.column as column_1' will be parsed! distinct on can be used also
|
27
|
-
# 2 {table_name: column} or { table_name: [column1, column2] }
|
28
|
-
# 3 table_name: 2
|
29
|
-
def update_aliases_to_select_values( select_values )
|
30
|
-
return if select_values.blank?
|
31
|
-
select_values.each do |sv|
|
32
|
-
# if sv is symbol that we assume that its a base table column and it will be aliased and added as usual
|
33
|
-
# all we need is some specials joins+select from related tables
|
34
|
-
if sv.is_a?(Hash)
|
35
|
-
flatten_hash_values(sv).each{|sub_sv| @base_class_node_aliases << [sub_sv, sub_sv]; @virtual_attributes_names << sub_sv }
|
36
|
-
elsif sv.is_a?(String)
|
37
|
-
# this is the case of long raw select
|
38
|
-
sv.split( ", " ).each do |sub_sv|
|
39
|
-
if sub_sv[/.+ as .+/i]
|
40
|
-
selected_column = sub_sv[/ as .+/i][4..-1]
|
41
|
-
@base_class_node_aliases << [selected_column, selected_column]
|
42
|
-
@virtual_attributes_names << selected_column
|
43
|
-
elsif sub_sv[/.+\.[^\*]+/]
|
44
|
-
selected_column = sub_sv[/\..+/][1..-1]
|
45
|
-
@base_class_node_aliases << [selected_column, selected_column]
|
46
|
-
@virtual_attributes_names << selected_column
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
4
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
5
|
+
::ActiveRecord::Associations::JoinDependency::Aliases.class_eval do # :nodoc:
|
6
|
+
def initialize(tables)
|
7
|
+
@tables = tables
|
8
|
+
@alias_cache = tables.each_with_object({}) { |table,h|
|
9
|
+
h[table.node] = table.columns.each_with_object({}) { |column,i|
|
10
|
+
i[column.name] = column.alias
|
11
|
+
}
|
12
|
+
}
|
13
|
+
@name_and_alias_cache = tables.each_with_object({}) { |table,h|
|
14
|
+
h[table.node] = table.columns.map { |column|
|
15
|
+
[column.name, column.alias]
|
16
|
+
}
|
17
|
+
@base_class_node_aliases ||= h[table.node] if table.node.is_a?(ActiveRecord::Associations::JoinDependency::JoinBase)
|
18
|
+
}
|
19
|
+
|
20
|
+
@virtual_attributes_names = []
|
21
|
+
end
|
22
|
+
# valid formats are:
|
23
|
+
# 1 'table_name.column' or 'table_name.column as column_1' will be parsed! distinct on can be used also
|
24
|
+
# 2 {table_name: column} or { table_name: [column1, column2] }
|
25
|
+
# 3 table_name: 2
|
26
|
+
def update_aliases_to_select_values( select_values )
|
27
|
+
return if select_values.blank?
|
28
|
+
select_values.each do |sv|
|
29
|
+
# if sv is symbol that we assume that its a base table column and it will be aliased and added as usual
|
30
|
+
# all we need is some specials joins+select from related tables
|
31
|
+
if sv.is_a?(Hash)
|
32
|
+
flatten_hash_values(sv).each{|sub_sv| @base_class_node_aliases << [sub_sv, sub_sv]; @virtual_attributes_names << sub_sv }
|
33
|
+
elsif sv.is_a?(String)
|
34
|
+
# this is the case of long raw select
|
35
|
+
sv.split( ", " ).each do |sub_sv|
|
36
|
+
if sub_sv[/.+ as .+/i]
|
37
|
+
selected_column = sub_sv[/ as .+/i][4..-1]
|
38
|
+
@base_class_node_aliases << [selected_column, selected_column]
|
39
|
+
@virtual_attributes_names << selected_column
|
40
|
+
elsif sub_sv[/.+\.[^\*]+/]
|
41
|
+
selected_column = sub_sv[/\..+/][1..-1]
|
42
|
+
@base_class_node_aliases << [selected_column, selected_column]
|
43
|
+
@virtual_attributes_names << selected_column
|
44
|
+
end
|
60
45
|
end
|
61
46
|
end
|
47
|
+
end
|
48
|
+
end
|
62
49
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
50
|
+
def slice_selected_attr_types( column_types )
|
51
|
+
column_types.slice( *@virtual_attributes_names )
|
52
|
+
end
|
68
53
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
|
75
|
-
}
|
76
|
-
}
|
77
|
-
|
78
|
-
model_cache = Hash.new { |h,klass| h[klass] = {} }
|
79
|
-
parents = model_cache[join_root]
|
80
|
-
column_aliases = aliases.column_aliases join_root
|
81
|
-
|
82
|
-
message_bus = ActiveSupport::Notifications.instrumenter
|
83
|
-
|
84
|
-
payload = {
|
85
|
-
record_count: result_set.length,
|
86
|
-
class_name: join_root.base_klass.name
|
87
|
-
}
|
88
|
-
|
89
|
-
message_bus.instrument('instantiation.active_record', payload) do
|
90
|
-
result_set.each { |row_hash|
|
91
|
-
parent_key = primary_key ? row_hash[primary_key] : row_hash
|
92
|
-
# DISTINCTION PART > join_root.instantiate(row_hash, column_aliases, aliases.slice_selected_attr_types( result_set.column_types ) )
|
93
|
-
# PREVIOUS > join_root.instantiate(row_hash, column_aliases )
|
94
|
-
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, aliases.slice_selected_attr_types( result_set.column_types ) )
|
95
|
-
construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
|
96
|
-
}
|
97
|
-
end
|
54
|
+
private
|
55
|
+
def flatten_hash_values( some_hash )
|
56
|
+
some_hash.values.map{ |value| value.is_a?(Hash) ? flatten_hash_values( value ) : value }.flatten
|
57
|
+
end
|
58
|
+
end
|
98
59
|
|
99
|
-
|
100
|
-
|
60
|
+
::ActiveRecord::Associations::JoinDependency::JoinBase.class_eval do
|
61
|
+
def instantiate(row, aliases, column_types = {}, &block)
|
62
|
+
base_klass.instantiate(extract_record(row, aliases), column_types, &block)
|
63
|
+
end
|
64
|
+
end
|
101
65
|
|
66
|
+
::ActiveRecord::Associations::JoinDependency.class_eval do
|
67
|
+
def instantiate(result_set, aliases)
|
68
|
+
primary_key = aliases.column_alias(join_root, join_root.primary_key)
|
69
|
+
|
70
|
+
seen = Hash.new { |h,parent_klass|
|
71
|
+
h[parent_klass] = Hash.new { |i,parent_id|
|
72
|
+
i[parent_id] = Hash.new { |j,child_klass| j[child_klass] = {} }
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
model_cache = Hash.new { |h,klass| h[klass] = {} }
|
77
|
+
parents = model_cache[join_root]
|
78
|
+
column_aliases = aliases.column_aliases join_root
|
79
|
+
|
80
|
+
message_bus = ActiveSupport::Notifications.instrumenter
|
81
|
+
|
82
|
+
payload = {
|
83
|
+
record_count: result_set.length,
|
84
|
+
class_name: join_root.base_klass.name
|
85
|
+
}
|
86
|
+
|
87
|
+
message_bus.instrument('instantiation.active_record', payload) do
|
88
|
+
result_set.each { |row_hash|
|
89
|
+
parent_key = primary_key ? row_hash[primary_key] : row_hash
|
90
|
+
# DISTINCTION PART > join_root.instantiate(row_hash, column_aliases, aliases.slice_selected_attr_types( result_set.column_types ) )
|
91
|
+
# PREVIOUS > join_root.instantiate(row_hash, column_aliases )
|
92
|
+
parent = parents[parent_key] ||= join_root.instantiate(row_hash, column_aliases, aliases.slice_selected_attr_types( result_set.column_types ) )
|
93
|
+
construct(parent, join_root, row_hash, result_set, seen, model_cache, aliases)
|
94
|
+
}
|
102
95
|
end
|
96
|
+
|
97
|
+
parents.values
|
103
98
|
end
|
104
99
|
end
|
105
100
|
|
106
|
-
module ActiveRecord
|
107
|
-
module FinderMethods
|
108
101
|
|
109
|
-
|
102
|
+
::ActiveRecord::FinderMethods.class_eval do
|
103
|
+
def find_with_associations
|
110
104
|
# NOTE: the JoinDependency constructed here needs to know about
|
111
105
|
# any joins already present in `self`, so pass them in
|
112
106
|
#
|
@@ -138,7 +132,6 @@ module ActiveRecord
|
|
138
132
|
end
|
139
133
|
end
|
140
134
|
end
|
141
|
-
|
142
|
-
end
|
143
135
|
end
|
144
136
|
|
137
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_select_on_includes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- alekseyl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-02-
|
11
|
+
date: 2017-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|