add initial ActiveRecord driver
This commit is contained in:
parent
288ed22806
commit
1c9e94f7e9
|
@ -0,0 +1,160 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'mysql2' unless defined? Mysql2
|
||||
require 'active_record/connection_adapters/mysql_adapter'
|
||||
|
||||
module ActiveRecord
|
||||
class Base
|
||||
def self.mysql2_connection(config)
|
||||
client = Mysql2::Client.new(config.symbolize_keys)
|
||||
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
||||
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
||||
end
|
||||
end
|
||||
|
||||
module ConnectionAdapters
|
||||
class Mysql2Column < MysqlColumn
|
||||
# Returns the Ruby class that corresponds to the abstract data type.
|
||||
def klass
|
||||
case type
|
||||
when :integer then Fixnum
|
||||
when :float then Float
|
||||
when :decimal then BigDecimal
|
||||
when :datetime then Time
|
||||
when :date then Time
|
||||
when :timestamp then Time
|
||||
when :time then Time
|
||||
when :text, :string then String
|
||||
when :binary then String
|
||||
when :boolean then Object
|
||||
end
|
||||
end
|
||||
|
||||
def type_cast(value)
|
||||
if type == :boolean
|
||||
self.class.value_to_boolean(value)
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def type_cast_code(var_name)
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
class Mysql2Adapter < MysqlAdapter
|
||||
PRIMARY = "PRIMARY".freeze
|
||||
|
||||
# QUOTING ==================================================
|
||||
def quote_string(string)
|
||||
@connection.escape(string)
|
||||
end
|
||||
|
||||
# CONNECTION MANAGEMENT ====================================
|
||||
|
||||
def active?
|
||||
@connection.query 'select 1'
|
||||
true
|
||||
rescue Mysql2::Error
|
||||
false
|
||||
end
|
||||
|
||||
def reconnect!
|
||||
reset!
|
||||
end
|
||||
|
||||
def disconnect!
|
||||
@connection = nil
|
||||
end
|
||||
|
||||
def reset!
|
||||
@connection = Mysql2::Client.new(@config)
|
||||
end
|
||||
|
||||
# DATABASE STATEMENTS ======================================
|
||||
|
||||
def select_values(sql, name = nil)
|
||||
result = select_rows(sql, name)
|
||||
result.map { |row| row.values.first }
|
||||
end
|
||||
|
||||
def select_rows(sql, name = nil)
|
||||
select(sql, name)
|
||||
end
|
||||
|
||||
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
||||
super sql, name
|
||||
id_value || @connection.last_id
|
||||
end
|
||||
alias :create :insert_sql
|
||||
|
||||
# SCHEMA STATEMENTS ========================================
|
||||
|
||||
def tables(name = nil)
|
||||
tables = []
|
||||
execute("SHOW TABLES", name).each(:symbolize_keys => true) do |field|
|
||||
tables << field.values.first
|
||||
end
|
||||
tables
|
||||
end
|
||||
|
||||
def indexes(table_name, name = nil)
|
||||
indexes = []
|
||||
current_index = nil
|
||||
result = execute("SHOW KEYS FROM #{quote_table_name(table_name)}", name)
|
||||
result.each(:symbolize_keys => true) do |row|
|
||||
if current_index != row[:Key_name]
|
||||
next if row[:Key_name] == PRIMARY # skip the primary key
|
||||
current_index = row[:Key_name]
|
||||
indexes << IndexDefinition.new(row[:Table], row[:Key_name], row[:Non_unique] == 0, [])
|
||||
end
|
||||
|
||||
indexes.last.columns << row[:Column_name]
|
||||
end
|
||||
indexes
|
||||
end
|
||||
|
||||
def columns(table_name, name = nil)
|
||||
sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
|
||||
columns = []
|
||||
result = execute(sql, :skip_logging)
|
||||
result.each(:symbolize_keys => true) { |field|
|
||||
columns << Mysql2Column.new(field[:Field], field[:Default], field[:Type], field[:Null] == "YES")
|
||||
}
|
||||
columns
|
||||
end
|
||||
|
||||
def show_variable(name)
|
||||
variables = select_all("SHOW VARIABLES LIKE '#{name}'")
|
||||
variables.first[:Value] unless variables.empty?
|
||||
end
|
||||
|
||||
def pk_and_sequence_for(table)
|
||||
keys = []
|
||||
result = execute("describe #{quote_table_name(table)}")
|
||||
result.each(:symbolize_keys) do |row|
|
||||
keys << row[:Field] if row[:Key] == "PRI"
|
||||
end
|
||||
keys.length == 1 ? [keys.first, nil] : nil
|
||||
end
|
||||
|
||||
private
|
||||
def connect
|
||||
# no-op
|
||||
end
|
||||
|
||||
def select(sql, name = nil)
|
||||
execute(sql, name).to_a
|
||||
end
|
||||
|
||||
def supports_views?
|
||||
version[0] >= 5
|
||||
end
|
||||
|
||||
def version
|
||||
@version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
# encoding: UTF-8
|
||||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
||||
require 'active_record'
|
||||
require 'active_record/connection_adapters/mysql2_adapter'
|
||||
|
||||
describe ActiveRecord::ConnectionAdapters::Mysql2Adapter do
|
||||
it "should be able to connect" do
|
||||
lambda {
|
||||
ActiveRecord::Base.establish_connection(:adapter => 'mysql2')
|
||||
}.should_not raise_error(Mysql2::Error)
|
||||
end
|
||||
|
||||
context "once connected" do
|
||||
before(:each) do
|
||||
@connection = ActiveRecord::Base.connection
|
||||
end
|
||||
|
||||
it "should be able to execute a raw query" do
|
||||
@connection.execute("SELECT 1 as one").first['one'].should eql(1)
|
||||
@connection.execute("SELECT NOW() as n").first['n'].class.should eql(Time)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue