mysql_framework 1.1.2 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mysql_framework/in_condition.rb +12 -0
- data/lib/mysql_framework/sql_column.rb +4 -0
- data/lib/mysql_framework/sql_query.rb +57 -15
- data/lib/mysql_framework/sql_table.rb +3 -1
- data/lib/mysql_framework/version.rb +1 -1
- data/lib/mysql_framework.rb +1 -0
- data/spec/lib/mysql_framework/sql_column_spec.rb +8 -0
- data/spec/lib/mysql_framework/sql_query_spec.rb +65 -10
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79a94352053f85513e65fe768c6a2dbe420c14dd84e483e6f5ee276029b3c494
|
4
|
+
data.tar.gz: 794c2b7cafbdfa11d9be23e924a71cec74140003396266c2cc2dec023f2c7c26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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
|
data/lib/mysql_framework.rb
CHANGED
@@ -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:
|
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-
|
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:
|
138
|
+
version: 1.3.1
|
138
139
|
requirements: []
|
139
140
|
rubyforge_project:
|
140
141
|
rubygems_version: 2.7.7
|