SlideShare ist ein Scribd-Unternehmen logo
1 von 64
Custom DataMapper
     Adapters
    By Josh Moore (   )
About Me
• Josh Moore

• Optimis Dev

• github.com/joshsmoore

• twitter.com/codingforrent

• www.codingforrent.com

• joshsmoore@gmail.com
DataMapper seams to be losing
 popularity why talk about it?
I enjoy non standard
       things...
It still has features
ActiveRecord/ActiveModel does
                 not...
Try something new...
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

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'})




comments = Comment.all(:body => 'hi')
post_ids = comments.collect { |c| c.post_id }
Post.all(:id => post_ids)
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|
  ...   Array of properties
  case condition.class.to_s
        * property - subclass of DataMapper::Property
        * ex. Post#id
  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)}}
    elseArray of properties
        * property - subclass of DataMapper::Property
...     * ex Coment#post_id
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




              end

Weitere ähnliche Inhalte

Was ist angesagt?

Database API, your new friend
Database API, your new friendDatabase API, your new friend
Database API, your new friend
kikoalonsob
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
Six Apart KK
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 

Was ist angesagt? (20)

Tutorial, Part 3: SharePoint 101: Jump-Starting the Developer by Rob Windsor ...
Tutorial, Part 3: SharePoint 101: Jump-Starting the Developer by Rob Windsor ...Tutorial, Part 3: SharePoint 101: Jump-Starting the Developer by Rob Windsor ...
Tutorial, Part 3: SharePoint 101: Jump-Starting the Developer by Rob Windsor ...
 
Apache pig
Apache pigApache pig
Apache pig
 
Perforce Object and Record Model
Perforce Object and Record Model  Perforce Object and Record Model
Perforce Object and Record Model
 
Testing stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.checkTesting stateful, concurrent, and async systems using test.check
Testing stateful, concurrent, and async systems using test.check
 
Database API, your new friend
Database API, your new friendDatabase API, your new friend
Database API, your new friend
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
GORM
GORMGORM
GORM
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Developer Testing Tools Roundup
Developer Testing Tools RoundupDeveloper Testing Tools Roundup
Developer Testing Tools Roundup
 
The Zen of Lithium
The Zen of LithiumThe Zen of Lithium
The Zen of Lithium
 
Bioinformatics p5-bioperlv2014
Bioinformatics p5-bioperlv2014Bioinformatics p5-bioperlv2014
Bioinformatics p5-bioperlv2014
 
DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail DBIx-DataModel v2.0 in detail
DBIx-DataModel v2.0 in detail
 
Syntactic sugar in Postgre SQL
Syntactic sugar in Postgre SQLSyntactic sugar in Postgre SQL
Syntactic sugar in Postgre SQL
 
Backbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The BrowserBackbone.js: Run your Application Inside The Browser
Backbone.js: Run your Application Inside The Browser
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Resource Routing in ExpressionEngine
Resource Routing in ExpressionEngineResource Routing in ExpressionEngine
Resource Routing in ExpressionEngine
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Array operators
Array operatorsArray operators
Array operators
 
Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09Spl Not A Bridge Too Far phpNW09
Spl Not A Bridge Too Far phpNW09
 

Ähnlich wie Dm adapter RubyConf.TW

第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource
Kaz Watanabe
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
Night Sailer
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
Jano Suchal
 
Introducing DataWave
Introducing DataWaveIntroducing DataWave
Introducing DataWave
Data Works MD
 

Ähnlich wie Dm adapter RubyConf.TW (20)

DataMapper
DataMapperDataMapper
DataMapper
 
Spring data iii
Spring data iiiSpring data iii
Spring data iii
 
第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource第49回Php勉強会@関東 Datasource
第49回Php勉強会@関東 Datasource
 
Java Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom TagsJava Web Programming [5/9] : EL, JSTL and Custom Tags
Java Web Programming [5/9] : EL, JSTL and Custom Tags
 
From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)From mysql to MongoDB(MongoDB2011北京交流会)
From mysql to MongoDB(MongoDB2011北京交流会)
 
TDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em RubyTDC 2012 - Patterns e Anti-Patterns em Ruby
TDC 2012 - Patterns e Anti-Patterns em Ruby
 
Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2Zend Framework Study@Tokyo #2
Zend Framework Study@Tokyo #2
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
 
All I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web FrameworkAll I Need to Know I Learned by Writing My Own Web Framework
All I Need to Know I Learned by Writing My Own Web Framework
 
mongodb-introduction
mongodb-introductionmongodb-introduction
mongodb-introduction
 
Design Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron PattersonDesign Summit - Rails 4 Migration - Aaron Patterson
Design Summit - Rails 4 Migration - Aaron Patterson
 
Introducing DataWave
Introducing DataWaveIntroducing DataWave
Introducing DataWave
 
From docker to kubernetes: running Apache Hadoop in a cloud native way
From docker to kubernetes: running Apache Hadoop in a cloud native wayFrom docker to kubernetes: running Apache Hadoop in a cloud native way
From docker to kubernetes: running Apache Hadoop in a cloud native way
 
Shooting the Rapids
Shooting the RapidsShooting the Rapids
Shooting the Rapids
 
No more struggles with Apache Spark workloads in production
No more struggles with Apache Spark workloads in productionNo more struggles with Apache Spark workloads in production
No more struggles with Apache Spark workloads in production
 
