dm-appengine 0.0.9 → 0.1.0

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.9"
8
+ GEM_VERSION = "0.1.0"
9
9
  HOMEPAGE = "http://code.google.com/p/appengine-jruby"
10
10
  SUMMARY = "A DataMapper adapter for Google App Engine"
11
11
 
@@ -21,8 +21,9 @@ spec = Gem::Specification.new do |s|
21
21
  s.email = ["ribrdb@google.com", "ninja@slaphack.com"]
22
22
  s.homepage = HOMEPAGE
23
23
 
24
- s.add_dependency("appengine-apis", ["~> 0.0.14"])
25
- s.add_dependency("dm-core", ["0.10.2"])
24
+ s.add_dependency("appengine-apis", ["~> 0.0.17"])
25
+ s.add_dependency("dm-core", ["~> 1.0"])
26
+ s.add_dependency("lexidecimal", ["~> 0.0"])
26
27
 
27
28
  s.require_path = 'lib'
28
29
  s.autorequire = GEM
@@ -21,10 +21,11 @@ autoload :Date, 'date'
21
21
  autoload :DateTime, 'date'
22
22
  require 'rubygems'
23
23
  require 'time'
24
+ require 'lexidecimal'
24
25
 
25
26
  require 'appengine-apis/datastore'
26
27
  require 'dm-core'
27
- require 'dm-appengine/types'
28
+ require 'dm-appengine/properties'
28
29
 
29
30
  module DataMapper
30
31
  autoload(:AppEngineResource, 'dm-appengine/appengine_resource')
@@ -68,11 +69,11 @@ module DataMapper
68
69
  property = properties[name]
69
70
  key = convert_value(property, attributes.delete(name))
70
71
  end
71
- if key.nil? || keys.first.serial? || key==0
72
+ if keys.first.serial? && (key.nil? || key == 0)
72
73
  entity = Datastore::Entity.new(kind)
73
74
  elsif key.kind_of?(AppEngine::Datastore::Key)
74
75
  entity = Datastore::Entity.new(key)
75
- elsif key.kind_of?(Hash) && property.type == Types::Key
76
+ elsif key.kind_of?(Hash) && property.kind_of?(Property::Key)
76
77
  # AppEngine::Datastore::Key should already have filtered this.
77
78
  # Since it didn't, we know it's a serial object with a parent.
78
79
  entity = Datastore::Entity.new(kind, key[:parent])
@@ -91,12 +92,21 @@ module DataMapper
91
92
  Datastore.put(entities)
92
93
  resources.zip(entities) do |resource, entity|
93
94
  key = entity.key
94
- if id = resource.model.serial(name)
95
- id.set!(resource, key.get_id)
96
- elsif id = resource.model.key(name).find{|k|k.type == Types::Key}
95
+ if id = resource.model.key(name).find{|k|k.kind_of? Property::Key}
97
96
  id.set!(resource, key)
97
+ elsif id = resource.model.serial(name)
98
+ # Order matters. Only sets to numeric id if it's a serial non-key.
99
+ id.set!(resource, key.get_id)
100
+ end
101
+ resource.instance_variable_set(:@__entity__, entity)
102
+
103
+ # TODO: We shouldn't be messing with keys like this.
104
+ # On the other hand, should keys be assuming they don't change?
105
+ # How does serial even work when dealing with true autoincrements?
106
+ # I guess it's just not valid?
107
+ if resource.instance_variable_defined?(:@_key)
108
+ resource.send(:remove_instance_variable, :@_key)
98
109
  end
99
- resource.instance_variable_set :@__entity__, entity
100
110
  end
101
111
  return created
102
112
  end
@@ -120,15 +130,15 @@ module DataMapper
120
130
  end
121
131
 
122
132
  def convert_value(property, value)
123
- value = property.value(value)
124
- if property.type == DataMapper::Types::Text && value
133
+ value = property.dump(value)
134
+ if property.kind_of?(Property::Text) && value
125
135
  AppEngine::Datastore::Text.new(value)
