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 +4 -3
- data/lib/appengine_adapter.rb +37 -20
- data/lib/dm-appengine/is_entity.rb +3 -3
- data/lib/dm-appengine/properties.rb +21 -0
- data/lib/dm-appengine/properties/key.rb +92 -0
- data/lib/dm-appengine/properties/list.rb +15 -0
- data/lib/dm-appengine/properties/native.rb +16 -0
- data/lib/dm-appengine/properties/rating.rb +13 -0
- data/lib/dm-appengine/properties/string.rb +70 -0
- data/spec/dm-appengine_spec.rb +55 -9
- metadata +39 -11
- data/lib/dm-appengine/types.rb +0 -202
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.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.
|
25
|
-
s.add_dependency("dm-core", ["0
|
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
|
data/lib/appengine_adapter.rb
CHANGED
@@ -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/
|
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
|
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.
|
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.
|
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.
|
124
|
-
if property.
|
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
|
-
|
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.
|
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
|
-
|
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.
|
412
|
-
|
413
|
-
elsif property.
|
414
|
-
|
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
|
-
|
429
|
+
key
|
417
430
|
end
|
418
431
|
else
|
419
|
-
|
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,
|
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,
|
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,
|
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,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
|
data/spec/dm-appengine_spec.rb
CHANGED
@@ -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/
|
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 :
|
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
|
177
|
+
it 'should support Decimal' do
|
164
178
|
one = BigDecimal.new('1.0')
|
165
|
-
a = TypeTest.new(:name => 'bigd', :
|
179
|
+
a = TypeTest.new(:name => 'bigd', :decimal => one)
|
166
180
|
a.save
|
167
181
|
a.reload
|
168
|
-
a.
|
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.
|
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
|
-
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-
|
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
|
-
-
|
32
|
-
version: 0.0.
|
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
|
-
|
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.
|
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
|
data/lib/dm-appengine/types.rb
DELETED
@@ -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
|