where_exists 1.1.0 → 1.1.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
2
  SHA1:
3
- metadata.gz: b896dc7f4e36987c9fee2d3f99624944241c5778
4
- data.tar.gz: 3b63cf040cc3eccc90b22ffb167815cbc6c26762
3
+ metadata.gz: '09bda87b615e0962be005bda294cc0227e1d76ce'
4
+ data.tar.gz: 4cb809c77b97dfaad246f1a90be28e75cc2bb5a2
5
5
  SHA512:
6
- metadata.gz: f41ff3048e44820bd889403986a48ad90f95e1b3c97b0cfcd43a5797b2c5fdf706b8c6ac21ff3c9655489610a1ec38675001fd10ad5452237b0d46862f02660b
7
- data.tar.gz: 744a933a1fcc1fc3bd5251fc1b686c3009d4b7894996a64bef294947d18ed283552b00a225213d3181ae9e8768f976fede2a26aec03c05e6910a35407c7d9003
6
+ metadata.gz: b4ca719701af78dfc661a35cb815adf49d1206072f0fa3db2af6a411677f7394ad19547706f0f14265462955231847922821732caa9c64ca4e22186cefeb1127
7
+ data.tar.gz: 6e147f5238c544d0691cfb982d38cc560b5baf6a97d82f5529b94cafed6683c9e1a0b7706b6d967e2cc0913b905906c0d3192d64e064407f60774cd6c309f94c
data/lib/where_exists.rb CHANGED
@@ -23,8 +23,16 @@ module WhereExists
23
23
  queries = where_exists_for_belongs_to_query(association, where_parameters)
24
24
  when :has_many, :has_one
25
25
  queries = where_exists_for_has_many_query(association, where_parameters)
26
+ when :has_and_belongs_to_many
27
+ queries = where_exists_for_habtm_query(association, where_parameters)
26
28
  else
27
- raise ArgumentError.new("where_exists: not supported association – #{association.macros.inspect}")
29
+ inspection = nil
30
+ begin
31
+ inspection = association.macros.inspect
32
+ rescue
33
+ inspection = association.macro
34
+ end
35
+ raise ArgumentError.new("where_exists: not supported association – #{inspection}")
28
36
  end
29
37
 
30
38
  if does_exist
@@ -33,7 +41,7 @@ module WhereExists
33
41
  not_string = "NOT "
34
42
  end
35
43
 
36
- queries_sql = queries.map{|query| "EXISTS (" + query.to_sql + ")"}.join(" OR ")
44
+ queries_sql = queries.map { |query| "EXISTS (" + query.to_sql + ")" }.join(" OR ")
37
45
 
38
46
  self.where("#{not_string}(#{queries_sql})")
39
47
  end
@@ -62,7 +70,7 @@ module WhereExists
62
70
  query = query.where(*where_parameters)
63
71
  end
64
72
  if association_scope
65
- result = result.instance_exec(&association_scope)
73
+ query = query.instance_exec(&association_scope)
66
74
  end
67
75
  if polymorphic
68
76
  other_type = connection.quote(associated_model.name)
@@ -92,10 +100,6 @@ module WhereExists
92
100
 
93
101
  result = associated_model.select("1").where("#{associated_ids} = #{self_ids}")
94
102
 
95
- if association_scope
96
- result = result.instance_exec(&association_scope)
97
- end
98
-
99
103
  if association.options[:as]
100
104
  other_types = quote_table_and_column_name(associated_model.table_name, association.type)
101
105
  self_class = connection.quote(self.name)
@@ -103,11 +107,49 @@ module WhereExists
103
107
  end
104
108
 
105
109
  if through
106
- result = result.where_exists(next_association.name, *where_parameters)
107
- else
108
- if where_parameters != []
109
- result = result.where(*where_parameters)
110
- end
110
+ return [result.where_exists(next_association.name, *where_parameters)]
111
+ end
112
+
113
+ if where_parameters != []
114
+ result = result.where(*where_parameters)
115
+ end
116
+ if association_scope
117
+ result = result.instance_exec(&association_scope)
118
+ end
119
+
120
+ [result]
121
+ end
122
+
123
+ def where_exists_for_habtm_query(association, where_parameters)
124
+ association_scope = association.scope
125
+
126
+ associated_model = association.klass
127
+
128
+ primary_key = association.options[:primary_key] || self.primary_key
129
+
130
+ join_table = [self.table_name, associated_model.table_name].sort.join("_")
131
+
132
+ self_ids = quote_table_and_column_name(self.table_name, primary_key)
133
+ join_ids = quote_table_and_column_name(join_table, association.foreign_key)
134
+ associated_join_ids = quote_table_and_column_name(join_table, "#{associated_model.name.downcase}_id")
135
+ associated_ids = quote_table_and_column_name(associated_model.table_name, associated_model.primary_key)
136
+
137
+ result =
138
+ associated_model.
139
+ select("1").
140
+ joins(
141
+ <<-SQL
142
+ INNER JOIN #{connection.quote_table_name(join_table)}
143
+ ON #{associated_ids} = #{associated_join_ids}
144
+ SQL
145
+ ).
146
+ where("#{join_ids} = #{self_ids}")
147
+
148
+ if where_parameters != []
149
+ result = result.where(*where_parameters)
150
+ end
151
+ if association_scope
152
+ result = result.instance_exec(&association_scope)
111
153
  end
