mysql_framework 1.1.2 → 2.0.0.rc1

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: 3dea6c1520ad570dfaf0070efd3df024dbd8d8ba9bc745970ebc59a82ad38418
4
- data.tar.gz: 7f2e6a694727e104584c5304673841cf06231b3efc538fb1a0bce23f69772293
3
+ metadata.gz: 79a94352053f85513e65fe768c6a2dbe420c14dd84e483e6f5ee276029b3c494
4
+ data.tar.gz: 794c2b7cafbdfa11d9be23e924a71cec74140003396266c2cc2dec023f2c7c26
5
5
  SHA512:
6
- metadata.gz: 6adf70afb9966e920ef972c187679847ea08d1638b3be8b5473bb031d5be41bc607a9143d313aafd106ff748f295b7679437f597f28a88b4e68afa6e1bcb9068
7
- data.tar.gz: '0057569f653959047e9c12feac892e9e0fc51f3fa99085bcd153f26374b4057e7dbdf45f6515d5254798064992065056e7d981369c7700986073390fc88a94e3'
6
+ metadata.gz: affb71d82cf2c8446d72b2a898abbade1d62a04dbebc97502ccef5a92c6c1e0377a9acc9dccf2a08ce6d7d9da03b64eb0b1d1a861715ca15977c2b53f6aa8c89
7
+ data.tar.gz: 8f48457c4dbc815b62406ab8c64fa14a4cc572d0f30c683d66a22a0e9cc7f68112d364edc0bf24d6569fabfaef5869e0606282a9a998910cf1c78bf2f785f264
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MysqlFramework
4
+ # This class is used to represent a Sql IN Condition for a column.
5
+ class InCondition < SqlCondition
6
+ # This method is called to get the condition as a string for a sql prepared statement
7
+ def to_s
8
+ params = value.map { |_| '?' }
9
+ "#{@column} #{@comparison} (#{params.join(', ')})"
10
+ end
11
+ end
12
+ end
@@ -46,6 +46,10 @@ module MysqlFramework
46
46
  SqlCondition.new(column: to_s, comparison: '<=', value: value)
47
47
  end
48
48
 
49
+ def in(*values)
50
+ InCondition.new(column: to_s, comparison: 'IN', value: values)
51
+ end
52
+
49
53
  # This method is called to generate an alias statement for this column.
50
54
  def as(name)
51
55
  "#{self} as `#{name}`"
@@ -9,11 +9,12 @@ module MysqlFramework
9
9
  def initialize
10
10
  @sql = ''
11
11
  @params = []
12
+ @lock = nil
12
13
  end
13
14
 
14
15
  # This method is called to access the sql string for this query.
15
16
  def sql
16
- @sql.strip
17
+ (@sql + @lock.to_s + @dup_query.to_s).strip
17
18
  end
18
19
 
19
20
  # This method is called to start a select query
@@ -76,19 +77,6 @@ module MysqlFramework
76
77
  self
77
78
  end
78
79
 
79
- # This method is called to specify the columns to bulk upsert.
80
- def bulk_upsert(columns)
81
- @sql += 'ON DUPLICATE KEY UPDATE '
82
-
83
- columns.each do |column|
84
- @sql += "#{column} = VALUES(#{column}), "
85
- end
86
-
87
- @sql = @sql.chomp(', ')
88
-
89
- self
90
- end
91
-
92
80
  # This method is called to specify the columns to update.
93
81
  def set(values)
94
82
  @sql += ' SET '
@@ -136,7 +124,13 @@ module MysqlFramework
136
124
  @sql += ' WHERE' unless @sql.include?('WHERE')
137
125
  @sql += " (#{conditions.join(' AND ')}) "
138
126
 
139
- conditions.each { |condition| @params << condition.value }
127
+ conditions.each do |condition|
128
+ if condition.value.is_a?(Enumerable)
129
+ @params.concat(condition.value)
130
+ else
131
+ @params << condition.value
132
+ end
133
+ end
140
134
 
141
135
  self
142
136
  end
