rspec-index-usage 0.0.1 → 0.1.0

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
  SHA256:
3
- metadata.gz: 62522b9854e0ad0cd7d84b44dfa1b019f0ebca89a1121837d885e9b5d1782bfe
4
- data.tar.gz: 6aa5e60ec2a3247fc07a0a131b2e05e8902c21e589c8e442c54d73b051aba03e
3
+ metadata.gz: f00b23350b41a0c0245b26ac250c514173c348f4ebe0eb75a386fad27de8c65e
4
+ data.tar.gz: fdabba3a7d4e83bd0ab3498bc8053982214f9c707704c3a8199ec178411e6fb4
5
5
  SHA512:
6
- metadata.gz: d848cf6f41f25b8ba1907ae344e65dcdc93f0ebc37d035f21a9326443567e94a5ddb1b038609838d00372177d7d83e3942bc30fc824da924dc5264bf10082b1b
7
- data.tar.gz: c087d3c28fa3f1e13ab05ca6137cb8a7dd4c5bd7fef8e1eaca32fa235c09863488463135be21de3de52688535b4af14c3f5e71bf5ddf5899dab94fd6f35b09cb
6
+ metadata.gz: 8f1f8be9656e054d5e1554868d25660a7d2f46b27bcf1ad3f5d90f38611c900135a04229b57084e30f9b2e6c30db467b1ea6017e1e10ac92d22bcd12bc08039b
7
+ data.tar.gz: 987303893e5072213b754bb8f553c1adfaeb219697966a064dba15f547f6687c71120460f5edf9a8c033d73f99868fa6954095c373071f0a04eb441513c56299
@@ -18,7 +18,9 @@ RSpec::Matchers.define :have_used_index do |expected_index|
18
18
  sql = event.payload[:sql]
19
19
  next unless sql
20
20
 
21
- queries << sql if sql.start_with?('SELECT') && !sql.match?(/\A(EXPLAIN|BEGIN|COMMIT|ROLLBACK)/i)
21
+ if sql.start_with?('SELECT') && !sql.match?(/\A(EXPLAIN|BEGIN|COMMIT|ROLLBACK)/i)
22
+ queries << { sql: sql, binds: event.payload[:binds] }
23
+ end
22
24
  end
23
25
 
24
26
  block.call
@@ -29,15 +31,14 @@ RSpec::Matchers.define :have_used_index do |expected_index|
29
31
  checker_class = IndexChecker.for_adapter(connection)
30
32
  checker = checker_class.new
31
33
 
32
- queries.any? { |sql| checker.check_sql(sql, expected_index, connection) }
34
+ queries.any? { |query| checker.check_sql(query[:sql], expected_index, connection, binds: query[:binds]) }
33
35
  end
34
36
 
35
- failure_message do |block|
37
+ failure_message do |_block|
36
38
  "expected the block to execute a query using index '#{expected_index}', but none did"
37
39
  end
38
40
 
39
- failure_message_when_negated do |block|
41
+ failure_message_when_negated do |_block|
40
42
  "expected the block not to execute a query using index '#{expected_index}', but one did"
41
43
  end
42
44
  end
43
-
@@ -10,11 +10,12 @@ RSpec::Matchers.define :use_index do |expected_index|
10
10
  checker.check(query, expected_index, connection)
11
11
  end
12
12
 
13
- failure_message do |query|
13
+ failure_message do |_query|
14
14
  "expected query to use index '#{expected_index}', but it didn't"
15
15
  end
16
16
 
17
- failure_message_when_negated do |query|
17
+ failure_message_when_negated do |_query|
18
18
  "expected query not to use index '#{expected_index}', but it did"
19
19
  end
20
- end
20
+ end
21
+
@@ -17,7 +17,7 @@ class IndexChecker
17
17
  raise NotImplementedError, 'Subclasses must implement check'
18
18
  end
19
19
 
20
- def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection)
20
+ def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection, binds: nil)
21
21
  raise NotImplementedError, 'Subclasses must implement check_sql'
22
22
  end
23
23
  end
@@ -6,11 +6,22 @@ class PostgresqlIndexChecker < IndexChecker
6
6
  check_sql(sql, expected_index, connection)
7
7
  end
8
8
 
9
- def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection)
9
+ def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection, binds: nil)
10
+ sql = substitute_binds(sql, binds, connection) if binds
10
11
  explain_sql = "EXPLAIN #{sql}"
11
12
  result = connection.execute(explain_sql)
12
- plan = result.map { |row| row[0] }.join("\n")
13
- plan.include?(expected_index)
13
+ plan = result.map { |row| row['QUERY PLAN'] }.join("\n")
14
+ plan.downcase.include?(expected_index.downcase)
14
15
  end
15
- end
16
16
 
17
+ private
18
+
19
+ def substitute_binds(sql, binds, connection)
20
+ binds.each_with_index do |bind, index|
21
+ placeholder = "$#{index + 1}"
22
+ quoted_value = connection.quote(bind.value)
23
+ sql = sql.gsub(placeholder, quoted_value)
24
+ end
25
+ sql
26
+ end
27
+ end
@@ -6,11 +6,21 @@ class SqliteIndexChecker < IndexChecker
6
6
  check_sql(sql, expected_index, connection)
7
7
  end
8
8
 
9
- def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection)
9
+ def check_sql(sql, expected_index, connection = ActiveRecord::Base.connection, binds: nil)
10
+ sql = substitute_binds(sql, binds, connection) if binds
10
11
  explain_sql = "EXPLAIN QUERY PLAN #{sql}"
11
12
  result = connection.execute(explain_sql)
12
13
  plan = result.map { |row| row.values.join(' ') }.join(' ')
13
- plan.include?(expected_index)
14
+ plan.downcase.include?(expected_index.downcase)
14
15
  end
15
- end
16
16
 
17
+ private
18
+
19
+ def substitute_binds(sql, binds, connection)
20
+ parts = sql.split('?')
21
+ if parts.size - 1 == binds.size
22
+ sql = parts.zip(binds.map { |bind| connection.quote(bind.value) }).flatten.compact.join
23
+ end
24
+ sql
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-index-usage
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pedro Sena