activerecord_any_of 1.4 → 2.0.1

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
- SHA1:
3
- metadata.gz: 47eee92223e93989b63ad4b3ae077bf438bf70fc
4
- data.tar.gz: 31b4d5f385ea3d699ad5abca878ef7612649959c
2
+ SHA256:
3
+ metadata.gz: 5ab240782530ddad6e3dd50748a79a0a4a924d856db8b116b41f1e88ccd82b31
4
+ data.tar.gz: 32063f28c9e58cb7ea8e1c75632321903ffa1cf2a84867953e3f6453908d7570
5
5
  SHA512:
6
- metadata.gz: 1b2d782aa4da21b7823f1ae978f6effcc0d55460dbbdb51bb7fabdd34d21ce9e50023de2c237857dfba6729d9d1d5c2f377d76d5f842f158d8ff5c4ff6a50552
7
- data.tar.gz: f174291bbc3e50f0a48ac8414988f84d01413f21a3a603b63ebc8270afd9163800d91f87f72351b9972ecc6f433fec5860ebb24deb3f17cfd77d6ff058549d7b
6
+ metadata.gz: e0539ca1b4224eb879b000ad86dc650a2f3bb9f7d737ece3e3d7c728540a185ca0aef0332e09b6e6ed377f37dd21357353f12c32f8f536a6c451bf3446b1da94
7
+ data.tar.gz: 4e14ceda1dbf47a56b07ece910000e9fff1d9400bd147493878a70de0247b0733bc4e5db8bb6beea2d76ae43f32493375e3569aef5fcac270655f9399e46abba
data/README.md CHANGED
@@ -1,16 +1,46 @@
1
1
  # ActiverecordAnyOf
2
2
 