136
+ elsif property.kind_of?(Property::Decimal) && value
137
+ Lexidecimal.decimal_to_string(value)
126
138
  else
127
139
  case value
128
140
  when Date, DateTime
129
141
  Time.parse(value.to_s)
130
- when BigDecimal
131
- value.to_s
132
142
  when Class
133
143
  value.name
134
144
  else
@@ -249,7 +259,7 @@ module DataMapper
249
259
  unless property.key?
250
260
  raise ArgumentError, "#{property_name(property)} is not the key"
251
261
  end
252
- Types::Key.typecast(value, property)
262
+ Property::Key.typecast_to_primitive(property, value)
253
263
  end
254
264
 
255
265
  def parse_or(or_op)
@@ -318,7 +328,7 @@ module DataMapper
318
328
 
319
329
  if op.kind_of?(InclusionComparison)
320
330
  parse_inclusion(op)
321
- elsif property.type == Types::AncestorKey
331
+ elsif property.kind_of?(Property::AncestorKey)
322
332
  @query.ancestor = value
323
333
  else
324
334
  if negated
@@ -393,7 +403,8 @@ module DataMapper
393
403
  hashes = entities.map do |entity|
394
404
  entity_to_hash(key_prop, entity)
395
405
  end
396
- resources = @model.load(hashes, @dm_query)
406
+ hashes.compact!
407
+ resources = hashes.empty? ? hashes : @model.load(hashes, @dm_query)
397
408
  resources.zip(entities) do |resource, entity|
398
409
  resource.instance_variable_set :@__entity__, entity
399
410
  end
@@ -408,15 +419,21 @@ module DataMapper
408
419
  @dm_query.fields.each do |property|
409
420
  name = property.field
410
421
  if property.key?
411
- if property.serial?
412
- hash[name] = key.get_id
413
- elsif property.type == String
414
- hash[name] = key.get_name
422
+ hash[name] = if property.kind_of? Property::Key
423
+ key
424
+ elsif property.serial?
425
+ key.get_id
426
+ elsif property.kind_of? Property::String
427
+ key.get_name
415
428
  else
416
- hash[name] = key
429
+ key
417
430
  end
418
431
  else
419
- hash[name] = property.typecast(entity.get_property(name))
432
+ value = entity.get_property(name)
433
+ if property.kind_of?(Property::Decimal) && value
434
+ value = Lexidecimal.string_to_decimal(entity.get_property(name))
435
+ end
436
+ hash[name] = value
420
437
  end
421
438
  end
422
439
  hash
@@ -75,14 +75,14 @@ module DataMapper
75
75
  end
76
76
 
77
77
  def ancestor_property(name)
78
- property name, Types::AncestorKey
78
+ property name, Property::AncestorKey
79
79
  # We don't want to ever set this. It's just for queries.
80
80
  undef_method name
81
81
  undef_method :"#{name}="
82
82
  end
83
83
 
84
84
  def primary_key(name)
85
- property name, DataMapper::Types::Key, :key => true
85
+ property name, Property::Key, :key => true
86
86
  end
87
87
 
88
88
  def parent_property(name)
@@ -104,7 +104,7 @@ module DataMapper
104
104
  variable = :"@#{name}"
105
105
 
106
106
  if add_id_property
107
- property key_getter, Types::Key
107
+ property key_getter, Property::Key
108
108
  end
109
109
 
110
110
  define_method(name) do
