dm-appengine 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -5
- data/lib/appengine_adapter.rb +48 -9
- data/lib/dm-appengine/types.rb +73 -6
- data/spec/dm-appengine_spec.rb +83 -1
- data/spec/spec_helper.rb +2 -1
- metadata +5 -25
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.
|
8
|
+
GEM_VERSION = "0.0.6"
|
9
9
|
AUTHOR = "Ryan Brown"
|
10
10
|
EMAIL = "ribrdb@gmail.com"
|
11
11
|
HOMEPAGE = "http://code.google.com/p/appengine-jruby"
|
@@ -23,10 +23,8 @@ spec = Gem::Specification.new do |s|
|
|
23
23
|
s.email = EMAIL
|
24
24
|
s.homepage = HOMEPAGE
|
25
25
|
|
26
|
-
s.add_dependency("appengine-apis", ["~> 0.0.
|
27
|
-
s.add_dependency("dm-core", ["
|
28
|
-
s.add_dependency("addressable")
|
29
|
-
s.add_dependency("extlib")
|
26
|
+
s.add_dependency("appengine-apis", ["~> 0.0.12"])
|
27
|
+
s.add_dependency("dm-core", ["0.10.2"])
|
30
28
|
|
31
29
|
s.require_path = 'lib'
|
32
30
|
s.autorequire = GEM
|
data/lib/appengine_adapter.rb
CHANGED
@@ -150,6 +150,14 @@ module DataMapper
|
|
150
150
|
LessThanComparison => LESS_THAN,
|
151
151
|
LessThanOrEqualToComparison => LESS_THAN_OR_EQUAL,
|
152
152
|
}.freeze
|
153
|
+
|
154
|
+
@@NEGATED_OPERATORS = {
|
155
|
+
EqualToComparison => NOT_EQUAL,
|
156
|
+
GreaterThanComparison => LESS_THAN_OR_EQUAL,
|
157
|
+
GreaterThanOrEqualToComparison => LESS_THAN,
|
158
|
+
LessThanComparison => GREATER_THAN_OR_EQUAL,
|
159
|
+
LessThanOrEqualToComparison => GREATER_THAN,
|
160
|
+
}.freeze
|
153
161
|
|
154
162
|
def initialize(query, kind, adapter)
|
155
163
|
@model = query.model
|
@@ -212,7 +220,13 @@ module DataMapper
|
|
212
220
|
when NullOperation then
|
213
221
|
return
|
214
222
|
when NotOperation then
|
215
|
-
|
223
|
+
if OrOperation === conditions.operand
|
224
|
+
parse_and(conditions.operand)
|
225
|
+
elsif AbstractComparison === conditions.operand
|
226
|
+
parse_comparison(conditions.operand)
|
227
|
+
else
|
228
|
+
raise NotImplementedError, "NOT operator is not supported with #{conditions.operand.class.name}"
|
229
|
+
end
|
216
230
|
when AbstractComparison then
|
217
231
|
parse_comparison(conditions)
|
218
232
|
when OrOperation then
|
@@ -226,7 +240,7 @@ module DataMapper
|
|
226
240
|
|
227
241
|
def parse_key(property, value)
|
228
242
|
unless property.key?
|
229
|
-
raise ArgumentError, "#{property_name(property
|
243
|
+
raise ArgumentError, "#{property_name(property)} is not the key"
|
230
244
|
end
|
231
245
|
case value
|
232
246
|
when Integer, String
|
@@ -234,7 +248,7 @@ module DataMapper
|
|
234
248
|
when Symbol
|
235
249
|
Datastore::Key.from_path(@kind, value.to_s)
|
236
250
|
else
|
237
|
-
raise ArgumentError "Unsupported key value #{value.inspect} (a #{value.class})"
|
251
|
+
raise ArgumentError, "Unsupported key value #{value.inspect} (a #{value.class})"
|
238
252
|
end
|
239
253
|
end
|
240
254
|
|
@@ -276,13 +290,17 @@ module DataMapper
|
|
276
290
|
end
|
277
291
|
|
278
292
|
def parse_comparison(op)
|
279
|
-
if op.
|
280
|
-
return
|
293
|
+
if op.respond_to?(:relationship?) && op.relationship?
|
294
|
+
return parse_conditions(op.foreign_key_mapping)
|
295
|
+
elsif (respond_to?(:foreign_key_conditions) &&
|
296
|
+
op.subject.kind_of?(Associations::Relationship))
|
297
|
+
return parse_conditions(foreign_key_conditions(op))
|
281
298
|
end
|
282
299
|
property = op.subject
|
283
300
|
value = op.value
|
301
|
+
negated = op.negated?
|
284
302
|
if @maybe_get
|
285
|
-
if property.key?
|
303
|
+
if property.key? && !negated
|
286
304
|
case op
|
287
305
|
when EqualToComparison
|
288
306
|
@keys << parse_key(property, value)
|
@@ -298,10 +316,14 @@ module DataMapper
|
|
298
316
|
end
|
299
317
|
end
|
300
318
|
|
301
|
-
if op.kind_of?
|
302
|
-
|
319
|
+
if op.kind_of?(InclusionComparison)
|
320
|
+
parse_inclusion(op)
|
303
321
|
else
|
304
|
-
|
322
|
+
if negated
|
323
|
+
filter_op = @@NEGATED_OPERATORS[op.class]
|
324
|
+
else
|
325
|
+
filter_op = @@OPERATORS[op.class]
|
326
|
+
end
|
305
327
|
if filter_op.nil?
|
306
328
|
raise ArgumentError, "#{op.class} is not a supported comparison"
|
307
329
|
end
|
@@ -311,9 +333,26 @@ module DataMapper
|
|
311
333
|
end
|
312
334
|
end
|
313
335
|
|
336
|
+
def parse_inclusion(op)
|
337
|
+
if Range === op.value
|
338
|
+
parse_range(op)
|
339
|
+
else
|
340
|
+
name = property_name(op.subject)
|
341
|
+
values = op.value.map {|x| property_value(op.subject, x)}
|
342
|
+
if op.negated?
|
343
|
+
values.each do |value|
|
344
|
+
@query.filter(name, NOT_EQUAL, value)
|
345
|
+
end
|
346
|
+
else
|
347
|
+
@query.filter(name, IN, java.util.ArrayList.new(values))
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
314
352
|
def parse_range(op)
|
315
353
|
range = op.value
|
316
354
|
raise NotImplementedError unless range.is_a? Range
|
355
|
+
raise NotImplementedError if op.negated?
|
317
356
|
name = property_name(op.subject)
|
318
357
|
begin_op = GREATER_THAN_OR_EQUAL
|
319
358
|
end_op = if range.exclude_end?
|
data/lib/dm-appengine/types.rb
CHANGED
@@ -17,7 +17,7 @@
|
|
17
17
|
#
|
18
18
|
# Custom types for App Engine
|
19
19
|
|
20
|
-
require 'dm-core/type'
|
20
|
+
require 'dm-core/type' unless defined? DataMapper::Type::PROPERTY_OPTIONS
|
21
21
|
|
22
22
|
module DataMapper
|
23
23
|
module Types
|
@@ -37,17 +37,84 @@ module DataMapper
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
class
|
40
|
+
class AppEngineStringType < Type
|
41
|
+
def self.dump(value, property)
|
42
|
+
self::DATASTORE_TYPE.new(value) if value
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.load(value, property)
|
46
|
+
value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class AppEngineNativeType < Type
|
51
|
+
primitive ::Object
|
52
|
+
|
53
|
+
def self.dump(value, property)
|
54
|
+
value
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.load(value, property)
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Blob < AppEngineStringType
|
41
63
|
primitive String
|
64
|
+
DATASTORE_TYPE = AppEngine::Datastore::Blob
|
42
65
|
size 1024 * 1024
|
43
|
-
|
66
|
+
end
|
67
|
+
|
68
|
+
class ByteString < AppEngineStringType
|
69
|
+
primitive String
|
70
|
+
DATASTORE_TYPE = AppEngine::Datastore::ByteString
|
71
|
+
size 500
|
72
|
+
end
|
73
|
+
|
74
|
+
class Link < AppEngineStringType
|
75
|
+
primitive String
|
76
|
+
DATASTORE_TYPE = AppEngine::Datastore::Link
|
77
|
+
size 2038
|
78
|
+
end
|
79
|
+
|
80
|
+
class Email < AppEngineStringType
|
81
|
+
primitive String
|
82
|
+
DATASTORE_TYPE = AppEngine::Datastore::Email
|
83
|
+
size 500
|
84
|
+
end
|
85
|
+
|
86
|
+
class Category < AppEngineStringType
|
87
|
+
primitive String
|
88
|
+
DATASTORE_TYPE = AppEngine::Datastore::Category
|
89
|
+
size 500
|
90
|
+
end
|
91
|
+
|
92
|
+
class PhoneNumber < AppEngineStringType
|
93
|
+
primitive String
|
94
|
+
DATASTORE_TYPE = AppEngine::Datastore::PhoneNumber
|
95
|
+
size 500
|
96
|
+
end
|
97
|
+
|
98
|
+
class PostalAddress < AppEngineStringType
|
99
|
+
primitive String
|
100
|
+
DATASTORE_TYPE = AppEngine::Datastore::PostalAddress
|
101
|
+
size 500
|
102
|
+
end
|
103
|
+
|
104
|
+
class Rating < Type
|
105
|
+
primitive ::Object
|
106
|
+
|
44
107
|
def self.dump(value, property)
|
45
|
-
AppEngine::Datastore::
|
108
|
+
AppEngine::Datastore::Rating.new(value) if value
|
46
109
|
end
|
47
110
|
|
48
111
|
def self.load(value, property)
|
49
|
-
value
|
112
|
+
value.rating if value
|
50
113
|
end
|
51
114
|
end
|
115
|
+
|
116
|
+
IMHandle = GeoPt = Key = User = AppEngineNativeType
|
117
|
+
|
118
|
+
# TODO store user as email and id?
|
52
119
|
end
|
53
|
-
end
|
120
|
+
end
|
data/spec/dm-appengine_spec.rb
CHANGED
@@ -35,9 +35,18 @@ class TypeTest
|
|
35
35
|
property :bigd, BigDecimal
|
36
36
|
property :flower, Object
|
37
37
|
property :klass, Class
|
38
|
-
$stderr.puts "list: #{List.primitive.ancestors})"
|
39
38
|
property :list, List
|
40
39
|
property :blob, Blob
|
40
|
+
property :bstring, ByteString
|
41
|
+
property :link, Link
|
42
|
+
property :email, Email
|
43
|
+
property :category, Category
|
44
|
+
property :phone, PhoneNumber
|
45
|
+
property :address, PostalAddress
|
46
|
+
property :rating, Rating
|
47
|
+
property :im, IMHandle
|
48
|
+
property :point, GeoPt
|
49
|
+
property :user, User
|
41
50
|
end
|
42
51
|
|
43
52
|
class Flower
|
@@ -180,5 +189,78 @@ describe DataMapper::Adapters::AppEngineAdapter do
|
|
180
189
|
a.reload
|
181
190
|
a.blob.should == '\0'
|
182
191
|
end
|
192
|
+
|
193
|
+
it 'should support ByteString' do
|
194
|
+
a = TypeTest.new(:name => 'bstring', :bstring => '\0')
|
195
|
+
a.save
|
196
|
+
a.reload
|
197
|
+
a.bstring.should == '\0'
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should support Link' do
|
201
|
+
link = "http://example.com/" + "0" * 1000
|
202
|
+
a = TypeTest.new(:name => 'link', :link => link)
|
203
|
+
a.save
|
204
|
+
a.reload
|
205
|
+
a.link.should == link
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should support Email' do
|
209
|
+
a = TypeTest.new(:name => 'email', :email => 'ribrdb@example.com')
|
210
|
+
a.save
|
211
|
+
a.reload
|
212
|
+
a.email.should == 'ribrdb@example.com'
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should support Category' do
|
216
|
+
a = TypeTest.new(:name => 'category', :category => 'tests')
|
217
|
+
a.save
|
218
|
+
a.reload
|
219
|
+
a.category.should == 'tests'
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should support PhoneNumbers" do
|
223
|
+
number = '555-1212'
|
224
|
+
a = TypeTest.new(:name => 'phone', :phone => number)
|
225
|
+
a.save
|
226
|
+
a.reload
|
227
|
+
a.phone.should == number
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should support PostalAddress" do
|
231
|
+
address = '345 Spear St'
|
232
|
+
a = TypeTest.new(:name => 'address', :address => address)
|
233
|
+
a.save
|
234
|
+
a.reload
|
235
|
+
a.address.should == address
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should support Rating" do
|
239
|
+
rating = 34
|
240
|
+
a = TypeTest.new(:name => 'rating', :rating => rating)
|
241
|
+
a.save
|
242
|
+
a.reload
|
243
|
+
a.rating.should == 34
|
244
|
+
end
|
245
|
+
|
246
|
+
it "should support IMHandle" do
|
247
|
+
im = AppEngine::Datastore::IMHandle.new(:xmpp, 'batman@google.com')
|
248
|
+
a = TypeTest.new(:name => 'im', :im => im)
|
249
|
+
a.save
|
250
|
+
a.reload
|
251
|
+
a.im.should == im
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should support GeoPt" do
|
255
|
+
latitude = 32.4
|
256
|
+
longitude = 72.2
|
257
|
+
point = AppEngine::Datastore::GeoPt.new(latitude, longitude)
|
258
|
+
a = TypeTest.new(:name => 'point', :point => point)
|
259
|
+
a.save
|
260
|
+
a.reload
|
261
|
+
a.point.should == point
|
262
|
+
a.point.latitude.should be_close(latitude, 0.1)
|
263
|
+
a.point.longitude.should be_close(longitude, 0.1)
|
264
|
+
end
|
183
265
|
end
|
184
266
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,10 +21,11 @@ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
|
|
21
21
|
require 'rubygems'
|
22
22
|
require 'appengine-sdk'
|
23
23
|
AppEngine::SDK.load_apiproxy
|
24
|
+
AppEngine::SDK.load_labs
|
24
25
|
require 'dm-core'
|
25
26
|
|
26
27
|
ADAPTERS = ['default']
|
27
28
|
PRIMARY = {'default' => "appengine://memory"}
|
28
29
|
|
29
30
|
DataMapper::Logger.new(STDERR, :debug)
|
30
|
-
DataMapper.setup(:default, 'appengine://memory')
|
31
|
+
DataMapper.setup(: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.
|
4
|
+
version: 0.0.6
|
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-
|
12
|
+
date: 2009-12-21 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.
|
23
|
+
version: 0.0.12
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: dm-core
|
@@ -28,29 +28,9 @@ dependencies:
|
|
28
28
|
version_requirement:
|
29
29
|
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.10.0
|
34
|
-
version:
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: addressable
|
37
|
-
type: :runtime
|
38
|
-
version_requirement:
|
39
|
-
version_requirements: !ruby/object:Gem::Requirement
|
40
|
-
requirements:
|
41
|
-
- - ">="
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: "0"
|
44
|
-
version:
|
45
|
-
- !ruby/object:Gem::Dependency
|
46
|
-
name: extlib
|
47
|
-
type: :runtime
|
48
|
-
version_requirement:
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - ">="
|
31
|
+
- - "="
|
52
32
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
33
|
+
version: 0.10.2
|
54
34
|
version:
|
55
35
|
description: A DataMapper adapter for Google App Engine
|
56
36
|
email: ribrdb@gmail.com
|