mysql_framework 2.0.0 → 2.1.3

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: 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.