112
154
 
113
155
  [result]
@@ -1,3 +1,3 @@
1
1
  module WhereExists
2
- VERSION = "1.1.0"
2
+ VERSION = "1.1.1"
3
3
  end
data/test/db/test.db CHANGED
Binary file
@@ -0,0 +1,92 @@
1
+ require 'test_helper'
2
+
3
+ ActiveRecord::Migration.create_table :tasks, :force => true do |t|
4
+ t.string :name
5
+ end
6
+
7
+ ActiveRecord::Migration.create_table :invoices_tasks, :force => true do |t|
8
+ t.integer :invoice_id
9
+ t.integer :task_id
10
+ end
11
+
12
+ ActiveRecord::Migration.create_table :invoices, :force => true do |t|
13
+ t.string :name
14
+ end
15
+
16
+ class Task < ActiveRecord::Base
17
+ has_and_belongs_to_many :connected_invoices, class_name: 'Invoice'
18
+ end
19
+
20
+ class Invoice < ActiveRecord::Base
21
+ has_and_belongs_to_many :tasks
22
+ has_and_belongs_to_many :unnamed_tasks, -> { where(name: nil) }
23
+ end
24
+
25
+ # Invoices -> LineItems <- Tasks <- Project
26
+
27
+ class HasAndBelongsToManyTest < Minitest::Test
28
+ def setup
29
+ ActiveRecord::Base.descendants.each(&:delete_all)
30
+ end
31
+
32
+ def test_with_standard_naming
33
+ task = Task.create!(name: 'task')
34
+ irrelevant_task = Task.create!(name: 'task_2')
35
+ invoice = Invoice.create!(name: 'invoice')
36
+ invoice_no_join = Invoice.create!(name: 'invoice_2')
37
+
38
+ invoice.tasks << task
39
+
40
+
41
+ result = Invoice.where_exists(:tasks, name: 'task')
42
+
43
+ assert_equal 1, result.length
44
+ assert_equal invoice.id, result.first.id
45
+
46
+ result = Invoice.where_exists(:tasks, name: 'task_2')
47
+
48
+ assert_equal 0, result.length
49
+
50
+ result = Invoice.where_not_exists(:tasks)
51
+ assert_equal 1, result.length
52
+ assert_equal invoice_no_join.id, result.first.id
53
+ end
54
+
55
+ def test_with_custom_naming
56
+ task = Task.create!(name: 'task')
57
+ task_no_join = Task.create!(name: 'invoice')
58
+ invoice = Invoice.create!(name: 'invoice')
59
+ irrelevant_invoice = Invoice.create!(name: 'invoice_2')
60
+
61
+ task.connected_invoices << invoice
62
+
63
+ result = Task.where_exists(:connected_invoices, name: 'invoice')
64
+
65
+ assert_equal 1, result.length
66
+ assert_equal task.id, result.first.id
67
+
68
+ result = Task.where_exists(:connected_invoices, name: 'invoice_2')
69
+
70
+ assert_equal 0, result.length
71
+
72
+ result = Task.where_not_exists(:connected_invoices)
73
+ assert_equal 1, result.length
74
+ assert_equal task_no_join.id, result.first.id
75
+
76
+ result = Task.where_not_exists(:connected_invoices, name: 'invoice_2')
77
+ assert_equal 2, result.length
78
+ end
79
+
80
+ def test_with_condition
81
+ task_1 = Task.create! name: nil
82
+ task_2 = Task.create! name: 'task 2'
83
+
84
+ invoice_1 = Invoice.create!(tasks: [task_1])
85
+ invoice_2 = Invoice.create!(tasks: [task_1, task_2])
86
+ invoice_3 = Invoice.create!(tasks: [task_2)
87
+
88
+ result_ids = Invoice.where_exists(:unnamed_tasks).pluck(:id)
89
+
90
+ assert_equal [invoice_1.id, invoice_2.id].sort, result_ids.sort
91
+ end
92
+ end
@@ -91,5 +91,10 @@ class HasManyThroughTest < Minitest::Test
91
91
 
92
92
  assert_equal 1, result.length
93
93
  assert_equal irrelevant_project.id, result.first.id
94
+
95
+ result = Project.where_not_exists(:invoices, "name = ?", 'relevant')
96
+
97
+ assert_equal 1, result.length
98
+ assert_equal irrelevant_project.id, result.first.id
94
99
  end
95
100
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: where_exists
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eugene Zolotarev
@@ -73,6 +73,7 @@ files:
73
73
  - test/belongs_to_test.rb
74
74
  - test/db/test.db
75
75
  - test/documentation_test.rb
76
+ - test/has_and_belongs_to_many.rb
76
77
  - test/has_many_polymorphic_test.rb
77
78
  - test/has_many_test.rb
78
79
  - test/has_many_through_test.rb
@@ -107,6 +108,7 @@ test_files:
107
108
  - test/documentation_test.rb
108
109
  - test/test_helper.rb
109
110
  - test/has_many_polymorphic_test.rb
111
+ - test/has_and_belongs_to_many.rb
110
112
  - test/belongs_to_polymorphic_test.rb
111
113
  - test/has_many_test.rb
112
114
  - test/has_many_through_test.rb