mysql2 0.1.2 → 0.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.
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.3 (April 15th, 2010)
4
+ * added an EventMachine Deferrable API
5
+ * added an ActiveRecord connection adapter
6
+ ** should be compatible with 2.3.5 and 3.0 (including Arel)
7
+
3
8
  ## 0.1.2 (April 9th, 2010)
4
9
  * fix a bug (copy/paste fail) around checking for empty TIME values and returning nil (thanks @marius)
5
10
 
@@ -75,6 +75,32 @@ NOTE: Because of the way MySQL's query API works, this method will block until t
75
75
  So if you really need things to stay async, it's best to just monitor the socket with something like EventMachine.
76
76
  If you need multiple query concurrency take a look at using a connection pool.
77
77
 
78
+ == ActiveRecord
79
+
80
+ To use the ActiveRecord driver, all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
81
+ That was easy right? :)
82
+
83
+ == EventMachine
84
+
85
+ The mysql2 EventMachine deferrable api allows you to make async queries using EventMachine,
86
+ while specifying callbacks for success for failure. Here's a simple example:
87
+
88
+ require 'mysql2/em'
89
+
90
+ EM.run do
91
+ client1 = Mysql2::EM::Client.new
92
+ defer1 = client1.query "SELECT sleep(3) as first_query"
93
+ defer1.callback do |result|
94
+ puts "Result: #{result.to_a.inspect}"
95
+ end
96
+
97
+ client2 = Mysql2::EM::Client.new
98
+ defer2 = client2.query "SELECT sleep(1) second_query"
99
+ defer2.callback do |result|
100
+ puts "Result: #{result.to_a.inspect}"
101
+ end
102
+ end
103
+
78
104
  == Compatibility
79
105
 
80
106
  The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
@@ -85,6 +111,8 @@ The specs pass on my system (SL 10.6.3, x86_64) in these rubies:
85
111
  * ruby-trunk
86
112
  * rbx-head
87
113
 
114
+ The ActiveRecord driver should work on 2.3.5 and 3.0
115
+
88
116
  == Yeah... but why?
89
117
 
90
118
  Someone: Dude, the Mysql gem works fiiiiiine.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.2
1
+ 0.1.3
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+ $LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
3
+
4
+ require 'rubygems'
5
+ require 'benchmark'
6
+ require 'active_record'
7
+ require 'ruby-debug'
8
+
9
+ number_of = 1
10
+ mysql2_opts = {
11
+ :adapter => 'mysql2',
12
+ :database => 'test'
13
+ }
14
+ mysql_opts = {
15
+ :adapter => 'mysql',
16
+ :database => 'test'
17
+ }
18
+
19
+ class TestModel < ActiveRecord::Base
20
+ set_table_name :mysql2_test
21
+ end
22
+
23
+ Benchmark.bmbm do |x|
24
+ x.report do
25
+ TestModel.establish_connection(mysql2_opts)
26
+ puts "Mysql2"
27
+ number_of.times do
28
+ TestModel.all(:limit => 1000)
29
+ end
30
+ end
31
+
32
+ x.report do
33
+ TestModel.establish_connection(mysql_opts)
34
+ puts "Mysql"
35
+ number_of.times do
36
+ TestModel.all(:limit => 1000)
37
+ end
38
+ end
39
+ end
@@ -7,12 +7,10 @@ require 'mysql2_ext'
7
7
  require 'do_mysql'
8
8
 
9
9
  number_of = 1000
10
- database = 'nbb_1_production'
11
10
  str = "abc'def\"ghi\0jkl%mno"
12
11
 
13
12
  Benchmark.bmbm do |x|
14
13
  mysql = Mysql.new("localhost", "root")
15
- mysql.query "USE #{database}"
16
14
  x.report do
17
15
  puts "Mysql"
18
16
  number_of.times do
@@ -21,7 +19,6 @@ Benchmark.bmbm do |x|
21
19
  end
22
20
 
23
21
  mysql2 = Mysql2::Client.new(:host => "localhost", :username => "root")
24
- mysql2.query "USE #{database}"
25
22
  x.report do
26
23
  puts "Mysql2"
27
24
  number_of.times do