@@ -218,5 +212,53 @@ module MysqlFramework
218
212
 
219
213
  self
220
214
  end
215
+
216
+ # This method allows you to add a pessimistic lock to the record.
217
+ # The default lock is `FOR UPDATE`
218
+ # If you require any custom lock, e.g. FOR SHARE, just pass that in as the condition
219
+ # query.lock('FOR SHARE')
220
+ def lock(condition = nil)
221
+ raise 'This must be a SELECT query' unless @sql.start_with?('SELECT')
222
+
223
+ @lock = ' ' + (condition || 'FOR UPDATE')
224
+ self
225
+ end
226
+
227
+ # For insert queries if you need to handle that a primary key already exists and automatically do an update instead.
228
+ # If you do not pass in a hash specifying a column name and custom value for it.
229
+ # @param update_values [Hash] key is a column name. A nil value will make the query update
230
+ # the column with the value specified in the insert. Otherwise any value will be interpreted
231
+ # literally via mysql.
232
+ # @return SqlQuery
233
+ # e.g.
234
+ # query.insert('users')
235
+ # .into('id', first_name', 'login_count')
236
+ # .values(1, 'Bob', 1)
237
+ # .duplicate_update(
238
+ # {
239
+ # first_name: nil,
240
+ # login_count: 'login_count + 5'
241
+ # }
242
+ # )
243
+ # This would first create a record like => `1, 'Bob', 1`.
244
+ # The second time it would update it with => `'Bob', 6` (Note the 1 is not used in the update)
245
+ def on_duplicate(update_values = {})
246
+ raise 'This must be an INSERT query' unless @sql.start_with?('INSERT')
247
+
248
+ duplicates = []
249
+ update_values.each do |column, col_value|
250
+ if col_value.nil?
251
+ # value comes from what the INSERT intended
252
+ updated_value = "#{column} = VALUES (#{column})"
253
+ else
254
+ # custom value specified by col_value
255
+ updated_value = "#{column} = #{col_value}"
256
+ end
257
+ duplicates << updated_value
258
+ end
259
+ @dup_query = " ON DUPLICATE KEY UPDATE #{duplicates.join(', ')}"
260
+
261
+ self
262
+ end
221
263
  end
222
264
  end
@@ -5,11 +5,13 @@ module MysqlFramework
5
5
  class SqlTable
6
6
  def initialize(name)
7
7
  @name = name
8
+ @column_objects = {}
8
9
  end
9
10
 
10
11
  # This method is called to get a sql column for this table
11
12
  def [](column)
12
- SqlColumn.new(table: @name, column: column)
13
+ return @column_objects[column.to_sym] if @column_objects[column.to_sym]
14
+ @column_objects[column.to_sym] = SqlColumn.new(table: @name, column: column)
13
15
  end
14
16
 
15
17
  def to_s
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MysqlFramework
4
- VERSION = '1.1.2'
4
+ VERSION = '2.0.0.rc1'
5
5
  end
@@ -7,6 +7,7 @@ require_relative 'mysql_framework/logger'
7
7
  require_relative 'mysql_framework/scripts'
8
8
  require_relative 'mysql_framework/sql_column'
9
9
  require_relative 'mysql_framework/sql_condition'
10
+ require_relative 'mysql_framework/in_condition'
10
11
  require_relative 'mysql_framework/sql_query'
11
12
  require_relative 'mysql_framework/sql_table'
12
13
  require_relative 'mysql_framework/version'
@@ -63,6 +63,14 @@ describe MysqlFramework::SqlColumn do
63
63
  end
64
64
  end
65
65
 
66
+ describe '#in' do
67
+ it 'returns a SqlCondition for the comparison' do
68
+ condition = subject.in('a', 'b', 'c')
69
+ expect(condition).to be_a(MysqlFramework::InCondition)
70
+ expect(condition.to_s).to eq('`gems`.`version` IN (?, ?, ?)')
71
+ end
72
+ end
73
+
66
74
  describe '#as' do
67
75
  it 'returns the column specified as another name' do
68
76
  expect(subject.as('v')).to eq('`gems`.`version` as `v`')
