Class: DataMapper::Persevere::Adapter

Inherits:
Adapters::AbstractAdapter
  • Object
show all
Extended by:
Chainable, Deprecate
Defined in:
lib/persevere_adapter/adapter.rb

Constant Summary collapse

RESERVED_CLASSNAMES =
['User','Transaction','Capability','File','Class', 'Object', 'Versioned']

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#persevereObject

This should go away when we have more methods exposed to retrieve versioned data (and schemas)



41
42
43
# File 'lib/persevere_adapter/adapter.rb', line 41

def persevere
  @persevere
end

Instance Method Details

#create(resources) ⇒ Integer

Used by DataMapper to put records into a data-store: “INSERT” in SQL-speak. It takes an array of the resources (model instances) to be saved. Resources each have a key that can be used to quickly look them up later without searching, if the adapter supports it.

Parameters:

  • resources (Array<DataMapper::Resource>)

    The set of resources (model instances)

Returns:

  • (Integer)

    The number of records that were actually saved into the data-store



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/persevere_adapter/adapter.rb', line 58

def create(resources)
  connect if @persevere.nil?
  created = 0
  
  check_schemas
  
  resources.each do |resource|
    resource = Persevere.enhance(resource)
    serial = resource.model.serial(self.name)
    path = "/#{resource.model.storage_name}/"
    # Invoke to_json_hash with a boolean to indicate this is a create
    # We might want to make this a post-to_json_hash cleanup instead
    payload = resource.to_json_hash.delete_if{|key,value| value.nil? }
    DataMapper.logger.debug("(Create) PATH/PAYLOAD: #{path} #{payload.inspect}")
    response = @persevere.create(path, payload)

    # Check the response, this needs to be more robust and raise
    # exceptions when there's a problem
    if response.code == "201"# good:
      rsrc_hash = JSON.parse(response.body)
      # Typecast attributes, DM expects them properly cast
      resource.model.properties.each do |prop|
        value = rsrc_hash[prop.field.to_s]
        rsrc_hash[prop.field.to_s] = prop.typecast(value) unless value.nil?
        # Shift date/time objects to the correct timezone because persevere is UTC
        case prop 
          when DateTime then rsrc_hash[prop.field.to_s] = value.new_offset(Rational(Time.now.getlocal.gmt_offset/3600, 24))
          when Time then rsrc_hash[prop.field.to_s] = value.getlocal
        end
      end
      
      serial.set!(resource, rsrc_hash["id"]) unless serial.nil?

      created += 1
    else
      return false
    end
  end

  # Return the number of resources created in persevere.
  return created
end

#delete(query) ⇒ Integer

Destroys all the records matching the given query. “DELETE” in SQL.

Parameters:

  • query (DataMapper::Query)

    The query used to locate the resources to be deleted.

Returns:

  • (Integer)

    The number of records that were deleted.



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'lib/persevere_adapter/adapter.rb', line 225

def delete(query)

  connect if @persevere.nil?

  deleted = 0

  if ! query.is_a?(DataMapper::Query)
    resources = [query].flatten
  else
    resources = read_many(query)
  end

  resources.each do |resource|
    tblname = resource.model.storage_name
    id = resource.attributes(:field)['id']
    
    # Retrieve the ID from persever if the resource doesn't have an ID field
    if id.nil?
      query = Persevere.enhance(resource.query)
      path = "/#{tblname}/#{query.to_json_query_filter}[={'id':id}]"
      response = @persevere.retrieve(path, {})
      id = JSON.parse(response.body)[0]['id'].match(/(\w+\/)*(\d+)/)[2]
    end
    
    path = "/#{tblname}/#{id}"
    # path = "/#{tblname}/#{resource.key.first}"
    
    DataMapper.logger.debug("(Delete) PATH/QUERY: #{path}")

    result = @persevere.delete(path)

    if result.code == "204" # ok
      deleted += 1
    end
  end
  return deleted
end

#delete_schema(schema_hash, project = nil) ⇒ Object



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/persevere_adapter/adapter.rb', line 347

def delete_schema(schema_hash, project = nil)
  if ! project.nil?
    if schema_hash.has_key?("id")
      if ! schema_hash['id'].index(project)
        schema_hash['id'] = "#{project}/#{schema_hash['id']}"
      end
    else
      DataMapper.logger.error("You need an id key/value in the hash")
    end
  end
  
  path = "/Class/#{schema_hash['id']}"
  result = @persevere.delete(path)
  if result.code == "204"
    return true
  else
    return false
  end
end

#get_schema(name = nil, project = nil) ⇒ Object

Other methods for the Yogo Data Management Toolkit



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/persevere_adapter/adapter.rb', line 268

def get_schema(name = nil, project = nil)
  path = nil
  single = false
  
  if name.nil? & project.nil?
    path = "/Class/"
  elsif project.nil?
    path = "/Class/#{name}"
  elsif name.nil?
    path = "/Class/#{project}/"
  else
    path = "/Class/#{project}/#{name}"
  end
  result = @persevere.retrieve(path)
  if result.code == "200"
    schemas = [JSON.parse(result.body)].flatten.select{ |schema| not RESERVED_CLASSNAMES.include?(schema['id']) }
    schemas.each do |schema|
      if schema.has_key?('properties')
        schema['properties']['id'] = { 'type' => "serial", 'index' => true }
      end
    end

    return name.nil? ? schemas : schemas[0..0]
  else
    return false
  end
