mysql2wrapper 0.0.1
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.
- data/.gitignore +18 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +20 -0
- data/README.md +6 -0
- data/Rakefile +1 -0
- data/config/database.yml +4 -0
- data/config/database_multiple.yml +9 -0
- data/example/sample.rb +77 -0
- data/lib/mysql2wrapper.rb +16 -0
- data/lib/mysql2wrapper/client.rb +203 -0
- data/lib/mysql2wrapper/version.rb +3 -0
- data/mysql2wrapper.gemspec +24 -0
- data/test/by_hand.rb +80 -0
- data/test/test.rb +382 -0
- data/test/test_helper.rb +5 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mysql2wrapper (0.0.1)
|
5
|
+
batchbase (= 0.0.2)
|
6
|
+
mysql2 (= 0.3.11)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: http://rubygems.org/
|
10
|
+
specs:
|
11
|
+
batchbase (0.0.2)
|
12
|
+
sys-proctable (= 0.9.1)
|
13
|
+
mysql2 (0.3.11)
|
14
|
+
sys-proctable (0.9.1)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
mysql2wrapper!
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/config/database.yml
ADDED
data/example/sample.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'mysql2wrapper'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
#
|
6
|
+
# HACKME サンプルをちょっとはマシに書く、、、、
|
7
|
+
#
|
8
|
+
|
9
|
+
|
10
|
+
logger = Logger.new(STDOUT)
|
11
|
+
# フォーマッターを変える
|
12
|
+
#logger.formatter = Kanamei::LogFormatter.formatter
|
13
|
+
db_yml_path = File::dirname(__FILE__) + '/../config/database.yml'
|
14
|
+
logger.info db_yml_path
|
15
|
+
|
16
|
+
# 第3引数は複数DB接続が無いならば指定不要
|
17
|
+
db_config = Mysql2wrapper::Client.config_from_yml(db_yml_path,'test')
|
18
|
+
|
19
|
+
client = Mysql2wrapper::Client.new(db_config,logger)
|
20
|
+
# ログ出力しないなら第二引数をnilで
|
21
|
+
#client = Mysql2wrapper::Client.new(db_config,nil)
|
22
|
+
|
23
|
+
query = '
|
24
|
+
DROP TABLE IF EXISTS `hoges`'
|
25
|
+
client.query query
|
26
|
+
query = '
|
27
|
+
CREATE TABLE IF NOT EXISTS `hoges` (
|
28
|
+
`id` int(11) NOT NULL auto_increment,
|
29
|
+
`value1` int(11) NOT NULL,
|
30
|
+
`created_at` datetime NOT NULL,
|
31
|
+
`updated_at` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
|
32
|
+
PRIMARY KEY (`id`)
|
33
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;'
|
34
|
+
client.query query
|
35
|
+
|
36
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
37
|
+
client.query "INSERT INTO hoges (value1,created_at)VALUES(#{Time.now.to_i},NOW())"
|
38
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
39
|
+
|
40
|
+
begin
|
41
|
+
# トランザクションはブロックを渡す(ARと同じく)
|
42
|
+
client.transaction do
|
43
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
44
|
+
client.query "INSERT INTO hoges (value1,created_at)VALUES(#{Time.now.to_i},NOW())"
|
45
|
+
client.query query
|
46
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
47
|
+
raise 'error' # call ROLLBACK
|
48
|
+
end
|
49
|
+
rescue
|
50
|
+
end
|
51
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
52
|
+
|
53
|
+
# ハッシュを引数にしたインサートの発行
|
54
|
+
@i = 0
|
55
|
+
hash = {
|
56
|
+
:value1=>proc{@i+=1}, # procを引数にもできる
|
57
|
+
:created_at=>'now()'.to_func
|
58
|
+
}
|
59
|
+
client.insert('hoges',hash)
|
60
|
+
logger.info "affected_rows:#{client.affected_rows}"
|
61
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
62
|
+
|
63
|
+
# 配列を引数にしたインサートの発行
|
64
|
+
ar = []
|
65
|
+
20.times{ar << hash}
|
66
|
+
client.insert('hoges',ar)
|
67
|
+
logger.info "affected_rows:#{client.affected_rows}" # Client#affected_rowsでマルチプルインサートのトータルインサート数が取れる
|
68
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
69
|
+
|
70
|
+
# ハッシュを引数にしたアップデート
|
71
|
+
client.update 'hoges',{:value1=>3},'id = 1'
|
72
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
73
|
+
# 全行アップデートをしたなら第三引数でMysql2wrapper::Client::UpdateAllClassを引数にしないとダメ
|
74
|
+
client.update 'hoges',{:value1=>3},Mysql2wrapper::Client::UpdateAllClass
|
75
|
+
# clientインスタンスにショートカットあり
|
76
|
+
client.update 'hoges',{:value1=>4},client.update_all_flag
|
77
|
+
logger.info "hoge has #{client.count 'hoges'}rows"
|
@@ -0,0 +1,203 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'mysql2'
|
5
|
+
|
6
|
+
class Mysql2wrapper::Client
|
7
|
+
attr_accessor :config, :client, :logger
|
8
|
+
attr_reader :affected_rows
|
9
|
+
|
10
|
+
# 全行更新用のフラグ表現クラス
|
11
|
+
class UpdateAllClass;end
|
12
|
+
|
13
|
+
UPDATE_ALL = UpdateAllClass
|
14
|
+
QUERY_BASE_COLOR = 35
|
15
|
+
QUERY_SPECIAL_COLOR = 31
|
16
|
+
|
17
|
+
MULTIPLE_INSERT_DEFAULT = 100
|
18
|
+
|
19
|
+
def initialize(config,_logger=Logger.new(STDOUT))
|
20
|
+
self.logger = _logger
|
21
|
+
if self.logger
|
22
|
+
self.logger.info "mysql2 client created with #{config.inspect}"
|
23
|
+
end
|
24
|
+
self.client = Mysql2::Client.new(config)
|
25
|
+
self.config = config
|
26
|
+
# サーバが古いので一応問題あるけど以下の方向で
|
27
|
+
# http://kennyqi.com/archives/61.html
|
28
|
+
self.class.query(self.client,"SET NAMES 'utf8'",self.logger)
|
29
|
+
self.class.query(self.client,"SET SQL_AUTO_IS_NULL=0",self.logger)
|
30
|
+
self.class.query(self.client,"SET SQL_MODE=STRICT_ALL_TABLES",self.logger)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.query(client,sql_query,logger=nil,color=QUERY_BASE_COLOR)
|
34
|
+
s = Time.now
|
35
|
+
ret = client.query(sql_query)
|
36
|
+
e = Time.now
|
37
|
+
if logger
|
38
|
+
# TODO too long sql shorten
|
39
|
+
if sql_query.size > 1400
|
40
|
+
sql_query = sql_query[0..600] + "\n<< trimed >>\n" + sql_query[(sql_query.size - 600)..(sql_query.size - 1)]
|
41
|
+
end
|
42
|
+
logger.info "[QUERY] "" \e[#{color}m (#{((e-s)*1000).round(2)}ms/#{client.affected_rows}rows) #{sql_query}\e[0m"
|
43
|
+
end
|
44
|
+
ret
|
45
|
+
end
|
46
|
+
|
47
|
+
def stop_logging
|
48
|
+
self.logger = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def dump
|
52
|
+
"#{self.config.inspect}\n#{self.client.pretty_inspect}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def query(str,color=QUERY_BASE_COLOR)
|
56
|
+
res = self.class.query(self.client,str,self.logger,color)
|
57
|
+
@affected_rows = self.client.affected_rows
|
58
|
+
res
|
59
|
+
end
|
60
|
+
|
61
|
+
def transaction(&proc)
|
62
|
+
raise ArgumentError, "No block was given" unless block_given?
|
63
|
+
#query "SET AUTOCOMMIT=0;",QUERY_SPECIAL_COLOR
|
64
|
+
query "BEGIN",QUERY_SPECIAL_COLOR
|
65
|
+
begin
|
66
|
+
yield
|
67
|
+
query "COMMIT",QUERY_SPECIAL_COLOR
|
68
|
+
rescue => e
|
69
|
+
query "ROLLBACK",QUERY_SPECIAL_COLOR
|
70
|
+
raise e
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.make_config_key_symbol(config)
|
75
|
+
new_config = {}
|
76
|
+
config.each do |key,value|
|
77
|
+
new_config[key.to_sym] = value
|
78
|
+
end
|
79
|
+
config = new_config
|
80
|
+
end
|
81
|
+
|
82
|
+
def count(table_name,key_name='*')
|
83
|
+
query("SELECT COUNT(#{escape(key_name)}) AS cnt FROM #{escape(table_name)}").first['cnt']
|
84
|
+
end
|
85
|
+
|
86
|
+
def close
|
87
|
+
self.client.close if self.client
|
88
|
+
end
|
89
|
+
|
90
|
+
def escape(str)
|
91
|
+
self.client.escape(str)
|
92
|
+
end
|
93
|
+
|
94
|
+
def sanitize(str)
|
95
|
+
escape(str)
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# where は 'WHERE'を付けずに指定
|
100
|
+
# 全行updateを使用するシチュエーションはほぼ0に
|
101
|
+
# 近いと思われるので、簡単には実行できなくしてます
|
102
|
+
# 実際に実行する際はwhereにUpdateAllを引数とします
|
103
|
+
# client.update 'test01',{:v_int1=>3},Mysql2wrapper::Client::UPDATE_ALL
|
104
|
+
#
|
105
|
+
def update(table_name,hash,where)
|
106
|
+
case where
|
107
|
+
when String
|
108
|
+
where = "WHERE #{where}"
|
109
|
+
when UpdateAllClass.class
|
110
|
+
where = ''
|
111
|
+
else
|
112
|
+
raise ArgumentError, "where must be String or UpdateAll"
|
113
|
+
end
|
114
|
+
query = "UPDATE `#{escape(table_name)}` SET #{
|
115
|
+
hash.map do |key,value|
|
116
|
+
"`#{escape(key.to_s)}` = #{proceed_value(value)}"
|
117
|
+
end.join(',')
|
118
|
+
}" + where
|
119
|
+
self.query(query)
|
120
|
+
end
|
121
|
+
|
122
|
+
def update_all_flag
|
123
|
+
self.class::UPDATE_ALL
|
124
|
+
end
|
125
|
+
|
126
|
+
def proceed_value(value)
|
127
|
+
case value
|
128
|
+
when Proc
|
129
|
+
"'#{escape(value.call.to_s)}'"
|
130
|
+
when nil
|
131
|
+
"NULL"
|
132
|
+
when TrueClass,FalseClass
|
133
|
+
if value
|
134
|
+
"'1'"
|
135
|
+
else
|
136
|
+
"'0'"
|
137
|
+
end
|
138
|
+
when Time,DateTime
|
139
|
+
"'#{value.strftime("%Y-%m-%d %H:%M:%S")}'"
|
140
|
+
when Date
|
141
|
+
"'#{value.strftime("%Y-%m-%d")}'"
|
142
|
+
else
|
143
|
+
s = value
|
144
|
+
s = s.to_s unless s.kind_of?(String)
|
145
|
+
if s.respond_to?(:function_sql?) && s.function_sql?
|
146
|
+
"#{value.to_s}"
|
147
|
+
else
|
148
|
+
"'#{escape(value.to_s)}'"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def insert(table_name,data,multiple_insert_by=MULTIPLE_INSERT_DEFAULT)
|
154
|
+
@affected_rows = 0 # 一応リセットしとくか、、、
|
155
|
+
affected_rows_total = 0
|
156
|
+
query = "INSERT INTO `#{escape(table_name)}`"
|
157
|
+
_datas = data.clone
|
158
|
+
case _datas
|
159
|
+
when Array
|
160
|
+
;
|
161
|
+
when Hash
|
162
|
+
_datas = [_datas]
|
163
|
+
else
|
164
|
+
raise ArgumentError, "data must be Array or Hash"
|
165
|
+
end
|
166
|
+
|
167
|
+
return nil if _datas.size == 0
|
168
|
+
|
169
|
+
# TODO affected_rows by multiple
|
170
|
+
_datas.each_slice(multiple_insert_by).each do |rows|
|
171
|
+
query = <<"EOS"
|
172
|
+
INSERT INTO `#{escape(table_name)}`
|
173
|
+
(#{rows.first.keys.map{|o|"`#{escape(o.to_s)}`"}.join(',')})
|
174
|
+
VALUES
|
175
|
+
#{
|
176
|
+
rows.map do |row|
|
177
|
+
"(#{
|
178
|
+
row.map do |key,value|
|
179
|
+
proceed_value(value)
|
180
|
+
end.join(',')
|
181
|
+
})"
|
182
|
+
end.join(',')
|
183
|
+
}
|
184
|
+
EOS
|
185
|
+
self.query(query.chomp)
|
186
|
+
affected_rows_total += self.client.affected_rows
|
187
|
+
end
|
188
|
+
@affected_rows = affected_rows_total
|
189
|
+
end
|
190
|
+
|
191
|
+
#
|
192
|
+
# db_server_nameはDB名そのもの(複数DB対応)
|
193
|
+
#
|
194
|
+
def self.config_from_yml(yml_path,environment,db_server_name=nil)
|
195
|
+
db_config = YAML.load_file(yml_path)[environment]
|
196
|
+
if db_server_name
|
197
|
+
db_config = self.make_config_key_symbol(db_config[db_server_name])
|
198
|
+
else
|
199
|
+
db_config = self.make_config_key_symbol(db_config)
|
200
|
+
end
|
201
|
+
db_config
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "mysql2wrapper/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "mysql2wrapper"
|
7
|
+
s.version = Mysql2wrapper::VERSION
|
8
|
+
s.authors = ["pacojp"]
|
9
|
+
s.email = ["paco.jp@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{oreore mysql2 wrapper class}
|
12
|
+
s.description = %q{oreore mysql2 wrapper class}
|
13
|
+
s.rubyforge_project = "mysql2wrapper"
|
14
|
+
s.add_dependency 'mysql2','0.3.11'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
data/test/by_hand.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
#
|
4
|
+
# trial space
|
5
|
+
#
|
6
|
+
|
7
|
+
$: << File.dirname(__FILE__)
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'test_helper'
|
11
|
+
require 'logger'
|
12
|
+
|
13
|
+
require 'mysql2wrapper'
|
14
|
+
|
15
|
+
db_yml_path = File::dirname(__FILE__) + '/../config/database.yml'
|
16
|
+
puts db_yml_path
|
17
|
+
# 第3引数は複数DB接続が無いならば指定不要
|
18
|
+
db_config = Mysql2wrapper::Client.config_from_yml(db_yml_path,'test')
|
19
|
+
|
20
|
+
client = Mysql2wrapper::Client.new(db_config)
|
21
|
+
query = 'DROP TABLE IF EXISTS `hoges`'
|
22
|
+
client.query(query)
|
23
|
+
query = '
|
24
|
+
CREATE TABLE IF NOT EXISTS `hoges` (
|
25
|
+
`id` int(11) NOT NULL auto_increment,
|
26
|
+
`v_int1` int(11) NOT NULL,
|
27
|
+
`v_int2` int(11) NOT NULL,
|
28
|
+
`v_int3` int(11),
|
29
|
+
`v_str1` varchar(10) NOT NULL,
|
30
|
+
`v_str2` varchar(10) NOT NULL,
|
31
|
+
`v_str3` varchar(10) NOT NULL,
|
32
|
+
`v_datetime1` datetime NOT NULL,
|
33
|
+
`v_datetime2` datetime NOT NULL,
|
34
|
+
`created_at` datetime NOT NULL,
|
35
|
+
`updated_at` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
|
36
|
+
PRIMARY KEY (`id`)
|
37
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
38
|
+
'
|
39
|
+
client.query query
|
40
|
+
|
41
|
+
@i = 0
|
42
|
+
increment = proc{@i+=1}
|
43
|
+
|
44
|
+
# hashでインサート
|
45
|
+
hash = {
|
46
|
+
:v_int1=>increment,
|
47
|
+
:v_int2=>rand(10000),
|
48
|
+
:v_int3=>nil,
|
49
|
+
:v_str1=>'test',
|
50
|
+
:v_str2=>'hoho',
|
51
|
+
:v_str3=>"CONCAT('My','S','QL')".to_func,
|
52
|
+
:v_datetime1=>Time.mktime(2011,12,3,4,5,6),
|
53
|
+
:v_datetime2=>DateTime.new(2011,12,3,4,5,6),
|
54
|
+
:created_at=>'NOW()'.to_func
|
55
|
+
}
|
56
|
+
client.insert('hoges',hash)
|
57
|
+
|
58
|
+
# hashの配列でマルチプルインサート
|
59
|
+
array = []
|
60
|
+
101.times{array << hash}
|
61
|
+
client.insert('hoges',array)
|
62
|
+
puts "hoge has #{client.count 'hoges'}rows"
|
63
|
+
|
64
|
+
client.transaction do
|
65
|
+
client.insert('hoges',hash)
|
66
|
+
end
|
67
|
+
puts "hoge has #{client.count 'hoges'}rows"
|
68
|
+
|
69
|
+
begin
|
70
|
+
client.transaction do
|
71
|
+
client.insert('hoges',hash)
|
72
|
+
raise 'roooooooooollback!'
|
73
|
+
end
|
74
|
+
rescue
|
75
|
+
end
|
76
|
+
puts "hoge has #{client.count 'hoges'}rows"
|
77
|
+
|
78
|
+
client.update 'hoges',{:v_int1=>2},'id = 1'
|
79
|
+
client.update 'hoges',{:v_int1=>2},client.class::UPDATE_ALL
|
80
|
+
|
data/test/test.rb
ADDED
@@ -0,0 +1,382 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)
|
4
|
+
require 'test_helper'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'Fileutils'
|
7
|
+
require 'logger'
|
8
|
+
|
9
|
+
#
|
10
|
+
# localhostに以下のデータベースを作成しrootのパスワード無しでアクセスできるようにしておいてください
|
11
|
+
#
|
12
|
+
# mysql2wrapper_test
|
13
|
+
# mysql2wrapper_test_master
|
14
|
+
# mysql2wrapper_test_slave
|
15
|
+
#
|
16
|
+
|
17
|
+
class TestMysql2wrapper < Test::Unit::TestCase
|
18
|
+
|
19
|
+
def setup
|
20
|
+
@i = 0
|
21
|
+
client = get_client
|
22
|
+
|
23
|
+
query = 'DROP TABLE IF EXISTS `test01`'
|
24
|
+
client.query query
|
25
|
+
query = 'DROP TABLE IF EXISTS `test02`'
|
26
|
+
client.query query
|
27
|
+
|
28
|
+
query = simple_table_create_query('test01')
|
29
|
+
client.query query
|
30
|
+
|
31
|
+
query = '
|
32
|
+
CREATE TABLE IF NOT EXISTS `test02` (
|
33
|
+
`id` int(11) NOT NULL auto_increment,
|
34
|
+
`v_int1` int(11) NOT NULL,
|
35
|
+
`v_int2` int(11) NOT NULL,
|
36
|
+
`v_int3` int(11),
|
37
|
+
`v_int4` int(11),
|
38
|
+
`v_bool1` tinyint(1) NOT NULL,
|
39
|
+
`v_bool2` tinyint(1) NOT NULL,
|
40
|
+
`v_bool3` tinyint(1),
|
41
|
+
`v_bool4` tinyint(1),
|
42
|
+
`v_str1` varchar(10) NOT NULL,
|
43
|
+
`v_str2` varchar(10) NOT NULL,
|
44
|
+
`v_str3` varchar(10),
|
45
|
+
`v_str4` varchar(10),
|
46
|
+
`v_date1` date NOT NULL,
|
47
|
+
`v_date2` date,
|
48
|
+
`v_date3` date,
|
49
|
+
`v_datetime1` datetime NOT NULL,
|
50
|
+
`v_datetime2` datetime,
|
51
|
+
`v_datetime3` datetime,
|
52
|
+
`v_time1` datetime NOT NULL,
|
53
|
+
`v_time2` datetime,
|
54
|
+
`v_time3` datetime,
|
55
|
+
`created_at` datetime NOT NULL,
|
56
|
+
`updated_at` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
|
57
|
+
PRIMARY KEY (`id`)
|
58
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
59
|
+
'
|
60
|
+
client.query query
|
61
|
+
|
62
|
+
client.close
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_client
|
66
|
+
db_yml_path = File::dirname(__FILE__) + '/../config/database.yml'
|
67
|
+
db_config = Mysql2wrapper::Client.config_from_yml(db_yml_path,'test')
|
68
|
+
client = Mysql2wrapper::Client.new(db_config,nil)
|
69
|
+
client
|
70
|
+
end
|
71
|
+
|
72
|
+
def simple_table_create_query(table)
|
73
|
+
"
|
74
|
+
CREATE TABLE IF NOT EXISTS `#{table}` (
|
75
|
+
`id` int(11) NOT NULL auto_increment,
|
76
|
+
`v_int1` int(11) NOT NULL,
|
77
|
+
`v_int2` int(11),
|
78
|
+
`v_str1` varchar(10) ,
|
79
|
+
`created_at` datetime NOT NULL,
|
80
|
+
`updated_at` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
|
81
|
+
PRIMARY KEY (`id`)
|
82
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
83
|
+
"
|
84
|
+
end
|
85
|
+
|
86
|
+
def hash_for_simple_table
|
87
|
+
{
|
88
|
+
:v_int1 => proc{ @i+=1 },
|
89
|
+
:created_at => 'NOW()'.to_func,
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def insert(client)
|
94
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(#{Time.now.to_i},NOW())"
|
95
|
+
client.query query
|
96
|
+
end
|
97
|
+
|
98
|
+
def count(client=get_client)
|
99
|
+
client.count('test01','id')
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_to_func
|
103
|
+
assert_equal false,''.function_sql?
|
104
|
+
assert_equal true,''.to_func.function_sql?
|
105
|
+
st = ""
|
106
|
+
assert_equal false,st.function_sql?
|
107
|
+
st = st.to_func
|
108
|
+
assert_equal true,st.function_sql?
|
109
|
+
assert_equal true,proc{"".to_func}.call.function_sql?
|
110
|
+
assert_equal true,Proc.new{"".to_func}.call.function_sql?
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_count
|
114
|
+
client = get_client
|
115
|
+
assert_equal 0,client.count('test01','id')
|
116
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(#{Time.now.to_i},NOW())"
|
117
|
+
client.query query
|
118
|
+
assert_equal 1,client.count('test01','id')
|
119
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(#{Time.now.to_i},NOW())"
|
120
|
+
client.query query
|
121
|
+
assert_equal 2,client.count('test01','id')
|
122
|
+
client.close
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_select
|
126
|
+
client = get_client
|
127
|
+
assert_equal 0,client.count('test01','id')
|
128
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(123,NOW())"
|
129
|
+
client.query query
|
130
|
+
assert_equal 1,client.count('test01','id')
|
131
|
+
res = client.query "SELECT * FROM test01 WHERE id = 1"
|
132
|
+
assert_equal 123, res.first['v_int1']
|
133
|
+
assert_equal 1, client.affected_rows
|
134
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(123,NOW())"
|
135
|
+
client.query query
|
136
|
+
res = client.query "SELECT * FROM test01 WHERE id = 1"
|
137
|
+
assert_equal 1, client.affected_rows
|
138
|
+
res = client.query "SELECT * FROM test01"
|
139
|
+
assert_equal 2, client.affected_rows
|
140
|
+
client.close
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_update
|
144
|
+
client = get_client
|
145
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(1,NOW())"
|
146
|
+
client.query query
|
147
|
+
client.query query
|
148
|
+
client.query query
|
149
|
+
|
150
|
+
res = client.query "SELECT * FROM test01 WHERE id = 1"
|
151
|
+
assert_equal 1, res.first['v_int1']
|
152
|
+
assert_equal nil, res.first['v_int2']
|
153
|
+
res = client.query "SELECT * FROM test01 WHERE id = 2"
|
154
|
+
assert_equal 1, res.first['v_int1']
|
155
|
+
assert_equal nil, res.first['v_int2']
|
156
|
+
|
157
|
+
client.update 'test01',{:v_int1=>2},'id = 1'
|
158
|
+
assert_equal 1, client.affected_rows
|
159
|
+
|
160
|
+
res = client.query "SELECT * FROM test01 WHERE id = 1"
|
161
|
+
assert_equal 2, res.first['v_int1']
|
162
|
+
assert_equal nil, res.first['v_int2']
|
163
|
+
res = client.query "SELECT * FROM test01 WHERE id = 2"
|
164
|
+
assert_equal 1, res.first['v_int1']
|
165
|
+
assert_equal nil, res.first['v_int2']
|
166
|
+
|
167
|
+
client.update 'test01',{:v_int1=>3}, client.update_all_flag
|
168
|
+
|
169
|
+
assert_equal 3, client.affected_rows
|
170
|
+
res = client.query "SELECT * FROM test01 WHERE id = 1"
|
171
|
+
assert_equal 3, res.first['v_int1']
|
172
|
+
assert_equal nil, res.first['v_int2']
|
173
|
+
res = client.query "SELECT * FROM test01 WHERE id = 2"
|
174
|
+
assert_equal 3, res.first['v_int1']
|
175
|
+
assert_equal nil, res.first['v_int2']
|
176
|
+
client.update 'test01',{:v_int1=>3},Mysql2wrapper::Client::UPDATE_ALL
|
177
|
+
assert_equal 0, client.affected_rows
|
178
|
+
client.update 'test01',{:v_int1=>4},client.update_all_flag
|
179
|
+
assert_equal 3, client.affected_rows
|
180
|
+
|
181
|
+
client.close
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_update_all_limitter
|
185
|
+
client = get_client
|
186
|
+
query = "INSERT INTO test01 (v_int1,created_at)VALUES(1,NOW())"
|
187
|
+
client.query query
|
188
|
+
|
189
|
+
assert_raise(ArgumentError){
|
190
|
+
client.update 'test01',{:v_int1=>3},nil
|
191
|
+
}
|
192
|
+
|
193
|
+
assert_raise(Mysql2::Error){
|
194
|
+
client.update 'test01',{:v_int1=>3},''
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_escape
|
199
|
+
client = get_client
|
200
|
+
assert_equal 0,client.count('test01','id')
|
201
|
+
query = "INSERT INTO test01 (v_int1,v_str1,created_at)VALUES(#{Time.now.to_i},'#{client.escape("'te'st'st'")}',NOW())"
|
202
|
+
client.query query
|
203
|
+
res = client.query "SELECT * FROM test01"
|
204
|
+
assert_equal 1,res.size
|
205
|
+
assert_equal "'te'st'st'",res.first['v_str1']
|
206
|
+
client.close
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_tranasction_simple
|
210
|
+
client = get_client
|
211
|
+
insert(client)
|
212
|
+
assert_equal 1,count(client)
|
213
|
+
begin
|
214
|
+
client.transaction do
|
215
|
+
insert(client)
|
216
|
+
assert_equal 2,count(client)
|
217
|
+
raise 'roooooooooollback!!!!'
|
218
|
+
end
|
219
|
+
rescue
|
220
|
+
end
|
221
|
+
assert_equal 1,count(client)
|
222
|
+
insert(client)
|
223
|
+
assert_equal 2,count(client)
|
224
|
+
client.close
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_tranasction_2_clients
|
228
|
+
client1 = get_client
|
229
|
+
client2 = get_client
|
230
|
+
insert(client1)
|
231
|
+
assert_equal 1,count(client1)
|
232
|
+
assert_equal 1,count(client2)
|
233
|
+
begin
|
234
|
+
# コネクションはトランザクション単位
|
235
|
+
client1.transaction do
|
236
|
+
insert(client1)
|
237
|
+
assert_equal 2,count(client1)
|
238
|
+
assert_equal 1,count(client2)
|
239
|
+
raise 'roooooooooollback!!!!'
|
240
|
+
end
|
241
|
+
rescue
|
242
|
+
end
|
243
|
+
assert_equal 1,count(client1)
|
244
|
+
assert_equal 1,count(client2)
|
245
|
+
|
246
|
+
client1.transaction do
|
247
|
+
insert(client2) # raiseしないなら
|
248
|
+
end
|
249
|
+
assert_equal 2,count(client1)
|
250
|
+
assert_equal 2,count(client2)
|
251
|
+
|
252
|
+
begin
|
253
|
+
# コネクションはトランザクション単位
|
254
|
+
# client1のtransactionブロック内でclient2のインサートを発行しても
|
255
|
+
# もちろんロールバックされない
|
256
|
+
client1.transaction do
|
257
|
+
insert(client1)
|
258
|
+
assert_equal 3,count(client1)
|
259
|
+
assert_equal 2,count(client2)
|
260
|
+
insert(client2)
|
261
|
+
assert_equal 3,count(client1) # ここは3
|
262
|
+
assert_equal 3,count(client2)
|
263
|
+
raise 'roooooooooollback!!!!'
|
264
|
+
end
|
265
|
+
rescue
|
266
|
+
end
|
267
|
+
assert_equal 3,count(client1)
|
268
|
+
assert_equal 3,count(client2)
|
269
|
+
client1.close
|
270
|
+
client2.close
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_insert
|
274
|
+
client = get_client
|
275
|
+
@i = 0
|
276
|
+
hash = {
|
277
|
+
:v_int1 => proc{ @i+=1 },
|
278
|
+
:v_int2 => 246,
|
279
|
+
:v_int3 => nil,
|
280
|
+
:v_str1=>"te'st日本語",
|
281
|
+
:v_str2=>"CONCAT('My','S','QL')".to_func,
|
282
|
+
:v_str3 => nil,
|
283
|
+
:v_bool1 => true,
|
284
|
+
:v_bool2 => false,
|
285
|
+
:v_bool3 => nil,
|
286
|
+
:v_date1 => Date.new(2000,1,2),
|
287
|
+
:v_date2 => nil,
|
288
|
+
:v_datetime1 => DateTime.new(2000,1,2,3,4,5),
|
289
|
+
:v_datetime2 => nil,
|
290
|
+
:v_time1 => Time.mktime(2000,1,2,3,4,5),
|
291
|
+
:v_time2 => nil,
|
292
|
+
:created_at => 'NOW()'.to_func,
|
293
|
+
}
|
294
|
+
client.insert('test02',hash)
|
295
|
+
assert_equal 1, client.affected_rows
|
296
|
+
client.insert('test02',hash)
|
297
|
+
res = client.query ("SELECT * FROM test02")
|
298
|
+
assert_equal 2, res.size
|
299
|
+
row = res.to_a.last
|
300
|
+
assert_equal 2, row['v_int1']
|
301
|
+
assert_equal 246, row['v_int2']
|
302
|
+
assert_equal nil, row['v_int3']
|
303
|
+
assert_equal nil, row['v_int4']
|
304
|
+
assert_equal 'te\'st日本語', row['v_str1']
|
305
|
+
assert_equal 'MySQL', row['v_str2']
|
306
|
+
assert_equal nil, row['v_str3']
|
307
|
+
assert_equal nil, row['v_str4']
|
308
|
+
assert_equal 1, row['v_bool1']
|
309
|
+
assert_equal 0, row['v_bool2']
|
310
|
+
assert_equal nil, row['v_bool3']
|
311
|
+
assert_equal nil, row['v_bool4']
|
312
|
+
assert_equal Date.new(2000,1,2),row['v_date1']
|
313
|
+
assert_equal nil, row['v_date2']
|
314
|
+
assert_equal nil, row['v_date3']
|
315
|
+
assert_equal Time.mktime(2000,1,2,3,4,5),row['v_datetime1']
|
316
|
+
assert_equal nil, row['v_datetime2']
|
317
|
+
assert_equal nil, row['v_datetime3']
|
318
|
+
assert_equal Time.mktime(2000,1,2,3,4,5),row['v_time1']
|
319
|
+
assert_equal nil, row['v_time2']
|
320
|
+
assert_equal nil, row['v_time3']
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_multiple_insert
|
324
|
+
client = get_client
|
325
|
+
@i = 0
|
326
|
+
hash = hash_for_simple_table
|
327
|
+
client.insert('test01',hash)
|
328
|
+
res = client.query ("SELECT * FROM test01")
|
329
|
+
assert_equal 1, res.size
|
330
|
+
assert_equal 1, client.affected_rows
|
331
|
+
client.insert('test01',hash)
|
332
|
+
res = client.query ("SELECT * FROM test01")
|
333
|
+
assert_equal 2, res.size
|
334
|
+
assert_equal 2, res.to_a.last['v_int1']
|
335
|
+
ar = []
|
336
|
+
111.times{ar << hash}
|
337
|
+
client.insert('test01',ar)
|
338
|
+
assert_equal 111, client.affected_rows
|
339
|
+
res = client.query ("SELECT * FROM test01")
|
340
|
+
assert_equal 113, res.size
|
341
|
+
assert_equal 113, res.to_a.last['v_int1']
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_sql_mode_is_strict_all_tables
|
345
|
+
assert_raise(Mysql2::Error) do
|
346
|
+
client = get_client
|
347
|
+
query = "INSERT INTO test01 (v_int1)values(1)"
|
348
|
+
client.query(query)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def test_multiple_database
|
353
|
+
db_yml_path = File::dirname(__FILE__) + '/../config/database_multiple.yml'
|
354
|
+
config_master = Mysql2wrapper::Client.config_from_yml(db_yml_path,'test','master')
|
355
|
+
config_slave = Mysql2wrapper::Client.config_from_yml(db_yml_path,'test','slave')
|
356
|
+
client_master = Mysql2wrapper::Client.new(config_master,nil)
|
357
|
+
client_slave = Mysql2wrapper::Client.new(config_slave,nil)
|
358
|
+
|
359
|
+
client_master.query 'DROP TABLE IF EXISTS tbl_master'
|
360
|
+
client_master.query simple_table_create_query('tbl_master')
|
361
|
+
client_slave.query 'DROP TABLE IF EXISTS tbl_slave'
|
362
|
+
client_slave.query simple_table_create_query('tbl_slave')
|
363
|
+
|
364
|
+
assert_equal 0,client_master.count('tbl_master')
|
365
|
+
assert_equal 0,client_slave.count('tbl_slave')
|
366
|
+
|
367
|
+
client_master.insert('tbl_master',hash_for_simple_table)
|
368
|
+
|
369
|
+
assert_equal 1,client_master.count('tbl_master')
|
370
|
+
assert_equal 0,client_slave.count('tbl_slave')
|
371
|
+
|
372
|
+
client_master.insert('tbl_master',hash_for_simple_table)
|
373
|
+
|
374
|
+
assert_equal 2,client_master.count('tbl_master')
|
375
|
+
assert_equal 0,client_slave.count('tbl_slave')
|
376
|
+
|
377
|
+
client_slave.insert('tbl_slave',hash_for_simple_table)
|
378
|
+
|
379
|
+
assert_equal 2,client_master.count('tbl_master')
|
380
|
+
assert_equal 1,client_slave.count('tbl_slave')
|
381
|
+
end
|
382
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mysql2wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- pacojp
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: mysql2
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - '='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.3.11
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.3.11
|
30
|
+
description: oreore mysql2 wrapper class
|
31
|
+
email:
|
32
|
+
- paco.jp@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- Gemfile.lock
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- config/database.yml
|
43
|
+
- config/database_multiple.yml
|
44
|
+
- example/sample.rb
|
45
|
+
- lib/mysql2wrapper.rb
|
46
|
+
- lib/mysql2wrapper/client.rb
|
47
|
+
- lib/mysql2wrapper/version.rb
|
48
|
+
- mysql2wrapper.gemspec
|
49
|
+
- test/by_hand.rb
|
50
|
+
- test/test.rb
|
51
|
+
- test/test_helper.rb
|
52
|
+
homepage: ''
|
53
|
+
licenses: []
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
require_paths:
|
57
|
+
- lib
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project: mysql2wrapper
|
72
|
+
rubygems_version: 1.8.23
|
73
|
+
signing_key:
|
74
|
+
specification_version: 3
|
75
|
+
summary: oreore mysql2 wrapper class
|
76
|
+
test_files:
|
77
|
+
- test/by_hand.rb
|
78
|
+
- test/test.rb
|
79
|
+
- test/test_helper.rb
|
80
|
+
has_rdoc:
|