@@ -29,7 +26,7 @@ Benchmark.bmbm do |x|
29
26
  end
30
27
  end
31
28
 
32
- do_mysql = DataObjects::Connection.new("mysql://localhost/#{database}")
29
+ do_mysql = DataObjects::Connection.new("mysql://localhost/test")
33
30
  x.report do
34
31
  puts "do_mysql"
35
32
  number_of.times do
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift 'lib'
4
+
5
+ require 'rubygems'
6
+ require 'eventmachine'
7
+ require 'mysql2/em'
8
+
9
+ EM.run do
10
+ client1 = Mysql2::EM::Client.new
11
+ defer1 = client1.query "SELECT sleep(3) as first_query"
12
+ defer1.callback do |result|
13
+ puts "Result: #{result.to_a.inspect}"
14
+ end
15
+
16
+ client2 = Mysql2::EM::Client.new
17
+ defer2 = client2.query "SELECT sleep(1) second_query"
18
+ defer2.callback do |result|
19
+ puts "Result: #{result.to_a.inspect}"
20
+ end
21
+ end
@@ -0,0 +1,165 @@
1
+ # encoding: utf-8
2
+
3
+ require 'mysql2' unless defined? Mysql2
4
+ require 'active_record/connection_adapters/mysql_adapter'
5
+
6
+ module ActiveRecord
7
+ class Base
8
+ def self.mysql2_connection(config)
9
+ client = Mysql2::Client.new(config.symbolize_keys)
10
+ options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
11
+ ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
12
+ end
13
+ end
14
+
15
+ module ConnectionAdapters
16
+ class Mysql2Column < MysqlColumn
17
+ # Returns the Ruby class that corresponds to the abstract data type.
18
+ def klass
19
+ case type
20
+ when :integer then Fixnum
21
+ when :float then Float
22
+ when :decimal then BigDecimal
23
+ when :datetime then Time
24
+ when :date then Time
25
+ when :timestamp then Time
26
+ when :time then Time
27
+ when :text, :string then String
28
+ when :binary then String
29
+ when :boolean then Object
30
+ end
31
+ end
32
+
33
+ def type_cast(value)
34
+ if type == :boolean
35
+ self.class.value_to_boolean(value)
36
+ else
37
+ value
38
+ end
39
+ end
40
+
41
+ def type_cast_code(var_name)
42
+ nil
43
+ end
44
+ end
45
+
46
+ class Mysql2Adapter < MysqlAdapter
47
+ PRIMARY = "PRIMARY".freeze
48
+ ADAPTER_NAME = "Mysql2".freeze
49
+
50
+ def adapter_name
51
+ ADAPTER_NAME
52
+ end
53
+
54
+ # QUOTING ==================================================
55
+ def quote_string(string)
56
+ @connection.escape(string)
57
+ end
58
+
59
+ # CONNECTION MANAGEMENT ====================================
60
+
61
+ def active?
62
+ @connection.query 'select 1'
63
+ true
64
+ rescue Mysql2::Error
65
+ false
66
+ end
67
+
68
+ def reconnect!
69
+ reset!
70
+ end
71
+
72
+ def disconnect!
73
+ @connection = nil
74
+ end
75
+
76
+ def reset!
77
+ @connection = Mysql2::Client.new(@config)
78
+ end
79
+
80
+ # DATABASE STATEMENTS ======================================
81
+
82
+ def select_values(sql, name = nil)
83
+ result = select_rows(sql, name)
84
+ result.map { |row| row.values.first }
85
+ end
86
+
87
+ def select_rows(sql, name = nil)
88
+ select(sql, name)
89
+ end
90
+
91
+ def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
92
+ super sql, name
93
+ id_value || @connection.last_id
94
+ end
95
+ alias :create :insert_sql
96
+
97
+ # SCHEMA STATEMENTS ========================================
98
+
99
+ def tables(name = nil)
100
+ tables = []
101
+ execute("SHOW TABLES", name).each(:symbolize_keys => true) do |field|
102
+ tables << field.values.first
103
+ end
104
+ tables
105
+ end
106
+
107
+ def indexes(table_name, name = nil)
108
+ indexes = []
109
+ current_index = nil
110
+ result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
111
+ result.each(:symbolize_keys => true) do |row|
112
+ if current_index != row[:Key_name]
113
+ next if row[:Key_name] == PRIMARY # skip the primary key
114
+ current_index = row[:Key_name]
115
+ indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [])
116
+ end
117
+
118
+ indexes.last.columns << row[:Column_name]
119
+ end
120
+ indexes
121
+ end
122
+
123
+ def columns(table_name, name = nil)
124
+ sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
125
+ columns = []
126
+ result = execute(sql, :skip_logging)
127
+ result.each(:symbolize_keys => true) { |field|
128
+ columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES")
129
+ }
130
+ columns
131
+ end
132
+
133
+ def show_variable(name)
134
+ variables = select_all("SHOW VARIABLES LIKE '#{name}'")
135
+ variables.first[:Value] unless variables.empty?
136
+ end
137
+
138
+ def pk_and_sequence_for(table)
139
+ keys = []
140
+ result = execute("describe #{quote_table_name(table)}")
141
+ result.each(:symbolize_keys) do |row|
142
+ keys << row[:Field] if row[:Key] == "PRI"
143
+ end
144
+ keys.length == 1 ? [keys.first, nil] : nil
145
+ end
146
+
147
+ private
148
+ def connect
149
+ # no-op
150
+ end
151
+
152
+ def select(sql, name = nil)
153
+ execute(sql, name).to_a
154
+ end
155
+
156
+ def supports_views?
157
+ version[0] >= 5
158
+ end
159
+
160
+ def version
161
+ @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,11 @@
1
+ module Arel
2
+ module SqlCompiler
3
+ class Mysql2Compiler < GenericCompiler
4
+ def limited_update_conditions(conditions, taken)
5
+ conditions << " LIMIT #{taken}"
6
+ conditions
7
+ end
8
+ end
9
+ end
10
+ end
11
+
@@ -5,5 +5,5 @@ require 'mysql2_ext'
5
5
  #
