kasket 4.9.1 → 4.10.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: 75e9005963ca629245005b0c9a2a9d94cb9023fac9cc12327045e25eaca547e0
4
- data.tar.gz: e7aec95609b6918646f3b2b420d5af038ef171888ac98cdea4c0fb16cf6ce086
3
+ metadata.gz: 5b7ff0fe3b5afa5c01eb36fc7f89bfe94669b98340bb1537546fe6019b0d61db
4
+ data.tar.gz: d69c8e0d2f9303456f5f647867a67496b49d95e8af114f51ec54acf95947d257
5
5
  SHA512:
6
- metadata.gz: f19bd6ca3a60073c738907e20052d461cdcc0139a1c300765ed3b029022107d7c477b6a5e6437bb34d73de5d8e2c6050eac3e6834ec6c7f27c3e7e1e5a0fa200
7
- data.tar.gz: effe82d0f1620cc7742407a46054b558675ac061050af22313daccdc52dc30204c5ae02c67f91aeea64ce07f4c687d2a6eb699c132a0914284d2554cec0d014b
6
+ metadata.gz: 610b4879bebfdd27f4796ce840aac305d30502702befab16623f8c1e7bd316dd7529ab5af4513d05e565b25cb716089e7b71ed34aad8c75099bf5493137c3e31
7
+ data.tar.gz: b6710e8aa232d3105822aec11431a8d3c76618c7d124e3e1773528c3decc3de57617ffa17f6a60425729e694a4cde8e281d74ed0bd7e88fcd3b34e371cae245b
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Kasket [![Build status](https://circleci.com/gh/zendesk/kasket.svg?style=svg)](https://circleci.com/gh/zendesk/kasket)
1
+ # Kasket
2
2
 
3
3
  ### Puts a cap on your queries
4
4
  A caching layer for ActiveRecord (3.x and 4.x)
@@ -12,26 +12,43 @@ module Kasket
12
12
  def initialize(model_class)
13
13
  @model_class = model_class
14
14
 
15
- @supported_query_pattern = /^select\s+((?:`|")#{@model_class.table_name}(?:`|")\.)?\* from (?:`|")#{@model_class.table_name}(?:`|") where (.*?)(|\s+limit 1)\s*$/i
15
+ @supported_query_pattern = /^select\s+(.+?)\s+from (?:`|")#{@model_class.table_name}(?:`|") where (.*?)(|\s+limit 1)\s*$/i
16
16
 
17
+ @star_pattern = /^((`|")#{@model_class.table_name}\2\.)?\*$/
17
18
  # Matches: `users`.id, `users`.`id`, users.id, id
18
19
  @table_and_column_pattern = /(?:(?:`|")?#{@model_class.table_name}(?:`|")?\.)?(?:`|")?([a-zA-Z]\w*)(?:`|")?/
19
20
  # Matches: KEY = VALUE, (KEY = VALUE), ()(KEY = VALUE))
20
21
  @key_eq_value_pattern = /^[\(\s]*#{@table_and_column_pattern}\s+(=|IN)\s+#{VALUE}[\)\s]*$/
21
22
  end
22
23
 
24
+ ##
25
+ # Parses a SQL query to produce a kasket query
26
+ #
27
+ # @param sql [String] the sql query to parse
28
+ # @return [Hash|nil] the kasket query, or nil if the sql query is not supported
23
29
  def parse(sql)
24
30
  if match = @supported_query_pattern.match(sql)
31
+ select = match[1]
32
+ unless @star_pattern.match? select
33
+ # If we're not selecting all columns using star, then ensure all columns are selected explicitly
34
+ select_columns = select.split(/\s*,\s*/).map do |s|
35
+ break unless column_match = @table_and_column_pattern.match(s)
36
+
37
+ column_match[1]
38
+ end.uniq
39
+ columns = @model_class.column_names
40
+ return unless columns.size == select_columns.size && (columns - select_columns).empty?
41
+ end
25
42
  where = match[2]
26
43
  limit = match[3]
27
44
 
28
45
  query = {}
29
46
  query[:attributes] = sorted_attribute_value_pairs(where)
30
- return nil if query[:attributes].nil?
47
+ return if query[:attributes].nil?
31
48
 
32
- if query[:attributes].size > 1 && query[:attributes].map(&:last).any? {|a| a.is_a?(Array)}
49
+ if query[:attributes].size > 1 && query[:attributes].map(&:last).any?(Array)
33
50
  # this is a query with IN conditions AND other conditions
34
- return nil
51
+ return
35
52
  end
36
53
 
37
54
  query[:index] = query[:attributes].map(&:first)
@@ -64,23 +64,11 @@ module Kasket
64
64
  end
65
65
 
66
66
  def find_by_sql_with_kasket_on_id_array(keys)
67
- begin
68
- key_attributes_map = Kasket.cache.read_multi(*keys)
69
- rescue RuntimeError => e
70
- # Elasticache Memcached has a bug where it returns a 0x00 binary protocol response with no data
71
- # during a reboot, causing the Dalli memcached client to throw a RuntimeError during a multi get
72
- # (https://github.com/petergoldstein/dalli/blob/v2.7.7/lib/dalli/server.rb#L148).
73
- # Fall back to the database when this happens.
74
- if e.message == "multi_response has completed"
75
- key_attributes_map = missing_records_from_db(keys)
76
- else
77
- raise
78
- end
79
- else
80
- found_keys, missing_keys = keys.partition {|k| key_attributes_map[k] }
81
- found_keys.each {|k| key_attributes_map[k] = instantiate(key_attributes_map[k].dup) }
82
- key_attributes_map.merge!(missing_records_from_db(missing_keys))
83
- end
67
+ key_attributes_map = Kasket.cache.read_multi(*keys)
68
+
69
+ found_keys, missing_keys = keys.partition {|k| key_attributes_map[k] }
70
+ found_keys.each {|k| key_attributes_map[k] = instantiate(key_attributes_map[k].dup) }
71
+ key_attributes_map.merge!(missing_records_from_db(missing_keys))
84
72
 
85
73
  key_attributes_map.values.compact
86
74
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Kasket
3
- VERSION = '4.9.1'
3
+ VERSION = '4.10.0'
4
4
  class Version
5
5
  MAJOR = Kasket::VERSION.split('.')[0]
6
6
  MINOR = Kasket::VERSION.split('.')[1]
@@ -52,11 +52,18 @@ module Kasket
52
52
  return :unsupported if ActiveRecord::VERSION::MAJOR < 5 ? node.having : node.havings.present?
53
53
  return :unsupported if node.set_quantifier
54
54
  return :unsupported if !node.source || node.source.empty?
55
- return :unsupported if node.projections.size != 1
55
+ return :unsupported if node.projections.empty?
56
56
 
57
57
  select = node.projections[0]
58
58
  select = select.name if select.respond_to?(:name)
59
- return :unsupported if select != '*'
59
+ if select != '*'
60
+ # If we're not selecting all columns using star, then ensure all columns are selected explicitly
61
+ column_names = @model_class.column_names
62
+ return :unsupported unless node.projections.size == column_names.size
63
+
64
+ projection_names = node.projections.map { |p| p.name if p.respond_to?(:name) }.compact
65
+ return unless (column_names - projection_names).empty?
66
+ end
60
67
 
61
68
  parts = [visit(node.source)]
62
69
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kasket
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.1
4
+ version: 4.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mick Staugaard
8
8
  - Eric Chapweske
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-08-27 00:00:00.000000000 Z
12
+ date: 2022-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -31,118 +31,6 @@ dependencies:
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '6.1'
34
- - !ruby/object:Gem::Dependency
35
- name: bump
36
- requirement: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
- type: :development
42
- prerelease: false
43
- version_requirements: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- - !ruby/object:Gem::Dependency
49
- name: bundler
50
- requirement: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :development
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: minitest
64
- requirement: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- type: :development
70
- prerelease: false
71
- version_requirements: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- - !ruby/object:Gem::Dependency
77
- name: minitest-rg
78
- requirement: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- type: :development
84
- prerelease: false
85
- version_requirements: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- - !ruby/object:Gem::Dependency
91
- name: mocha
92
- requirement: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- type: :development
98
- prerelease: false
99
- version_requirements: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- - !ruby/object:Gem::Dependency
105
- name: rake
106
- requirement: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- type: :development
112
- prerelease: false
113
- version_requirements: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- - !ruby/object:Gem::Dependency
119
- name: timecop
120
- requirement: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- type: :development
126
- prerelease: false
127
- version_requirements: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - ">="
130
- - !ruby/object:Gem::Version
131
- version: '0'
132
- - !ruby/object:Gem::Dependency
133
- name: wwtd
134
- requirement: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ">="
137
- - !ruby/object:Gem::Version
138
- version: '0'
139
- type: :development
140
- prerelease: false
141
- version_requirements: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
34
  description: puts a cap on your queries
147
35
  email:
148
36
  - mick@zendesk.com
@@ -165,7 +53,7 @@ homepage: http://github.com/zendesk/kasket
165
53
  licenses:
166
54
  - Apache License Version 2.0
167
55
  metadata: {}
168
- post_install_message:
56
+ post_install_message:
169
57
  rdoc_options: []
170
58
  require_paths:
171
59
  - lib
@@ -180,8 +68,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
68
  - !ruby/object:Gem::Version
181
69
  version: '0'
182
70
  requirements: []
183
- rubygems_version: 3.1.6
184
- signing_key:
71
+ rubygems_version: 3.0.3.1
72
+ signing_key:
185
73
  specification_version: 4
186
74
  summary: A write back caching layer on active record
187
75
  test_files: []