Successfully reported this slideshow.

Dm adapter

557 views

Published on

Published in: Business, Technology
  • Be the first to comment

  • Be the first to like this

Dm adapter

  1. 1. Custom DataMapper Adapters By Josh Moore
  2. 2. About Me• Josh Moore• Optimis International• github.com/joshsmoore• twitter.com/codingforrent• www.codingforrent.com
  3. 3. About this presentation• Not an introduction to DataMapper• Mostly Code• Why?
  4. 4. 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
  5. 5. Terms term meaningStorage Engine Whatever is persisting the data Resource A model field A property on a model Repository DataMapper term for the storage engine
  6. 6. Preamblerequire dm-core Just do itmodule DataMapper Just do it module Adapters class TestAdapter < AbstractAdapter ... end Just do it const_added(:TestAdapter) endend
  7. 7. Symbol Hashdef initialize(name, options)end
  8. 8. def initialize(name, options) Just do it superend
  9. 9. def initialize(name, options) superend
  10. 10. Connect to yourdef initialize(name, options) adapter super @conn = Mongo::Connection.new( options[:host], options[:port]) @adapter = @conn[options[:database]]end
  11. 11. 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
  12. 12. 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
  13. 13. 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
  14. 14. Array of Resourcesdef create(resources)end Return number of resources created
  15. 15. 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
  16. 16. 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
  17. 17. • 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"}
  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 Unless an Exception is raised the resource will be considered saved
  20. 20. DataMapper::Querydef read(query)end Return a Array of Hashes key: field name value: unmarshed value {field_name => value}
  21. 21. def read(query) conditions = parse_query_conditions(query) @adapter[query.model.storage_name].find( conditions)end
  22. 22. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association
  23. 23. Query Structure DataMapper::Query #conditions Operation #operands Set Operation Condition Array #subject Field Association:conditions => ["updated_at > ?", Time.now]
  24. 24. 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}}
  25. 25. 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}}
  26. 26. DataMapper::Querydef parse_query_conditions(query) mongo_conditions = {} Return a hash mongo_conditions
  27. 27. 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
  28. 28. 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
  29. 29. 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
  30. 30. 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
  31. 31. Post.all(:comments => {:body => hi 2})
  32. 32. 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...
  33. 33. 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...
  34. 34. conditions.operands.each do |condition| ... case condition.class.to_s Array of properties when ...InclusionComparison * property - subclass of DataMapper::Property if condition.subject.instance_of?DataMapper::Associations::OneToMany::Relationship pk = condition.subject.parent_key.first.field ck = condition.subject.child_key.first.name mongo_conditions[pk] = {"$in" => condition.value.collect {|r| r.send(ck)}} elseArray of properties * property - subclass of DataMapper::Property...
  35. 35. 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...
  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| ... 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...
  38. 38. Operation• DataMapper::Query::Conditions::AndOperation• DataMapper::Query::Conditions::OrOperation• DataMapper::Query::Conditions::NotOperation
  39. 39. 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
  40. 40. What is not covered• Nested Operands
  41. 41. 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
  42. 42. def delete(resources) conditions = parse_query_conditions(resources.query) record_count = read(resources.query).count @adapter[resources.storage_name].remove(conditions) record_countend
  43. 43. 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)
  44. 44. 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
  45. 45. 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
  46. 46. 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)
  47. 47. 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
  48. 48. Be Kind log• DataMapper.logger
  49. 49. You can stop now
  50. 50. 80/20 rule
  51. 51. But, if you want to keep going...
  52. 52. Post.create.key
  53. 53. Post.create.key ["4e15cab882034dc7f7000002"]
  54. 54. Post.create.key
  55. 55. Just do itmodule DataMapper Just do it module Is module Mongo def is_mongo(options={}) property :_id, String, :key => true, :default => end end end Just do it Model.append_extensions(Is::Mongo)end
  56. 56. class Post include DataMapper::Resource property :title, String has n, :comments is :mongoend
  57. 57. class Post include DataMapper::Resource property :title, String has n, :comments is :mongoend Post.create.key [""]
  58. 58. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  59. 59. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  60. 60. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  61. 61. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  62. 62. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  63. 63. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key ["4e15cab882034dc7f7000002"]
  64. 64. def create(resources) resources.collect do |resource| fields =attributes_as_fields(resource.attributes(:property)) fields.delete _id b_id = @adapter[resource.class.storage_name].insert fields resource._id = b_id.to_s if resource.instance_variables.include? @_key resource.send :remove_instance_variable, :@_key end end.sizeend Post.create.key
  65. 65. Whats left• Aggregation• Native types• DataMapper.logger

×