Custom DataMapper
     Adapters
     By Josh Moore
About Me
• Josh Moore

• Optimis International

• github.com/joshsmoore

• twitter.com/codingforrent

• www.codingforrent.com
About this
          presentation

• Not an introduction to DataMapper

• Mostly Code

• Why?
Examples
class Comment                class Post
  include                      include
      DataMapper::Resource         DataMapper::Resource

 property :id, Serial         property :id, Serial
 property :body, String       property :title, String

  belongs_to :post            has n, :comments
end                          end
Terms
    term                        meaning

Storage Engine       Whatever is persisting the data


  Resource                      A model


     field               A property on a model


  Repository     DataMapper term for the storage engine
Preamble
require 'dm-core'
                        Just do it
module DataMapper
                     Just do it
  module Adapters
    class TestAdapter < AbstractAdapter
       ...
    end
                                   Just do it
    const_added(:TestAdapter)
  end
end
Symbol
                                Hash



def initialize(name, options)




end
def initialize(name, options)
          Just do it
 super




end
def initialize(name, options)
 super




end
Connect
                                    to your
def initialize(name, options)      adapter
 super
 @conn = Mongo::Connection.new(
            options[:host], options[:port])
 @adapter = @conn[options[:database]]




end
def initialize(name, options)
 super
 @conn = Mongo::Connection.new(
                  Sub class of: DataMapper::Property
            options[:host], options[:port])
 @adapter = @conn[options[:database]]
 @field_naming_convention = Proc.new do |field|
   field.model.storage_name + '_' + field.name.to_s
 end
                   Return a String




end
def initialize(name, options)
 super
 @conn = Mongo::Connection.new(
             options[:host], options[:port])
 @adapter = @conn[options[:database]]
 @field_naming_convention = Proc.new do |field|
    field.model.storage_name String (class.to_s)
                                    + '_' + field.name.to_s
 end
 @resource_naming_convention = Proc.new do |resource|
    resource.downcase
 end                Return a String
end
def initialize(name, options)
 super
 @conn = Mongo::Connection.new(
             options[:host], options[:port])
 @adapter = @conn[options[:database]]
 @field_naming_convention = Proc.new do |field|
    field.model.storage_name + '_' + field.name.to_s
 end
 @resource_naming_convention = Proc.new do |resource|
    resource.downcase
 end
end
Array of Resources
def create(resources)




end
           Return number of resources created
def create(resources)
 resources.collect do |resource|
   initialize_serial(resource,
      @adapter[resource.class.storage_name].find.count)
   fields = attributes_as_fields(
                 resource.attributes(:property))
   @adapter[resource.class.storage_name].insert(fields)
 end.size

end
def create(resources)
 resources.collect do |resource|
   initialize_serial(resource,
      @adapter[resource.class.storage_name].find.count)
   fields = attributes_as_fields(
                 resource.attributes(:property))
   @adapter[resource.class.storage_name].insert(fields)
 end.size

end
•   Accepts: Hash
                     •   Key: Sub class of: DataMapper::Property
                     •   Value: non marshaled data
                     •   example:

                     {<DataMapper::Property::String(title)>   =>
                     "hasdf"}
def create(resources)
 resources.collect do |resource|
   initialize_serial(resource,
      @adapter[resource.class.storage_name].find.count)
   fields = attributes_as_fields(
                 resource.attributes(:property))
   @adapter[resource.class.storage_name].insert(fields)
 end.size
             • Return: Hash
             • Key: @field_naming_convention result
end          • Value: Marshaled data
             • Only values that are set
             •Example:
             {"post_title" => "hasdf"}
def create(resources)
 resources.collect do |resource|
   initialize_serial(resource,
      @adapter[resource.class.storage_name].find.count)
   fields = attributes_as_fields(
                 resource.attributes(:property))
   @adapter[resource.class.storage_name].insert(fields)
 end.size

