mysql_framework 2.0.0 → 2.1.3

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
2
  SHA256:
3
- metadata.gz: 67610b6f4fad6d1ae4feca440f9952c02c92e56dc9add1f8ae65c5258cbb70e5
4
- data.tar.gz: d27443bd3f0d37eecc86471f43a9a67047dea2a873b122851cb32b3f41062c47
3
+ metadata.gz: 38653f6e3d1d849566574e58eb8386b4c32890370404cb3eade583b0070f5041
4
+ data.tar.gz: 5534eca9f224d13580cfd09f4e2478208857e5b353c9a664ed7b772bf8a088e1
5
5
  SHA512:
6
- metadata.gz: def004956a96d594de0afe4e6b2f6033d539b0affc5ba08e9a83813f46dd8f0beaa9d0e6e65d45bb985cbd931c5d33c39a0b093412850fb8e7acd33130418893
7
- data.tar.gz: bb88d080d02dbf476de3f7c94ff4982b93fb92ac63aaf7a472944a13859de7bf01458e1cb8b6e9af6c2b38e2b49e277c610abaed4d078f6a43d9df01ba2f6517
6
+ metadata.gz: aa4e726ac90ac8b1ecd8ca20a64b4c33e81d003c395b49c340f712df500fc7879956f5479f9c23e53fe20ca947d41d2798ad42732c596a03ab219129f02a7dbd
7
+ data.tar.gz: ba2080bb5f7595b82996a48a0316ed70cf7560b5687abb9d5c9768c73f5e2b296e42378aa9139c80e2d5f705a8fa7bdb08167a740c019a6d5d0a0825436873e7
@@ -59,10 +59,9 @@ module MysqlFramework
59
59
 
60
60
  # This method is called to check a client back in to the connection when no longer needed.
61
61
  def check_in(client)
62
- return client.close unless connection_pool_enabled?
63
-
64
- client = new_client if client.closed?
62
+ return client&.close unless connection_pool_enabled?
65
63
 
64
+ client = new_client if client.nil? || client.closed?
66
65
  @connection_pool.push(client)
67
66
  end
68
67
 
@@ -75,10 +74,20 @@ module MysqlFramework
75
74
  end
76
75
 
77
76
  # This method is called to execute a prepared statement
77
+ #
78
+ # @note Ensure we free any result and close each statement, otherwise we
79
+ # can run into a 'Commands out of sync' error if multiple threads are
80
+ # running different queries at the same time.
78
81
  def execute(query, provided_client = nil)
79
82
  with_client(provided_client) do |client|
80
- statement = client.prepare(query.sql)
81
- statement.execute(*query.params)
83
+ begin
84
+ statement = client.prepare(query.sql)
85
+ result = statement.execute(*query.params)
86
+ result&.to_a
87
+ ensure
88
+ result&.free
89
+ statement&.close
90
+ end
82
91
  end
83
92
  end
84
93
 
@@ -50,7 +50,12 @@ module MysqlFramework
50
50
  end
51
51
 
52
52
  def invalid_nil_value?(value)
53
+ return false if skip_nil_validation?
53
54
  nil_comparison? == false && value.nil?
54
55
  end
56
+
57
+ def skip_nil_validation?
58
+ ENV.fetch('MYSQL_FRAMEWORK_SKIP_NIL_VALUE_VALIDATION', 'false').downcase == 'true'
59
+ end
55
60
  end
56
61
  end
@@ -120,11 +120,14 @@ module MysqlFramework
120
120
  end
121
121
 
122
122
  # This method is called to specify a where clause for a query.
123
+ #
124
+ # Condition values are added to @params unless the value is nil.
123
125
  def where(*conditions)
124
126
  @sql += ' WHERE' unless @sql.include?('WHERE')
125
127
  @sql += " (#{conditions.join(' AND ')}) "
126
128
 
127
129
  conditions.each do |condition|
130
+ next if condition.value.nil?
128
131
  if condition.value.is_a?(Enumerable)
129
132
  @params.concat(condition.value)
130
133
  else
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MysqlFramework
4
- VERSION = '2.0.0'
4
+ VERSION = '2.1.3'
5
5
  end
@@ -232,6 +232,24 @@ describe MysqlFramework::Connector do
232
232
  subject.check_in(client)
233
233
  end
234
234
  end
235
+
236
+ context 'when client is nil' do
237
+ let(:client) { nil }
238
+
239
+ context 'when connection pooling is enabled' do
240
+ it 'does not raise an error' do
241
+ expect { subject.check_in(client) }.not_to raise_error
242
+ end
243
+ end
244
+
245
+ context 'when connection pooling is disabled' do
246
+ let(:connection_pooling_enabled) { 'false' }
247
+
248
+ it 'does not raise an error' do
249
+ expect { subject.check_in(client) }.not_to raise_error
250
+ end
251
+ end
252
+ end
235
253
  end
236
254
 
237
255
  describe '#with_client' do
@@ -272,6 +290,62 @@ describe MysqlFramework::Connector do
272
290
  expect(results.length).to eq(1)
273
291
  expect(results[0][:id]).to eq(guid)
274
292
  end
