dm-adapter-simpledb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ require 'dm-types'
2
+
3
+ # NOTE: Do not try to clear SdbArray properties by assigning nil. Instead,
4
+ # assign an empty array:
5
+ #
6
+ # resource.array_prop = []
7
+ # resource.save
8
+ #
9
+ # The reason has to do with DataMapper's lazy-load handling - a lazy-loaded
10
+ # property has a value of nil until it is loaded. If you assign nil, DM thinks
11
+ # that
12
+ module DataMapper
13
+ module Types
14
+ class SdbArray < DataMapper::Type
15
+ primitive ::Object
16
+ lazy true
17
+
18
+ def self.load(value, property)
19
+ value
20
+ end
21
+
22
+ def self.dump(value, property)
23
+ dumped = ::Object.new
24
+ # This is a little screwy. DataMapper has a fixed list of values it
25
+ # considers primitives, and it insists that the value that comes out of
26
+ # a type's .dump() method MUST match one of these types. For SimpleDB
27
+ # Array is effectively a primitive because of the way it stores values,
28
+ # but DM doesn't include Array in it's list of valid primtive types. So
29
+ # we need to return an object which IS considered a primitive - in this
30
+ # case a plain 'ole Ruby Object. In order to convey the actual array
31
+ # value to the backend, we tack on a #to_ary method which returns the
32
+ # array data. RightAws calls Array() on all values before writing them,
33
+ # which in turn calls #to_ary(), and winds up with the correct data. In
34
+ # effect we are sneaking the array data through DataMapper inside a
35
+ # singleton method.
36
+ singleton_class = (class << dumped; self; end)
37
+ singleton_class.send(:define_method, :to_ary) do
38
+ value
39
+ end
40
+ singleton_class.send(:define_method, :to_s) do
41
+ value.to_s
42
+ end
43
+ dumped
44
+ end
45
+
46
+ def self.typecast(value, property)
47
+ value
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,84 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.parent.expand_path + 'lib/simpledb_adapter'
3
+ require 'ruby-debug'
4
+ require 'benchmark'
5
+
6
+ access_key = ENV['AMAZON_ACCESS_KEY_ID']
7
+ secret_key = ENV['AMAZON_SECRET_ACCESS_KEY']
8
+
9
+ #For those that don't like to mess up their ENV
10
+ if access_key==nil && secret_key==nil
11
+ lines = File.readlines(File.join(File.dirname(__FILE__),'..','aws_config'))
12
+ access_key = lines[0].strip
13
+ secret_key = lines[1].strip
14
+ end
15
+
16
+ DataMapper.setup(:default, {
17
+ :adapter => 'simpledb',
18
+ :access_key => access_key,
19
+ :secret_key => secret_key,
20
+ :domain => 'benchmark'
21
+ })
22
+
23
+ class Person
24
+ include DataMapper::Resource
25
+
26
+ property :id, String, :key => true
27
+ property :name, String, :key => true
28
+ property :age, Integer
29
+ property :wealth, Float
30
+ property :birthday, Date
31
+ property :created_at, DateTime
32
+ end
33
+
34
+ @adapter = repository(:default).adapter
35
+
36
+
37
+ def rand_str(length = 10)
38
+ (0...length).map{65.+(rand(25)).chr}.join
39
+ end
40
+
41
+ def clean_up
42
+ #clean up by removing the benchmark storage model
43
+ ENV['destroy']='true'
44
+ @adapter.destroy_model_storage(repository(:default), Person)
45
+ ENV['destroy']='false'
46
+ end
47
+
48
+ #clean_up
49
+ #sleep(5)
50
+
51
+ Person.auto_migrate!
52
+ sleep(1)
53
+
54
+ Benchmark.bm do|b|
55
+ friends = []
56
+ number = 200
57
+
58
+ b.report("creating #{number} users") do
59
+ number.times do
60
+ friend_attrs = { :id => "person-#{rand_str}-#{Time.now.to_f.to_s}", :name => "name #{Time.now.to_f.to_s} #{rand_str}", :age => 25, :wealth => 25.00, :birthday => Date.today }
61
+ friend = Person.create(friend_attrs)
62
+ friends << friend
63
+ end
64
+ end
65
+
66
+ sleep(5.5) #let everything distribute through SDB
67
+ Person.all(:age => 25) #seems to make sure the first one gets the right amount
68
+
69
+ b.report("Finding all users age 25, 100 Times") do
70
+ 100.times do
71
+ people = Person.all(:age => 25, :limit => number)
72
+ if people.length!=number
73
+ puts "warning wrong number or users #{people.length}"
74
+ #clean_up
75
+ #raise "wrong amount of peoplefound"
76
+ end
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ clean_up
83
+ sleep(2)
84
+
@@ -0,0 +1,15 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+
4
+ describe 'associations' do
5
+ it 'should work with belongs_to associations'
6
+ it 'should work with has n associations'
7
+ end
8
+
9
+ describe 'STI' do
10
+ it 'should override default type'
11
+ it 'should load descendents on parent.all'
12
+ it 'should raise an error if you have a column named couchdb_type'
13
+ end
14
+
15
+
@@ -0,0 +1,18 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+
4
+ require 'dm-core/spec/adapter_shared_spec'
5
+
6
+ describe DataMapper::Adapters::SimpleDBAdapter do
7
+ before :all do
8
+ @adapter = DataMapper::Repository.adapters[:default]
9
+ @old_consistency_policy = @adapter.consistency_policy
10
+ @adapter.consistency_policy = :automatic
11
+ end
12
+
13
+ after :all do
14
+ @adapter.consistency_policy = @old_consistency_policy
15
+ end
16
+
17
+ it_should_behave_like 'An Adapter'
18
+ end
@@ -0,0 +1,51 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+
4
+ class Professor
5
+ include DataMapper::Resource
6
+
7
+ property :id, String, :key => true
8
+ property :name, String, :key => true
9
+ property :age, Integer
10
+ property :wealth, Float
11
+ property :birthday, Date
12
+ property :created_at, DateTime
13
+
14
+ end
15
+
16
+ describe 'with multiple records saved' do
17
+ before(:each) do
18
+ @adapter.wait_for_consistency
19
+ @person_attrs = { :id => "person-#{Time.now.to_f.to_s}", :name => 'Jeremy Boles', :age => 25, :wealth => 25.00, :birthday => Date.today }
20
+ @jeremy = Professor.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Jeremy Boles", :age => 25))
21
+ @danielle = Professor.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Danille Boles", :age => 26))
22
+ @keegan = Professor.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Keegan Jones", :age => 20))
23
+ @adapter.wait_for_consistency
24
+ end
25
+
26
+ after(:each) do
27
+ @jeremy.destroy
28
+ @danielle.destroy
29
+ @keegan.destroy
30
+ end
31
+
32
+ it 'should handle DateTime' do
33
+ time = DateTime.civil(1970,1,1)
34
+ @jeremy.created_at = time
35
+ @jeremy.save
36
+ @adapter.wait_for_consistency
37
+ person = Professor.get!(@jeremy.id, @jeremy.name)
38
+ person.created_at.should == time
39
+ end
40
+
41
+ it 'should handle Date' do
42
+ person = Professor.get!(@jeremy.id, @jeremy.name)
43
+ person.birthday.should == @jeremy.birthday
44
+ end
45
+
46
+ it 'should match with Data' do
47
+ people = Professor.all(:birthday => Date.today)
48
+ people.length.should == 3
49
+ end
50
+
51
+ end
@@ -0,0 +1,110 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+
4
+ class Hero
5
+ include DataMapper::Resource
6
+
7
+ property :id, String, :key => true
8
+ property :name, String, :key => true
9
+ property :age, Integer
10
+ property :wealth, Float
11
+ property :birthday, Date
12
+ property :created_at, DateTime
13
+
14
+ end
15
+
16
+ describe 'with multiple records saved' do
17
+ before(:each) do
18
+ @person_attrs = { :id => "person-#{Time.now.to_f.to_s}", :name => 'Jeremy Boles', :age => 25, :wealth => 25.00, :birthday => Date.today }
19
+ @jeremy = Hero.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Jeremy Boles", :age => 25))
20
+ @danielle = Hero.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Danille Boles", :age => 26))
21
+ @keegan = Hero.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Keegan Jones", :age => 20, :wealth => 15.00))
22
+ @adapter.wait_for_consistency
23
+ end
24
+
25
+ after(:each) do
26
+ @jeremy.destroy
27
+ @danielle.destroy
28
+ @keegan.destroy
29
+ end
30
+
31
+ it 'should handle limit one case' do
32
+ persons = Hero.all(:limit => 1)
33
+ persons.length.should ==1
34
+ end
35
+
36
+ it 'should handle max item limit case' do
37
+ persons = Hero.all(:limit => 3)
38
+ persons.length.should ==3
39
+ end
40
+
41
+ it 'should handle max item if limit is large case' do
42
+ persons = Hero.all(:limit => 150)
43
+ persons.length.should ==3
44
+ end
45
+
46
+ it 'should handle ordering asc results with a limit' do
47
+ persons = Hero.all(:order => [:age.asc], :limit => 2)
48
+ persons.inspect #can't access via array until loaded? Weird
49
+ persons.length.should ==2
50
+ persons[0].should == @keegan
51
+ persons[1].should == @jeremy
52
+ end
53
+
54
+ it 'should handle ordering asc results' do
55
+ persons = Hero.all(:order => [:age.asc])
56
+ persons.inspect #can't access via array until loaded? Weird
57
+ persons[0].should == @keegan
58
+ persons[1].should == @jeremy
59
+ persons[2].should == @danielle
60
+ end
61
+
62
+ it 'should handle ordering desc results' do
63
+ persons = Hero.all(:order => [:age.desc])
64
+ persons.inspect #can't access via array until loaded? Weird
65
+ persons[0].should == @danielle
66
+ persons[1].should == @jeremy
67
+ persons[2].should == @keegan
68
+ end
69
+
70
+ it 'should handle ordering results with multiple conditionss' do
71
+ persons = Hero.all(:age.gt => 20, :wealth.gt => 20, :order => [:age.desc])
72
+ persons.inspect #can't access via array until loaded? Weird
73
+ persons.length.should ==2
74
+ persons[0].should == @danielle
75
+ persons[1].should == @jeremy
76
+ end
77
+
78
+ it 'should handle ordering results with ordered by conditions' do
79
+ persons = Hero.all(:age.gt => 20, :order => [:age.desc])
80
+ persons.inspect #can't access via array until loaded? Weird
81
+ persons.length.should ==2
82
+ persons[0].should == @danielle
83
+ persons[1].should == @jeremy
84
+ end
85
+
86
+ it 'should handle ordering results with unorder by conditions' do
87
+ persons = Hero.all(:wealth.gt => 20.00, :order => [:age.desc])
88
+ persons.inspect #can't access via array until loaded? Weird
89
+ persons.length.should ==2
90
+ persons[0].should == @danielle
91
+ persons[1].should == @jeremy
92
+ end
93
+
94
+ context "with many entries" do
95
+ before :each do
96
+ resources = []
97
+ 111.times do |i|
98
+ resources << Hero.new(:id => i, :name => "Hero#{i}")
99
+ end
100
+ DataMapper.repository(:default).create(resources)
101
+ @adapter.wait_for_consistency
102
+ end
103
+
104
+ it "should support limits over 100" do
105
+ results = Hero.all(:limit => 110)
106
+ results.should have(110).entries
107
+ end
108
+ end
109
+
110
+ end
@@ -0,0 +1,41 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+ require 'dm-migrations'
4
+
5
+ describe 'support migrations' do
6
+
7
+ #TODO do this on different storage
8
+ class Person
9
+ include DataMapper::Resource
10
+
11
+ property :id, String, :key => true
12
+ property :name, String, :key => true
13
+ property :age, Integer
14
+ property :wealth, Float
15
+ property :birthday, Date
16
+ property :created_at, DateTime
17
+
18
+ end
19
+
20
+ # test can't be run simultanious make it delete a throwawaable storage model
21
+ # instead of the one used by all the tests
22
+ # it "should destroy model storage" do
23
+ # ENV['destroy']='true'
24
+ # @adapter.destroy_model_storage(repository(:default), Person)
25
+ # @adapter.storage_exists?("missionaries").should == false
26
+ # ENV['destroy']='false'
27
+ # @adapter.create_model_storage(repository(:default), Person)
28
+ # @adapter.storage_exists?("missionaries").should == true
29
+ # end
30
+
31
+ before :all do
32
+ @sdb.delete_domain(@domain)
33
+ end
34
+
35
+ it "should create model storage" do
36
+ DataMapper.auto_migrate!
37
+ @adapter.storage_exists?(@domain).should == true
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,111 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
3
+
4
+ class Person
5
+ include DataMapper::Resource
6
+
7
+ property :id, String, :key => true
8
+ property :name, String, :key => true
9
+ property :age, Integer
10
+ property :wealth, Float
11
+ property :birthday, Date
12
+ property :created_at, DateTime
13
+
14
+ belongs_to :company
15
+ end
16
+
17
+ #TODO write some tests with company or drop this
18
+ class Company
19
+ include DataMapper::Resource
20
+
21
+ property :id, String, :key => true
22
+ property :name, String, :key => true
23
+
24
+ has n, :people
25
+ end
26
+
27
+ describe 'with multiple records saved' do
28
+ before(:all) do
29
+ @person_attrs = { :id => "person-#{Time.now.to_f.to_s}", :name => 'Jeremy Boles', :age => 25, :wealth => 25.00, :birthday => Date.today }
30
+ @jeremy = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Jeremy Boles", :age => 25))
31
+ @danielle = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Danille Boles", :age => 26))
32
+ @keegan = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Keegan Jones", :age => 20))
33
+ @adapter.wait_for_consistency
34
+ end
35
+
36
+ after(:all) do
37
+ @jeremy.destroy
38
+ @danielle.destroy
39
+ @keegan.destroy
40
+ end
41
+
42
+ it 'should get all records' do
43
+ Person.all.length.should == 3
44
+ end
45
+
46
+ it 'should get records by eql matcher' do
47
+ people = Person.all(:age => 25)
48
+ people.length.should == 1
49
+ end
50
+
51
+ it 'should get record by eql matcher' do
52
+ person = Person.first(:conditions => {:age => 25})
53
+ person.should_not be_nil
54
+ end
55
+
56
+ it 'should get records by not matcher' do
57
+ people = Person.all(:age.not => 25)
58
+ people.should have(2).entries
59
+ end
60
+
61
+ it 'should get record by not matcher' do
62
+ person = Person.first(:age.not => 25)
63
+ person.should_not be_nil
64
+ end
65
+
66
+ it 'should get records by gt matcher' do
67
+ people = Person.all(:age.gt => 25)
68
+ people.length.should == 1
69
+ end
70
+
71
+ it 'should get records by gte matcher' do
72
+ people = Person.all(:age.gte => 25)
73
+ people.length.should == 2
74
+ end
75
+
76
+ it 'should get records by lt matcher' do
77
+ people = Person.all(:age.lt => 25)
78
+ people.length.should == 1
79
+ end
80
+
81
+ it 'should get records by lte matcher' do
82
+ people = Person.all(:age.lte => 25)
83
+ people.length.should == 2
84
+ end
85
+
86
+ it 'should get record by lte matcher' do
87
+ person = Person.first(:age.lte => 25)
88
+ person.should_not be_nil
89
+ end
90
+
91
+ it 'should get records with multiple matchers' do
92
+ people = Person.all(:birthday => Date.today, :age.lte => 25)
93
+ people.length.should == 2
94
+ end
95
+
96
+ it 'should get records by the like matcher' do
97
+ people = Person.all(:name.like => 'Jeremy%')
98
+ people.should == [@jeremy]
99
+ end
100
+
101
+ it 'should get records by the IN matcher' do
102
+ people = Person.all(:id => [@jeremy.id, @danielle.id])
103
+ people.should include(@jeremy)
104
+ people.should include(@danielle)
105
+ people.should_not include(@keegan)
106
+ end
107
+ it "should get no records if IN array is empty" do
108
+ people = Person.all(:id => [])
109
+ people.should be_empty
110
+ end
111
+ end