@@ -139,16 +139,6 @@ describe MysqlFramework::SqlQuery do
139
139
  end
140
140
  end
141
141
 
142
- describe '#bulk_upsert' do
143
- it 'sets the sql for the upsert statement' do
144
- columns = %w(column_1 column_2)
145
-
146
- subject.bulk_upsert(columns)
147
-
148
- expect(subject.sql).to eq('ON DUPLICATE KEY UPDATE column_1 = VALUES(column_1), column_2 = VALUES(column_2)')
149
- end
150
- end
151
-
152
142
  describe '#set' do
153
143
  it 'sets the sql for the set statement' do
154
144
  subject.set(name: 'mysql_framework', author: 'sage', created_at: '2016-06-28 10:00:00')
@@ -330,4 +320,69 @@ describe MysqlFramework::SqlQuery do
330
320
  end
331
321
  end
332
322
  end
323
+
324
+ describe '#lock' do
325
+ it 'appends `FOR_UPDATE` to the query' do
326
+ subject.select('*').from(gems).lock
327
+ expect(subject.sql).to end_with('FOR UPDATE')
328
+ end
329
+ end
330
+
331
+ describe '#on_duplicate' do
332
+ let(:query) do
333
+ subject.insert(gems)
334
+ .into(
335
+ gems[:id],
336
+ gems[:name],
337
+ gems[:author]
338
+ )
339
+ .values(
340
+ 1,
341
+ 'mysql_framework',
342
+ 'Bob Hope'
343
+ )
344
+ end
345
+
346
+ context 'when no custom values are specified' do
347
+ it 'updates with the value from the INSERT clause' do
348
+ query.on_duplicate(
349
+ {
350
+ gems[:name] => nil,
351
+ gems[:author] => nil
352
+ }
353
+ )
354
+
355
+ expect(query.sql)
356
+ .to end_with 'ON DUPLICATE KEY UPDATE `gems`.`name` = VALUES (`gems`.`name`), `gems`.`author` = VALUES (`gems`.`author`)'
357
+ end
358
+ end
359
+
360
+ context 'when a custom value is specified' do
361
+ it 'updates the value based on the custom value' do
362
+ query.on_duplicate(
363
+ {
364
+ gems[:name] => '"mysql_alternative"',
365
+ gems[:author] => '"Michael Caine"'
366
+ }
367
+ )
368
+
369
+ expect(query.sql)
370
+ .to end_with 'ON DUPLICATE KEY UPDATE `gems`.`name` = "mysql_alternative", `gems`.`author` = "Michael Caine"'
371
+ end
372
+ end
373
+
374
+ context 'when column names are specified instead of SqlColumn objects' do
375
+ it 'updates the value based on the custom column key names' do
376
+ query.on_duplicate(
377
+ {
378
+ name: '"mysql_alternative"',
379
+ author: '"Michael Caine"'
380
+ }
381
+ )
382
+
383
+ expect(query.sql)
384
+ .to end_with 'ON DUPLICATE KEY UPDATE name = "mysql_alternative", author = "Michael Caine"'
385
+ end
386
+ end
387
+ end
333
388
  end
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: 1.1.2
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sage
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-08-09 00:00:00.000000000 Z
11
+ date: 2019-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -89,6 +89,7 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - lib/mysql_framework.rb
91
91
  - lib/mysql_framework/connector.rb
92
+ - lib/mysql_framework/in_condition.rb
92
93
  - lib/mysql_framework/logger.rb
93
94
  - lib/mysql_framework/scripts.rb
94
95
  - lib/mysql_framework/scripts/base.rb
@@ -132,9 +133,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
133
  version: '0'
133
134
  required_rubygems_version: !ruby/object:Gem::Requirement
134
135
  requirements:
135
- - - ">="
136
+ - - ">"
136
137
  - !ruby/object:Gem::Version
137
- version: '0'
138
+ version: 1.3.1
138
139
  requirements: []
139
140
  rubyforge_project:
140
141
  rubygems_version: 2.7.7