Dm adapter RubyConf.TW

1,135 views
968 views

Published on

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,135
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

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
  • Dm adapter RubyConf.TW

    1. 1. Custom DataMapper Adapters By Josh Moore ( )
    2. 2. About Me• Josh Moore• Optimis Dev• github.com/joshsmoore• twitter.com/codingforrent• www.codingforrent.com• joshsmoore@gmail.com
    3. 3. DataMapper seams to be losing popularity why talk about it?
    4. 4. I enjoy non standard things...
    5. 5. It still has featuresActiveRecord/ActiveModel does not...
    6. 6. Try something new...
    7. 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. 8. Terms term meaningResource A model field A property on a modelRepository DataMapper term for the storage engine
    9. 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. 10. Symbol Hashdef initialize(name, options)end
    11. 11. def initialize(name, options) Just do it superend
    12. 12. def initialize(name, options) superend
    13. 13. Connect to yourdef initialize(name, options) adapter super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]]end
    14. 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. 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. 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. 17. Array of Resourcesdef create(resources)end Return number of resources created
    18. 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. 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. 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. 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. 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. 23. DataMapper::Querydef read(query)end Return a Array of Hashes key: field name value: unmarshed value {field_name => value}
    24. 24. def read(query) conditions = parse_query_conditions(query) @adapter[query.model.storage_name].find( conditions)end
    25. 25. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association
    26. 26. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association:conditions => ["updated_at > ?", Time.now]
    27. 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. 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. 29. DataMapper::Querydef parse_query_conditions(query) mongo_conditions = {} Return a hash mongo_conditions
    30. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 41. Operation• DataMapper::Query::Conditions::AndOperation• DataMapper::Query::Conditions::OrOperation• DataMapper::Query::Conditions::NotOperation
    42. 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. 43. What is not covered• Nested Operands
    44. 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. 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. 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. 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. 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. 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. 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. 51. Be Kind log• DataMapper.logger
    52. 52. You can stop now end

    ×