activerecord_any_of 1.4 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 47eee92223e93989b63ad4b3ae077bf438bf70fc
4
- data.tar.gz: 31b4d5f385ea3d699ad5abca878ef7612649959c
2
+ SHA256:
3
+ metadata.gz: 3f426526955604bce6800c7d7b84913cd198ad0a0b821be1e5fa7dc5b0bb215b
4
+ data.tar.gz: '08597e05b96433c2bd29cd95750beba918810fe50c320733bb864e93b273eeb1'
5
5
  SHA512:
6
- metadata.gz: 1b2d782aa4da21b7823f1ae978f6effcc0d55460dbbdb51bb7fabdd34d21ce9e50023de2c237857dfba6729d9d1d5c2f377d76d5f842f158d8ff5c4ff6a50552
7
- data.tar.gz: f174291bbc3e50f0a48ac8414988f84d01413f21a3a603b63ebc8270afd9163800d91f87f72351b9972ecc6f433fec5860ebb24deb3f17cfd77d6ff058549d7b
6
+ metadata.gz: a4451ade0e580f14d30f943989c3263e1ee322bfb6d9a32483c29407c1f9b3e96e4781b7ec9a6adda3ae02675c711f0d4e6009e8c88d378fc1786ad02e33660b
7
+ data.tar.gz: e64bb560165f871e14687b27bab765d30e5a575bce057b1387a58115ec40cb8b7b15707228675f0ade9847bfeb94f7326239c97d38fd13cc1bc78d24b03bb428
data/README.md CHANGED
@@ -6,11 +6,36 @@ This gem provides `#any_of` and `#none_of` on ActiveRecord.
6
6
 
