lib/dm-core/adapters.rb
module DataMapper
module Adapters
extend Chainable
extend DataMapper::Assertions
# Set up an adapter for a storage engine
#
# @see DataMapper.setup
#
# @api private
def self.new(repository_name, options)
options = normalize_options(options)
case options.fetch(:adapter)
when 'java'
# discover the real adapter
jndi_uri = "#{options[:scheme]}:#{options[:path]}"
context = javax.naming.InitialContext.new
ds= context.lookup(jndi_uri)
conn = ds.getConnection
begin
metadata = conn.getMetaData
driver_name = metadata.getDriverName
driver = case driver_name
when /mysql/i then 'mysql'
when /oracle/i then 'oracle'
when /postgres/i then 'postgres'
when /sqlite/i then 'sqlite'
when /sqlserver|tds|Microsoft SQL/i then 'sqlserver'
else
nil # not supported
end # case
options[:adapter] = driver
ensure
conn.close
end
else
driver = options.fetch(:adapter)
end # case
adapter_class(driver).new(repository_name, options)
end
# The path used to require the in memory adapter
#
# Set this if you want to register your own adapter
# to be used when you specify an 'in_memory' connection
# during
#
# @see DataMapper.setup
#
# @param [String] path
# the path used to require the desired in memory adapter
#
# @api semipublic
def self.in_memory_adapter_path=(path)
@in_memory_adapter_path = path
end
# The path used to require the in memory adapter
#
# @see DataMapper.setup
#
# @return [String]
# the path used to require the desired in memory adapter
#
# @api semipublic
def self.in_memory_adapter_path
@in_memory_adapter_path ||= 'dm-core/adapters/in_memory_adapter'
end
class << self
private
# Normalize the arguments passed to new()
#
# Turns options hash or connection URI into the options hash used
# by the adapter.
#
# @param [Hash, Addressable::URI, String] options
# the options to be normalized
#
# @return [Mash]
# the options normalized as a Mash
#
# @api private
def normalize_options(options)
case options
when Hash then normalize_options_hash(options)
when Addressable::URI then normalize_options_uri(options)
when String then normalize_options_string(options)
else
assert_kind_of 'options', options, Hash, Addressable::URI, String
end
end
# Normalize Hash options into a Mash
#
# @param [Hash] hash
# the hash to be normalized
#
# @return [Mash]
# the options normalized as a Mash
#
# @api private
def normalize_options_hash(hash)
DataMapper::Ext::Hash.to_mash(hash)
end
# Normalize Addressable::URI options into a Mash
#
# @param [Addressable::URI] uri
# the uri to be normalized
#
# @return [Mash]
# the options normalized as a Mash
#
# @api private
def normalize_options_uri(uri)
options = normalize_options_hash(uri.to_hash)
# Extract the name/value pairs from the query portion of the
# connection uri, and set them as options directly.
if options.fetch(:query)
options.update(uri.query_values)
end
options[:adapter] = options.fetch(:scheme)
options
end
# Normalize String options into a Mash
#
# @param [String] string
# the string to be normalized
#
# @return [Mash]
# the options normalized as a Mash
#
# @api private
def normalize_options_string(string)
normalize_options_uri(Addressable::URI.parse(string))
end
# Return the adapter class constant
#
# @example
# DataMapper::Adapters.send(:adapter_class, 'mysql') # => DataMapper::Adapters::MysqlAdapter
#
# @param [Symbol] name
# the name of the adapter
#
# @return [Class]
# the AbstractAdapter subclass
#
# @api private
def adapter_class(name)
adapter_name = normalize_adapter_name(name)
class_name = (DataMapper::Inflector.camelize(adapter_name) << 'Adapter').to_sym
load_adapter(adapter_name) unless const_defined?(class_name)
const_get(class_name)
end
# Return the name of the adapter
#
# @example
# DataMapper::Adapters.adapter_name('MysqlAdapter') # => 'mysql'
#
# @param [String] const_name
# the adapter constant name
#
# @return [String]
# the name of the adapter
#
# @api semipublic
def adapter_name(const_name)
const_name.to_s.chomp('Adapter').downcase
end
# Require the adapter library
#
# @param [String, Symbol] name
# the name of the adapter
#
# @return [Boolean]
# true if the adapter is loaded
#
# @api private
def load_adapter(name)
require "dm-#{name}-adapter"
rescue LoadError => original_error
begin
require in_memory_adapter?(name) ? in_memory_adapter_path : legacy_path(name)
rescue LoadError
raise original_error
end
end
# Returns wether or not the given adapter name is considered an in memory adapter
#
# @param [String, Symbol] name
# the name of the adapter
#
# @return [Boolean]
# true if the adapter is considered to be an in memory adapter
#
# @api private
def in_memory_adapter?(name)
name.to_s == 'in_memory'
end
# Returns the fallback filename that would be used to require the named adapter
#
# The fallback format is "#{name}_adapter" and will be phased out in favor of
# the properly 'namespaced' "dm-#{name}-adapter" format.
#
# @param [String, Symbol] name
# the name of the adapter to require
#
# @return [String]
# the filename that gets required for the adapter identified by name
#
# @api private
def legacy_path(name)
"#{name}_adapter"
end
# Adjust the adapter name to match the name used in the gem providing the adapter
#
# @param [String, Symbol] name
# the name of the adapter
#
# @return [String]
# the normalized adapter name
#
# @api private
def normalize_adapter_name(name)
case (original = name.to_s)
when 'sqlite3'
'sqlite'
when 'inmemory' # Addressable >= v2.4 does not support underscores in scheme
'in_memory'
else
original
end
end
end
extendable do
# @api private
def const_added(const_name)
end
end
end # module Adapters
end # module DataMapper