Class: CloudKit::Resource
Overview
A CloudKit::Resource represents a “resource” in the REST/HTTP sense of the word. It encapsulates a JSON document and its metadata such as its URI, ETag, Last-Modified date, remote user, and historical versions.
Instance Attribute Summary collapse
-
#etag ⇒ Object
readonly
Returns the value of attribute etag.
-
#json ⇒ Object
readonly
Returns the value of attribute json.
-
#last_modified ⇒ Object
readonly
Returns the value of attribute last_modified.
-
#remote_user ⇒ Object
readonly
Returns the value of attribute remote_user.
-
#uri ⇒ Object
readonly
Returns the value of attribute uri.
Class Method Summary collapse
-
.all(spec = {}) ⇒ Object
Find all resources with the given properties.
-
.create(uri, json, remote_user = nil) ⇒ Object
Create a new resource.
-
.current(spec = {}) ⇒ Object
Find all current resources with the given properties.
-
.first(spec) ⇒ Object
Find the first matching resource or nil.
Instance Method Summary collapse
-
#archived? ⇒ Boolean
Returns true if the resource is archived i.e.
-
#current? ⇒ Boolean
Returns true if the resource is not archived and not deleted.
-
#delete ⇒ Object
Delete the given resource.
-
#deleted? ⇒ Boolean
Returns true if the resource has been deleted.
-
#initialize(uri, json, remote_user = nil, options = {}) ⇒ Resource
constructor
Initialize a new instance of a resource.
-
#parsed_json ⇒ Object
Returns and caches the parsed JSON representation for this resource.
-
#previous_version ⇒ Object
Returns the most recent previous version of the given resource.
-
#previous_versions ⇒ Object
Returns all previous versions of a resource, reverse ordered by Last-Modified date.
-
#save ⇒ Object
Save the resource.
-
#update(json, remote_user = nil) ⇒ Object
Update the json and optionally the remote_user for the current resource.
-
#versions ⇒ Object
Returns all versions of the given resource, reverse ordered by Last-Modified date, including the current version of the resource.
Constructor Details
#initialize(uri, json, remote_user = nil, options = {}) ⇒ Resource
Initialize a new instance of a resource.
Parameters
-
uri - A CloudKit::URI for the resource or its parent collection.
-
json - A string representing a valid JSON object.
-
remote_user - Optional. The URI for the user creating the resource.
-
options - Optional. A hash of other internal properties to set, mostly for internal use.
17 18 19 20 21 22 |
# File 'lib/cloudkit/store/resource.rb', line 17 def initialize(uri, json, remote_user=nil, ={}) (.merge( :uri => uri, :json => json, :remote_user => remote_user)) end |
Instance Attribute Details
#etag ⇒ Object (readonly)
Returns the value of attribute etag.
8 9 10 |
# File 'lib/cloudkit/store/resource.rb', line 8 def etag @etag end |
#json ⇒ Object (readonly)
Returns the value of attribute json.
8 9 10 |
# File 'lib/cloudkit/store/resource.rb', line 8 def json @json end |
#last_modified ⇒ Object (readonly)
Returns the value of attribute last_modified.
8 9 10 |
# File 'lib/cloudkit/store/resource.rb', line 8 def last_modified @last_modified end |
#remote_user ⇒ Object (readonly)
Returns the value of attribute remote_user.
8 9 10 |
# File 'lib/cloudkit/store/resource.rb', line 8 def remote_user @remote_user end |
#uri ⇒ Object (readonly)
Returns the value of attribute uri.
8 9 10 |
# File 'lib/cloudkit/store/resource.rb', line 8 def uri @uri end |
Class Method Details
.all(spec = {}) ⇒ Object
Find all resources with the given properties. Expects a hash specifying the search parameters. Returns an array of Resources.
144 145 146 147 148 149 150 |
# File 'lib/cloudkit/store/resource.rb', line 144 def self.all(spec={}) CloudKit.storage_adapter.query { |q| spec.keys.each { |k| q.add_condition(k.to_s, :eql, escape(spec[k])) } }.reverse.map { |hash| build_from_hash(hash) } end |
.create(uri, json, remote_user = nil) ⇒ Object
Create a new resource. Intializes and saves in one step.
Parameters
-
uri - A CloudKit::URI for the resource or its parent collection.
-
json - A string representing a valid JSON object.
-
remote_user - Optional. The URI for the user creating the resource.
130 131 132 133 134 |
# File 'lib/cloudkit/store/resource.rb', line 130 def self.create(uri, json, remote_user=nil) resource = new(uri, json, remote_user) resource.save resource end |
.current(spec = {}) ⇒ Object
Find all current resources with the given properties. Expectes a hash specifying the search parameters. Returns an array of Resources.
138 139 140 |
# File 'lib/cloudkit/store/resource.rb', line 138 def self.current(spec={}) all({:deleted => false, :archived => false}.merge(spec)) end |
.first(spec) ⇒ Object
Find the first matching resource or nil. Expects a hash specifying the search parameters.
154 155 156 |
# File 'lib/cloudkit/store/resource.rb', line 154 def self.first(spec) all(spec)[0] end |
Instance Method Details
#archived? ⇒ Boolean
Returns true if the resource is archived i.e. not the current version.
110 111 112 |
# File 'lib/cloudkit/store/resource.rb', line 110 def archived? @archived end |
#current? ⇒ Boolean
Returns true if the resource is not archived and not deleted.
115 116 117 |
# File 'lib/cloudkit/store/resource.rb', line 115 def current? !@deleted && !@archived end |
#delete ⇒ Object
Delete the given resource. This is a soft delete, archiving the previous resource and inserting a deleted resource placeholder at the old URI. Raises HistoricalIntegrityViolation for attempts to delete resources that are not current.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/cloudkit/store/resource.rb', line 66 def delete raise HistoricalIntegrityViolation unless current? transaction do original_uri = @uri record = CloudKit.storage_adapter[@id] record['uri'] = "#{@uri.string}/versions/#{@etag}" record['archived'] = escape(true) @uri = wrap_uri(record['uri']) @archived = unescape(record['archived']) CloudKit.storage_adapter[@id] = record self.class.new(original_uri, @json, @remote_user, {:deleted => true}).save end reload end |
#deleted? ⇒ Boolean
Returns true if the resource has been deleted.
105 106 107 |
# File 'lib/cloudkit/store/resource.rb', line 105 def deleted? @deleted end |
#parsed_json ⇒ Object
Returns and caches the parsed JSON representation for this resource.
120 121 122 |
# File 'lib/cloudkit/store/resource.rb', line 120 def parsed_json @parsed_json ||= JSON.parse(@json) end |
#previous_version ⇒ Object
Returns the most recent previous version of the given resource.
100 101 102 |
# File 'lib/cloudkit/store/resource.rb', line 100 def previous_version @previous_version ||= previous_versions[0] end |
#previous_versions ⇒ Object
Returns all previous versions of a resource, reverse ordered by Last-Modified date.
95 96 97 |
# File 'lib/cloudkit/store/resource.rb', line 95 def previous_versions @previous_versions ||= versions[1..-1] rescue [] end |
#save ⇒ Object
Save the resource. If this is a new resource with only a resource collection URI, its full URI will be generated. ETags and Last-Modified dates are also generated upon saving. No manual reloads are required.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/cloudkit/store/resource.rb', line 27 def save @id ||= '%064d' % CloudKit.storage_adapter.generate_unique_id @etag = UUID.generate unless @deleted @last_modified = Time.now.httpdate CloudKit.storage_adapter[@id] = { 'uri' => @uri.cannonical_uri_string, 'etag' => escape(@etag), 'last_modified' => @last_modified, 'json' => @json, 'deleted' => escape(@deleted), 'archived' => escape(@archived), 'remote_user' => escape(@remote_user), 'collection_reference' => @collection_reference ||= @uri.collection_uri_fragment, 'resource_reference' => @resource_reference ||= @uri.cannonical_uri_string }.merge(escape_values(parsed_json)) reload end |
#update(json, remote_user = nil) ⇒ Object
Update the json and optionally the remote_user for the current resource. Automatically archives the previous version, generating new ETag and Last-Modified dates. Raises HistoricalIntegrityViolation for attempts to modify resources that are not current.
50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/cloudkit/store/resource.rb', line 50 def update(json, remote_user=nil) raise HistoricalIntegrityViolation unless current? transaction do record = CloudKit.storage_adapter[@id] record['uri'] = "#{@uri.string}/versions/#{@etag}" record['archived'] = escape(true) CloudKit.storage_adapter[@id] = record self.class.create(@uri, json, remote_user || @remote_user) end reload end |
#versions ⇒ Object
Returns all versions of the given resource, reverse ordered by Last-Modified date, including the current version of the resource.
83 84 85 86 87 88 89 90 91 |
# File 'lib/cloudkit/store/resource.rb', line 83 def versions # TODO make this a collection proxy, only loading the first, then the # rest as needed during iteration (possibly in chunks) return nil if @archived @versions ||= [self].concat(CloudKit.storage_adapter.query { |q| q.add_condition('resource_reference', :eql, @resource_reference) q.add_condition('archived', :eql, 'true') }.reverse.map { |hash| self.class.build_from_hash(hash) }) end |