lib/rest_adapter.rb in dm-rest-adapter-0.9.3 vs lib/rest_adapter.rb in dm-rest-adapter-0.9.4
- old
+ new
@@ -1,41 +1,44 @@
require 'rubygems'
require 'pathname'
require Pathname(__FILE__).dirname + 'rest_adapter/version'
gem 'dm-core', DataMapper::More::RestAdapter::VERSION
require 'dm-core'
+
+gem 'extlib', '=0.9.4'
require 'extlib'
+
require 'dm-serializer'
require 'net/http'
require 'rexml/document'
# TODO: Abstract XML support out from the protocol
# TODO: Build JSON support
module DataMapper
module Adapters
class RestAdapter < AbstractAdapter
include Extlib
-
+
# Creates a new resource in the specified repository.
def create(resources)
count = 0
resources.each do |resource|
resource_name = Inflection.underscore(resource.class.name)
result = http_post("/#{resource_name.pluralize}.xml", resource.to_xml)
# TODO: Raise error if cannot reach server
- success = result.instance_of?(Net::HTTPCreated)
+ success = result.instance_of?(Net::HTTPCreated)
if success
count += 1
# TODO: Fix commented out code below to work through the identity_map of the repository
# values = parse_resource(result.body, resource.class)
# resource.id = updated_resource.id
end
# TODO: We're not using the response to update the DataMapper::Resource with the newly acquired ID!!!
end
count
end
-
+
# read_set
#
# Examples of query string:
# A. []
# GET /books/
@@ -60,93 +63,93 @@
end
collection.load(resource_meta[:values])
end
end
end
-
+
def read_one(query)
resource = nil
resource_name = resource_name_from_query(query)
resources_meta = nil
if query.conditions.empty? && query.limit == 1
results = read_set_all(repository, query, resource_name)
resource_meta = results.first unless results.empty?
else
id = query.conditions.first[2]
# KLUGE: Again, we're assuming below that we're dealing with a pluralized resource mapping
-
+
response = http_get("/#{resource_name.pluralize}/#{id}.xml")
-
+
# KLUGE: Rails returns HTML if it can't find a resource. A properly RESTful app would return a 404, right?
return nil if response.is_a? Net::HTTPNotFound || response.content_type == "text/html"
-
+
data = response.body
resource_meta = parse_resource(data, query.model, query)
end
- if resource_meta
+ if resource_meta
if resource_meta.has_key?(:associations)
load_nested_resources_from resource_meta[:associations], query
end
resource = query.model.load(resource_meta[:values], query)
end
resource
end
-
+
def update(attributes, query)
# TODO What if we have a compound key?
raise NotImplementedError.new unless is_single_resource_query? query
id = query.conditions.first[2]
resource = nil
- query.repository.scope do
+ query.repository.scope do
resource = query.model.get(id)
end
attributes.each do |attr, val|
resource.send("#{attr.name}=", val)
end
# KLUGE: Again, we're assuming below that we're dealing with a pluralized resource mapping
res = http_put("/#{resource_name_from_query(query).pluralize}/#{id}.xml", resource.to_xml)
# TODO: Raise error if cannot reach server
res.kind_of?(Net::HTTPSuccess) ? 1 : 0
end
-
+
def delete(query)
raise NotImplementedError.new unless is_single_resource_query? query
id = query.conditions.first[2]
res = http_delete("/#{resource_name_from_query(query).pluralize}/#{id}.xml")
res.kind_of?(Net::HTTPSuccess) ? 1 : 0
end
-
- protected
+
+ protected
def load_nested_resources_from(nested_resources, query)
nested_resources.each do |resource_meta|
# TODO: Houston, we have a problem. Model#load expects a Query. When we're nested, we don't have a query yet...
#resource_meta[:model].load(resource_meta[:values])
#if resource_meta.has_key? :associations
# load_nested_resources_from resource_meta, query
#end
end
end
-
+
def read_set_all(repository, query, resource_name)
# TODO: how do we know whether the resource we're talking to is singular or plural?
res = http_get("/#{resource_name.pluralize}.xml")
data = res.body
parse_resources(data, query.model, query)
# TODO: Raise error if cannot reach server
end
-
+
# GET /books/4200
def read_set_for_condition(repository, query, resource_name)
# More complex conditions
raise NotImplementedError.new
- end
-
+ end
+
# query.conditions like [[:eql, #<Property:Book:id>, 4200]]
def is_single_resource_query?(query)
query.conditions.length == 1 && query.conditions.first.first == :eql && query.conditions.first[1].name == :id
end
-
+
def http_put(uri, data = nil)
request { |http| http.put(uri, data, {"Content-Type", "application/xml"}) }
end
def http_post(uri, data)
@@ -165,17 +168,17 @@
res = nil
Net::HTTP.start(@uri[:host], @uri[:port].to_i) do |http|
res = yield(http)
end
res
- end
+ end
def values_from_rexml(entity_element, dm_model_class)
resource = {}
resource[:values] = []
entity_element.elements.each do |field_element|
- attribute = dm_model_class.properties(repository.name).find do |property|
+ attribute = dm_model_class.properties(repository.name).find do |property|
# *MUST* use Inflection.underscore on the XML as Rails converts '_' to '-' in the XML
property.name.to_s == Inflection.underscore(field_element.name.to_s)
end
if attribute
resource[:values] << field_element.text
@@ -186,11 +189,11 @@
end
if association
field_element.each_element do |associated_element|
model = association[1].child_model
(resource[:associations] ||= []) << {
- :model => model,
+ :model => model,
:value => values_from_rexml(associated_element, association[1].child_model)
}
end
end
end
@@ -202,11 +205,11 @@
# TODO: handle singular resource case as well....
entity_element = REXML::XPath.first(doc, "/#{resource_name_from_model(dm_model_class)}")
return nil unless entity_element
values_from_rexml(entity_element, dm_model_class)
end
-
+
def parse_resources(xml, dm_model_class, query = nil)
doc = REXML::Document::new(xml)
# # TODO: handle singular resource case as well....
# array = XPath(doc, "/*[@type='array']")
# if array
@@ -214,17 +217,17 @@
# else
resource_name = resource_name_from_model dm_model_class
doc.elements.collect("#{resource_name.pluralize}/#{resource_name}") do |entity_element|
values_from_rexml(entity_element, dm_model_class)
end
- end
-
+ end
+
def resource_name_from_model(model)
Inflection.underscore(model.name)
end
-
+
def resource_name_from_query(query)
resource_name_from_model(query.model)
end
end
end
-end
\ No newline at end of file
+end