Dm adapter RubyConf.TW
Upcoming SlideShare
Loading in...5
×
 

Dm adapter RubyConf.TW

on

  • 966 views

 

Statistics

Views

Total Views
966
Views on SlideShare
965
Embed Views
1

Actions

Likes
0
Downloads
8
Comments
0

1 Embed 1

http://coderwall.com 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • * 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
  • \n
  • \n
  • * About the little ruby Code in the middle\n* Will not focus on either DB OR DM\n
  • * last commit was almost a month ago\n* It is true\n* ActiveRecord lots of improvements\n
  • \n
  • \n
  • * Associations across multiple repositories\n
  • * 王建興 talked about picking different things from different languages... Why not learn different ORMs to?\n
  • \n
  • * xdite will think it is stupid\n
  • \n
  • * With the addition of the initialization mostly just CRUD operations\n* CRUD\n
  • \n
  • \n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • * Raw Access to connection through adapter\n* Persisted through entire instance, so if time out need to reconnect\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • * Association - subclass of DataMapper::Associations::*::Relationship\n* Field - subclass of DataMapper::Property\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • * Only top level Operation\n* own your own for recursive solution\n
  • \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • * .field - the repository name\n* .name - the resource name\n* value IS UNMARSHALED \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • * info - used for logging what you are sending to the repository\n
  • \n
  • * 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
  • * Mongo specific example \n* But demonstrates the process of modifying a models\n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • * Be kind log\n* at info log the query parameters that are being passed to repository\n* Mongo supports Array and Hash natively\n
  • \n
  • \n
  • \n
  • \n
  • \n

Dm adapter RubyConf.TW Dm adapter RubyConf.TW Presentation Transcript

  • 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 featuresActiveRecord/ActiveModel does not...
  • Try something new...
  • Examplesclass 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, :commentsend end
  • Terms term meaningResource A model field A property on a modelRepository DataMapper term for the storage engine
  • Preamblerequire dm-core Just do itmodule DataMapper Just do it module Adapters class TestAdapter < AbstractAdapter ... end Just do it const_added(:TestAdapter) endend
  • Symbol Hashdef initialize(name, options)end
  • def initialize(name, options) Just do it superend
  • def initialize(name, options) superend
  • Connect to yourdef 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 Stringend
  • 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 Stringend
  • 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 endend
  • Array of Resourcesdef 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.sizeend
  • 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.sizeend
  • • 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 resultend • 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.sizeend
  • 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.sizeend Unless an Exception is raised the resource will be considered saved
  • DataMapper::Querydef 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::Querydef 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_conditionsend 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_conditionsend 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_conditionsend 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_conditionsend
  • 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_countend
  • DataMapper::Collectiondef delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_countend 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_countend 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).countend
  • Unmarshaled hash of changes {<DataMapper::Property::String(title)> => "hasdf"} DataMapper::Collectiondef 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).countend 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).countend Unless an Exception is raised the resource will be considered saved
  • Be Kind log• DataMapper.logger
  • You can stop now end