dm-appengine 0.0.9 → 0.1.0

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.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