1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
module OrmAdapter
class Base
attr_reader :klass
# Your ORM adapter needs to inherit from this Base class and its adapter
# will be registered. To create an adapter you should create an inner
# constant "OrmAdapter" e.g. ActiveRecord::Base::OrmAdapter
#
# @see orm_adapters/active_record
# @see orm_adapters/datamapper
# @see orm_adapters/mongoid
def self.inherited(adapter)
OrmAdapter.adapters << adapter
super
end
def initialize(klass)
@klass = klass
end
# Get a list of column/property/field names
def column_names
raise NotSupportedError
end
# Get an instance by id of the model. Raises an error if a model is not found.
# This should comply with ActiveModel#to_key API, i.e.:
#
# User.to_adapter.get!(@user.to_key) == @user
#
def get!(id)
raise NotSupportedError
end
# Get an instance by id of the model. Returns nil if a model is not found.
# This should comply with ActiveModel#to_key API, i.e.:
#
# User.to_adapter.get(@user.to_key) == @user
#
def get(id)
raise NotSupportedError
end
# Find the first instance, optionally matching conditions, and specifying order
#
# You can call with just conditions, providing a hash
#
# User.to_adapter.find_first :name => "Fred", :age => 23
#
# Or you can specify :order, and :conditions as keys
#
# User.to_adapter.find_first :conditions => {:name => "Fred", :age => 23}
# User.to_adapter.find_first :order => [:age, :desc]
# User.to_adapter.find_first :order => :name, :conditions => {:age => 18}
#
# When specifying :order, it may be
# * a single arg e.g. <tt>:order => :name</tt>
# * a single pair with :asc, or :desc as last, e.g. <tt>:order => [:name, :desc]</tt>
# * an array of single args or pairs (with :asc or :desc as last), e.g. <tt>:order => [[:name, :asc], [:age, :desc]]</tt>
#
def find_first(options = {})
raise NotSupportedError
end
# Find all models, optionally matching conditions, and specifying order
# @see OrmAdapter::Base#find_first for how to specify order and conditions
def find_all(options = {})
raise NotSupportedError
end
# Create a model using attributes
def create!(attributes = {})
raise NotSupportedError
end
# Destroy an instance by passing in the instance itself.
def destroy(object)
raise NotSupportedError
end
protected
def valid_object?(object)
object.class == klass
end
def wrap_key(key)
key.is_a?(Array) ? key.first : key
end
# given an options hash,
# with optional :conditions, :order, :limit and :offset keys,
# returns conditions, normalized order, limit and offset
def extract_conditions!(options = {})
order = normalize_order(options.delete(:order))
limit = options.delete(:limit)
offset = options.delete(:offset)
conditions = options.delete(:conditions) || options
[conditions, order, limit, offset]
end
# given an order argument, returns an array of pairs, with each pair containing the attribute, and :asc or :desc
def normalize_order(order)
order = Array(order)
if order.length == 2 && !order[0].is_a?(Array) && [:asc, :desc].include?(order[1])
order = [order]
else
order = order.map {|pair| pair.is_a?(Array) ? pair : [pair, :asc] }
end
order.each do |pair|
pair.length == 2 or raise ArgumentError, "each order clause must be a pair (unknown clause #{pair.inspect})"
[:asc, :desc].include?(pair[1]) or raise ArgumentError, "order must be specified with :asc or :desc (unknown key #{pair[1].inspect})"
end
order
end
end
class NotSupportedError < NotImplementedError
def to_s
"method not supported by this orm adapter"
end
end
end
|