module Lolita
module Adapter
class Mongoid
include Lolita::Adapter::AbstractAdapter
attr_reader :dbi, :klass
def initialize(dbi)
@dbi=dbi
@klass=dbi.klass
end
# Association adapter
class Association
attr_reader :association,:adapter
def initialize(assoc_object,adapter)
@association = assoc_object
@adapter = adapter
end
def method_missing(method, *args, &block)
@association.send(method,*args,&block)
end
def key
@association.foreign_key
end
def native_macro
@association.macro
end
def macro
convertator = {
:references_many => :many, :references_one => :one, :referenced_in => :one,
:references_and_referenced_in_many => :many_to_many, :embeds_one => :one, :embeds_many => :many
}
convertator[@association.macro]
end
end
# Return all class associations
def associations
# is caching ok?
unless @associations
@associations = {}
klass.relations.each{|name,association|
@associations[name.to_sym] = Association.new(association,self)
}
end
@associations
end
# Return all association class names
def associations_class_names
self.associations.map{|name,association|
association.class_name
}
end
# Detect if class reflect on association by name
def reflect_on_association(name)
if orm_association = klass.reflect_on_association(name)
Association.new(orm_association,self)
end
end
# Each field from ORM is changed to this class instance.
class Field
include Lolita::Adapter::FieldHelper
attr_reader :field, :name,:options, :type, :adapter
def initialize(column,adapter)
@field = column
raise ArgumentError, "Cannot initialize adapter field for nil" unless @field
@adapter = adapter
set_attributes
end
def association
if @association.nil?
possible_association = @adapter.associations.detect{|name,association|
[association.key.to_s].include?(@name.to_s)
}
@association = if possible_association
possible_association.last
else
false
end
end
@association
end
def method_missing(method,*args,&block)
@field.send(method,*args,&block)
end
def primary?
!!self.options[:primary]
end
private
def type_cast(type)
if type.to_s=="Object" || type.to_s.split("::").last == "Object"
"string"
elsif type.to_s.match(/::/)
type.to_s.split("::").last
else
type.to_s.underscore
end
end
def set_attributes
@name = @field.name
@type = type_cast(@field.type)
@options = @field.options.merge({
:primary => @field.type.to_s == "BSON::ObjectId",
:native_type => @field.type.to_s
})
end
end # end of field
def fields
@fields||=self.klass.fields.collect{|name,field|
Field.new(field,self)
}
@fields
end
def field_by_name(name)
self.fields.detect{|field|
field.name.to_s == name.to_s
}
end
def field_by_association(name)
possible_association = self.associations.detect{|assoc_name,association|
name.to_s == assoc_name.to_s
}
if possible_association
self.field_by_name(possible_association.last.key)
end
end
def find_by_id(id)
self.klass.unscoped.where(:_id => id).first
end
# This method is used to paginate, main reason is for list and for index action.
# Method accepts three arguments
# page - page that should be shown (integer)
# per - how many records there should be in page
# options - Hash with optional information.
# By default, Lolita::Configuration::List passes request, with current request information.
# Also it passes :pagination_method that is used to detect if there is special method(-s) in model
# that should be used for creating page.
def paginate(page,per,options ={})
scope = nil
if options[:pagination_method]
if options[:pagination_method].respond_to?(:each)
options[:pagination_method].each do |method_name|
options[:previous_scope] = scope
if new_scope = pagination_scope_from_klass(method_name,page,per,options)
scope = scope ? scope.merge(new_scope) : new_scope
end
end
else
scope = pagination_scope_from_klass(options[:pagination_method],page,per,options)
end
raise ArgumentError, "Didn't generate any scope from #{options} page:{page} per:#{per}" unless scope
scope
else
klass.unscoped.page(page).per(per)
end
end
def pagination_scope_from_klass(method_name,page,per,options)
if klass.respond_to?(method_name)
klass.send(method_name,page,per,options)
end
end
def db
self.klass.db
end
def db_name
self.klass.db.name
end
def collection
self.klass.collection
end
def collection_name
self.klass.collection_name
end
def collection_name=(value)
self.klass.collection_name = value
end
def collections
db.collections
end
def collection_names
db.collection_names
end
end
end
end