@@ -0,0 +1,21 @@
1
+ module DataMapper
2
+ class Property
3
+ prefix = 'dm-appengine/properties'
4
+
5
+ class_mapping = [
6
+ ['key', [:AncestorKey, :Key]],
7
+ ['native', [:AppEngineNative, :IMHandle, :GeoPt, :User]],
8
+ ['string', [:AppEngineStringType, :Blob, :ByteString, :Link, :Email,
9
+ :Category, :PhoneNumber, :PostalAddress]],
10
+ ['rating', [:Rating]],
11
+ ['list', [:List]]
12
+ ]
13
+
14
+ class_mapping.each do |name, classes|
15
+ path = "#{prefix}/#{name}"
16
+ classes.each do |klass|
17
+ autoload(klass, path)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,92 @@
1
+ module DataMapper
2
+ class Property
3
+ class Key < Object
4
+ primitive AppEngine::Datastore::Key
5
+ include PassThroughLoadDump
6
+
7
+ def dump(value)
8
+ typecast(value)
9
+ end
10
+ def load(value)
11
+ value
12
+ end
13
+
14
+ def typecast(value)
15
+ if value.nil?
16
+ value
17
+ else
18
+ super
19
+ end
20
+ end
21
+
22
+ def self.typecast_to_primitive(property, value)
23
+ case value
24
+ when ::AppEngine::Datastore::Key, ::NilClass
25
+ value
26
+ when ::Integer, ::String
27
+ AppEngine::Datastore::Key.from_path(kind(property), value)
28
+ when ::Symbol
29
+ AppEngine::Datastore::Key.from_path(kind(property), value.to_s)
30
+ when ::Hash
31
+ parent = self.typecast_to_primitive(property, value[:parent])
32
+ id = value[:id]
33
+ name = value[:name]
34
+ if id
35
+ id_or_name = id.to_i
36
+ elsif name
37
+ id_or_name = name.to_s
38
+ end
39
+ if parent
40
+ id_or_name ||= 0
41
+ parent.getChild(kind(property), id_or_name)
42
+ else
43
+ self.typecast_to_primitive(property, property.typecast(id_or_name))
44
+ end
45
+ else
46
+ raise ArgumentError, "Unsupported key value #{value.inspect} (a #{value.class})"
47
+ end
48
+ end
49
+
50
+ def self.kind(property)
51
+ property.model.repository.adapter.kind(property.model)
52
+ end
53
+
54
+ def typecast_to_primitive(value)
55
+ self.class.typecast_to_primitive(self, value)
56
+ end
57
+
58
+ accept_options :serial
59
+
60
+ # THIS IS A HACK.
61
+ # I'm not sure the best way to do this. The key is not technically required at
62
+ # object creation time, but should be seen as required after that.
63
+ def initialize(model, name, options = {}, type = nil)
64
+ super
65
+ @serial = options.fetch(:serial, @key)
66
+ end
67
+
68
+ VALID_KEY_OPTS = Set.new([:id, :name, :parent]).freeze
69
+
70
+ def valid?(value, negated = false)
71
+ if value.kind_of? Hash
72
+ return false unless value.keys.all?{|k| VALID_KEY_OPTS.include? k}
73
+ !(value[:id] && value[:name])
74
+ else
75
+ super
76
+ end
77
+ end
78
+ end
79
+
80
+ # Hack to allow a property defined as AppEngine::Datastore::Key to work.
81
+ # This is needed for associations -- child_key tries to define it as
82
+ # the primitive of the parent key type. It then takes that type name and
83
+ # tries to resolve it in DM::Property, so we catch it here.
84
+ module Java
85
+ module ComGoogleAppengineApiDatastore
86
+ end
87
+ end
88
+ Java::ComGoogleAppengineApiDatastore::Key = Key
89
+
90
+ class AncestorKey < Key; end
91
+ end
92
+ end
@@ -0,0 +1,15 @@
1
+ module DataMapper
2
+ class Property
3
+ class List < Object
4
+ primitive ::Object
5
+
6
+ def dump(value)
7
+ value
8
+ end
9
+
10
+ def load(value)
11
+ value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module DataMapper
2
+ class Property
3
+ class AppEngineNative < Property
4
+ primitive ::Object
5
+
6
+ def dump(value)
7
+ value
8
+ end
9
+
10
+ def load(value)
11
+ value
12
+ end
13
+ end
14
+ IMHandle = GeoPt = User = AppEngineNative
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ module DataMapper
2
+ class Property
3
+ class Rating < Integer
4
+ def self.dump(value, property)
5
+ AppEngine::Datastore::Rating.new(typecast(value)) if value
6
+ end
7
+
8
+ def self.load(value, property)
9
+ value.rating if value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,70 @@
1
+ module DataMapper
2
+ class Property
3
+ class AppEngineStringType < String
4
+ def self.dump(value, property)
5
+ if value.nil?
6
+ nil
7
+ else
8
+ typecast(value)
9
+ end
10
+ end
11
+
12
+ def self.load(value, property)
13
+ value
14
+ end
15
+
16
+ def typecast_to_primitive(value)
17
+ primitive.new(value) if value
18
+ end
19
+
20
+ #Overriding the default string length.
21
+ def initialize(model, name, options = {}, type = nil)
22
+ super
23
+ @length = @options.fetch(:length, self.class.length)
24
+ end
25
+
26
+ def self.inherited klass
27
+ klass.extend ClassMethods
28
+ end
29
+
30
+ module ClassMethods
31
+ attr_accessor :length
32
+ end
33
+ end
34
+
35
+ class Blob < AppEngineStringType
36
+ primitive AppEngine::Datastore::Blob
37
+ self.length = 1024 * 1024
38
+ end
39
+
40
+ class ByteString < AppEngineStringType
41
+ primitive AppEngine::Datastore::ByteString
42
+ self.length = 500
43
+ end
44
+
45
+ class Link < AppEngineStringType
46
+ primitive AppEngine::Datastore::Link
47
+ self.length = 2038
48
+ end
49
+
50
+ class Email < AppEngineStringType
51
+ primitive AppEngine::Datastore::Email
52
+ self.length = 500
53
+ end
54
+
55
+ class Category < AppEngineStringType
56
+ primitive AppEngine::Datastore::Category
57
+ self.length = 500
58
+ end
59
+
60
+ class PhoneNumber < AppEngineStringType
61
+ primitive AppEngine::Datastore::PhoneNumber
62
+ self.length = 500
63
+ end
64
+
65
+ class PostalAddress < AppEngineStringType
66
+ primitive AppEngine::Datastore::PostalAddress
67
+ self.length = 500
68
+ end
69
+ end
70
+ end
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require File.dirname(__FILE__) + '/spec_helper'
19
- require 'dm-core/spec/adapter_shared_spec'
19
+ require 'dm-core/spec/shared/adapter_spec'
20
20
 