7
7
  `#any_of` is inspired by [any_of from mongoid](http://two.mongoid.org/docs/querying/criteria.html#any_of).
8
8
 
9
- Its main purpose is to both :
9
+ It was released before `#or` was implemented in ActiveRecord. Its main purpose was to both :
10
10
 
11
11
  * remove the need to write a sql string when we want an `OR`
12
12
  * allows to write dynamic `OR` queries, which would be a pain with a string
13
13
 
14
+ It can still be useful today given the various ways you can call it. While
15
+ ActiveRecord's `#or` only accepts relations, you can pass to `#any_of` and
16
+ `#none_of` the same kind of conditions you would pass to `#where`:
17
+
18
+
19
+ ```ruby
20
+ User.where.any_of({ active: true }, ['offline = ?', required_status], 'posts_count > 0')
21
+ ```
22
+
23
+ And you can still use relations, like AR's `#or`:
24
+
25
+ ```ruby
26
+ inactive_users = User.not_activated
27
+ offline_users = User.offline
28
+
29
+ User.where.any_of(inactive_users, offline)
30
+ ```
31
+
32
+ ## Installation
33
+
34
+ In your Gemfile :
35
+
36
+ ```
37
+ gem 'activerecord_any_of'
38
+ ```
14
39
 
15
40
  ## Usage
16
41
 
@@ -18,7 +43,6 @@ Its main purpose is to both :
18
43
 
19
44
  It allows to compute an `OR` like query that leverages AR's `#where` syntax:
20
45
 
21
-
22
46
  #### basics
23
47
 
24
48
  ```ruby
@@ -26,26 +50,23 @@ User.where.any_of(first_name: 'Joe', last_name: 'Joe')
26
50
  # => SELECT * FROM users WHERE first_name = 'Joe' OR last_name = 'Joe'
27
51
  ```
28
52
 
29
-
30
53
  #### grouped conditions
31
54
 
32
55
  You can separate sets of hash condition by explicitly group them as hashes :
33
56
 
34
57
  ```ruby
35
- User.where.any_of({first_name: 'John', last_name: 'Joe'}, {first_name: 'Simon', last_name: 'Joe'})
58
+ User.where.any_of({ first_name: 'John', last_name: 'Joe' }, { first_name: 'Simon', last_name: 'Joe' })
36
59
  # => SELECT * FROM users WHERE ( first_name = 'John' AND last_name = 'Joe' ) OR ( first_name = 'Simon' AND last_name = 'Joe' )
37
60
  ```
38
61
 
39
-
40
62
  #### it's plain #where syntax
41
63
 
42
64
  Each `#any_of` set is the same kind you would have passed to #where :
43
65
 
44
66
  ```ruby
45
- Client.where.any_of("orders_count = '2'", ["name = ?", 'Joe'], {email: 'joe@example.com'})
67
+ Client.where.any_of("orders_count = '2'", ["name = ?", 'Joe'], { email: 'joe@example.com' })
46
68
  ```
47
69
 
48
-
49
70
  #### with relations
50
71
 
51
72
  You can as well pass `#any_of` to other relations :
@@ -54,16 +75,14 @@ You can as well pass `#any_of` to other relations :
54
75
  Client.where("orders_count = '2'").where.any_of({ email: 'joe@example.com' }, { email: 'john@example.com' })
55
76
  ```
56
77
 
57
-
58
78
  #### with associations
59
79
 
60
80
  And with associations :
61
81
 
62
82
  ```ruby
63
- User.find(1).posts.where.any_of({published: false}, "user_id IS NULL")
83
+ User.find(1).posts.where.any_of({ published: false }, 'user_id IS NULL')
64
84
  ```
65
85
 
66
-
67
86
  #### dynamic OR queries
68
87
 
69
88
  The best part is that `#any_of` accepts other relations as parameter, to help compute
@@ -81,64 +100,6 @@ inactive_users = User.where.any_of(banned_users, unconfirmed_users)
81
100
 
82
101
  ```ruby
83
102
  banned_users = User.where(banned: true)
84
- unconfirmed_users = User.where("confirmed_at IS NULL")
103
+ unconfirmed_users = User.where('confirmed_at IS NULL')
85
104
  active_users = User.where.none_of(banned_users, unconfirmed_users)
86
105
  ```
87
-
88
- ## Rails-3
89
-
90
- `activerecord_any_of` uses WhereChain, which has been introduced in rails-4. In
91
- rails-3, simply call `#any_of` and `#none_of` directly, without using `#where` :
92
-
93
- ```ruby
94
- manual_removal = User.where(id: params[:users][:destroy_ids])
95
- User.any_of(manual_removal, "email like '%@example.com'", {banned: true})
96
- @company.users.any_of(manual_removal, "email like '%@example.com'", {banned: true})
97
- User.where(offline: false).any_of( manual_removal, "email like '%@example.com'", {banned: true})
98
- ```
99
-
100
- ## Installation
101
-
102
- In your Gemfile :
103
-
104
- ```
105
- gem 'activerecord_any_of'
106
- ```
107
-
108
- Activerecord_any_of supports rails >= 3.2.13 and rails-4 (let me know if tests
109
- pass for rails < 3.2.13, I may edit gem dependencies).
110
-
111
-
112
- ## Why not an `#or` method instead ?
113
-
114
- ```ruby
115
- User.where( "email LIKE '%@example.com" ).where( active: true ).or( offline: true )
116
- ```
117
-
118
- What does this query do ? `where (email LIKE '%@example.com' AND active = '1' )
119
- OR offline = '1'` ? Or `where email LIKE '%@example.com' AND ( active = '1' OR
120
- offline = '1' )` ? This can quickly get messy and counter intuitive.
121
-
122
- The MongoId solution is quite elegant. Using `#any_of`, it is made clear which
123
- conditions are grouped through `OR` and which are grouped through `AND` :
124
-
125
- * `User.where( "email LIKE '%@example.com" ).where.any_of({ active: true }, { offline: true })`
126
- * `fakes = User.where( "email LIKE '%@example.com'" ).where( active: true ); User.where.any_of( fakes, { offline: true })`
127
-
128
-
129
- ## Running test
130
-
131
- Testing is done using TravisCI. You can use the wonderful [wwtd gem](https://github.com/grosser/wwtd) to run all tests locally. By default, the task to run is `bundle exec rake spec`, and will run against `sqlite3` in memory. You can change the database like so: `DB=postgresql bundle exec rake spec`. Please note that you may need to change the credentials for your database in the `database.yml` file. *Do not commit those changes.*
132
-
133
- ## Pull requests
134
-
135
- This gem is extracted from a pull request made to activerecord core, and
136
- still hope to be merged. So, any pull request here should respects usual
137
- [Rails contributing rules](http://guides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-code)
138
- when it makes sense (especially : coding conventions) to make integration
139
- in source pull request easy.
140
-
141
-
142
- ## Licence
143
-
144
- MIT-LICENSE.
data/Rakefile CHANGED
@@ -1,2 +1,4 @@
1
- require "bundler/gem_tasks"
2
- task :default => :spec
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ task default: :spec
@@ -1,136 +1,141 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiverecordAnyOf
4
+ # Main class allowing to build alternative conditions for the query.
2
5
  class AlternativeBuilder
3
6
  def initialize(match_type, context, *queries)
4
- if Hash === queries.first and queries.count == 1
5
- queries = queries.first.each_pair.map { |attr, predicate| Hash[attr, predicate] }
7
+ if queries.first.is_a?(Hash) && (queries.count == 1)
8
+ queries = queries.first.each_pair.map { |attr, predicate| { attr => predicate } }
6
9
  end
7
10
 
8
- @builder = match_type == :negative ? NegativeBuilder.new(context, *queries) : PositiveBuilder.new(context, *queries)
11
+ @builder = if match_type == :negative
12
+ NegativeBuilder.new(context,
13
+ *queries)
14
+ else
15
+ PositiveBuilder.new(context, *queries)
16
+ end
9
17
  end
10
18
 
11
19
  def build
12
20
  @builder.build
13
21
  end
14
22
 
23
+ # Common methods for both the positive builder and the negative one.
15
24
  class Builder
16
- attr_accessor :queries_bind_values, :queries_joins_values
25
+ attr_accessor :queries_joins_values
17
26
 
18
27
  def initialize(context, *source_queries)
19
- @context, @source_queries = context, source_queries
20
- @queries_bind_values, @queries_joins_values = [], { includes: [], joins: [], references: [] }
21
- end
22
-
23
- def build
24
- ActiveRecord::Base.connection.supports_statement_cache? ? with_statement_cache : without_statement_cache
28
+ @context = context
29
+ @source_queries = source_queries
30
+ @queries_joins_values = { includes: [], joins: [], references: [] }
25
31
  end
26
32
 
27
33
  private
28
34
 
29
- def queries
30
- @queries ||= @source_queries.map do |query|
31
- if String === query || Hash === query
32
- query = where(query)
33
- elsif Array === query
34
- query = where(*query)
35
- end
36
-
37
- self.queries_bind_values += query.bind_values if query.bind_values.any?
38
- queries_joins_values[:includes].concat(query.includes_values) if query.includes_values.any?
39
- queries_joins_values[:joins].concat(query.joins_values) if query.joins_values.any?
40
- queries_joins_values[:references].concat(query.references_values) if ActiveRecord::VERSION::MAJOR >= 4 && query.references_values.any?
41
- query.arel.constraints.reduce(:and)
42
- end
35
+ def query_to_relation(query)
36
+ if query.is_a?(String) || query.is_a?(Hash)
37
+ query = where(query)
38
+ elsif query.is_a?(Array)
39
+ query = where(*query)
43
40
  end
44
41
 
45
- def uniq_queries_joins_values
46
- @uniq_queries_joins_values ||= begin
47
- { includes: [], joins: [], references: [] }.tap do |values|
48
- queries_joins_values.each do |join_type, statements|
49
- if statements.first.respond_to?(:to_sql)
50
- values[ join_type ] = statements.uniq( &:to_sql )
51
- else
52
- values[ join_type ] = statements.uniq
53
- end
54
- end
55
- end
56
- end
42
+ query
43
+ end
44
+
45
+ def append_join_values(query)
46
+ { includes_values: :includes, joins_values: :joins, references_values: :references }.each do |q, joins|
47
+ values = query.send(q)
48
+ queries_joins_values[joins].concat(values) if values.any?
57
49
  end
50
+ end
58
51
 
59
- def method_missing(method_name, *args, &block)
60
- @context.send(method_name, *args, &block)
52
+ def queries
53
+ @queries ||= @source_queries.map do |query|
54
+ query = query_to_relation(query)
55
+ append_join_values(query)
56
+ query.arel.constraints.reduce(:and)
61
57
  end
58
+ end
62
59
 
63
- def add_joins_to(relation)
64
- relation = relation.references(uniq_queries_joins_values[:references]) if ActiveRecord::VERSION::MAJOR >= 4
65
- relation = relation.includes(uniq_queries_joins_values[:includes])
66
- relation.joins(uniq_queries_joins_values[:joins])
60
+ def uniq_queries_joins_values
61
+ @uniq_queries_joins_values ||= { includes: [], joins: [], references: [] }.tap do |values|
62
+ queries_joins_values.each do |join_type, statements|
63
+ values[join_type] = if statements.first.respond_to?(:to_sql)
64
+ statements.uniq(&:to_sql)
65
+ else
66
+ statements.uniq
67
+ end
68
+ end
67
69
  end
70
+ end
68
71
 
69
- def add_related_values_to(relation)
70
- relation.bind_values += queries_bind_values
71
- relation.includes_values += uniq_queries_joins_values[:includes]
72
- relation.joins_values += uniq_queries_joins_values[:joins]
73
- relation.references_values += uniq_queries_joins_values[:references] if ActiveRecord::VERSION::MAJOR >= 4
72
+ def map_multiple_bind_values(query)
73
+ query.children.map do |child|
74
+ next unless child.respond_to?(:right)
75
+ next unless child.right.respond_to?(:value)
74
76
 
75
- relation
77
+ child.right.value
76
78
  end
79
+ end
80
+
81
+ def queries_bind_values
82
+ queries.map do |query|
83
+ if query.respond_to?(:children)
84
+ map_multiple_bind_values(query)
85
+ else
86
+ next unless query.respond_to?(:right)
87
+ next unless query.right.respond_to?(:value)
77
88
 
78
- def unprepare_query(query)
79
- query.gsub(/((?<!\\)'.*?(?<!\\)'|(?<!\\)".*?(?<!\\)")|(\=\ \$\d+)/) do |match|
80
- $2 and $2.gsub(/\=\ \$\d+/, "= ?") or match
89
+ query.right.value
81
90
  end
82
- end
83
- end
91
+ end.flatten.compact
92
+ end
84
93
 
85
- class PositiveBuilder < Builder
86
- private
94
+ def method_missing(method_name, *args, &block)
95
+ @context.send(method_name, *args, &block)
96
+ end
87
97
 
88
- def with_statement_cache
89
- if queries && queries_bind_values.any?
90
- relation = where([unprepare_query(queries.reduce(:or).to_sql), *queries_bind_values.map { |v| v[1] }])
91
- else
92
- relation = where(queries.reduce(:or).to_sql)
93
- end
98
+ def respond_to_missing?(method, *)
99
+ @context.respond_to? method
100
+ end
94
101
 
95
- add_joins_to relation
96
- end
102
+ def add_joins_to(relation)
103
+ relation = relation.references(uniq_queries_joins_values[:references])
104
+ relation = relation.includes(uniq_queries_joins_values[:includes])
105
+ relation.joins(uniq_queries_joins_values[:joins])
106
+ end
97
107
 
98
- def without_statement_cache
99
- relation = where(queries.reduce(:or))
100
- add_related_values_to relation
108
+ def unprepare_query(query)
109
+ query.gsub(/((?<!\\)'.*?(?<!\\)'|(?<!\\)".*?(?<!\\)")|(=\ \$\d+)/) do |match|
110
+ ::Regexp.last_match(2)&.gsub(/=\ \$\d+/, '= ?') or match
101
111
  end
112
+ end
102
113
  end
103
114
 
104
- class NegativeBuilder < Builder
105
- private
106
-
107
- def with_statement_cache
108
- if ActiveRecord::VERSION::MAJOR >= 4
109
- if queries && queries_bind_values.any?
110
- relation = where.not([unprepare_query(queries.reduce(:or).to_sql), *queries_bind_values.map { |v| v[1] }])
111
- else
112
- relation = where.not(queries.reduce(:or).to_sql)
113
- end
114
- else
115
- if queries && queries_bind_values.any?
116
- relation = where([unprepare_query(Arel::Nodes::Not.new(queries.reduce(:or)).to_sql), *queries_bind_values.map { |v| v[1] }])
117
- else
118
- relation = where(Arel::Nodes::Not.new(queries.reduce(:or)).to_sql)
119
- end
120
- end
115
+ # Returns records that match any of the conditions, ie `#any_of`.
116
+ class PositiveBuilder < Builder
117
+ def build
118
+ relation = if queries && queries_bind_values.any?
119
+ where([unprepare_query(queries.reduce(:or).to_sql), *queries_bind_values])
120
+ else
121
+ where(queries.reduce(:or).to_sql)
122
+ end
121
123
 
122
- add_joins_to relation
123
- end
124
+ add_joins_to relation
125
+ end
126
+ end
124
127
 
125
- def without_statement_cache
126
- if ActiveRecord::VERSION::MAJOR >= 4
127
- relation = where.not(queries.reduce(:or))
128
- else
129
- relation = where(Arel::Nodes::Not.new(queries.reduce(:or)))
130
- end
128
+ # Returns records that match none of the conditions, ie `#none_of`.
129
+ class NegativeBuilder < Builder
130
+ def build
131
+ relation = if queries && queries_bind_values.any?
132
+ where.not([unprepare_query(queries.reduce(:or).to_sql), *queries_bind_values])
133
+ else
134
+ where.not(queries.reduce(:or).to_sql)
135
+ end
131
136
 
132
- add_related_values_to relation
133
- end
137
+ add_joins_to relation
138
+ end
134
139
  end
135
140
  end
136
141
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiverecordAnyOf
2
- VERSION = "1.4"
4
+ VERSION = '2.0'
3
5
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'activerecord_any_of/alternative_builder'
2
4
 
3
5
  module ActiverecordAnyOf
6
+ # Injected into WhereChain.
4
7
  module Chained
5
8
  # Returns a new relation, which includes results matching any of the conditions
6
9
  # passed as parameters. You can think of it as a sql <tt>OR</tt> implementation :
@@ -12,7 +15,8 @@ module ActiverecordAnyOf
12
15
  # You can separate sets of hash condition by explicitly group them as hashes :
13
16
  #
14
17
  # User.where.any_of({first_name: 'John', last_name: 'Joe'}, {first_name: 'Simon', last_name: 'Joe'})
15
- # # => SELECT * FROM users WHERE ( first_name = 'John' AND last_name = 'Joe' ) OR ( first_name = 'Simon' AND last_name = 'Joe' )
18
+ # # => SELECT * FROM users WHERE ( first_name = 'John' AND last_name = 'Joe' ) OR
19
+ # ( first_name = 'Simon' AND last_name = 'Joe' )
16
20
  #
17
21
  #
18
22
  # Each #any_of set is the same kind you would have passed to #where :
@@ -38,6 +42,7 @@ module ActiverecordAnyOf
38
42
  # inactive_users = User.where.any_of(banned_users, unconfirmed_users)
39
43
  def any_of(*queries)
40
44
  raise ArgumentError, 'Called any_of() with no arguments.' if queries.none?
45
+
41
46
  AlternativeBuilder.new(:positive, @scope, *queries).build
42
47
  end
43
48
 
@@ -51,43 +56,10 @@ module ActiverecordAnyOf
51
56
  # active_users = User.where.none_of(banned_users, unconfirmed_users)
52
57
  def none_of(*queries)
53
58
  raise ArgumentError, 'Called none_of() with no arguments.' if queries.none?
54
- AlternativeBuilder.new(:negative, @scope, *queries).build
55
- end
56
- end
57
-
58
- module Deprecated
59
- def any_of(*queries)
60
- if ActiveRecord::VERSION::MAJOR >= 4
61
- ActiveSupport::Deprecation.warn( "Calling #any_of directly is deprecated and will be removed in activerecord_any_of-1.2.\nPlease call it with #where : User.where.any_of(cond1, cond2)." )
62
- end
63
-
64
- raise ArgumentError, 'Called any_of() with no arguments.' if queries.none?
65
- AlternativeBuilder.new(:positive, self, *queries).build
66
- end
67
-
68
- def none_of(*queries)
69
- if ActiveRecord::VERSION::MAJOR >= 4
70
- ActiveSupport::Deprecation.warn( "Calling #none_of directly is deprecated and will be removed in activerecord_any_of-1.2.\nPlease call it with #where : User.where.none_of(cond1, cond2)." )
71
- end
72
59
 
73
- raise ArgumentError, 'Called none_of() with no arguments.' if queries.none?
74
- AlternativeBuilder.new(:negative, self, *queries).build
60
+ AlternativeBuilder.new(:negative, @scope, *queries).build
75
61
  end
76
62
  end
77
63
  end
78
64
 
79
- if ActiveRecord::VERSION::MAJOR >= 4
80
- module ActiverecordAnyOfDelegation
81
- delegate :any_of, to: :all
82
- delegate :none_of, to: :all
83
- end
84
- else
85
- module ActiverecordAnyOfDelegation
86
- delegate :any_of, to: :scoped
87
- delegate :none_of, to: :scoped
88
- end
89
- end
90
-
91
- ActiveRecord::Relation.send(:include, ActiverecordAnyOf::Deprecated)
92
- ActiveRecord::Relation::WhereChain.send(:include, ActiverecordAnyOf::Chained) if ActiveRecord::VERSION::MAJOR >= 4
93
- ActiveRecord::Base.send(:extend, ActiverecordAnyOfDelegation)
65
+ ActiveRecord::Relation::WhereChain.include ActiverecordAnyOf::Chained
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord_any_of
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.4'
4
+ version: '2.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Olivier El Mekki
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-23 00:00:00.000000000 Z
11
+ date: 2023-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,76 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 3.2.13
19
+ version: '7'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '5'
22
+ version: '8'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 3.2.13
29
+ version: '7'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '5'
33
- - !ruby/object:Gem::Dependency
34
- name: rspec-rails
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '2.12'
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: '2.12'
47
- - !ruby/object:Gem::Dependency
48
- name: rake
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '10'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '10'
61
- - !ruby/object:Gem::Dependency
62
- name: combustion
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - ">="
66
- - !ruby/object:Gem::Version
67
- version: 0.5.1
68
- type: :development
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - ">="
73
- - !ruby/object:Gem::Version
74
- version: 0.5.1
75
- - !ruby/object:Gem::Dependency
76
- name: database_cleaner
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - ">="
80
- - !ruby/object:Gem::Version
81
- version: '0'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - ">="
87
- - !ruby/object:Gem::Version
88
- version: '0'
32
+ version: '8'
89
33
  description: Any_of allows to compute dynamic OR queries.
90
34
  email:
91
35
  - olivier@el-mekki.com
@@ -99,19 +43,12 @@ files:
99
43
  - lib/activerecord_any_of.rb
100
44
  - lib/activerecord_any_of/alternative_builder.rb
101
45
  - lib/activerecord_any_of/version.rb
102
- - spec/activerecord_any_of_spec.rb
103
- - spec/db/database.yml
104
- - spec/db/schema.rb
105
- - spec/fixtures/authors.yml
106
- - spec/fixtures/posts.yml
107
- - spec/fixtures/users.yml
108
- - spec/spec_helper.rb
109
- - spec/support/models.rb
110
46
  homepage: https://github.com/oelmekki/activerecord_any_of
111
47
  licenses:
112
48
  - MIT
113
- metadata: {}
114
- post_install_message:
49
+ metadata:
50
+ rubygems_mfa_required: 'true'
51
+ post_install_message:
115
52
  rdoc_options: []
116
53
  require_paths:
117
54
  - lib
@@ -119,24 +56,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
56
  requirements:
120
57
  - - ">="
121
58
  - !ruby/object:Gem::Version
122
- version: '0'
59
+ version: 2.7.0
123
60
  required_rubygems_version: !ruby/object:Gem::Requirement
124
61
  requirements:
125
62
  - - ">="
126
63
  - !ruby/object:Gem::Version
127
64
  version: '0'
128
65
  requirements: []
129
- rubyforge_project:
130
- rubygems_version: 2.5.1
131
- signing_key:
66
+ rubygems_version: 3.3.26
67
+ signing_key:
132
68
  specification_version: 4
133
69
  summary: Mongoid's any_of like implementation for activerecord
134
- test_files:
135
- - spec/activerecord_any_of_spec.rb
136
- - spec/fixtures/users.yml
137
- - spec/fixtures/authors.yml
138
- - spec/fixtures/posts.yml
139
- - spec/support/models.rb
140
- - spec/db/database.yml
141
- - spec/db/schema.rb
142
- - spec/spec_helper.rb
70
+ test_files: []
@@ -1,233 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ActiverecordAnyOf do
4
- fixtures :authors, :posts, :users
5
-
6
- describe 'finding with alternate conditions' do
7
- let(:davids) { Author.where(name: "David") }
8
-
9
- it "matches hash combinations" do
10
- if ActiveRecord::VERSION::MAJOR >= 4
11
- expect(Author.where.any_of({name: 'David'}, {name: 'Mary'})).to match_array(authors(:david, :mary))
12
- else
13
- expect(Author.any_of({name: 'David'}, {name: 'Mary'})).to match_array(authors(:david, :mary))
14
- end
15
- end
16
-
17
- it "matches combination of hash and array" do
18
- if ActiveRecord::VERSION::MAJOR >= 4
19
- expect(Author.where.any_of({name: 'David'}, ['name = ?', 'Mary'])).to match_array(authors(:david, :mary))
20
- else
21
- expect(Author.any_of({name: 'David'}, ['name = ?', 'Mary'])).to match_array(authors(:david, :mary))
22
- end
23
- end
24
-
25
- it "matches a combination of hashes, arrays, and AR relations" do
26
- if ActiveRecord::VERSION::MAJOR >= 4
27
- expect(Author.where.any_of(davids, ['name = ?', 'Mary'], {name: 'Bob'})).to match_array(authors(:david, :mary, :bob))
28
- else
29
- expect(Author.any_of(davids, ['name = ?', 'Mary'], {name: 'Bob'})).to match_array(authors(:david, :mary, :bob))
30
- end
31
- end
32
-
33
- it "matches a combination of strings, hashes, and AR relations" do
34
- if ActiveRecord::VERSION::MAJOR >= 4
35
- expect(Author.where.any_of(davids, "name = 'Mary'", {name: 'Bob', id: 3})).to match_array(authors(:david, :mary, :bob))
36
- else
37
- expect(Author.any_of(davids, "name = 'Mary'", {name: 'Bob', id: 3})).to match_array(authors(:david, :mary, :bob))
38
- end
39
- end
40
-
41
- it "doesn't find combinations previously filtered out" do
42
- if ActiveRecord::VERSION::MAJOR >= 4
43
- expect(Author.where.not(name: 'Mary').where.any_of(davids, ['name = ?', 'Mary'])).to match_array([authors(:david)])
44
- else
45
- expect(Author.where("name != 'Mary'").any_of(davids, ['name = ?', 'Mary'])).to match_array([authors(:david)])
46
- end
47
- end
48
- end
49
-
50
- it 'finding with alternate conditions on has_many association' do
51
- david = authors(:david)
52
- welcome = david.posts.where(body: 'Such a lovely day')
53
- expected = ['Welcome to the weblog', 'So I was thinking']
54
-
55
- if ActiveRecord::VERSION::MAJOR >= 4
56
- expect(david.posts.where.any_of(welcome, {type: 'SpecialPost'}).map(&:title)).to match_array(expected)
57
- else
58
- expect(david.posts.any_of(welcome, {type: 'SpecialPost'}).map(&:title)).to match_array(expected)
59
- end
60
- end
61
-
62
- it 'finds with combined polymorphic associations' do
63
- company = Company.create!
64
- university = University.create!
65
-
66
- company.users << users(:ezra)
67
- university.users << users(:aria)
68
-
69
- if ActiveRecord::VERSION::MAJOR >= 4
70
- expect(User.where.any_of(company.users, university.users)).to match_array(users(:ezra, :aria))
71
- else
72
- expect(User.any_of(company.users, university.users)).to match_array(users(:ezra, :aria))
73
- end
74
- end
75
-
76
- it 'finds with more than 2 combined polymorphic associations' do
77
- company = Company.create!
78
- university = University.create!
79
- company2 = Company.create!
80
-
81
- company.users << users(:ezra)
82
- university.users << users(:aria)
83
- company2.users << users(:james)
84
-
85
- if ActiveRecord::VERSION::MAJOR >= 4
86
- expect(User.where.any_of(company.users, university.users, company2.users)).to match_array(users(:ezra, :aria, :james))
87
- else
88
- expect(User.any_of(company.users, university.users, company2.users)).to match_array(users(:ezra, :aria, :james))
89
- end
90
- end
91
-
92
- it 'finds alternatives with combined has_many associations' do
93
- david, mary = authors(:david, :mary)
94
-
95
- if ActiveRecord::VERSION::MAJOR >= 4
96
- expect(Post.where.any_of(david.posts, mary.posts)).to match_array(david.posts + mary.posts)
97
- else
98
- expect(Post.any_of(david.posts, mary.posts)).to match_array(david.posts + mary.posts)
99
- end
100
- end
101
-
102
- it 'finds alternatives with more than 2 combined has_many associations' do
103
- david, mary, bob = authors(:david, :mary, :bob)
104
-
105
- if ActiveRecord::VERSION::MAJOR >= 4
106
- expect(Post.where.any_of(david.posts, mary.posts, bob.posts)).to match_array(david.posts + mary.posts + bob.posts)
107
- else
108
- expect(Post.any_of(david.posts, mary.posts, bob.posts)).to match_array(david.posts + mary.posts + bob.posts)
109
- end
110
- end
111
-
112
- describe 'finding alternate dynamically with joined queries' do
113
- it "matches combined AR relations with joins" do
114
- david = Author.where(posts: { title: 'Welcome to the weblog' }).joins(:posts)
115
- mary = Author.where(posts: { title: "eager loading with OR'd conditions" }).joins(:posts)
116
-
117
- if ActiveRecord::VERSION::MAJOR >= 4
118
- expect(Author.where.any_of(david, mary)).to match_array(authors(:david, :mary))
119
- else
120
- expect(Author.any_of(david, mary)).to match_array(authors(:david, :mary))
121
- end
122
- end
123
-
124
- it "matches combined AR relations with joins and includes" do
125
- if ActiveRecord::VERSION::MAJOR >= 4
126
- david = Author.where(posts: { title: 'Welcome to the weblog' }).includes(:posts).references(:posts)
127
- mary = Author.where(posts: { title: "eager loading with OR'd conditions" }).includes(:posts).references(:posts)
128
- expect(Author.where.any_of(david, mary)).to match_array(authors(:david, :mary))
129
- else
130
- david = Author.where(posts: { title: 'Welcome to the weblog' }).includes(:posts)
131
- mary = Author.where(posts: { title: "eager loading with OR'd conditions" }).includes(:posts)
132
- expect(Author.any_of(david, mary)).to match_array(authors(:david, :mary))
133
- end
134
- end
135
- end
136
-
137
- it 'finding with alternate negative conditions' do
138
- if ActiveRecord::VERSION::MAJOR >= 4
139
- expect(Author.where.none_of({name: 'David'}, {name: 'Mary'})).to match_array([authors(:bob)])
140
- else
141
- expect(Author.none_of({name: 'David'}, {name: 'Mary'})).to match_array([authors(:bob)])
142
- end
143
- end
144
-
145
- it 'finding with alternate negative conditions on association' do
146
- david = Author.where(name: 'David').first
147
- welcome = david.posts.where(body: 'Such a lovely day')
148
- expected = ['sti comments', 'sti me', 'habtm sti test']
149
-
150
- if ActiveRecord::VERSION::MAJOR >= 4
151
- expect(david.posts.where.none_of(welcome, {type: 'SpecialPost'}).map(&:title)).to match_array(expected)
152
- else
153
- expect(david.posts.none_of(welcome, {type: 'SpecialPost'}).map(&:title)).to match_array(expected)
154
- end
155
- end
156
-
157
- it 'calling #any_of with no argument raises exception' do
158
- if ActiveRecord::VERSION::MAJOR >= 4
159
- expect { Author.where.any_of }.to raise_exception(ArgumentError)
160
- else
161
- expect { Author.any_of }.to raise_exception(ArgumentError)
162
- end
163
- end
164
-
165
- it 'calling #none_of with no argument raises exception' do
166
- if ActiveRecord::VERSION::MAJOR >= 4
167
- expect { Author.where.none_of }.to raise_exception(ArgumentError)
168
- else
169
- expect { Author.none_of }.to raise_exception(ArgumentError)
170
- end
171
- end
172
-
173
- it 'calling #any_of after including via a hash does not raise an exception' do
174
- if ActiveRecord::VERSION::MAJOR >= 4
175
- expect { User.includes(memberships: :companies).where.any_of(user_id: 1, company_id: 1) }.
176
- to_not raise_exception
177
- else
178
- expect { User.includes(memberships: :companies).any_of(user_id: 1, company_id: 1) }.
179
- to_not raise_exception
180
- end
181
- end
182
-
183
- it 'calling #any_of after a wildcard query works' do
184
- if ActiveRecord::VERSION::MAJOR >= 4
185
- expect(Author.where("name like '%av%'").where.any_of({name: 'David'}, {name: 'Mary'})).to match_array([authors(:david)])
186
- else
187
- expect(Author.where("name like '%av%'").any_of({name: 'David'}, {name: 'Mary'})).to match_array([authors(:david)])
188
- end
189
- end
190
-
191
- it 'calling #any_of with a single Hash as parameter expands it' do
192
- if ActiveRecord::VERSION::MAJOR >= 4
193
- expect(Author.where.any_of(name: 'David', id: 2)).to match_array(authors(:david, :mary))
194
- else
195
- expect(Author.any_of(name: 'David', id: 2)).to match_array(authors(:david, :mary))
196
- end
197
- end
198
-
199
- it "does not fail on hudge number for bind values" do
200
- conditions = [
201
- { name: 'Mary' },
202
- { name: 'David' },
203
- { name: 'David1' },
204
- { name: 'David2' },
205
- { name: 'David3' },
206
- { name: 'David4' },
207
- { name: 'David5' },
208
- { name: 'David6' },
209
- { name: 'David7' },
210
- { name: 'David8' },
211
- { name: 'David9' },
212
- { name: 'David10' },
213
- { name: 'David11' },
214
- { name: 'David12' },
215
- { name: 'David13' },
216
- { name: 'David14' }
217
- ]
218
-
219
- if ActiveRecord::VERSION::MAJOR >= 4
220
- expect(Author.where.any_of(*conditions)).to match_array(authors(:david, :mary))
221
- else
222
- expect(Author.any_of(*conditions)).to match_array(authors(:david, :mary))
223
- end
224
- end
225
-
226
- if ActiveRecord::VERSION::MAJOR >= 4
227
- it 'calling directly #any_of is deprecated in rails-4' do
228
- allow(ActiveSupport::Deprecation).to receive(:warn)
229
- Author.any_of({name: 'David'}, {name: 'Mary'})
230
- expect(ActiveSupport::Deprecation).to have_received(:warn)
231
- end
232
- end
233
- end
data/spec/db/database.yml DELETED
@@ -1,28 +0,0 @@
1
- sqlite3:
2
- adapter: <%= "jdbc" if defined? JRUBY_VERSION %>sqlite3
3
- database: activerecord_any_of.sqlite3.db
4
- sqlite3mem:
5
- adapter: <%= "jdbc" if defined? JRUBY_VERSION %>sqlite3
6
- database: ":memory:"
7
- postgresql:
8
- adapter: postgresql
9
- encoding: unicode
10
- database: activerecord_any_of_test
11
- pool: 5
12
- username: postgres
13
- password:
14
- min_messages: warning
15
- mysql:
16
- adapter: <%= defined?(JRUBY_VERSION) ? "jdbcmysql" : "mysql2" %>
17
- host: localhost
18
- username: root
19
- password:
20
- database: activerecord_any_of_test
21
- encoding: utf8
22
- ## Add DB Configuration to run Oracle tests
23
- oracle:
24
- adapter: oracle_enhanced
25
- host: localhost
26
- username: activerecord_any_of_dev
27
- password:
28
- database: xe
data/spec/db/schema.rb DELETED
@@ -1,33 +0,0 @@
1
- ActiveRecord::Schema.define do
2
- create_table :authors do |t|
3
- t.string :name
4
- t.datetime :created_at
5
- t.datetime :updated_at
6
- end
7
-
8
- create_table :posts do |t|
9
- t.string :title
10
- t.text :body
11
- t.integer :author_id
12
- t.string :type
13
- t.datetime :created_at
14
- t.datetime :updated_at
15
- end
16
-
17
- create_table :companies do |t|
18
- t.string :name
19
- end
20
-
21
- create_table :universities do |t|
22
- t.string :name
23
- end
24
-
25
- create_table :memberships do |t|
26
- t.references :organization, polymorphic: true
27
- t.references :user
28
- end
29
-
30
- create_table :users do |t|
31
- t.string :name
32
- end
33
- end
@@ -1,11 +0,0 @@
1
- david:
2
- id: 1
3
- name: David
4
-
5
- mary:
6
- id: 2
7
- name: Mary
8
-
9
- bob:
10
- id: 3
11
- name: Bob
@@ -1,76 +0,0 @@
1
- welcome:
2
- id: 1
3
- author_id: 1
4
- title: Welcome to the weblog
5
- body: Such a lovely day
6
- type: Post
7
-
8
- thinking:
9
- id: 2
10
- author_id: 1
11
- title: So I was thinking
12
- body: Like I hopefully always am
13
- type: SpecialPost
14
-
15
- authorless:
16
- id: 3
17
- author_id: 0
18
- title: I don't have any comments
19
- body: I just don't want to
20
- type: Post
21
-
22
- sti_comments:
23
- id: 4
24
- author_id: 1
25
- title: sti comments
26
- body: hello
27
- type: Post
28
-
29
- sti_post_and_comments:
30
- id: 5
31
- author_id: 1
32
- title: sti me
33
- body: hello
34
- type: StiPost
35
-
36
- sti_habtm:
37
- id: 6
38
- author_id: 1
39
- title: habtm sti test
40
- body: hello
41
- type: Post
42
-
43
- eager_other:
44
- id: 7
45
- author_id: 2
46
- title: eager loading with OR'd conditions
47
- body: hello
48
- type: Post
49
-
50
- misc_by_bob:
51
- id: 8
52
- author_id: 3
53
- title: misc post by bob
54
- body: hello
55
- type: Post
56
-
57
- misc_by_mary:
58
- id: 9
59
- author_id: 2
60
- title: misc post by mary
61
- body: hello
62
- type: Post
63
-
64
- other_by_bob:
65
- id: 10
66
- author_id: 3
67
- title: other post by bob
68
- body: hello
69
- type: Post
70
-
71
- other_by_mary:
72
- id: 11
73
- author_id: 2
74
- title: other post by mary
75
- body: hello
76
- type: Post
@@ -1,9 +0,0 @@
1
- ezra:
2
- id: 1
3
- name: "Ezra"
4
- aria:
5
- id: 2
6
- name: "Aria"
7
- james:
8
- id: 3
9
- name: "James"
data/spec/spec_helper.rb DELETED
@@ -1,36 +0,0 @@
1
- plugin_test_dir = File.dirname(__FILE__)
2
-
3
- require 'rubygems'
4
- require 'bundler/setup'
5
- require 'pry'
6
-
7
- require 'logger'
8
- require 'rails/all'
9
- require 'active_record'
10
- ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log")
11
-
12
- require 'yaml'
13
- require 'erb'
14
- ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read(plugin_test_dir + "/db/database.yml")).result)
15
- ActiveRecord::Base.establish_connection((ENV["DB"] ||= 'sqlite3mem').to_sym)
16
- ActiveRecord::Migration.verbose = false
17
-
18
- require 'combustion/database'
19
- Combustion::Database.create_database(ActiveRecord::Base.configurations[ENV["DB"]])
20
- load(File.join(plugin_test_dir, "db", "schema.rb"))
21
-
22
- require 'activerecord_any_of'
23
- require 'support/models'
24
-
25
- require 'action_controller'
26
- require 'rspec/rails'
27
- require 'database_cleaner'
28
- RSpec.configure do |config|
29
- config.fixture_path = "#{plugin_test_dir}/fixtures"
30
- config.use_transactional_fixtures = true
31
- config.after(:suite) do
32
- unless /sqlite/ === ENV['DB']
33
- Combustion::Database.drop_database(ActiveRecord::Base.configurations[ENV['DB']])
34
- end
35
- end
36
- end
@@ -1,34 +0,0 @@
1
- class Author < ActiveRecord::Base
2
- has_many :posts
3
- end
4
-
5
- class Post < ActiveRecord::Base
6
- belongs_to :author
7
- end
8
-
9
- class SpecialPost < Post
10
- end
11
-
12
- class StiPost < Post
13
- end
14
-
15
- class User < ActiveRecord::Base
16
- has_many :memberships
17
- has_many :companies, through: :memberships, source: :organization, source_type: "Company"
18
- has_many :universities, through: :memberships, source: :organization, source_type: "University"
19
- end
20
-
21
- class Membership < ActiveRecord::Base
22
- belongs_to :user
23
- belongs_to :organization, polymorphic: true
24
- end
25
-
26
- class Company < ActiveRecord::Base
27
- has_many :memberships, as: :organization
28
- has_many :users, through: :memberships
29
- end
30
-
31
- class University < ActiveRecord::Base
32
- has_many :memberships, as: :organization
33
- has_many :users, through: :memberships
34
- end