6
6
  # A modern, simple and very fast Mysql library for Ruby - binding to libmysql
7
7
  module Mysql2
8
- VERSION = "0.1.2"
8
+ VERSION = "0.1.3"
9
9
  end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'eventmachine' unless defined? EventMachine
4
+ require 'mysql2' unless defined? Mysql2
5
+
6
+ module Mysql2
7
+ module EM
8
+ class Client < ::Mysql2::Client
9
+ module Watcher
10
+ def initialize(client, deferable)
11
+ @client = client
12
+ @deferable = deferable
13
+ end
14
+
15
+ def notify_readable
16
+ begin
17
+ @deferable.succeed(@client.async_result)
18
+ rescue Exception => e
19
+ @deferable.fail(e)
20
+ end
21
+ detach
22
+ end
23
+ end
24
+
25
+ def query(sql, opts={})
26
+ super(sql, opts.merge(:async => true))
27
+ deferable = ::EM::DefaultDeferrable.new
28
+ ::EM.watch(self.socket, Watcher, self, deferable).notify_readable = true
29
+ deferable
30
+ end
31
+ end
32
+ end
33
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mysql2}
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brian Lopez"]
12
- s.date = %q{2010-04-09}
12
+ s.date = %q{2010-04-15}
13
13
  s.email = %q{seniorlopez@gmail.com}
14
14
  s.extensions = ["ext/extconf.rb"]
15
15
  s.extra_rdoc_files = [
@@ -22,14 +22,21 @@ Gem::Specification.new do |s|
22
22
  "README.rdoc",
23
23
  "Rakefile",
24
24
  "VERSION",
25
+ "benchmark/active_record.rb",
25
26
  "benchmark/escape.rb",
26
27
  "benchmark/query.rb",
27
28
  "benchmark/setup_db.rb",
29
+ "examples/eventmachine.rb",
28
30
  "ext/extconf.rb",
29
31
  "ext/mysql2_ext.c",
30
32
  "ext/mysql2_ext.h",
33
+ "lib/active_record/connection_adapters/mysql2_adapter.rb",
34
+ "lib/arel/engines/sql/compilers/mysql2_compiler.rb",
31
35
  "lib/mysql2.rb",
36
+ "lib/mysql2/em.rb",
32
37
  "mysql2.gemspec",
38
+ "spec/active_record/active_record_spec.rb",
39
+ "spec/em/em_spec.rb",
33
40
  "spec/mysql2/client_spec.rb",
34
41
  "spec/mysql2/result_spec.rb",
35
42
  "spec/rcov.opts",
@@ -42,9 +49,12 @@ Gem::Specification.new do |s|
42
49
  s.rubygems_version = %q{1.3.6}
43
50
  s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql}