21
21
  class TextTest
22
22
  include DataMapper::Resource
@@ -32,7 +32,7 @@ class TypeTest
32
32
  property :time, Time
33
33
  property :date, Date
34
34
  property :datetime, DateTime
35
- property :bigd, BigDecimal
35
+ property :decimal, Decimal
36
36
  property :flower, Object
37
37
  property :klass, Class
38
38
  property :list, List
@@ -69,9 +69,23 @@ class KeyTest
69
69
  property :string, String
70
70
  end
71
71
 
72
+ class Person
73
+ include DataMapper::AppEngineResource
74
+
75
+ property :name, String
76
+ property :type, Discriminator
77
+ end
78
+
79
+ class Male < Person; end
80
+ class Father < Male; end
81
+ class Son < Male; end
82
+
83
+ class Woman < Person; end
84
+ class Mother < Woman; end
85
+ class Daughter < Woman; end
86
+
72
87
  describe DataMapper::Adapters::AppEngineAdapter do
73
88
  before :all do
74
- AppEngine::Testing.install_test_env
75
89
  AppEngine::Testing.install_test_datastore
76
90
  end
77
91
 
@@ -160,12 +174,12 @@ describe DataMapper::Adapters::AppEngineAdapter do
160
174
  a.datetime.should == date
161
175
  end