Jquery 4
Jquery 4Jquery 4
Jquery 4
 
Developing a Real-time Engine with Akka, Cassandra, and Spray
Developing a Real-time Engine with Akka, Cassandra, and SprayDeveloping a Real-time Engine with Akka, Cassandra, and Spray
Developing a Real-time Engine with Akka, Cassandra, and Spray
 
I Phone On Rails
I Phone On RailsI Phone On Rails
I Phone On Rails
 
Hadoop Integration in Cassandra
Hadoop Integration in CassandraHadoop Integration in Cassandra
Hadoop Integration in Cassandra
 
Tools for Making Machine Learning more Reactive
Tools for Making Machine Learning more ReactiveTools for Making Machine Learning more Reactive
Tools for Making Machine Learning more Reactive
 

Kürzlich hochgeladen

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
Enterprise Knowledge
 

Kürzlich hochgeladen (20)

IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 

Dm adapter RubyConf.TW

  • 1. Custom DataMapper Adapters By Josh Moore ( )
  • 2. About Me • Josh Moore • Optimis Dev • github.com/joshsmoore • twitter.com/codingforrent • www.codingforrent.com • joshsmoore@gmail.com
  • 3.
  • 4. DataMapper seams to be losing popularity why talk about it?
  • 5. I enjoy non standard things...
  • 6. It still has features ActiveRecord/ActiveModel does not...
  • 8. 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
  • 9.
  • 10. Terms term meaning Resource A model field A property on a model Repository DataMapper term for the storage engine
  • 11.
  • 12. 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
  • 13.
  • 14.
  • 15. Symbol Hash def initialize(name, options) end
  • 16. def initialize(name, options) Just do it super end
  • 18. Connect to your def initialize(name, options) adapter super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]] end
  • 19. 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
  • 20. 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
  • 21. 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
  • 22.
  • 23.
  • 24. Array of Resources def create(resources) end Return number of resources created
  • 25. 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
  • 26. 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
  • 27. 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"}
  • 28. 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
  • 29. 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
  • 30.
  • 31.
  • 32. DataMapper::Query def read(query) end Return a Array of Hashes key: field name value: unmarshed value {field_name => value}
  • 33. def read(query) conditions = parse_query_conditions(query) @adapter[query.model.storage_name].find( conditions) end
  • 34. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association
  • 35. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association :conditions => ["updated_at > ?", Time.now]
  • 36. 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}}
  • 37. 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}}
  • 38.
  • 39. DataMapper::Query def parse_query_conditions(query) mongo_conditions = {} Return a hash mongo_conditions
  • 40. 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
  • 41. 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
  • 42. 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
  • 43. 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
  • 44. Post.all(:comments => {:body => 'hi'}) comments = Comment.all(:body => 'hi') post_ids = comments.collect { |c| c.post_id } Post.all(:id => post_ids)
  • 45. 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 ...
  • 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| ... Array of properties case condition.class.to_s * property - subclass of DataMapper::Property * ex. Post#id 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)}} elseArray of properties * property - subclass of DataMapper::Property ... * ex Coment#post_id
  • 48. 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 ...
  • 49. 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 ...
  • 50. 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 ...
  • 52. 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
  • 53. What is not covered • Nested Operands
  • 54. 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
  • 55.
  • 56. def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_count end
  • 57. 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)
  • 58. 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
  • 59.
  • 60. 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
  • 61. 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)
  • 62. 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
  • 63. Be Kind log • DataMapper.logger
  • 64. You can stop now end

Hinweis der Redaktion

  1. \n
  2. * 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
  3. \n
  4. \n
  5. * About the little ruby Code in the middle\n* Will not focus on either DB OR DM\n
  6. * last commit was almost a month ago\n* It is true\n* ActiveRecord lots of improvements\n
  7. \n
  8. \n
  9. * Associations across multiple repositories\n
  10. * &amp;#x738B;&amp;#x5EFA;&amp;#x8208; talked about picking different things from different languages... Why not learn different ORMs to?\n
  11. \n
  12. * xdite will think it is stupid\n
  13. \n
  14. * With the addition of the initialization mostly just CRUD operations\n* CRUD\n
  15. \n
  16. \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. * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  36. * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  37. * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  38. * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  39. * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\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. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  80. * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  81. * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  82. * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\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. * Only top level Operation\n* own your own for recursive solution\n
  98. * Only top level Operation\n* own your own for recursive solution\n
  99. * Only top level Operation\n* own your own for recursive solution\n
  100. * Only top level Operation\n* own your own for recursive solution\n
  101. * Only top level Operation\n* own your own for recursive solution\n
  102. \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. * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  111. * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  112. * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  113. * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  114. * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \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. \n
  143. \n
  144. \n
  145. \n
  146. \n
  147. * info - used for logging what you are sending to the repository\n
  148. \n
  149. * 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
  150. * Mongo specific example \n* But demonstrates the process of modifying a models\n
  151. \n
  152. \n
  153. \n
  154. \n
  155. \n
  156. \n
  157. \n
  158. \n
  159. \n
  160. \n
  161. \n
  162. \n
  163. \n
  164. \n
  165. \n
  166. * Be kind log\n* at info log the query parameters that are being passed to repository\n* Mongo supports Array and Hash natively\n
  167. \n
  168. \n
  169. \n
  170. \n
  171. \n