end
def create(resources)
 resources.collect do |resource|
   initialize_serial(resource,
      @adapter[resource.class.storage_name].find.count)
   fields = attributes_as_fields(
                 resource.attributes(:property))
   @adapter[resource.class.storage_name].insert(fields)
 end.size

end         Unless an Exception is raised the
           resource will be considered saved
DataMapper::Query

def read(query)




end
              Return a Array of Hashes
                    key: field name
              value: unmarshed value
               {field_name => value}
def read(query)

 conditions = parse_query_conditions(query)
 @adapter[query.model.storage_name].find(
                                 conditions)
end
Query Structure
               DataMapper::Query

                  #conditions


                   Operation

                  #operands


                     Set




 Operation         Condition              Array

                   #subject
       Field                       Association
Query Structure
                          DataMapper::Query

                             #conditions


                              Operation

                             #operands


                                Set




            Operation         Condition              Array

                              #subject
                  Field                       Association



:conditions => ["updated_at > ?", Time.now]
Query Structure
                            DataMapper::Query

                               #conditions


                                Operation

                               #operands


                                  Set




              Operation         Condition              Array

                                #subject
                    Field                       Association



  :conditions => ["updated_at > ?", Time.now]
:conditions => {:updated_at => {"$gte" => Time.now}}
Query Structure
                            DataMapper::Query

                               #conditions


                                Operation

                               #operands


                                  Set




              Operation         Condition
                                                     Hash
                                                      Array

                                #subject
                    Field                       Association



  :conditions => ["updated_at > ?", Time.now]
:conditions => {:updated_at => {"$gte" => Time.now}}
DataMapper::Query

def parse_query_conditions(query)
  mongo_conditions = {}




                                    Return a hash

 mongo_conditions
query.conditions.operands.each do |condition|
         def parse_query_conditions(query)
           mongo_conditions = {}
  case condition.class.to_s
  when 'DataMapper::Query::Conditions::GreaterThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$gt" => condition.value}
  when 'DataMapper::Query::Conditions::LessThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$lt" => condition.value}
  else
    mongo_conditions[condition.subject.field] =
      condition.value
  end      mongo_conditions
end      end
query.conditions.operands.each do |condition|
         def parse_query_conditions(query)
           mongo_conditions = {}
  case condition.class.to_s
  when 'DataMapper::Query::Conditions::GreaterThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$gt" => condition.value}
  when 'DataMapper::Query::Conditions::LessThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$lt" => condition.value}
  else
    mongo_conditions[condition.subject.field] =
      condition.value
  end      mongo_conditions
end      end
query.conditions.operands.each do |condition|
         def parse_query_conditions(query)
           mongo_conditions = {}
  case condition.class.to_s
  when 'DataMapper::Query::Conditions::GreaterThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$gt" => condition.value}
  when 'DataMapper::Query::Conditions::LessThanComparison'
    mongo_conditions[condition.subject.field] =
      { "$lt" => condition.value}
  else
    mongo_conditions[condition.subject.field] =
      condition.value
  end      mongo_conditions
end      end
def parse_query_conditions(query)
  mongo_conditions = {}

 query.conditions.operands.each do |condition|
   case condition.class.to_s
   when 'DataMapper::Query::Conditions::GreaterThanComparison'
     mongo_conditions[condition.subject.field] =
       { "$gt" => condition.value}
   when 'DataMapper::Query::Conditions::LessThanComparison'
     mongo_conditions[condition.subject.field] =
       { "$lt" => condition.value}
   else
     mongo_conditions[condition.subject.field] =
       condition.value
   end
 end

  mongo_conditions
end
Post.all(:comments => {:body => 'hi 2'})
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
  when '...InclusionComparison'
    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
      pk = condition.subject.parent_key.first.field
      ck = condition.subject.child_key.first.name
      mongo_conditions[pk] = {"$in" =>
        condition.value.collect {|r| r.send(ck)}}
    else
...
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
  when '...InclusionComparison'
    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
      pk = condition.subject.parent_key.first.field
      ck = condition.subject.child_key.first.name
      mongo_conditions[pk] = {"$in" =>
        condition.value.collect {|r| r.send(ck)}}
    else
