rails_or 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ruby.yml +62 -0
- data/.gitignore +10 -9
- data/.rubocop.yml +1227 -0
- data/CHANGELOG.md +77 -77
- data/CODE_OF_CONDUCT.md +48 -48
- data/LICENSE.txt +21 -21
- data/README.md +152 -133
- data/Rakefile +5 -5
- data/bin/console +3 -3
- data/bin/setup +8 -8
- data/gemfiles/3.2.gemfile +10 -13
- data/gemfiles/4.2.gemfile +10 -13
- data/gemfiles/5.0.gemfile +10 -13
- data/gemfiles/5.1.gemfile +10 -13
- data/gemfiles/5.2.gemfile +10 -0
- data/gemfiles/6.0.gemfile +10 -0
- data/gemfiles/6.1.gemfile +10 -0
- data/lib/rails_or.rb +63 -119
- data/lib/rails_or/active_record/extension.rb +52 -0
- data/lib/rails_or/patches/null_relation.rb +8 -0
- data/lib/rails_or/version.rb +3 -3
- data/lib/rails_or/where_binding_mixs.rb +38 -38
- data/rails_or.gemspec +43 -37
- metadata +26 -10
- data/.travis.yml +0 -21
data/Rakefile
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rake/testtask'
|
3
3
|
|
4
4
|
Rake::TestTask.new(:test) do |t|
|
5
|
-
t.libs <<
|
6
|
-
t.libs <<
|
5
|
+
t.libs << 'test'
|
6
|
+
t.libs << 'lib'
|
7
7
|
t.test_files = FileList['test/**/*_test.rb']
|
8
8
|
end
|
9
9
|
|
10
|
-
task :
|
10
|
+
task default: :test
|
data/bin/console
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'rails_or'
|
5
5
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
@@ -10,5 +10,5 @@ require "rails_or"
|
|
10
10
|
# require "pry"
|
11
11
|
# Pry.start
|
12
12
|
|
13
|
-
require
|
13
|
+
require 'irb'
|
14
14
|
IRB.start
|
data/bin/setup
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
set -euo pipefail
|
3
|
-
IFS=$'\n\t'
|
4
|
-
set -vx
|
5
|
-
|
6
|
-
bundle install --gemfile=gemfiles/4.2.gemfile
|
7
|
-
|
8
|
-
# Do any other automated setup that you need to do here
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
set -euo pipefail
|
3
|
+
IFS=$'\n\t'
|
4
|
+
set -vx
|
5
|
+
|
6
|
+
bundle install --gemfile=gemfiles/4.2.gemfile
|
7
|
+
|
8
|
+
# Do any other automated setup that you need to do here
|
data/gemfiles/3.2.gemfile
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gemspec :path => "../"
|
13
|
-
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activerecord', '~> 3.2.0'
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem 'simplecov', '< 0.18'
|
7
|
+
gem 'sqlite3', '~> 1.3.6'
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec path: '../'
|
data/gemfiles/4.2.gemfile
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gemspec :path => "../"
|
13
|
-
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activerecord', '~> 4.2.0'
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem 'simplecov', '< 0.18'
|
7
|
+
gem 'sqlite3', '~> 1.3.6'
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec path: '../'
|
data/gemfiles/5.0.gemfile
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gemspec :path => "../"
|
13
|
-
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activerecord', '~> 5.0.0'
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem 'simplecov', '< 0.18'
|
7
|
+
gem 'sqlite3', '~> 1.3.6'
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec path: '../'
|
data/gemfiles/5.1.gemfile
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
gemspec :path => "../"
|
13
|
-
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'activerecord', '~> 5.1.0'
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem 'simplecov', '< 0.18'
|
7
|
+
gem 'sqlite3', '~> 1.3.6'
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec path: '../'
|
data/lib/rails_or.rb
CHANGED
@@ -1,119 +1,63 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require 'active_record'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def or_having(hash)
|
65
|
-
self.or(rails_or_spwan_relation(:having, hash))
|
66
|
-
end
|
67
|
-
|
68
|
-
private
|
69
|
-
|
70
|
-
def rails_or_values_to_arel(values)
|
71
|
-
values.map!{|x| rails_or_wrap_arel(x) }
|
72
|
-
return (values.size > 1 ? Arel::Nodes::And.new(values) : values)
|
73
|
-
end
|
74
|
-
|
75
|
-
def rails_or_wrap_arel(node)
|
76
|
-
return node if Arel::Nodes::Equality === node
|
77
|
-
return Arel::Nodes::Grouping.new(String === node ? Arel.sql(node) : node)
|
78
|
-
end
|
79
|
-
|
80
|
-
def rails_or_parse_parameter(*other)
|
81
|
-
other = other.first if other.size == 1
|
82
|
-
case other
|
83
|
-
when Hash ; rails_or_spwan_relation(:where, other)
|
84
|
-
when Array ; rails_or_spwan_relation(:where, other)
|
85
|
-
when String ; rails_or_spwan_relation(:where, other)
|
86
|
-
else ; other
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def rails_or_copy_values_to(relation) # For Rails 5
|
91
|
-
relation.joins_values = self.joins_values
|
92
|
-
relation.limit_value = self.limit_value
|
93
|
-
relation.group_values = self.group_values
|
94
|
-
relation.distinct_value = self.distinct_value
|
95
|
-
relation.order_values = self.order_values
|
96
|
-
relation.offset_value = self.offset_value
|
97
|
-
relation.references_values = self.references_values
|
98
|
-
end
|
99
|
-
|
100
|
-
def rails_or_spwan_relation(method, condition)
|
101
|
-
relation = klass.send(method, condition)
|
102
|
-
relation.send(ASSIGN_FROM_VALUE, send(FROM_VALUE_METHOD))
|
103
|
-
rails_or_copy_values_to(relation) if IS_RAILS5_FLAG
|
104
|
-
return relation
|
105
|
-
end
|
106
|
-
|
107
|
-
def rails_or_get_current_scope
|
108
|
-
return self.clone if IS_RAILS3_FLAG
|
109
|
-
# ref: https://github.com/rails/rails/blob/17ef58db1776a795c9f9e31a1634db7bcdc3ecdf/activerecord/lib/active_record/scoping/named.rb#L26
|
110
|
-
# return self.all # <- cannot use this because some gem changes this method's behavior
|
111
|
-
return (self.current_scope || self.default_scoped).clone
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
class ActiveRecord::Base
|
116
|
-
def self.or(*args)
|
117
|
-
self.where('').or(*args)
|
118
|
-
end
|
119
|
-
end
|
1
|
+
require 'rails_or/version'
|
2
|
+
require 'rails_or/where_binding_mixs'
|
3
|
+
require 'active_record'
|
4
|
+
require 'rails_or/patches/null_relation' if defined?(ActiveRecord::NullRelation)
|
5
|
+
require 'rails_or/active_record/extension'
|
6
|
+
|
7
|
+
module RailsOr
|
8
|
+
IS_RAILS3_FLAG = Gem::Version.new(ActiveRecord::VERSION::STRING) < Gem::Version.new('4.0.0')
|
9
|
+
IS_RAILS5_FLAG = Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('5.0.0')
|
10
|
+
FROM_VALUE_METHOD = %i[from_value from_clause].find{|s| ActiveRecord::Relation.method_defined?(s) }
|
11
|
+
ASSIGN_FROM_VALUE = :"#{FROM_VALUE_METHOD}="
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def values_to_arel(values)
|
15
|
+
values.map!{|x| wrap_arel(x) }
|
16
|
+
return (values.size > 1 ? Arel::Nodes::And.new(values) : values)
|
17
|
+
end
|
18
|
+
|
19
|
+
def spawn_relation(relation, method, condition)
|
20
|
+
new_relation = relation.klass.send(method, condition)
|
21
|
+
|
22
|
+
from_value = relation.send(FROM_VALUE_METHOD)
|
23
|
+
new_relation.send(ASSIGN_FROM_VALUE, from_value) if from_value.present?
|
24
|
+
|
25
|
+
copy_values(new_relation, relation) if IS_RAILS5_FLAG
|
26
|
+
return new_relation
|
27
|
+
end
|
28
|
+
|
29
|
+
def get_current_scope(relation)
|
30
|
+
return relation.clone if IS_RAILS3_FLAG
|
31
|
+
# ref: https://github.com/rails/rails/blob/17ef58db1776a795c9f9e31a1634db7bcdc3ecdf/activerecord/lib/active_record/scoping/named.rb#L26
|
32
|
+
# return relation.all # <- cannot use this because some gem changes this method's behavior
|
33
|
+
return (relation.current_scope || relation.default_scoped).clone
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_parameter(relation, *other)
|
37
|
+
other = other.first if other.size == 1
|
38
|
+
case other
|
39
|
+
when Hash ; spawn_relation(relation, :where, other)
|
40
|
+
when Array ; spawn_relation(relation, :where, other)
|
41
|
+
when String ; spawn_relation(relation, :where, other)
|
42
|
+
else ; other
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def wrap_arel(node)
|
49
|
+
return node if Arel::Nodes::Equality === node
|
50
|
+
return Arel::Nodes::Grouping.new(String === node ? Arel.sql(node) : node)
|
51
|
+
end
|
52
|
+
|
53
|
+
def copy_values(to, from) # For Rails 5, 6
|
54
|
+
to.joins_values = from.joins_values if from.joins_values.any?
|
55
|
+
to.limit_value = from.limit_value
|
56
|
+
to.group_values = from.group_values if from.group_values.any?
|
57
|
+
to.distinct_value = from.distinct_value
|
58
|
+
to.order_values = from.order_values if from.order_values.any?
|
59
|
+
to.offset_value = from.offset_value
|
60
|
+
to.references_values = from.references_values
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class ActiveRecord::Relation
|
2
|
+
if method_defined?(:or)
|
3
|
+
if not method_defined?(:rails5_or)
|
4
|
+
alias rails5_or or
|
5
|
+
def or(*other)
|
6
|
+
rails5_or(RailsOr.parse_parameter(self, *other))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
else
|
10
|
+
def or(*other)
|
11
|
+
other = RailsOr.parse_parameter(self, *other)
|
12
|
+
combining = group_values.any? ? :having : :where
|
13
|
+
left = RailsOr::WhereBindingMixs.new(send("#{combining}_values"), bind_values)
|
14
|
+
right = RailsOr::WhereBindingMixs.new(other.send("#{combining}_values"), other.bind_values)
|
15
|
+
common = left & right
|
16
|
+
|
17
|
+
left -= common
|
18
|
+
right -= common
|
19
|
+
|
20
|
+
if left.where_values.any? && right.where_values.any?
|
21
|
+
arel_or = Arel::Nodes::Or.new(
|
22
|
+
RailsOr.values_to_arel(left.where_values),
|
23
|
+
RailsOr.values_to_arel(right.where_values),
|
24
|
+
)
|
25
|
+
common += RailsOr::WhereBindingMixs.new([arel_or], left.bind_values + right.bind_values)
|
26
|
+
end
|
27
|
+
|
28
|
+
relation = RailsOr.get_current_scope(self)
|
29
|
+
if defined?(ActiveRecord::NullRelation) # Rails 3 does not have ActiveRecord::NullRelation
|
30
|
+
return other if relation.is_a?(ActiveRecord::NullRelation)
|
31
|
+
return relation if other.is_a?(ActiveRecord::NullRelation)
|
32
|
+
end
|
33
|
+
relation.send("#{combining}_values=", common.where_values)
|
34
|
+
relation.bind_values = common.bind_values
|
35
|
+
return relation
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def or_not(*args) # Works in Rails 4+
|
40
|
+
self.or(klass.where.not(*args))
|
41
|
+
end
|
42
|
+
|
43
|
+
def or_having(hash)
|
44
|
+
self.or(RailsOr.spawn_relation(self, :having, hash))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class ActiveRecord::Base
|
49
|
+
def self.or(*args)
|
50
|
+
where('').or(*args)
|
51
|
+
end
|
52
|
+
end
|
data/lib/rails_or/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module RailsOr
|
2
|
-
VERSION =
|
3
|
-
end
|
1
|
+
module RailsOr
|
2
|
+
VERSION = '1.1.9'
|
3
|
+
end
|
@@ -1,38 +1,38 @@
|
|
1
|
-
class RailsOr::WhereBindingMixs
|
2
|
-
attr_reader :where_values
|
3
|
-
attr_reader :bind_values
|
4
|
-
|
5
|
-
def initialize(where_values, bind_values)
|
6
|
-
@where_values = where_values
|
7
|
-
@bind_values = bind_values
|
8
|
-
end
|
9
|
-
|
10
|
-
def +(other)
|
11
|
-
self.class.new(@where_values + other.where_values, @bind_values + other.bind_values)
|
12
|
-
end
|
13
|
-
|
14
|
-
def -(other)
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def &(other)
|
19
|
-
common_where_values = @where_values & other.where_values
|
20
|
-
return
|
21
|
-
end
|
22
|
-
|
23
|
-
def select
|
24
|
-
binds_index = 0
|
25
|
-
new_bind_values = []
|
26
|
-
new_where_values = @where_values.select do |node|
|
27
|
-
flag = yield(node)
|
28
|
-
if not node.is_a?(String)
|
29
|
-
binds_contains = node.grep(Arel::Nodes::BindParam).size
|
30
|
-
pre_binds_index = binds_index
|
31
|
-
binds_index += binds_contains
|
32
|
-
(pre_binds_index...binds_index).each{|i| new_bind_values << @bind_values[i] } if flag
|
33
|
-
end
|
34
|
-
next flag
|
35
|
-
end
|
36
|
-
return self.class.new(new_where_values, new_bind_values)
|
37
|
-
end
|
38
|
-
end
|
1
|
+
class RailsOr::WhereBindingMixs
|
2
|
+
attr_reader :where_values
|
3
|
+
attr_reader :bind_values
|
4
|
+
|
5
|
+
def initialize(where_values, bind_values)
|
6
|
+
@where_values = where_values
|
7
|
+
@bind_values = bind_values
|
8
|
+
end
|
9
|
+
|
10
|
+
def +(other)
|
11
|
+
self.class.new(@where_values + other.where_values, @bind_values + other.bind_values)
|
12
|
+
end
|
13
|
+
|
14
|
+
def -(other)
|
15
|
+
select{|node| !other.where_values.include?(node) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def &(other)
|
19
|
+
common_where_values = @where_values & other.where_values
|
20
|
+
return select{|node| common_where_values.include?(node) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def select
|
24
|
+
binds_index = 0
|
25
|
+
new_bind_values = []
|
26
|
+
new_where_values = @where_values.select do |node|
|
27
|
+
flag = yield(node)
|
28
|
+
if not node.is_a?(String)
|
29
|
+
binds_contains = node.grep(Arel::Nodes::BindParam).size
|
30
|
+
pre_binds_index = binds_index
|
31
|
+
binds_index += binds_contains
|
32
|
+
(pre_binds_index...binds_index).each{|i| new_bind_values << @bind_values[i] } if flag
|
33
|
+
end
|
34
|
+
next flag
|
35
|
+
end
|
36
|
+
return self.class.new(new_where_values, new_bind_values)
|
37
|
+
end
|
38
|
+
end
|