end

#put_schema(schema_hash, project = nil) ⇒ Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/persevere_adapter/adapter.rb', line 298

def put_schema(schema_hash, project = nil)
  path = "/Class/"
  if ! project.nil?
    if schema_hash.has_key?("id")
      if ! schema_hash['id'].index(project)
        schema_hash['id'] = "#{project}/#{schema_hash['id']}"
      end
    else
      DataMapper.logger.error("You need an id key/value in the hash")
    end
  end
  
  properties = schema_hash.delete('properties')
  schema_hash['extends'] = { "$ref" => "/Class/Versioned" } if @options[:versioned]
  schema_hash.delete_if{|key,value| value.nil? }
  result = @persevere.create(path, schema_hash)
  if result.code == '201'
    # return JSON.parse(result.body)
    schema_hash['properties'] = properties
    return update_schema(schema_hash)
  else
    return false
  end
end

#read(query) ⇒ DataMapper::Collection

Looks up a collection of records from the data-store: “SELECT” in SQL. Used by Model#all to search for a set of records; that set is in a DataMapper::Collection object.

Parameters:

  • query (DataMapper::Query)

    The query to be used to seach for the resources

Returns:

  • (DataMapper::Collection)

    A collection of all the resources found by the query.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/persevere_adapter/adapter.rb', line 159

def read(query)
  connect if @persevere.nil?
  query = Persevere.enhance(query)
  
  resources = Array.new
  tblname = query.model.storage_name
  
  json_query, headers = query.to_json_query
  
  path = "/#{tblname}/#{json_query}"
  DataMapper.logger.debug("--> PATH/QUERY/HEADERS: #{path} #{headers.inspect}")
  
  response = @persevere.retrieve(path, headers)
  
  if response.code.match(/20?/)
    results = JSON.parse(response.body)
    results.each do |rsrc_hash|
      # Typecast attributes, DM expects them properly cast
      query.fields.each do |prop|
        object_reference = false
        pname = prop.field.to_s

        value = rsrc_hash[pname]
        # Dereference references
        unless value.nil?
          if prop.field == 'id'
            rsrc_hash[pname]  = prop.typecast(value.to_s.match(/(#{tblname})?\/?([a-zA-Z0-9_-]+$)/)[2])
          else
            rsrc_hash[pname] = prop.typecast(value)
          end
        end
        # Shift date/time objects to the correct timezone because persevere is UTC
        case prop 
          when DateTime then rsrc_hash[pname] = value.new_offset(Rational(Time.now.getlocal.gmt_offset/3600, 24))
          when Time then rsrc_hash[pname] = value.getlocal
        end
      end
    end
    resources = query.model.load(results, query)
  end
  # We could almost elimate this if regexp was working in persevere.

  # This won't work if the RegExp is nested more then 1 layer deep.
  if query.conditions.class == DataMapper::Query::Conditions::AndOperation
    regexp_conds = query.conditions.operands.select do |obj| 
      obj.is_a?(DataMapper::Query::Conditions::RegexpComparison) || 
      ( obj.is_a?(DataMapper::Query::Conditions::NotOperation) && obj.operand.is_a?(DataMapper::Query::Conditions::RegexpComparison) )
    end
    regexp_conds.each{|cond| resources = resources.select{|resource| cond.matches?(resource)} }
   
  end

  # query.match_records(resources)
  resources
end

#update(attributes, query) ⇒ Integer

Used by DataMapper to update the attributes on existing records in a data-store: “UPDATE” in SQL-speak. It takes a hash of the attributes to update with, as well as a query object that specifies which resources should be updated.

Parameters:

  • attributes (Hash)

    A set of key-value pairs of the attributes to update the resources with.

  • query (DataMapper::Query)

    The query that should be used to find the resource(s) to update.

Returns:

  • (Integer)

    the number of records that were successfully updated



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/persevere_adapter/adapter.rb', line 118

def update(attributes, query)
  connect if @persevere.nil?
  updated = 0
  
  check_schemas
  
  if ! query.is_a?(DataMapper::Query)
    resources = [query].flatten
  else
    resources = read_many(query)
  end

  resources.each do |resource|
    resource = Persevere.enhance(resource)
    tblname = resource.model.storage_name
    path = "/#{tblname}/#{resource.key.first}"
    payload = resource.to_json_hash
    DataMapper.logger.debug("(Update) PATH/PAYLOAD: #{path} #{payload.inspect}")
    result = @persevere.update(path, payload)

    if result.code == "200"
      updated += 1
    else
      return false
    end
  end
  return updated
end

#update_schema(schema_hash, project = nil) ⇒ Object



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
# File 'lib/persevere_adapter/adapter.rb', line 325

def update_schema(schema_hash, project = nil)
  id = schema_hash['id']
  payload = schema_hash.reject{|key,value| key.to_sym.eql?(:id) }
  payload['extends'] = { "$ref" => "/Class/Versioned" } if @options[:versioned]

  if project.nil?
    path = "/Class/#{id}"
  else
    path =  "/Class/#{project}/#{id}"
  end

  result = @persevere.update(path, payload)

  if result.code == '200'
    return result.body
  else
    return false
  end
end