...
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
        Array of properties
  when '...InclusionComparison'
        * property - subclass of DataMapper::Property

    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
      pk = condition.subject.parent_key.first.field
      ck = condition.subject.child_key.first.name
      mongo_conditions[pk] = {"$in" =>
        condition.value.collect {|r| r.send(ck)}}
    elseArray of properties
        * property - subclass of DataMapper::Property
...
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
  when '...InclusionComparison'
    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
     Array of resources
        pk = condition.subject.parent_key.first.field
     * [#<Comment..>, #<Comment..>,...]

        ck = condition.subject.child_key.first.name
        mongo_conditions[pk] = {"$in" =>
          condition.value.collect {|r| r.send(ck)}}
    else
...
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
  when '...InclusionComparison'
    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
      pk = condition.subject.parent_key.first.field
      ck = condition.subject.child_key.first.name
      mongo_conditions[pk] = {"$in" =>
        condition.value.collect {|r| r.send(ck)}}
    else
...
conditions.operands.each do |condition|
  ...
  case condition.class.to_s
  when '...InclusionComparison'
    if condition.subject.instance_of?
DataMapper::Associations::OneToMany::Relationship
      pk = condition.subject.parent_key.first.field
      ck = condition.subject.child_key.first.name
      mongo_conditions[pk] = {"$in" =>
        condition.value.collect {|r| r.send(ck)}}
    else
...
Operation

• DataMapper::Query::Conditions::AndOperation

• DataMapper::Query::Conditions::OrOperation

• DataMapper::Query::Conditions::NotOperation
Condition
• DataMapper::Query::Conditions::EqualToComparison

• DataMapper::Query::Conditions::InclusionComparison

• DataMapper::Query::Conditions::RegexpComparison

• DataMapper::Query::Conditions::LikeComparison

• DataMapper::Query::Conditions::GreaterThanComparison

• DataMapper::Query::Conditions::LessThanComparison

• DataMapper::Query::Conditions::GreaterThanOrEqualToComparison

• DataMapper::Query::Conditions::LessThanOrEqualToComparison
What is not covered


• Nested Operands
If your backed does not
 have a query language
                      A Array of Hashes
                        key: field name
                  value: unmarshed value
                  [{field_name => value}]




def read(query)
  query.filter_records(records)
end
def delete(resources)
  conditions = parse_query_conditions(resources.query)
  record_count = read(resources.query).count
  @adapter[resources.storage_name].remove(conditions)
  record_count
end
DataMapper::Collection

def delete(resources)
  conditions = parse_query_conditions(resources.query)
  record_count = read(resources.query).count
  @adapter[resources.storage_name].remove(conditions)
  record_count
end     Number of resources deleted (int)
def delete(resources)
  conditions = parse_query_conditions(resources.query)
  record_count = read(resources.query).count
  @adapter[resources.storage_name].remove(conditions)
  record_count
end



           Unless an Exception is raised the
          resource will be considered saved
def update(changes, resources)
  conditions = parse_query_conditions(resources.query)
  @adapter[resources.storage_name].update(conditions,
     {"$set" => attributes_as_fields(changes)},
     {:multi => true})
  read(resources.query).count
end
Unmarshaled hash of changes

        {<DataMapper::Property::String(title)>
             => "hasdf"}



                                            DataMapper::Collection

def update(changes, resources)
  conditions = parse_query_conditions(resources.query)
  @adapter[resources.storage_name].update(conditions,
     {"$set" => attributes_as_fields(changes)},
     {:multi => true})
  read(resources.query).count
end
       Number of resources updated (int)
def update(changes, resources)
  conditions = parse_query_conditions(resources.query)
  @adapter[resources.storage_name].update(conditions,
     {"$set" => attributes_as_fields(changes)},
     {:multi => true})
  read(resources.query).count
end
            Unless an Exception is raised the
           resource will be considered saved
Be Kind log


• DataMapper.logger
You can stop now
80/20 rule
But, if you want to
  keep going...
Post.create.key
Post.create.key

 ["4e15cab882034dc7f7000002"]
Post.create.key
Just do it
module DataMapper
                      Just do it
  module Is
    module Mongo
      def is_mongo(options={})
        property :_id, String,
            :key => true, :default => ''
      end
    end
  end
                                           Just do it
  Model.append_extensions(Is::Mongo)
end
class Post
  include DataMapper::Resource

 property :title, String

 has n, :comments

  is :mongo
end
class Post
  include DataMapper::Resource

 property :title, String

 has n, :comments

  is :mongo
end

     Post.create.key

                 [""]
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key

                       ["4e15cab882034dc7f7000002"]
def create(resources)
  resources.collect do |resource|
    fields =
attributes_as_fields(resource.attributes(:property))
    fields.delete '_id'
    b_id = @adapter[resource.class.storage_name].insert
                          fields
    resource._id = b_id.to_s

    if resource.instance_variables.include? '@_key'
      resource.send :remove_instance_variable, :@_key
    end
  end.size
end                 Post.create.key
Whats left

• Aggregation

• Native types

• DataMapper.logger

Dm adapter

  • 1.
    Custom DataMapper Adapters By Josh Moore
  • 2.
    About Me • JoshMoore • Optimis International • github.com/joshsmoore • twitter.com/codingforrent • www.codingforrent.com
  • 4.
    About this presentation • Not an introduction to DataMapper • Mostly Code • Why?
  • 5.
    Examples class Comment class Post include include DataMapper::Resource DataMapper::Resource property :id, Serial property :id, Serial property :body, String property :title, String belongs_to :post has n, :comments end end
  • 7.
    Terms term meaning Storage Engine Whatever is persisting the data Resource A model field A property on a model Repository DataMapper term for the storage engine
  • 9.
    Preamble require 'dm-core' Just do it module DataMapper Just do it module Adapters class TestAdapter < AbstractAdapter ... end Just do it const_added(:TestAdapter) end end
  • 12.
    Symbol Hash def initialize(name, options) end
  • 13.
    def initialize(name, options) Just do it super end
  • 14.
  • 15.
    Connect to your def initialize(name, options) adapter super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]] end
  • 16.
    def initialize(name, options) super @conn = Mongo::Connection.new( Sub class of: DataMapper::Property options[:host], options[:port]) @adapter = @conn[options[:database]] @field_naming_convention = Proc.new do |field| field.model.storage_name + '_' + field.name.to_s end Return a String end
  • 17.
    def initialize(name, options) super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]] @field_naming_convention = Proc.new do |field| field.model.storage_name String (class.to_s) + '_' + field.name.to_s end @resource_naming_convention = Proc.new do |resource| resource.downcase end Return a String end
  • 18.
    def initialize(name, options) super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]] @field_naming_convention = Proc.new do |field| field.model.storage_name + '_' + field.name.to_s end @resource_naming_convention = Proc.new do |resource| resource.downcase end end
  • 21.
    Array of Resources defcreate(resources) end Return number of resources created
  • 22.
    def create(resources) resources.collectdo |resource| initialize_serial(resource, @adapter[resource.class.storage_name].find.count) fields = attributes_as_fields( resource.attributes(:property)) @adapter[resource.class.storage_name].insert(fields) end.size end
  • 23.
    def create(resources) resources.collectdo |resource| initialize_serial(resource, @adapter[resource.class.storage_name].find.count) fields = attributes_as_fields( resource.attributes(:property)) @adapter[resource.class.storage_name].insert(fields) end.size end
  • 24.
    Accepts: Hash • Key: Sub class of: DataMapper::Property • Value: non marshaled data • example: {<DataMapper::Property::String(title)> => "hasdf"} def create(resources) resources.collect do |resource| initialize_serial(resource, @adapter[resource.class.storage_name].find.count) fields = attributes_as_fields( resource.attributes(:property)) @adapter[resource.class.storage_name].insert(fields) end.size • Return: Hash • Key: @field_naming_convention result end • Value: Marshaled data • Only values that are set •Example: {"post_title" => "hasdf"}
  • 25.
    def create(resources) resources.collectdo |resource| initialize_serial(resource, @adapter[resource.class.storage_name].find.count) fields = attributes_as_fields( resource.attributes(:property)) @adapter[resource.class.storage_name].insert(fields) end.size end
  • 26.
    def create(resources) resources.collectdo |resource| initialize_serial(resource, @adapter[resource.class.storage_name].find.count) fields = attributes_as_fields( resource.attributes(:property)) @adapter[resource.class.storage_name].insert(fields) end.size end Unless an Exception is raised the resource will be considered saved
  • 29.
    DataMapper::Query def read(query) end Return a Array of Hashes key: field name value: unmarshed value {field_name => value}
  • 30.
    def read(query) conditions= parse_query_conditions(query) @adapter[query.model.storage_name].find( conditions) end
  • 31.
    Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association
  • 32.
    Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association :conditions => ["updated_at > ?", Time.now]
  • 33.
    Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association :conditions => ["updated_at > ?", Time.now] :conditions => {:updated_at => {"$gte" => Time.now}}
  • 34.
    Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Hash Array #subject Field Association :conditions => ["updated_at > ?", Time.now] :conditions => {:updated_at => {"$gte" => Time.now}}
  • 36.
    DataMapper::Query def parse_query_conditions(query) mongo_conditions = {} Return a hash mongo_conditions
  • 37.
    query.conditions.operands.each do |condition| def parse_query_conditions(query) mongo_conditions = {} case condition.class.to_s when 'DataMapper::Query::Conditions::GreaterThanComparison' mongo_conditions[condition.subject.field] = { "$gt" => condition.value} when 'DataMapper::Query::Conditions::LessThanComparison' mongo_conditions[condition.subject.field] = { "$lt" => condition.value} else mongo_conditions[condition.subject.field] = condition.value end mongo_conditions end end
  • 38.
    query.conditions.operands.each do |condition| def parse_query_conditions(query) mongo_conditions = {} case condition.class.to_s when 'DataMapper::Query::Conditions::GreaterThanComparison' mongo_conditions[condition.subject.field] = { "$gt" => condition.value} when 'DataMapper::Query::Conditions::LessThanComparison' mongo_conditions[condition.subject.field] = { "$lt" => condition.value} else mongo_conditions[condition.subject.field] = condition.value end mongo_conditions end end
  • 39.
    query.conditions.operands.each do |condition| def parse_query_conditions(query) mongo_conditions = {} case condition.class.to_s when 'DataMapper::Query::Conditions::GreaterThanComparison' mongo_conditions[condition.subject.field] = { "$gt" => condition.value} when 'DataMapper::Query::Conditions::LessThanComparison' mongo_conditions[condition.subject.field] = { "$lt" => condition.value} else mongo_conditions[condition.subject.field] = condition.value end mongo_conditions end end
  • 40.
    def parse_query_conditions(query) mongo_conditions = {} query.conditions.operands.each do |condition| case condition.class.to_s when 'DataMapper::Query::Conditions::GreaterThanComparison' mongo_conditions[condition.subject.field] = { "$gt" => condition.value} when 'DataMapper::Query::Conditions::LessThanComparison' mongo_conditions[condition.subject.field] = { "$lt" => condition.value} else mongo_conditions[condition.subject.field] = condition.value end end mongo_conditions end
  • 41.
  • 42.
    conditions.operands.each do |condition| ... case condition.class.to_s when '...InclusionComparison' if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} else ...
  • 43.
    conditions.operands.each do |condition| ... case condition.class.to_s when '...InclusionComparison' if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} else ...
  • 44.
    conditions.operands.each do |condition| ... case condition.class.to_s Array of properties when '...InclusionComparison' * property - subclass of DataMapper::Property if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} elseArray of properties * property - subclass of DataMapper::Property ...
  • 45.
    conditions.operands.each do |condition| ... case condition.class.to_s when '...InclusionComparison' if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship Array of resources pk = condition.subject.parent_key.first.field * [#<Comment..>, #<Comment..>,...] ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} else ...
  • 46.
    conditions.operands.each do |condition| ... case condition.class.to_s when '...InclusionComparison' if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} else ...
  • 47.
    conditions.operands.each do |condition| ... case condition.class.to_s when '...InclusionComparison' if condition.subject.instance_of? DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} else ...
  • 48.
  • 49.
    Condition • DataMapper::Query::Conditions::EqualToComparison • DataMapper::Query::Conditions::InclusionComparison •DataMapper::Query::Conditions::RegexpComparison • DataMapper::Query::Conditions::LikeComparison • DataMapper::Query::Conditions::GreaterThanComparison • DataMapper::Query::Conditions::LessThanComparison • DataMapper::Query::Conditions::GreaterThanOrEqualToComparison • DataMapper::Query::Conditions::LessThanOrEqualToComparison
  • 50.
    What is notcovered • Nested Operands
  • 51.
    If your backeddoes not have a query language A Array of Hashes key: field name value: unmarshed value [{field_name => value}] def read(query) query.filter_records(records) end
  • 53.
    def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_count end
  • 54.
    DataMapper::Collection def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_count end Number of resources deleted (int)
  • 55.
    def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_count end Unless an Exception is raised the resource will be considered saved
  • 57.
    def update(changes, resources) conditions = parse_query_conditions(resources.query) @adapter[resources.storage_name].update(conditions, {"$set" => attributes_as_fields(changes)}, {:multi => true}) read(resources.query).count end
  • 58.
    Unmarshaled hash ofchanges {<DataMapper::Property::String(title)> => "hasdf"} DataMapper::Collection def update(changes, resources) conditions = parse_query_conditions(resources.query) @adapter[resources.storage_name].update(conditions, {"$set" => attributes_as_fields(changes)}, {:multi => true}) read(resources.query).count end Number of resources updated (int)
  • 59.
    def update(changes, resources) conditions = parse_query_conditions(resources.query) @adapter[resources.storage_name].update(conditions, {"$set" => attributes_as_fields(changes)}, {:multi => true}) read(resources.query).count end Unless an Exception is raised the resource will be considered saved
  • 60.
    Be Kind log •DataMapper.logger
  • 61.
  • 62.
  • 63.
    But, if youwant to keep going...
  • 64.
  • 65.
  • 66.
  • 67.
    Just do it moduleDataMapper Just do it module Is module Mongo def is_mongo(options={}) property :_id, String, :key => true, :default => '' end end end Just do it Model.append_extensions(Is::Mongo) end
  • 68.
    class Post include DataMapper::Resource property :title, String has n, :comments is :mongo end
  • 69.
    class Post include DataMapper::Resource property :title, String has n, :comments is :mongo end Post.create.key [""]
  • 70.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 71.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 72.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 73.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 74.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 75.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key ["4e15cab882034dc7f7000002"]
  • 76.
    def create(resources) resources.collect do |resource| fields = attributes_as_fields(resource.attributes(:property)) fields.delete '_id' b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? '@_key' resource.send :remove_instance_variable, :@_key end end.size end Post.create.key
  • 77.
    Whats left • Aggregation •Native types • DataMapper.logger

