dm-appengine 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ require 'date'
5
5
  require 'spec/rake/spectask'
6
6
 
7
7
  GEM = "dm-appengine"
8
- GEM_VERSION = "0.0.2"
8
+ GEM_VERSION = "0.0.3"
9
9
  AUTHOR = "Ryan Brown"
10
10
  EMAIL = "ribrdb@gmail.com"
11
11
  HOMEPAGE = "http://code.google.com/p/appengine-jruby"
@@ -28,7 +28,8 @@ spec = Gem::Specification.new do |s|
28
28
 
29
29
  s.require_path = 'lib'
30
30
  s.autorequire = GEM
31
- s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{lib,spec}/**/*")
31
+ s.files = %w(LICENSE README.rdoc Rakefile lib/appengine_adapter.rb) +
32
+ Dir.glob("spec/**/*")
32
33
  end
33
34
 
34
35
  task :default => :spec
@@ -21,8 +21,6 @@ require 'date'
21
21
  require 'rubygems'
22
22
  require 'time'
23
23
 
24
- gem 'appengine-apis', '~> 0.0.6'
25
-
26
24
  require 'appengine-apis/datastore'
27
25
  require 'dm-core'
28
26
 
@@ -359,13 +357,13 @@ module DataMapper
359
357
  # TODO: This is broken. We should be setting all properties
360
358
  return if entity.nil?
361
359
  key = entity.get_key
362
- hash = entity.to_hash
360
+ hash = {}
363
361
  @dm_query.fields.each do |property|
364
362
  name = property.field
365
363
  if property.key?
366
364
  hash[name] = key.get_name || key.get_id
367
365
  else
368
- hash[name] = property.typecast(hash[name])
366
+ hash[name] = property.typecast(entity.get_property(name))
369
367
  end
370
368
  end
371
369
  hash
@@ -19,7 +19,9 @@ $TESTING=true
19
19
  $:.push File.join(File.dirname(__FILE__), '..', 'lib')
20
20
 
21
21
  require 'rubygems'
22
- require 'dm-appengine'
22
+ require 'appengine-sdk'
23
+ AppEngine::SDK.load_apiproxy
24
+ require 'dm-core'
23
25
 
24
26
  ADAPTERS = ['default']
25
27
  PRIMARY = {'default' => "appengine://memory"}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-appengine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Brown
@@ -9,7 +9,7 @@ autorequire: dm-appengine
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-27 00:00:00 -07:00
12
+ date: 2009-08-14 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -46,9 +46,6 @@ files:
46
46
  - README.rdoc
47
47
  - Rakefile
48
48
  - lib/appengine_adapter.rb
49
- - lib/dm-appengine/appengine_resource.rb
50
- - lib/dm-appengine/transactions.rb
51
- - lib/dm-appengine.rb-custom_resource
52
49
  - spec/dm-appengine_spec.rb
53
50
  - spec/spec_helper.rb
54
51
  has_rdoc: true