162
176
 
163
- it 'should support BigDecimal' do
177
+ it 'should support Decimal' do
164
178
  one = BigDecimal.new('1.0')
165
- a = TypeTest.new(:name => 'bigd', :bigd => one)
179
+ a = TypeTest.new(:name => 'bigd', :decimal => one)
166
180
  a.save
167
181
  a.reload
168
- a.bigd.should == one
182
+ a.decimal.should == one
169
183
  end
170
184
 
171
185
  it 'should support Object' do
@@ -188,7 +202,7 @@ describe DataMapper::Adapters::AppEngineAdapter do
188
202
  a = TypeTest.new(:name => 'list', :list => [1, 2, 3])
189
203
  a.save
190
204
  a.reload
191
- a.list.should == [1, 2, 3]
205
+ a.list.to_a.should == [1, 2, 3]
192
206
  TypeTest.all(:list => 2).should == [a]
193
207
  end
194
208
 
@@ -407,15 +421,47 @@ describe DataMapper::Adapters::AppEngineAdapter do
407
421
  parent = KeyTest.create(:string => 'foo')
408
422
  key = parent.appengine_key
409
423
  key.should be_kind_of AppEngine::Datastore::Key
410
- key.should_not_receive :getChild
411
424
 
412
- child = KeyTest.create(:appengine_key => {:parent => key})
425
+ child = KeyTest.new(:appengine_key => {:parent => key})
413
426
  child_key = child.appengine_key
414
427
  child_key.should be_kind_of AppEngine::Datastore::Key
415
428
  child_key.parent.should == key
429
+ child_key.inspect.should =~ /no-id-yet/
430
+
431
+ child.save
416
432
 
417
433
  child_key.id.should_not be_nil
418
434
  child_key.id.should be > 0
419
435
  end
420
436
  end
437
+
438
+ it 'should allow children to be created' do
439
+ Daughter.create(:name => 'Jill')
440
+ end
441
+
442
+ describe 'with a parent and child' do
443
+ before :each do
444
+ @daughter = Daughter.create :name => 'Jill'
445
+ @mother = Mother.create :name => 'Mom'
446
+ @person = Person.create :name => 'nobody'
447
+ end
448
+
449
+ it 'Should be possible to find the daughter under the daughter class' do
450
+ Daughter.first.name.should == 'Jill'
451
+ Daughter.first(:name => 'Jill').should_not be_nil
452
+ end
453
+
454
+ it 'Should be possible to find the daughter under the parent class' do
455
+ Woman.first(:name => 'Jill').should_not be_nil
456
+ end
457
+
458
+ it 'Should not be possible to find the daughter under a sibling class' do
459
+ Mother.first(:name => 'Jill').should be_nil
460
+ end
461
+
462
+ it 'Should not be possible to find parent classes under the child class' do
463
+ Person.first(:name => 'nobody').should_not be_nil
464
+ Daughter.first(:name => 'nobody').should be_nil
465
+ end
466
+ end
421
467
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-appengine
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 27
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
8
+ - 1
7
9
  - 0
8
- - 9
9
- version: 0.0.9
10
+ version: 0.1.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Ryan Brown
@@ -15,37 +16,55 @@ autorequire: dm-appengine
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-05-14 00:00:00 -07:00
19
+ date: 2010-06-09 00:00:00 -04:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
22
23
  name: appengine-apis
23
24
  prerelease: false
24
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
25
27
  requirements:
26
28
  - - ~>
27
29
  - !ruby/object:Gem::Version
30
+ hash: 61
28
31
  segments:
29
32
  - 0
30
33
  - 0
31
- - 14
32
- version: 0.0.14
34
+ - 17
35
+ version: 0.0.17
33
36
  type: :runtime
34
37
  version_requirements: *id001
35
38
  - !ruby/object:Gem::Dependency
