mysql2 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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