@@ -1,365 +0,0 @@
1
- #!/usr/bin/ruby1.8 -w
2
- #
3
- # Copyright:: Copyright 2009 Google Inc.
4
- # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- # Datamapper adapter for Google App Engine
19
-
20
- $:.unshift(File.dirname(__FILE__)) unless
21
- $:.include?(File.dirname(__FILE__)) ||
22
- $:.include?(File.expand_path(File.dirname(__FILE__)))
23
-
24
- require 'rubygems'
25
- gem 'appengine-apis', '~> 0.0.3'
26
-
27
- require 'appengine-apis/datastore'
28
- require 'dm-core'
29
- require 'dm-appengine/appengine_resource'
30
-
31
- module DataMapper
32
- module Adapters
33
- class AppEngineAdapter < AbstractAdapter
34
- Datastore = AppEngine::Datastore
35
-
36
- def initialize(name, uri_or_options)
37
- super
38
- if uri_or_options.kind_of? Hash
39
- options = uri_or_options
40
- if options['host'] == 'memory'
41
- require 'appengine-apis/testing'
42
- begin
43
- AppEngine::ApiProxy.get_app_id
44
- rescue NoMethodError
45
- AppEngine::Testing::install_test_env
46
- end
47
- AppEngine::Testing::install_test_datastore
48
- end
49
- end
50
- @resource_naming_convention = lambda do |value|
51
- Extlib::Inflection.pluralize(Extlib::Inflection.camelize(value))
52
- end
53
- end
54
-
55
- def kind(model)
56
- model.storage_name(name)
57
- end
58
-
59
- def create(resources)
60
- created = 0
61
- entities = []
62
- resources.each do |resource|
63
- attributes = resource.attributes
64
-
65
- entity = create_entity(resource)
66
-
67
- attributes.each do |name, value|
68
- unless name =~ /^__.+__$/
69
- entity.set_property(name.to_s, value)
70
- end
71
- end
72
- entities << entity
73
- created += 1
74
- end
75
- Datastore.put(entities)
76
- resources.zip(entities) do |resource, entity|
77
- key = entity.key
78
- if identity_field = resource.model.identity_field(name)
79
- identity_field.set!(resource, key.get_name || key.get_id)
80
- end
81
- resource.instance_variable_set :@__entity__, entity
82
- end
83
- return created
84
- end
85
-
86
- def read(query)
87
- query = QueryBuilder.new(query, kind(query.model), self)
88
- query.run
89
- end
90
-
91
- def update(attributes, collection)
92
- attributes = attributes_as_fields(attributes)
93
- entities = collection.collect do |resource|
94
- entity = resource.instance_variable_get :@__entity__
95
- entity.update(attributes)
96
- end
97
-
98
- Datastore.put(entities)
99
- entities.size
100
- end
101
-
102
- def delete(collection)
103
- keys = collection.collect do |resource|
104
- entity = resource.instance_variable_get :@__entity__
105
- entity.key
106
- end
107
- Datastore.delete(keys)
108
- end
109
-
110
- private
111
-
112
- def create_entity(resource)
113
- kind = self.kind(resource.model)
114
- parent, name = resource.appengine_key_components(resource.repository)
115
- if name.kind_of? Integer
116
- if name == 0
117
- name = nil
118
- else
119
- raise ArgumentError, 'Numeric ids must be assigned by the Datastore'
120
- end
121
- end
122
- if name
123
- Datastore::Entity.new(kind, name, parent)
124
- elsif parent
125
- Datastore::Entity.new(kind, parent)
126
- else
127
- Datastore::Entity.new(kind)
128
- end
129
- end
130
-
131
- class QueryBuilder
132
- import Datastore::JavaDatastore::FetchOptions
133
- include Datastore::Query::Constants
134
- @@OPERATORS = {
135
- Conditions::EqualToComparison => EQUAL,
136
- Conditions::GreaterThanComparison => GREATER_THAN,
137
- Conditions::GreaterThanOrEqualToComparison => GREATER_THAN_OR_EQUAL,
138
- Conditions::LessThanComparison => LESS_THAN,
139
- Conditions::LessThanOrEqualToComparison => LESS_THAN_OR_EQUAL,
140
- }.freeze
141
-
142
- def initialize(query, kind, adapter)
143
- @model = query.model
144
- @kind = kind
145
- @limit = query.limit
146
- @offset = query.offset
147
- @maybe_get = true
148
- @must_be_get = false
149
- @keys = []
150
- @dm_query = query
151
- @adapter_name = adapter.name
152
-
153
- @query = Datastore::Query.new(kind)
154
- parse_order(query.order)
155
- parse_conditions(query.conditions)
156
- raise NotImplementedError if @must_be_get && !@maybe_get
157
- end
158
-
159
- def property_name(property, qualify=false)
160
- if qualify
161
- table_name = property.model.storage_name(name)
162
- "#{table_name}.#{property.field}"
163
- else
164
- property.field
165
- end
166
- end
167
-
168
- def parse_order(order)
169
- if order.size == 1 && order[0].direction != :desc
170
- if order[0].property.key?
171
- # omit the default key ordering.
172
- # This lets inequality filters work
173
- return
174
- end
175
- end
176
- order.map do |order|
177
- if order.direction == :desc
178
- direction = DESCENDING
179
- else
180
- direction = ASCENDING
181
- end
182
- name = if order.property.key?
183
- '__key__'
184
- else
185
- property_name(order.property)
186
- end
187
- @query.sort(name, direction)
188
- end
189
- end
190
-
191
- def parse_conditions(conditions)
192
- case conditions
193
- when Conditions::NotOperation then
194
- raise NotImplementedError, "NOT operator is not supported"
195
- when Conditions::AbstractComparison then
196
- parse_comparison(conditions)
197
- when Conditions::OrOperation then
198
- parse_or(conditions)
199
- when Conditions::AndOperation then
200
- parse_and(conditions)
201
- else
202
- raise ArgumentError, "invalid conditions #{conditions.class}: #{conditions.inspect}"
203
- end
204
- end
205
-
206
- def parse_key(property, value)
207
- unless property.key?
208
- raise ArgumentError, "#{property_name(property, true)} is not the key"
209
- end
210
- case value
211
- when Integer, String
212
- Datastore::Key.from_path(@kind, value)
213
- when Symbol
214
- Datastore::Key.from_path(@kind, value.to_s)
215
- else
216
- raise ArgumentError "Unsupported key value #{value.inspect} (a #{value.class})"
217
- end
218
- end
219
-
220
- def parse_or(or_op)
221
- if !@maybe_get
222
- raise NotImplementedError, "OR only supported with key equality comparisons"
223
- end
224
- @must_be_get = true
225
- or_op.operands.each do |op|
226
- case op
227
- when Conditions::OrOperation then
228
- parse_or(op)
229
- when Conditions::EqualToComparison then
230
- key = parse_key(op.property, op.value)
231
- @keys << key
232
- when Conditions::InclusionComparison then
233
- parse_key_inclusion(op)
234
- else
235
- raise NotImplementedError, "Unsupported condition #{op.class} inside OR"
236
- end
237
- end
238
- end
239
-
240
- def parse_key_inclusion(op)
241
- raise NotImplementedError unless op.value.kind_of? Array
242
- op.value.each do |value|
243
- @keys << parse_key(op.property, value)
244
- end
245
- end
246
-
247
- def parse_and(op)
248
- if @maybe_get && (@found_and || op.operands.size > 1)
249
- @maybe_get = false
250
- end
251
- @found_and = true
252
- op.operands.each do |conditions|
253
- parse_conditions(conditions)
254
- end
255
- end
256
-
257
- def parse_comparison(op)
258
- property = op.property
259
- value = op.value
260
- if @maybe_get
261
- if property.key?
262
- case op
263
- when Conditions::EqualToComparison
264
- @keys << parse_key(property, value)
265
- when Conditions::InclusionComparison
266
- parse_key_inclusion(op)
267
- @must_be_get = true
268
- return
269
- else
270
- @maybe_get = false
271
- end
272
- elsif ['__ancestor__', '__parent__'].include? property.field
273
- if value.java_kind_of? AppEngine::Datastore::Key
274
- query.ancestor = value
275
- else
276
- query.ancestor = value.entity.key
277
- end
278
- return
279
- else
280
- @maybe_get = false
281
- end
282
- end
283
-
284
- if op.kind_of? Conditions::InclusionComparison
285
- parse_range(op)
286
- else
287
- filter_op = @@OPERATORS[op.class]
288
- if filter_op.nil?
289
- raise ArgumentError, "#{op.class} is not a supported comparison"
290
- end
291
- @query.filter(property_name(op.property), filter_op, op.value)
292
- end
293
- end
294
-
295
- def parse_range(op)
296
- range = op.value
297
- raise NotImplementedError unless range.is_a? Range
298
- name = property_name(op.property)
299
- begin_op = GREATER_THAN_OR_EQUAL
300
- end_op = if range.exclude_end?
301
- LESS_THAN
302
- else
303
- LESS_THAN_OR_EQUAL
304
- end
305
- @query.filter(name, begin_op, range.begin)
306
- @query.filter(name, end_op, range.end)
307
- end
308
-
309
- def is_get?
310
- @maybe_get && @keys.size > 0
311
- end
312
-
313
- def get_entities
314
- if is_get?
315
- Datastore.get(@keys)
316
- else
317
- begin
318
- chunk_size = FetchOptions::DEFAULT_CHUNK_SIZE
319
- options = FetchOptions::Builder.with_chunk_size(
320
- chunk_size)
321
- options.limit(@limit) if @limit
322
- options.offset(@offset) if @offset
323
- @query.iterator(options).collect {|e| e}
324
- rescue java.lang.IllegalArgumentException => ex
325
- raise ArgumentError, ex.message
326
- end
327
- end
328
- end
329
-
330
- def run
331
- key_prop = @model.key(@adapter_name)[0].field
332
- get_entities.map do |entity|
333
- entity_to_model(key_prop, entity)
334
- end
335
- end
336
-
337
- def entity_to_model(key_prop, entity)
338
- # TODO: This is broken. We should be setting all properties
339
- return if entity.nil?
340
- props = entity.to_hash
341
- props['__entity__'] = entity
342
- props['__parent__'] = entity.key.parent
343
-
344
- key = entity.get_key
345
- id_or_name = key.get_name || key.get_id
346
-
347
- @dm_query.fields.map do |property|
348
- if property.key? && property.type == id_or_name.class
349
- props[property.field] = id_or_name
350
- break
351
- end
352
- end
353
- props
354
- end
355
-
356
- def keys
357
- @keys
358
- end
359
- end
360
- end
361
-
362
- # required naming scheme
363
- AppengineAdapter = AppEngineAdapter
364
- end
365
- end
@@ -1,34 +0,0 @@
1
- #!/usr/bin/ruby1.8 -w
2
- #
3
- # Copyright:: Copyright 2009 Google Inc.
4
- # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- # Custom Resource class for App Engine. Adds optimistic transaction support.
19
-
20
- module DataMapper
21
- module AppEngineResource
22
-
23
- def self.included(mod)
24
- mod.class_eval do
25
- include DataMapper::Resource
26
-
27
- def transaction(retries=3, &block)
28
- AppEngine::Datastore.transaction(retries, &block)
29
- end
30
- end
31
- end
32
-
33
- end
34
- end
@@ -1,26 +0,0 @@
1
- #!/usr/bin/ruby1.8 -w
2
- #
3
- # Copyright:: Copyright 2009 Google Inc.
4
- # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
- # Datamapper adapter for Google App Engine
19
-
20
- require 'appengine-apis/datastore'
21
-
22
- module AppEngine::Datastore
23
- class DMTransaction
24
-
25
- end
26
- end