293
+
294
+ context 'when cleaning up resources' do
295
+ let(:mock_client) { double('client') }
296
+ let(:mock_statement) { double('statement') }
297
+ let(:mock_result) { double('result') }
298
+ let(:select_query) { MysqlFramework::SqlQuery.new.select('*').from('demo') }
299
+
300
+ before do
301
+ allow(mock_result).to receive(:to_a)
302
+ allow(mock_result).to receive(:free)
303
+
304
+ allow(mock_statement).to receive(:close)
305
+ allow(mock_statement).to receive(:execute).and_return(mock_result)
306
+
307
+ allow(mock_client).to receive(:prepare).and_return(mock_statement)
308
+ end
309
+
310
+ it 'frees the result' do
311
+ expect(mock_result).to receive(:free)
312
+
313
+ subject.execute(select_query, mock_client)
314
+ end
315
+
316
+ it 'closes the statement' do
317
+ expect(mock_statement).to receive(:close)
318
+
319
+ subject.execute(select_query, mock_client)
320
+ end
321
+ end
322
+
323
+ it 'does not raise a commands out of sync error' do
324
+ threads = []
325
+ threads << Thread.new do
326
+ 350.times do
327
+ update_query = MysqlFramework::SqlQuery.new.update('gems')
328
+ .set(updated_at: Time.now)
329
+ expect { subject.execute(update_query) }.not_to raise_error
330
+ end
331
+ end
332
+
333
+ threads << Thread.new do
334
+ 350.times do
335
+ select_query = MysqlFramework::SqlQuery.new.select('*').from('demo')
336
+ expect { subject.execute(select_query) }.not_to raise_error
337
+ end
338
+ end
339
+
340
+ threads << Thread.new do
341
+ 350.times do
342
+ select_query = MysqlFramework::SqlQuery.new.select('*').from('test')
343
+ expect { subject.execute(select_query) }.not_to raise_error
344
+ end
345
+ end
346
+
347
+ threads.each(&:join)
348
+ end
275
349
  end
276
350
 
277
351
  describe '#query' do
@@ -3,6 +3,12 @@
3
3
  describe MysqlFramework::SqlCondition do
4
4
  subject { described_class.new(column: 'version', comparison: '=', value: '1.0.0') }
5
5
 
6
+ before :each do
7
+ allow_any_instance_of(MysqlFramework::SqlCondition).to receive(:skip_nil_validation?).and_return(skip_nil_validation)
8
+ end
9
+
10
+ let(:skip_nil_validation) { false }
11
+
6
12
  describe '#to_s' do
7
13
  it 'returns the condition as a string for a prepared statement' do
8
14
  expect(subject.to_s).to eq('version = ?')
@@ -16,6 +22,14 @@ describe MysqlFramework::SqlCondition do
16
22
  it 'does raises an ArgumentError' do
17
23
  expect { subject }.to raise_error(ArgumentError, "Comparison of = requires value to be not nil")
18
24
  end
25
+
26
+ context 'when skip_nil_validation? is true' do
27
+ let(:skip_nil_validation) { true }
28
+
29
+ it 'does not raise an ArgumentError' do
30
+ expect(subject.value).to be_nil
31
+ end
32
+ end
19
33
  end
20
34
  end
21
35
 
@@ -33,6 +47,14 @@ describe MysqlFramework::SqlCondition do
33
47
  it 'raises an ArgumentError if value is set' do
34
48
  expect { subject }.to raise_error(ArgumentError, 'Cannot set value when comparison is IS NULL')
35
49
  end
50
+
51
+ context 'when skip_nil_validation? is true' do
52
+ let(:skip_nil_validation) { true }
53
+
54
+ it 'raises an ArgumentError if value is set' do
55
+ expect { subject }.to raise_error(ArgumentError, 'Cannot set value when comparison is IS NULL')
56
+ end
57
+ end
36
58
  end
37
59
  end
38
60
 
@@ -67,6 +89,14 @@ describe MysqlFramework::SqlCondition do
67
89
  it 'raises an ArgumentError if value is set' do
68
90
  expect { subject }.to raise_error(ArgumentError, 'Cannot set value when comparison is IS NOT NULL')
69
91
  end
92
+
93
+ context 'when skip_nil_validation? is true' do
94
+ let(:skip_nil_validation) { true }
95
+
96
+ it 'raises an ArgumentError if value is set' do
97
+ expect { subject }.to raise_error(ArgumentError, 'Cannot set value when comparison is IS NOT NULL')
98
+ end
99
+ end
70
100
  end
71
101
  end
72
102
 
@@ -50,6 +50,19 @@ describe MysqlFramework::SqlQuery do
50
50
  expect(subject.params).to eq(['9876'])
51
51
  end
52
52
 
53
+ context 'when a select query contains conditions with nil values' do
54
+ it 'does not store them as parameters' do
55
+ subject.select('*')
56
+ .from(gems, 40)
57
+ .where(
58
+ MysqlFramework::SqlCondition.new(column: 'id', comparison: '=', value: 9876),
59
+ MysqlFramework::SqlCondition.new(column: 'foo', comparison: 'IS NOT NULL'),
60
+ )
61
+ expect(subject.sql).to eq('SELECT * FROM `gems` PARTITION (p40) WHERE (id = ? AND foo IS NOT NULL)')
62
+ expect(subject.params.size).to eq 1
63
+ end
64
+ end
65
+
53
66
  it 'builds a joined select query as expected' do
54
67
  subject.select('*')
55
68
  .from(gems, 40)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mysql_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sage
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-22 00:00:00.000000000 Z
11
+ date: 2021-03-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -137,8 +137,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
139
  requirements: []
140
- rubyforge_project:
141
- rubygems_version: 2.7.7
140
+ rubygems_version: 3.0.8
142
141
  signing_key:
143
142
  specification_version: 4
144
143
  summary: A lightweight framework to provide managers for working with MySQL.