3
+ > Warning! Development of activerecord_any_of is now happening on
4
+ > [Gitlab](https://gitlab.com/oelmekki/activerecord_any_of).
5
+ >
6
+ > Please go there for issues and merge requests.
7
+
3
8
  ## Introduction
4
9
 
5
10
  This gem provides `#any_of` and `#none_of` on ActiveRecord.
6
11
 
7
- `#any_of` is inspired by [any_of from mongoid](http://two.mongoid.org/docs/querying/criteria.html#any_of).
12
+ `#any_of` is inspired by [any_of from mongoid](https://www.mongodb.com/docs/mongoid/current/reference/queries/#any-of-behavior).
8
13
 
9
- Its main purpose is to both :
14
+ It was released before `#or` was implemented in ActiveRecord. Its main purpose was to both :
10
15
 
11
16
  * remove the need to write a sql string when we want an `OR`
12
17
  * allows to write dynamic `OR` queries, which would be a pain with a string
13
18
 
19
+ It can still be useful today given the various ways you can call it. While
20
+ ActiveRecord's `#or` only accepts relations, you can pass to `#any_of` and
21
+ `#none_of` the same kind of conditions you would pass to `#where`:
22
+
23
+
24
+ ```ruby
25
+ User.where.any_of({ active: true }, ['offline = ?', required_status], 'posts_count > 0')
26
+ ```
27
+
28
+ And you can still use relations, like AR's `#or`:
29
+
30
+ ```ruby
31
+ inactive_users = User.not_activated
32
+ offline_users = User.offline
33
+
34
+ User.where.any_of(inactive_users, offline)
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ In your Gemfile :
40
+
41
+ ```
42
+ gem 'activerecord_any_of'
43
+ ```
14
44
 
15
45
  ## Usage
16
46
 
@@ -18,7 +48,6 @@ Its main purpose is to both :
18
48
 
19
49
  It allows to compute an `OR` like query that leverages AR's `#where` syntax:
20
50
 
21
-
22
51
  #### basics
23
52
 
24
53
  ```ruby
@@ -26,26 +55,23 @@ User.where.any_of(first_name: 'Joe', last_name: 'Joe')
26
55
  # => SELECT * FROM users WHERE first_name = 'Joe' OR last_name = 'Joe'
27
56
  ```
28
57
 
29
-
30
58
  #### grouped conditions
31
59
 
32
60
  You can separate sets of hash condition by explicitly group them as hashes :
33
61
 
34
62
  ```ruby
35
- User.where.any_of({first_name: 'John', last_name: 'Joe'}, {first_name: 'Simon', last_name: 'Joe'})
63
+ User.where.any_of({ first_name: 'John', last_name: 'Joe' }, { first_name: 'Simon', last_name: 'Joe' })
36
64
  # => SELECT * FROM users WHERE ( first_name = 'John' AND last_name = 'Joe' ) OR ( first_name = 'Simon' AND last_name = 'Joe' )
37
65
  ```
38
66
 
39
-
40
67
  #### it's plain #where syntax
41
68
 
42
69
  Each `#any_of` set is the same kind you would have passed to #where :
43
70
 
44
71
  ```ruby
45
- Client.where.any_of("orders_count = '2'", ["name = ?", 'Joe'], {email: 'joe@example.com'})
72
+ Client.where.any_of("orders_count = '2'", ["name = ?", 'Joe'], { email: 'joe@example.com' })
46
73
  ```
47
74
 
48
-
49
75
  #### with relations
50
76
 
51
77
  You can as well pass `#any_of` to other relations :
@@ -54,16 +80,14 @@ You can as well pass `#any_of` to other relations :
54
80
  Client.where("orders_count = '2'").where.any_of({ email: 'joe@example.com' }, { email: 'john@example.com' })
55
81
  ```
56
82
 
57
-
58
83
  #### with associations
59
84
 
60
85
  And with associations :
61
86
 
62
87
  ```ruby
63
- User.find(1).posts.where.any_of({published: false}, "user_id IS NULL")
88
+ User.find(1).posts.where.any_of({ published: false }, 'user_id IS NULL')
64
89
  ```
65
90
 
66
-
67
91
  #### dynamic OR queries
68
92
 
69
93
  The best part is that `#any_of` accepts other relations as parameter, to help compute
@@ -81,64 +105,6 @@ inactive_users = User.where.any_of(banned_users, unconfirmed_users)
81
105
 
82
106
  ```ruby
83
107
  banned_users = User.where(banned: true)
84
- unconfirmed_users = User.where("confirmed_at IS NULL")
108
+ unconfirmed_users = User.where('confirmed_at IS NULL')
85
109
  active_users = User.where.none_of(banned_users, unconfirmed_users)
86
110
  ```
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,149 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiverecordAnyOf
4
+ IS_RAILS_6 = ActiveRecord.version.to_s.between?('6', '7')
5
+
6
+ # Main class allowing to build alternative conditions for the query.
2
7
  class AlternativeBuilder
3
8
  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] }
9
+ if queries.first.is_a?(Hash) && (queries.count == 1)
10
+ queries = queries.first.each_pair.map { |attr, predicate| { attr => predicate } }
6
11
  end
7
12
 
8
- @builder = match_type == :negative ? NegativeBuilder.new(context, *queries) : PositiveBuilder.new(context, *queries)
13
+ @builder = if match_type == :negative
14
+ NegativeBuilder.new(context,
15
+ *queries)
16
+ else
17
+ PositiveBuilder.new(context, *queries)
18
+ end
9
19
  end
10
20
 
11
21
  def build
12
22
  @builder.build
13
23
  end
14
24
 
25
+ # Common methods for both the positive builder and the negative one.
15
26
  class Builder
16
- attr_accessor :queries_bind_values, :queries_joins_values
27
+ attr_accessor :queries_joins_values
17
28
 
18
29
  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
30
+ @context = context
31
+ @source_queries = source_queries
32
+ @queries_joins_values = { includes: [], joins: [], references: [] }
25
33
  end
26
34
 
27
35
  private
28
36
 
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
37
+ def query_to_relation(query)
38
+ if query.is_a?(String) || query.is_a?(Hash)
39
+ query = where(query)
40
+ elsif query.is_a?(Array)
41
+ query = where(*query)
43
42
  end
44
43
 
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
44
+ query
45
+ end
46
+
47
+ def append_join_values(query)
48
+ { includes_values: :includes, joins_values: :joins, references_values: :references }.each do |q, joins|
49
+ values = query.send(q)
50
+ queries_joins_values[joins].concat(values) if values.any?
57
51
  end
52
+ end
58
53
 
59
- def method_missing(method_name, *args, &block)
60
- @context.send(method_name, *args, &block)
54
+ def queries
55
+ @queries ||= @source_queries.map do |query|
56
+ query = query_to_relation(query)
57
+ append_join_values(query)
58
+ query.arel.constraints.reduce(:and)
61
59
  end
60
+ end
62
61
 
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])
62
+ def uniq_queries_joins_values
63
+ @uniq_queries_joins_values ||= { includes: [], joins: [], references: [] }.tap do |values|
64
+ queries_joins_values.each do |join_type, statements|
65
+ values[join_type] = if statements.first.respond_to?(:to_sql)
66
+ statements.uniq(&:to_sql)
67
+ else
68
+ statements.uniq
69
+ end
70
+ end
67
71
  end