36
39
  name: dm-core
37
40
  prerelease: false
38
41
  requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
39
43
  requirements:
40
- - - "="
44
+ - - ~>
41
45
  - !ruby/object:Gem::Version
46
+ hash: 15
42
47
  segments:
48
+ - 1
43
49
  - 0
44
- - 10
45
- - 2
46
- version: 0.10.2
50
+ version: "1.0"
47
51
  type: :runtime
48
52
  version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: lexidecimal
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 11
62
+ segments:
63
+ - 0
64
+ - 0
65
+ version: "0.0"
66
+ type: :runtime
67
+ version_requirements: *id003
49
68
  description: A DataMapper adapter for Google App Engine
50
69
  email:
51
70
  - ribrdb@google.com
@@ -65,9 +84,14 @@ files:
65
84
  - spec/dm-is-entity_spec.rb
66
85
  - spec/spec_helper.rb
67
86
  - lib/appengine_adapter.rb
87
+ - lib/dm-appengine/properties/rating.rb
88
+ - lib/dm-appengine/properties/list.rb
89
+ - lib/dm-appengine/properties/string.rb
90
+ - lib/dm-appengine/properties/key.rb
91
+ - lib/dm-appengine/properties/native.rb
92
+ - lib/dm-appengine/properties.rb
68
93
  - lib/dm-appengine/appengine_resource.rb
69
94
  - lib/dm-appengine/is_entity.rb
70
- - lib/dm-appengine/types.rb
71
95
  has_rdoc: true
72
96
  homepage: http://code.google.com/p/appengine-jruby
73
97
  licenses: []
@@ -78,23 +102,27 @@ rdoc_options: []
78
102
  require_paths:
79
103
  - lib
80
104
  required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
81
106
  requirements:
82
107
  - - ">="
83
108
  - !ruby/object:Gem::Version
109
+ hash: 3
84
110
  segments:
85
111
  - 0
86
112
  version: "0"
87
113
  required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
88
115
  requirements:
89
116
  - - ">="
90
117
  - !ruby/object:Gem::Version
118
+ hash: 3
91
119
  segments:
92
120
  - 0
93
121
  version: "0"
94
122
  requirements: []
95
123
 
96
124
  rubyforge_project:
97
- rubygems_version: 1.3.6
125
+ rubygems_version: 1.3.7
98
126
  signing_key:
99
127
  specification_version: 3
100
128
  summary: A DataMapper adapter for Google App Engine
