2. About Me
• Josh Moore
• Optimis International
• github.com/joshsmoore
• twitter.com/codingforrent
• www.codingforrent.com
3.
4. About this
presentation
• Not an introduction to DataMapper
• Mostly Code
• Why?
5. 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
6.
7. Terms
term meaning
Storage Engine Whatever is persisting the data
Resource A model
field A property on a model
Repository DataMapper term for the storage engine
8.
9. 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
15. Connect
to your
def initialize(name, options) adapter
super
@conn = Mongo::Connection.new(
options[:host], options[:port])
@adapter = @conn[options[:database]]
end
16. 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
17. 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
18. 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. 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
23. 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
24. • 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"}
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 Unless an Exception is raised the
resource will be considered saved
37. 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
38. 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
39. 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
40. 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
42. 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
...
43. 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
...
44. 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
...
45. 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
...
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|
...
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
...
51. 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
54. 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)
55. 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
58. 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)
59. 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
67. Just do it
module 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
68. class Post
include DataMapper::Resource
property :title, String
has n, :comments
is :mongo
end
69. class Post
include DataMapper::Resource
property :title, String
has n, :comments
is :mongo
end
Post.create.key
[""]
70. 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.size
end Post.create.key
71. 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.size
end Post.create.key
72. 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.size
end Post.create.key
73. 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.size
end Post.create.key
74. 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.size
end Post.create.key
75. 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.size
end Post.create.key
["4e15cab882034dc7f7000002"]
76. 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.size
end Post.create.key
* 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
* About the little ruby Code in the middle\n* Will not focus on either DB OR DM\n
\n
\n
\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