44
51
  s.test_files = [
45
- "spec/mysql2/client_spec.rb",
52
+ "spec/active_record/active_record_spec.rb",
53
+ "spec/em/em_spec.rb",
54
+ "spec/mysql2/client_spec.rb",
46
55
  "spec/mysql2/result_spec.rb",
47
- "spec/spec_helper.rb"
56
+ "spec/spec_helper.rb",
57
+ "examples/eventmachine.rb"
48
58
  ]
49
59
 
50
60
  if s.respond_to? :specification_version then
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+ require 'active_record'
4
+ require 'active_record/connection_adapters/mysql2_adapter'
5
+
6
+ describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
7
+ it "should be able to connect" do
8
+ lambda {
9
+ ActiveRecord::Base.establish_connection(:adapter => 'mysql2')
10
+ }.should_not raise_error(Mysql2::Error)
11
+ end
12
+
13
+ context "once connected" do
14
+ before(:each) do
15
+ @connection = ActiveRecord::Base.connection
16
+ end
17
+
18
+ it "should be able to execute a raw query" do
19
+ @connection.execute("SELECT 1 as one").first['one'].should eql(1)
20
+ @connection.execute("SELECT NOW() as n").first['n'].class.should eql(Time)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
3
+ require 'mysql2/em'
4
+
5
+ describe Mysql2::EM::Client do
6
+ it "should support async queries" do
7
+ results = []
8
+ EM.run do
9
+ client1 = Mysql2::EM::Client.new
10
+ defer1 = client1.query "SELECT sleep(0.05) as first_query"
11
+ defer1.callback do |result|
12
+ results << result.first
13
+ EM.stop_event_loop
14
+ end
15
+
16
+ client2 = Mysql2::EM::Client.new
17
+ defer2 = client2.query "SELECT sleep(0.025) second_query"
18
+ defer2.callback do |result|
19
+ results << result.first
20
+ end
21
+ end
22
+
23
+ results[0].keys.should include("second_query")
24
+ results[1].keys.should include("first_query")
25
+ end
26
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 2
9
- version: 0.1.2
8
+ - 3
9
+ version: 0.1.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Brian Lopez
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-09 00:00:00 -07:00
17
+ date: 2010-04-15 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
@@ -33,14 +33,21 @@ files:
33
33
  - README.rdoc
34
34
  - Rakefile
35
35
  - VERSION
36
+ - benchmark/active_record.rb
36
37
  - benchmark/escape.rb
37
38
  - benchmark/query.rb
38
39
  - benchmark/setup_db.rb
40
+ - examples/eventmachine.rb
39
41
  - ext/extconf.rb
40
42
  - ext/mysql2_ext.c
41
43
  - ext/mysql2_ext.h
44
+ - lib/active_record/connection_adapters/mysql2_adapter.rb
45
+ - lib/arel/engines/sql/compilers/mysql2_compiler.rb
42
46
  - lib/mysql2.rb
47
+ - lib/mysql2/em.rb
43
48
  - mysql2.gemspec
49
+ - spec/active_record/active_record_spec.rb
50
+ - spec/em/em_spec.rb
44
51
  - spec/mysql2/client_spec.rb
45
52
  - spec/mysql2/result_spec.rb
46
53
  - spec/rcov.opts
@@ -78,6 +85,9 @@ signing_key:
78
85
  specification_version: 3
79
86
  summary: A simple, fast Mysql library for Ruby, binding to libmysql
80
87
  test_files:
88
+ - spec/active_record/active_record_spec.rb
89
+ - spec/em/em_spec.rb
81
90
  - spec/mysql2/client_spec.rb
82
91
  - spec/mysql2/result_spec.rb
83
92
  - spec/spec_helper.rb
93
+ - examples/eventmachine.rb