Dm adapter RubyConf.TW

  • 751 views
Uploaded on

 

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
751
On Slideshare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
8
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • \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

Transcript

  • 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. DataMapper seams to be losing popularity why talk about it?
  • 4. I enjoy non standard things...
  • 5. It still has featuresActiveRecord/ActiveModel does not...
  • 6. Try something new...
  • 7. 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
  • 8. Terms term meaningResource A model field A property on a modelRepository DataMapper term for the storage engine
  • 9. Preamblerequire dm-core Just do itmodule DataMapper Just do it module Adapters class TestAdapter < AbstractAdapter ... end Just do it const_added(:TestAdapter) endend
  • 10. Symbol Hashdef initialize(name, options)end
  • 11. def initialize(name, options) Just do it superend
  • 12. def initialize(name, options) superend
  • 13. Connect to yourdef initialize(name, options) adapter super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]]end
  • 14. 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
  • 15. 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
  • 16. 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
  • 17. Array of Resourcesdef create(resources)end Return number of resources created
  • 18. 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
  • 19. 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
  • 20. • 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"}
  • 21. 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
  • 22. 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
  • 23. DataMapper::Querydef read(query)end Return a Array of Hashes key: field name value: unmarshed value {field_name => value}
  • 24. def read(query) conditions = parse_query_conditions(query) @adapter[query.model.storage_name].find( conditions)end
  • 25. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association
  • 26. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association:conditions => ["updated_at > ?", Time.now]
  • 27. 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}}
  • 28. 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}}
  • 29. DataMapper::Querydef parse_query_conditions(query) mongo_conditions = {} Return a hash mongo_conditions
  • 30. 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
  • 31. 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
  • 32. 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
  • 33. 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
  • 34. Post.all(:comments => {:body => hi})comments = Comment.all(:body => hi)post_ids = comments.collect { |c| c.post_id }Post.all(:id => post_ids)
  • 35. 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...
  • 36. 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...
  • 37. 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
  • 38. 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...
  • 39. 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...
  • 40. 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...
  • 41. Operation• DataMapper::Query::Conditions::AndOperation• DataMapper::Query::Conditions::OrOperation• DataMapper::Query::Conditions::NotOperation
  • 42. 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
  • 43. What is not covered• Nested Operands
  • 44. 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
  • 45. def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_countend
  • 46. 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)
  • 47. 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
  • 48. 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
  • 49. 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)
  • 50. 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
  • 51. Be Kind log• DataMapper.logger
  • 52. You can stop now end