72
+ end
68
73
 
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
74
+ def map_multiple_bind_values(query)
75
+ query.children.map do |child|
76
+ next unless child.respond_to?(:right)
77
+ next unless child.right.respond_to?(:value)
74
78
 
75
- relation
79
+ child.right.value
76
80
  end
81
+ end
82
+
83
+ def queries_bind_values
84
+ queries.map do |query|
85
+ if query.respond_to?(:children)
86
+ map_multiple_bind_values(query)
87
+ else
88
+ next unless query.respond_to?(:right)
89
+ next unless query.right.respond_to?(:value)
77
90
 
78
- def unprepare_query(query)
79
- query.gsub(/((?<!\\)'.*?(?<!\\)'|(?<!\\)".*?(?<!\\)")|(\=\ \$\d+)/) do |match|
80
- $2 and $2.gsub(/\=\ \$\d+/, "= ?") or match
91
+ query.right.value
81
92
  end
82
- end
83
- end
93
+ end.flatten.compact
94
+ end
84
95
 
85
- class PositiveBuilder < Builder
86
- private
96
+ def method_missing(method_name, *args, &block)
97
+ @context.send(method_name, *args, &block)
98
+ end
87
99
 
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
100
+ def respond_to_missing?(method, *)
101
+ @context.respond_to? method
102
+ end
103
+
104
+ def add_joins_to(relation)
105
+ relation = relation.references(uniq_queries_joins_values[:references])
106
+ relation = relation.includes(uniq_queries_joins_values[:includes])
107
+ relation.joins(uniq_queries_joins_values[:joins])
108
+ end
94
109
 
95
- add_joins_to relation
110
+ def unprepare_query(query)
111
+ query.gsub(/((?<!\\)'.*?(?<!\\)'|(?<!\\)".*?(?<!\\)")|(=\ \$\d+)/) do |match|
112
+ ::Regexp.last_match(2)&.gsub(/=\ \$\d+/, '= ?') or match
96
113
  end
114
+ end
97
115
 
98
- def without_statement_cache
99
- relation = where(queries.reduce(:or))
100
- add_related_values_to relation
116
+ def bind_values
117
+ queries_bind_values.tap do |values|
118
+ values.map!(&:value) if IS_RAILS_6
101
119
  end
120
+ end
102
121
  end
103
122
 
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
123
+ # Returns records that match any of the conditions, ie `#any_of`.
124
+ class PositiveBuilder < Builder
125
+ def build
126
+ relation = if queries && queries_bind_values.any?
127
+ where([unprepare_query(queries.reduce(:or).to_sql), *bind_values])
128
+ else
129
+ where(queries.reduce(:or).to_sql)
130
+ end
121
131
 
122
- add_joins_to relation
123
- end
132
+ add_joins_to relation
133
+ end
134
+ end
124
135
 
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
136
+ # Returns records that match none of the conditions, ie `#none_of`.
137
+ class NegativeBuilder < Builder
138
+ def build
139
+ relation = if queries && queries_bind_values.any?
140
+ where.not([unprepare_query(queries.reduce(:or).to_sql), *bind_values])
141
+ else
142
+ where.not(queries.reduce(:or).to_sql)
143
+ end
131
144
 
132
- add_related_values_to relation
133
- end
145
+ add_joins_to relation
146
+ end
134
147
  end
135
148
  end
136
149
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiverecordAnyOf
2
- VERSION = "1.4"
4
+ VERSION = '2.0.1'
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.1
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-30 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: '6'
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: '6'
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