dm-appengine 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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