Editor's Notes

  • #2 \n
  • #3 * Work mostly with backend data transformations from Transactional Database to Reporting datastore\n* When you have a child the blogging slows down\n* Talk quickly when I am nervous, let me know if to fast\n
  • #4 * About the little ruby Code in the middle\n* Will not focus on either DB OR DM\n
  • #5 \n
  • #6 \n
  • #7 \n
  • #8 \n
  • #9 * With the addition of the initialization mostly just CRUD operations\n* CRUD\n
  • #10 \n
  • #11 \n
  • #12 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #13 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #14 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #15 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #16 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #17 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #18 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #19 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #20 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #21 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #22 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #23 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #24 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #25 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #26 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #27 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #28 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #29 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #30 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #31 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #32 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #33 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #34 * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • #35 \n
  • #36 \n
  • #37 \n
  • #38 \n
  • #39 \n
  • #40 \n
  • #41 \n
  • #42 \n
  • #43 \n
  • #44 \n
  • #45 \n
  • #46 \n
  • #47 \n
  • #48 \n
  • #49 \n
  • #50 \n
  • #51 \n
  • #52 \n
  • #53 \n
  • #54 \n
  • #55 \n
  • #56 \n
  • #57 \n
  • #58 \n
  • #59 \n
  • #60 \n
  • #61 \n
  • #62 \n
  • #63 \n
  • #64 \n
  • #65 \n
  • #66 \n
  • #67 \n
  • #68 \n
  • #69 \n
  • #70 \n
  • #71 \n
  • #72 \n
  • #73 \n
  • #74 * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • #75 * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • #76 * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • #77 * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • #78 * Only top level Operation\n* own your own for recursive solution\n
  • #79 * Only top level Operation\n* own your own for recursive solution\n
  • #80 * Only top level Operation\n* own your own for recursive solution\n
  • #81 * Only top level Operation\n* own your own for recursive solution\n
  • #82 * Only top level Operation\n* own your own for recursive solution\n
  • #83 * Only top level Operation\n* own your own for recursive solution\n
  • #84 * Only top level Operation\n* own your own for recursive solution\n
  • #85 * Only top level Operation\n* own your own for recursive solution\n
  • #86 * Only top level Operation\n* own your own for recursive solution\n
  • #87 * Only top level Operation\n* own your own for recursive solution\n
  • #88 * Only top level Operation\n* own your own for recursive solution\n
  • #89 * Only top level Operation\n* own your own for recursive solution\n
  • #90 * Only top level Operation\n* own your own for recursive solution\n
  • #91 * Only top level Operation\n* own your own for recursive solution\n
  • #92 * Only top level Operation\n* own your own for recursive solution\n
  • #93 * Only top level Operation\n* own your own for recursive solution\n
  • #94 * Only top level Operation\n* own your own for recursive solution\n
  • #95 * Only top level Operation\n* own your own for recursive solution\n
  • #96 * Only top level Operation\n* own your own for recursive solution\n
  • #97 \n
  • #98 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #99 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #100 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #101 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #102 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #103 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #104 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #105 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #106 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #107 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #108 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #109 * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • #110 \n
  • #111 \n
  • #112 \n
  • #113 \n
  • #114 \n
  • #115 \n
  • #116 \n
  • #117 \n
  • #118 \n
  • #119 \n
  • #120 \n
  • #121 \n
  • #122 \n
  • #123 \n
  • #124 \n
  • #125 \n
  • #126 \n
  • #127 \n
  • #128 \n
  • #129 \n
  • #130 \n
  • #131 \n
  • #132 \n
  • #133 \n
  • #134 \n
  • #135 \n
  • #136 \n
  • #137 \n
  • #138 \n
  • #139 \n
  • #140 \n
  • #141 \n
  • #142 * info - used for logging what you are sending to the repository\n
  • #143 \n
  • #144 * The first part of the presentation is the 80 percent that makes the most difference\n* The last (more repository specific) part is the 20 percent\n
  • #145 * Mongo specific example \n* But demonstrates the process of modifying a models\n
  • #146 \n
  • #147 \n
  • #148 \n
  • #149 \n
  • #150 \n
  • #151 \n
  • #152 \n
  • #153 \n
  • #154 \n
  • #155 \n
  • #156 \n
  • #157 \n
  • #158 \n
  • #159 \n
  • #160 \n
  • #161 * Be kind log\n* at info log the query parameters that are being passed to repository\n
  • #162 \n
  • #163 \n
  • #164 \n
  • #165 \n