@@ -1,202 +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 types for App Engine
19
-
20
- require 'dm-core/type' unless defined? DataMapper::Type::PROPERTY_OPTIONS
21
- require 'dm-core/property' unless defined? DataMapper::Property::PRIMITIVES
22
-
23
- module DataMapper
24
- module Types
25
- class List < Type
26
- primitive ::Object
27
-
28
- def self.dump(value, property)
29
- value
30
- end
31
-
32
- def self.load(value, property)
33
- value.to_a if value
34
- end
35
-
36
- def self._type=(type)
37
- @type = type
38
- end
39
- end
40
-
41
- class AppEngineStringType < Type
42
- def self.dump(value, property)
43
- self::DATASTORE_TYPE.new(value) if value
44
- end
45
-
46
- def self.load(value, property)
47
- value
48
- end
49
- end
50
-
51
- class AppEngineNativeType < Type
52
- primitive ::Object
53
-
54
- def self.dump(value, property)
55
- value
56
- end
57
-
58
- def self.load(value, property)
59
- value
60
- end
61
- end
62
-
63
- class Blob < AppEngineStringType
64
- primitive String
65
- DATASTORE_TYPE = AppEngine::Datastore::Blob
66
- size 1024 * 1024
67
- end
68
-
69
- class ByteString < AppEngineStringType
70
- primitive String
71
- DATASTORE_TYPE = AppEngine::Datastore::ByteString
72
- size 500
73
- end
74
-
75
- class Link < AppEngineStringType
76
- primitive String
77
- DATASTORE_TYPE = AppEngine::Datastore::Link
78
- size 2038
79
- end
80
-
81
- class Email < AppEngineStringType
82
- primitive String
83
- DATASTORE_TYPE = AppEngine::Datastore::Email
84
- size 500
85
- end
86
-
87
- class Category < AppEngineStringType
88
- primitive String
89
- DATASTORE_TYPE = AppEngine::Datastore::Category
90
- size 500
91
- end
92
-
93
- class PhoneNumber < AppEngineStringType
94
- primitive String
95
- DATASTORE_TYPE = AppEngine::Datastore::PhoneNumber
96
- size 500
97
- end
98
-
99
- class PostalAddress < AppEngineStringType
100
- primitive String
101
- DATASTORE_TYPE = AppEngine::Datastore::PostalAddress
102
- size 500
103
- end
104
-
105
- class Rating < Type
106
- primitive ::Object
107
-
108
- def self.dump(value, property)
109
- AppEngine::Datastore::Rating.new(value) if value
110
- end
111
-
112
- def self.load(value, property)
113
- value.rating if value
114
- end
115
- end
116
-
117
- IMHandle = GeoPt = User = AppEngineNativeType
118
-
119
- class Key < Type
120
- primitive AppEngine::Datastore::Key
121
-
122
- def self.dump(value, property)
123
- property.typecast(value)
124
- end
125
-
126
- def self.load(value, property)
127
- value
128
- end
129
-
130
- def self.typecast(value, property)
131
- case value
132
- when AppEngine::Datastore::Key, NilClass
133
- value
134
- when Integer, String
135
- AppEngine::Datastore::Key.from_path(kind(property), value)
136
- when Symbol
137
- AppEngine::Datastore::Key.from_path(kind(property), value.to_s)
138
- when Hash
139
- parent = property.typecast(value[:parent])
140
- id = value[:id]
141
- name = value[:name]
142
- if id
143
- id_or_name = id.to_i
144
- elsif name
145
- id_or_name = name.to_s
146
- end
147
- if parent
148
- if id_or_name || (!property.key?)
149
- parent.getChild(kind(property), id_or_name)
150
- else
151
- # TODO: is it sane to not typecast this?
152
- value
153
- end
154
- else
155
- property.typecast(id_or_name)
156
- end
157
- else
158
- raise ArgumentError, "Unsupported key value #{value.inspect} (a #{value.class})"
159
- end
160
- end
161
-
162
- def self.kind(property)
163
- property.model.repository.adapter.kind(property.model)
164
- end
165
- end
166
-
167
- # Hacks for primitive types.
168
- # AppEngine::Datastore::Key truly IS a primitive,
169
- # as far as AppEngine is concerned.
170
- original_primitives = Property::PRIMITIVES
171
- Property::PRIMITIVES = (original_primitives.dup << AppEngine::Datastore::Key).freeze
172
-
173
- # Hack to allow a property defined as AppEngine::Datastore::Key to work.
174
- # This is needed for associations -- child_key tries to define it as
175
- # the primitive of the parent key type. It then takes that type name and
176
- # tries to resolve it in DM::Types, so we catch it here.
177
- module Java
178
- module ComGoogleAppengineApiDatastore
179
- end
180
- end
181
- Java::ComGoogleAppengineApiDatastore::Key = Key
182
-
183
- # Should NOT be used directly!
184
- # Also, should be sharing these better...
185
- class AncestorKey < Type
186
- primitive AppEngine::Datastore::Key
187
- def self.dump(value, property)
188
- property.typecast(value)
189
- end
190
-
191
- def self.load(value, property)
192
- value
193
- end
194
-
195
- def self.typecast(value, property)
196
- Key.typecast(value, property)
197
- end
198
- end
199
-
200
- # TODO store user as email and id?
201
- end
202
- end