Class: DataMapper::Adapters::AppEngineAdapter

Inherits:
AbstractAdapter
  • Object
show all
Defined in:
lib/appengine_adapter.rb

Defined Under Namespace

Classes: QueryBuilder

Constant Summary collapse

Datastore =
AppEngine::Datastore

Instance Method Summary collapse

Constructor Details

#initialize(name, uri_or_options) ⇒ AppEngineAdapter

Returns a new instance of AppEngineAdapter.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/appengine_adapter.rb', line 37

def initialize(name, uri_or_options)
  super
  if uri_or_options.kind_of? Hash
    options = uri_or_options
    if options['host'] == 'memory'
      require 'appengine-apis/testing'
      AppEngine::Testing::install_test_datastore
    end
  end
  self.resource_naming_convention = lambda do |value|
    Extlib::Inflection.pluralize(Extlib::Inflection.camelize(value)).tap do |name|
      if name != value
        warn "Pluralized default storage name '#{name}' is deprecated on App Engine and will be changed! To use singular storage names, MIGRATE YOUR DATA FIRST, then run this sometime after the adapter is setup, but before your models load:"
        warn '  DataMapper.repository.adapter.singular_naming_convention!'
        warn "If you are on Rails, place that line somewhere after `require 'rails_dm_datastore'` in environment.rb."
      end
    end
  end
end

Instance Method Details

#convert_value(property, value) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/appengine_adapter.rb', line 144

def convert_value(property, value)
  value = property.dump(value)
  if property.kind_of?(Property::Text) && value
    AppEngine::Datastore::Text.new(value)
  elsif property.kind_of?(Property::Decimal) && value
    Lexidecimal.decimal_to_string(value)
  else
    case value
    when Date, DateTime
      Time.parse(value.to_s)
    when Class
      value.name
    else
      value
    end
  end
end

#create(resources) ⇒ Object



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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/appengine_adapter.rb', line 67

def create(resources)
  created = 0
  entities = []
  resources.each do |resource|
    repository = resource.repository
    model = resource.model
    attributes = resource.attributes
    properties = model.properties(repository.name)
    
    kind = self.kind(model)
    keys = properties.key
    raise "Multiple keys in #{resource.inspect}" if keys.size > 1
    if keys.size == 1
      name = keys.first.name
      property = properties[name]
      key = convert_value(property, attributes.delete(name))
    end
    if keys.first.serial? && (key.nil? || key == 0)
      entity = Datastore::Entity.new(kind)
    elsif key.kind_of?(AppEngine::Datastore::Key)
      entity = Datastore::Entity.new(key)
    elsif key.kind_of?(Hash) && property.kind_of?(Property::Key)
      # AppEngine::Datastore::Key should already have filtered this.
      # Since it didn't, we know it's a serial object with a parent.
      entity = Datastore::Entity.new(kind, key[:parent])
    else
      entity = Datastore::Entity.new(kind, key)
    end
    
    attributes.each do |name, value|
      property = properties[name]
      value = convert_value(property, value)
      entity.set_property(property.field, value)
    end
    entities << entity
    created += 1
  end
  Datastore.put(entities)
  resources.zip(entities) do |resource, entity|
    key = entity.key
    if id = resource.model.key(name).find{|k|k.kind_of? Property::Key}
      id.set!(resource, key)
    elsif id = resource.model.serial(name)
      # Order matters. Only sets to numeric id if it's a serial non-key.
      id.set!(resource, key.get_id)
    end
    resource.instance_variable_set(:@__entity__, entity)
    
    # TODO: We shouldn't be messing with keys like this.
    # On the other hand, should keys be assuming they don't change?
    # How does serial even work when dealing with true autoincrements?
    # I guess it's just not valid?
    if resource.instance_variable_defined?(:@_key)
      resource.send(:remove_instance_variable, :@_key)
    end
  end
  return created
end

#delete(collection) ⇒ Object



162
163
164
165
166
167
168
# File 'lib/appengine_adapter.rb', line 162

def delete(collection)
  keys = collection.collect do |resource|
    entity = resource.instance_variable_get :@__entity__
    entity.key
  end
  Datastore.delete(keys)
end

#kind(model) ⇒ Object



63
64
65
# File 'lib/appengine_adapter.rb', line 63

def kind(model)
  model.storage_name(name)
end

#read(query) ⇒ Object



126
127
128
129
# File 'lib/appengine_adapter.rb', line 126

def read(query)
  query = QueryBuilder.new(query, kind(query.model), self)
  query.run
end

#singular_naming_convention!Object



57
58
59
60
61
# File 'lib/appengine_adapter.rb', line 57

def singular_naming_convention!
  self.resource_naming_convention = lambda do |value|
    value
  end
end

#update(attributes, collection) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/appengine_adapter.rb', line 131

def update(attributes, collection)
  attributes = attributes.map do |property, value|
    [property.field, convert_value(property, value)]
  end
  entities = collection.collect do |resource|
    entity = resource.instance_variable_get :@__entity__
    entity.update(attributes)
  end

  Datastore.put(entities)
  entities.size
end