require 'addressable/uri' module ROM # Abstract adapter class # # @api public class Adapter include Equalizer.new(:connection) @adapters = [] # Return connection URI associated with the adapter # # @return [String] # # @api public attr_reader :uri # Return connection object # # @return [Object] type varies depending on the adapter # # @api public attr_reader :connection # Setup an adapter instance with the given connection URI # # @example # # Adapter = Class.new(ROM::Adapter) # # adapter = Adapter.new('mysql://localhost/test') # # adapter.uri.scheme # => 'mysql' # adapter.uri.host # => 'localhost' # adapter.uri.path # => '/test' # # @param [String] uri_string # # @return [Adapter] # # @api public def self.setup(uri_string) uri = Addressable::URI.parse(uri_string) unless adapter = self[uri.scheme] raise ArgumentError, "#{uri_string.inspect} uri is not supported" end adapter.new(uri) end # Register adapter class # # @example # # Adapter = Class.new(ROM::Adapter) { # def self.schemes # [:super_db] # end # } # # ROM::Adapter.register(Adapter) # ROM::Adapter[:super_db] # => Adapter # # @return [Array] registered adapters # # @api public def self.register(adapter) @adapters.unshift adapter end # Return adapter class for the given scheme # # @see Adapter.register # # @return [Class] adapter class # # @api public def self.[](scheme) @adapters.detect { |adapter| adapter.schemes.include?(scheme.to_sym) } end # @api private def initialize(uri) @uri = uri end # Extension hook for adding adapter-specific behavior to a relation class # # @param [Class] klass Relation class generated by ROM # # @return [Class] extended relation class # # @api public def extend_relation_class(klass) klass end # Extension hook for adding adapter-specific behavior to a relation instance # # @param [Relation] relation # # @return [Relation] extended relation instance # # @api public def extend_relation_instance(relation) relation end # Builds a command # # @param [Symbol] name of the command # @param [Relation] relation used by the command # @param [CommandDSL::Definition] command definition object # # @return [Object] created command instance # # @api public def command(name, relation, definition) type = definition.type || name klass = case type when :create then command_namespace.const_get(:Create) when :update then command_namespace.const_get(:Update) when :delete then command_namespace.const_get(:Delete) else raise ArgumentError, "#{type.inspect} is not a supported command type" end klass.new(relation, definition.to_h) end # Schema inference hook # # Every adapter that supports schema inference should implement this method # # @return [Array] array with datasets and their names # # @api private def schema [] end # Return namespace with adapter-specific command classes # # @return [Module] # # @api private def command_namespace self.class.const_get(:Commands) end end end