jeremyboles-dm-adapter-simpledb 0.9.3
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/README +0 -0
- data/Rakefile +63 -0
- data/dm-adapter-simpledb.gemspec +38 -0
- data/lib/simpledb_adapter.rb +163 -0
- data/spec/simpledb_adapter_spec.rb +131 -0
- metadata +89 -0
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'pathname'
|
5
|
+
require "rake/gempackagetask"
|
6
|
+
|
7
|
+
ROOT = Pathname(__FILE__).dirname.expand_path
|
8
|
+
require ROOT + 'lib/simpledb_adapter'
|
9
|
+
|
10
|
+
task :default => [ :spec ]
|
11
|
+
|
12
|
+
desc 'Run specifications'
|
13
|
+
Spec::Rake::SpecTask.new(:spec) do |t|
|
14
|
+
if File.exists?('spec/spec.opts')
|
15
|
+
t.spec_opts << '--options' << 'spec/spec.opts'
|
16
|
+
end
|
17
|
+
t.spec_files = Pathname.glob((ROOT + 'spec/**/*_spec.rb').to_s)
|
18
|
+
|
19
|
+
begin
|
20
|
+
t.rcov = ENV.has_key?('NO_RCOV') ? ENV['NO_RCOV'] != 'true' : true
|
21
|
+
t.rcov_opts << '--exclude' << 'spec'
|
22
|
+
t.rcov_opts << '--text-summary'
|
23
|
+
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
24
|
+
rescue Exception
|
25
|
+
# rcov not installed
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
spec = Gem::Specification.new do |s|
|
31
|
+
s.name = "dm-adapter-simpledb"
|
32
|
+
s.version = "0.9.3"
|
33
|
+
s.date = "2008-10-01"
|
34
|
+
s.summary = "A DatMapper adapter for SimpleDB"
|
35
|
+
s.email = "jeremy@jeremyboles.com"
|
36
|
+
s.homepage = "http://github.com/jeremyboles/dm-adapter-simpledb"
|
37
|
+
s.description = "A DataMapper adapter for Amazon's SimpleDB"
|
38
|
+
s.has_rdoc = true
|
39
|
+
s.authors = ["Jeremy Boles"]
|
40
|
+
s.files = ["lib/simpledb_adapter.rb",
|
41
|
+
"README",
|
42
|
+
"Rakefile",
|
43
|
+
"dm-adapter-simpledb.gemspec"]
|
44
|
+
s.test_files = ["spec/simpledb_adapter_spec.rb",
|
45
|
+
"spec.opts",
|
46
|
+
"spec_helper.rb"]
|
47
|
+
s.rdoc_options = ["--main", "README.txt"]
|
48
|
+
s.extra_rdoc_files = ["README.txt"]
|
49
|
+
s.add_dependency("rspec", ["> 0.0.0"])
|
50
|
+
s.add_dependency("dm-core", ["> 0.0.0"])
|
51
|
+
s.add_dependency("aws-sdb", ["> 0.0.0"])
|
52
|
+
end
|
53
|
+
|
54
|
+
Rake::GemPackageTask.new(spec) do |package|
|
55
|
+
package.gem_spec = spec
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Create a gemspec file"
|
59
|
+
task :gemspec do
|
60
|
+
File.open("dm-adapter-simpledb.gemspec", "w") do |file|
|
61
|
+
file.puts spec.to_ruby
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{dm-adapter-simpledb}
|
3
|
+
s.version = "0.9.3"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Jeremy Boles"]
|
7
|
+
s.date = %q{2008-10-01}
|
8
|
+
s.description = %q{A DataMapper adapter for Amazon's SimpleDB}
|
9
|
+
s.email = %q{jeremy@jeremyboles.com}
|
10
|
+
s.extra_rdoc_files = ["README.txt"]
|
11
|
+
s.files = ["lib/simpledb_adapter.rb", "README", "Rakefile", "dm-adapter-simpledb.gemspec", "spec/simpledb_adapter_spec.rb", "spec.opts", "spec_helper.rb", "README.txt"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://github.com/jeremyboles/dm-adapter-simpledb}
|
14
|
+
s.rdoc_options = ["--main", "README.txt"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubygems_version = %q{1.2.0}
|
17
|
+
s.summary = %q{A DatMapper adapter for SimpleDB}
|
18
|
+
s.test_files = ["spec/simpledb_adapter_spec.rb", "spec.opts", "spec_helper.rb"]
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 2
|
23
|
+
|
24
|
+
if current_version >= 3 then
|
25
|
+
s.add_runtime_dependency(%q<rspec>, ["> 0.0.0"])
|
26
|
+
s.add_runtime_dependency(%q<dm-core>, ["> 0.0.0"])
|
27
|
+
s.add_runtime_dependency(%q<aws-sdb>, ["> 0.0.0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<rspec>, ["> 0.0.0"])
|
30
|
+
s.add_dependency(%q<dm-core>, ["> 0.0.0"])
|
31
|
+
s.add_dependency(%q<aws-sdb>, ["> 0.0.0"])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
s.add_dependency(%q<rspec>, ["> 0.0.0"])
|
35
|
+
s.add_dependency(%q<dm-core>, ["> 0.0.0"])
|
36
|
+
s.add_dependency(%q<aws-sdb>, ["> 0.0.0"])
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'dm-core'
|
3
|
+
require 'aws_sdb'
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
module DataMapper
|
7
|
+
module Adapters
|
8
|
+
class SimpleDBAdapter < AbstractAdapter
|
9
|
+
|
10
|
+
def create(resources)
|
11
|
+
created = 0
|
12
|
+
resources.each do |resource|
|
13
|
+
simpledb_type = simpledb_type(resource.model)
|
14
|
+
attributes = resource.attributes.merge(:simpledb_type => simpledb_type)
|
15
|
+
|
16
|
+
item_name = "#{simpledb_type}+"
|
17
|
+
keys = resource.model.key(self.name).sort {|a,b| a.name.to_s <=> b.name.to_s}
|
18
|
+
item_name += keys.map do |property|
|
19
|
+
resource.instance_variable_get(property.instance_variable_name)
|
20
|
+
end.join('-')
|
21
|
+
item_name = Digest::SHA1.hexdigest(item_name)
|
22
|
+
|
23
|
+
sdb.put_attributes(domain, item_name, attributes)
|
24
|
+
|
25
|
+
created += 1
|
26
|
+
end
|
27
|
+
created
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(query)
|
31
|
+
deleted = 0
|
32
|
+
simpledb_type = simpledb_type(query.model)
|
33
|
+
|
34
|
+
item_name = "#{simpledb_type}+"
|
35
|
+
keys = query.model.key(self.name).sort {|a,b| a.name.to_s <=> b.name.to_s }
|
36
|
+
conditions = query.conditions.sort {|a,b| a[1].name.to_s <=> b[1].name.to_s }
|
37
|
+
item_name += conditions.map do |property|
|
38
|
+
property[2].to_s
|
39
|
+
end.join('-')
|
40
|
+
item_name = Digest::SHA1.hexdigest(item_name)
|
41
|
+
|
42
|
+
sdb.delete_attributes(domain, item_name)
|
43
|
+
|
44
|
+
deleted += 1
|
45
|
+
|
46
|
+
# Curosity check to make sure we are only dealing with a delete
|
47
|
+
conditions = conditions.map {|c| c[0] }.uniq
|
48
|
+
operators = [ :gt, :gte, :lt, :lte, :not, :like, :in ]
|
49
|
+
raise NotImplementedError.new('Only :eql on delete at the moment') if (operators - conditions).size != operators.size
|
50
|
+
|
51
|
+
deleted
|
52
|
+
end
|
53
|
+
|
54
|
+
def read_many(query)
|
55
|
+
simpledb_type = simpledb_type(query.model)
|
56
|
+
|
57
|
+
conditions = ["['simpledb_type' = '#{simpledb_type}']"]
|
58
|
+
if query.conditions.size > 0
|
59
|
+
conditions += query.conditions.map do |condition|
|
60
|
+
operator = case condition[0]
|
61
|
+
when :eql then '='
|
62
|
+
when :not then '!='
|
63
|
+
when :gt then '>'
|
64
|
+
when :gte then '>='
|
65
|
+
when :lt then '<'
|
66
|
+
when :lte then '<='
|
67
|
+
else raise "Invalid query operator: #{operator.inspect}"
|
68
|
+
end
|
69
|
+
"['#{condition[1].name.to_s}' #{operator} '#{condition[2].to_s}']"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
results = sdb.query(domain, conditions.compact.join(' intersection '))
|
74
|
+
results = results[0].map {|d| sdb.get_attributes(domain, d) }
|
75
|
+
|
76
|
+
Collection.new(query) do |collection|
|
77
|
+
results.each do |result|
|
78
|
+
data = query.fields.map do |property|
|
79
|
+
value = result[property.field.to_s]
|
80
|
+
if value.size > 1
|
81
|
+
value.map {|v| property.typecast(v) }
|
82
|
+
else
|
83
|
+
property.typecast(value[0])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
collection.load(data)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def read_one(query)
|
92
|
+
simpledb_type = simpledb_type(query.model)
|
93
|
+
|
94
|
+
item_name = "#{simpledb_type}+"
|
95
|
+
keys = query.model.key(self.name).sort {|a,b| a.name.to_s <=> b.name.to_s }
|
96
|
+
conditions = query.conditions.sort {|a,b| a[1].name.to_s <=> b[1].name.to_s }
|
97
|
+
item_name += conditions.map do |property|
|
98
|
+
property[2].to_s
|
99
|
+
end.join('-')
|
100
|
+
item_name = Digest::SHA1.hexdigest(item_name)
|
101
|
+
|
102
|
+
data = sdb.get_attributes(domain, item_name)
|
103
|
+
unless data.empty?
|
104
|
+
data = query.fields.map do |property|
|
105
|
+
value = data[property.field.to_s]
|
106
|
+
if value.size > 1
|
107
|
+
value.map {|v| property.typecast(v) }
|
108
|
+
else
|
109
|
+
property.typecast(value[0])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
query.model.load(data, query)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def update(attributes, query)
|
118
|
+
updated = 0
|
119
|
+
|
120
|
+
simpledb_type = simpledb_type(query.model)
|
121
|
+
|
122
|
+
item_name = "#{simpledb_type}+"
|
123
|
+
keys = query.model.key(self.name).sort {|a,b| a.name.to_s <=> b.name.to_s }
|
124
|
+
conditions = query.conditions.sort {|a,b| a[1].name.to_s <=> b[1].name.to_s }
|
125
|
+
item_name += conditions.map do |property|
|
126
|
+
property[2].to_s
|
127
|
+
end.join('-')
|
128
|
+
item_name = Digest::SHA1.hexdigest(item_name)
|
129
|
+
|
130
|
+
attributes = attributes.to_a.map {|a| [a.first.name.to_s, a.last]}.to_hash
|
131
|
+
sdb.put_attributes(domain, item_name, attributes, true)
|
132
|
+
|
133
|
+
updated += 1
|
134
|
+
|
135
|
+
# Curosity check to make sure we are only dealing with a delete
|
136
|
+
conditions = conditions.map {|c| c[0] }.uniq
|
137
|
+
selectors = [ :gt, :gte, :lt, :lte, :not, :like, :in ]
|
138
|
+
raise NotImplementedError.new('Only :eql on delete at the moment') if (selectors - conditions).size != selectors.size
|
139
|
+
|
140
|
+
updated
|
141
|
+
end
|
142
|
+
private
|
143
|
+
|
144
|
+
def domain
|
145
|
+
@uri[:domain]
|
146
|
+
end
|
147
|
+
|
148
|
+
def sdb
|
149
|
+
@sdb ||= AwsSdb::Service.new(:access_key_id => @uri[:access_key], :secret_access_key => @uri [:secret_key])
|
150
|
+
@sdb
|
151
|
+
end
|
152
|
+
|
153
|
+
def simpledb_type(model)
|
154
|
+
model.storage_name(model.repository.name)
|
155
|
+
end
|
156
|
+
|
157
|
+
end # class SimpleDBAdapter
|
158
|
+
|
159
|
+
# Required naming scheme.
|
160
|
+
SimpledbAdapter = SimpleDBAdapter
|
161
|
+
|
162
|
+
end # module Adapters
|
163
|
+
end # module DataMapper
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require Pathname(__FILE__).dirname.expand_path + 'spec_helper'
|
3
|
+
|
4
|
+
describe DataMapper::Adapters::SimpleDBAdapter do
|
5
|
+
before(:each) do
|
6
|
+
@person_attrs = { :id => "person-#{Time.now.to_f.to_s}", :name => 'Jeremy Boles', :age => 25,
|
7
|
+
:wealth => 25.00, :birthday => Date.today }
|
8
|
+
@person = Person.new(@person_attrs)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should create a record' do
|
12
|
+
@person.save.should be_true
|
13
|
+
@person.id.should_not be_nil
|
14
|
+
@person.destroy
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'with a saved record' do
|
18
|
+
before(:each) { @person.save }
|
19
|
+
after(:each) { @person.destroy }
|
20
|
+
|
21
|
+
it 'should get a record' do
|
22
|
+
person = Person.get!(@person.id, @person.name)
|
23
|
+
person.should_not be_nil
|
24
|
+
person.wealth.should == @person.wealth
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should not get records of the wrong type by id' do
|
28
|
+
Company.get(@person.id, @person.name).should == nil
|
29
|
+
lambda { Company.get!(@person.id, @person.name) }.should raise_error(DataMapper::ObjectNotFoundError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should update a record' do
|
33
|
+
person = Person.get!(@person.id, @person.name)
|
34
|
+
person.wealth = 100.00
|
35
|
+
person.save
|
36
|
+
|
37
|
+
person = Person.get!(@person.id, @person.name)
|
38
|
+
person.wealth.should_not == @person.wealth
|
39
|
+
person.age.should == @person.age
|
40
|
+
person.id.should == @person.id
|
41
|
+
person.name.should == @person.name
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should destroy a record' do
|
45
|
+
@person.destroy.should be_true
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'with multiple records saved' do
|
51
|
+
before(:each) do
|
52
|
+
@jeremy = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Jeremy Boles", :age => 25))
|
53
|
+
@danielle = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Danille Boles", :age => 26))
|
54
|
+
@keegan = Person.create(@person_attrs.merge(:id => Time.now.to_f.to_s, :name => "Keegan Jones", :age => 20))
|
55
|
+
end
|
56
|
+
|
57
|
+
after(:each) do
|
58
|
+
@jeremy.destroy
|
59
|
+
@danielle.destroy
|
60
|
+
@keegan.destroy
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should get all records' do
|
64
|
+
Person.all.length.should == 3
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should get records by eql matcher' do
|
68
|
+
people = Person.all(:age => 25)
|
69
|
+
people.length.should == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should get records by not matcher' do
|
73
|
+
people = Person.all(:age.not => 25)
|
74
|
+
people.length.should == 2
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should get records by gt matcher' do
|
78
|
+
people = Person.all(:age.gt => 25)
|
79
|
+
people.length.should == 1
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should get records by gte matcher' do
|
83
|
+
people = Person.all(:age.gte => 25)
|
84
|
+
people.length.should == 2
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'should get records by lt matcher' do
|
88
|
+
people = Person.all(:age.lt => 25)
|
89
|
+
people.length.should == 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should get records by lte matcher' do
|
93
|
+
people = Person.all(:age.lte => 25)
|
94
|
+
people.length.should == 2
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should get records with multiple matchers' do
|
98
|
+
people = Person.all(:birthday => Date.today, :age.lte => 25)
|
99
|
+
people.length.should == 2
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should handle DateTime' do
|
103
|
+
pending 'Need to figure out how to coerce DateTime'
|
104
|
+
time = Time.now
|
105
|
+
@jeremy.created_at = time
|
106
|
+
@jeremy.save
|
107
|
+
person = Person.get!(@jeremy.id, @jeremy.name)
|
108
|
+
person.created_at.should == time
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should handle Date' do
|
112
|
+
person = Person.get!(@jeremy.id, @jeremy.name)
|
113
|
+
person.birthday.should == @jeremy.birthday
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should order records'
|
117
|
+
it 'should get records by the like matcher'
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
describe 'associations' do
|
122
|
+
it 'should work with belongs_to associations'
|
123
|
+
it 'should work with has n associations'
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'STI' do
|
127
|
+
it 'should override default type'
|
128
|
+
it 'should load descendents on parent.all'
|
129
|
+
it 'should raise an error if you have a column named couchdb_type'
|
130
|
+
end
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jeremyboles-dm-adapter-simpledb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeremy Boles
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-10-01 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.0
|
23
|
+
version:
|
24
|
+
- !ruby/object:Gem::Dependency
|
25
|
+
name: dm-core
|
26
|
+
version_requirement:
|
27
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
|
+
requirements:
|
29
|
+
- - ">"
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.0.0
|
32
|
+
version:
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: aws-sdb
|
35
|
+
version_requirement:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.0.0
|
41
|
+
version:
|
42
|
+
description: A DataMapper adapter for Amazon's SimpleDB
|
43
|
+
email: jeremy@jeremyboles.com
|
44
|
+
executables: []
|
45
|
+
|
46
|
+
extensions: []
|
47
|
+
|
48
|
+
extra_rdoc_files:
|
49
|
+
- README.txt
|
50
|
+
files:
|
51
|
+
- lib/simpledb_adapter.rb
|
52
|
+
- README
|
53
|
+
- Rakefile
|
54
|
+
- dm-adapter-simpledb.gemspec
|
55
|
+
- spec/simpledb_adapter_spec.rb
|
56
|
+
- spec.opts
|
57
|
+
- spec_helper.rb
|
58
|
+
- README.txt
|
59
|
+
has_rdoc: true
|
60
|
+
homepage: http://github.com/jeremyboles/dm-adapter-simpledb
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --main
|
64
|
+
- README.txt
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.2.0
|
83
|
+
signing_key:
|
84
|
+
specification_version: 2
|
85
|
+
summary: A DatMapper adapter for SimpleDB
|
86
|
+
test_files:
|
87
|
+
- spec/simpledb_adapter_spec.rb
|
88
|
+
- spec.opts
|
89
|
+
- spec_helper.rb
|