dm-appengine 0.0.5 → 0.0.6

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.5"
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.3"])
27
- s.add_dependency("dm-core", ["~> 0.10.0"])
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
@@ -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
- raise NotImplementedError, "NOT operator is not supported"
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, true)} is not the key"
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.subject.kind_of?(Associations::Relationship)
280
- return foreign_key_conditions(op)
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? InclusionComparison
302
- parse_range(op)
319
+ if op.kind_of?(InclusionComparison)
320
+ parse_inclusion(op)
303
321
  else
304
- filter_op = @@OPERATORS[op.class]
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?
@@ -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 Blob < Type
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::Blob.new(value) if value
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
@@ -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.5
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-10-05 00:00:00 -07:00
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.3
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: "0"
33
+ version: 0.10.2
54
34
  version:
55
35
  description: A DataMapper adapter for Google App Engine
56
36
  email: ribrdb@gmail.com