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 +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
|