sdb_dal 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/sdb_dal/and_condition.rb +10 -0
- data/lib/sdb_dal/attribute_range.rb +57 -0
- data/lib/sdb_dal/domain_attribute_description.rb +83 -0
- data/lib/sdb_dal/domain_object.rb +642 -0
- data/lib/sdb_dal/domain_object_cache_item.rb +14 -0
- data/lib/sdb_dal/equals_condition.rb +18 -0
- data/lib/sdb_dal/geo.rb +188 -0
- data/lib/sdb_dal/index_description.rb +29 -0
- data/lib/sdb_dal/is_null_transform.rb +16 -0
- data/lib/sdb_dal/lazy_loading_text.rb +27 -0
- data/lib/sdb_dal/memory_repository.rb +168 -0
- data/lib/sdb_dal/memory_storage.rb +29 -0
- data/lib/sdb_dal/or_condition.rb +53 -0
- data/lib/sdb_dal/query_string_auth_generator.rb +166 -0
- data/lib/sdb_dal/reference.rb +28 -0
- data/lib/sdb_dal/repository.rb +366 -0
- data/lib/sdb_dal/s3.rb +594 -0
- data/lib/sdb_dal/sdb_formatter.rb +119 -0
- data/lib/sdb_dal/starts_with_condition.rb +21 -0
- data/lib/sdb_dal/storage.rb +188 -0
- data/lib/sdb_dal/tag_cloud.rb +56 -0
- data/lib/sdb_dal/tracker_description.rb +26 -0
- data/lib/sdb_dal.rb +8 -0
- metadata +75 -0
data/lib/sdb_dal/geo.rb
ADDED
@@ -0,0 +1,188 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
module Geo
|
4
|
+
|
5
|
+
class Location
|
6
|
+
|
7
|
+
|
8
|
+
attr_accessor :latitude
|
9
|
+
attr_accessor :longitude
|
10
|
+
|
11
|
+
def initialize(lat,lon)
|
12
|
+
self.latitude=lat
|
13
|
+
self.longitude=lon
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_address
|
17
|
+
if latitude==nil || longitude==nil
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
address='t'
|
21
|
+
right=0
|
22
|
+
top=0
|
23
|
+
width=180.0
|
24
|
+
height=90.0
|
25
|
+
16.times do
|
26
|
+
|
27
|
+
if latitude>top
|
28
|
+
top=top+height/2.0
|
29
|
+
if longitude<right
|
30
|
+
right=right-width/2.0
|
31
|
+
address<<'q'
|
32
|
+
else
|
33
|
+
right=right+width/2.0
|
34
|
+
address << 'r'
|
35
|
+
end
|
36
|
+
else
|
37
|
+
|
38
|
+
top=top-height/2.0
|
39
|
+
if longitude<right
|
40
|
+
right=right-width/2.0
|
41
|
+
address<<'t'
|
42
|
+
else
|
43
|
+
right=right+width/2.0
|
44
|
+
address << 's'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
width=width/2.0
|
48
|
+
height=height/2.0
|
49
|
+
# puts "#{address} w=#{width} h=#{height} r=#{right} t=#{top}"
|
50
|
+
end
|
51
|
+
return address
|
52
|
+
end
|
53
|
+
def get_nearby_addresses(zoom_level)
|
54
|
+
address=self.to_address
|
55
|
+
if address.length>(zoom_level+1)
|
56
|
+
address=address.slice(0,zoom_level+1)
|
57
|
+
end
|
58
|
+
|
59
|
+
result=[address]
|
60
|
+
|
61
|
+
tileWidth=360.0/(2**zoom_level)
|
62
|
+
tileHeight=180.0/(2**zoom_level)
|
63
|
+
|
64
|
+
other=Geo::Location.new(self.latitude+tileHeight,self.longitude+tileWidth)
|
65
|
+
result << other.to_address.slice(0,zoom_level+1)
|
66
|
+
|
67
|
+
other=Geo::Location.new(self.latitude+tileHeight,self.longitude)
|
68
|
+
result << other.to_address.slice(0,zoom_level+1)
|
69
|
+
|
70
|
+
other=Geo::Location.new(self.latitude+tileHeight,self.longitude-tileWidth)
|
71
|
+
result << other.to_address.slice(0,zoom_level+1)
|
72
|
+
|
73
|
+
other=Geo::Location.new(self.latitude-tileHeight,self.longitude+tileWidth)
|
74
|
+
result << other.to_address.slice(0,zoom_level+1)
|
75
|
+
|
76
|
+
other=Geo::Location.new(self.latitude-tileHeight,self.longitude)
|
77
|
+
result << other.to_address.slice(0,zoom_level+1)
|
78
|
+
|
79
|
+
other=Geo::Location.new(self.latitude-tileHeight,self.longitude-tileWidth)
|
80
|
+
result << other.to_address.slice(0,zoom_level+1)
|
81
|
+
|
82
|
+
|
83
|
+
other=Geo::Location.new(self.latitude,self.longitude+tileWidth)
|
84
|
+
result << other.to_address.slice(0,zoom_level+1)
|
85
|
+
|
86
|
+
other=Geo::Location.new(self.latitude,self.longitude-tileWidth)
|
87
|
+
result << other.to_address.slice(0,zoom_level+1)
|
88
|
+
|
89
|
+
|
90
|
+
end
|
91
|
+
def Location.to_location(address)
|
92
|
+
width=90.0
|
93
|
+
height=45.0
|
94
|
+
|
95
|
+
index=0
|
96
|
+
x=0
|
97
|
+
y=0
|
98
|
+
length=address.length-1
|
99
|
+
length.times do
|
100
|
+
index+=1
|
101
|
+
|
102
|
+
puts address[index].chr
|
103
|
+
case address[index].chr
|
104
|
+
|
105
|
+
when 'r'
|
106
|
+
x+=width
|
107
|
+
y+=height
|
108
|
+
when 'q'
|
109
|
+
x-=width
|
110
|
+
y+=height
|
111
|
+
|
112
|
+
when 't'
|
113
|
+
x-=width
|
114
|
+
y-=height
|
115
|
+
when 's'
|
116
|
+
x+=width
|
117
|
+
y-=height
|
118
|
+
end
|
119
|
+
width/=2
|
120
|
+
height/=2
|
121
|
+
end
|
122
|
+
loc=Location.new
|
123
|
+
loc.latitude=y
|
124
|
+
loc.longitude=x
|
125
|
+
return loc
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.deg2rad(deg)
|
129
|
+
(deg * Math::PI / 180)
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.rad2deg(rad)
|
133
|
+
(rad * 180 / Math::PI)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.acos(rad)
|
137
|
+
Math.atan2(Math.sqrt(1 - rad**2), rad)
|
138
|
+
end
|
139
|
+
|
140
|
+
def distance_in_miles( loc2)
|
141
|
+
lat2 = loc2.latitude
|
142
|
+
lon2 = loc2.longitude
|
143
|
+
theta = self.longitude - lon2
|
144
|
+
|
145
|
+
dist = Math.sin(self.deg2rad(self.latitude)) * Math.sin(deg2rad(lat2)) + Math.cos(self.deg2rad(self.latitude)) * Math.cos(self.deg2rad(lat2)) * Math.cos(deg2rad(theta))
|
146
|
+
|
147
|
+
dist = self.rad2deg(self.acos(dist))
|
148
|
+
|
149
|
+
(dist * 60 * 1.1515).round #distance in miles
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
#mixin
|
155
|
+
#locatable object must have latitude, longitude and address attributes
|
156
|
+
module Locatable
|
157
|
+
def location
|
158
|
+
return Geo::Location.new(latitude,longitude)
|
159
|
+
end
|
160
|
+
def get_nearby(zoom_level=7,order=nil)
|
161
|
+
if latitude==nil or longitude==nil
|
162
|
+
return []
|
163
|
+
end
|
164
|
+
result= self.class.find_near(self.location,zoom_level,order)
|
165
|
+
result.delete_if{|item|item.id==id}
|
166
|
+
return result
|
167
|
+
end
|
168
|
+
|
169
|
+
def find_near(loc,zoom_level=7,order_by=nil,order=:ascending)
|
170
|
+
nearby= loc.get_nearby_addresses(zoom_level)
|
171
|
+
|
172
|
+
address_params=[]
|
173
|
+
for address in nearby
|
174
|
+
|
175
|
+
address_params<<StartsWithCondition.new(self.AttributeDescription(:address),address)
|
176
|
+
|
177
|
+
end
|
178
|
+
orCondition=OrCondition.new(address_params)
|
179
|
+
|
180
|
+
return find(:all,:limit => 24,:order_by => order_by,:order => order,:conditions=>[orCondition])
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
module Xxx
|
185
|
+
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
class IndexDescription < DomainAttributeDescription
|
4
|
+
include SdbFormatter
|
5
|
+
attr_accessor :columns
|
6
|
+
|
7
|
+
|
8
|
+
def initialize(name,columns)
|
9
|
+
self.name=name
|
10
|
+
self.columns=columns
|
11
|
+
self.value_type =:string
|
12
|
+
self.is_primary_key=false
|
13
|
+
end
|
14
|
+
|
15
|
+
def format_index_entry(attribute_descriptions,attribute_values)
|
16
|
+
result=""
|
17
|
+
columns.each do |column|
|
18
|
+
if column.respond_to?(:transform)
|
19
|
+
result << column.transform(attribute_values[column.source_column] )
|
20
|
+
else
|
21
|
+
result<<attribute_descriptions[column].format_for_sdb(attribute_values[column]).to_s
|
22
|
+
end
|
23
|
+
result<<"&"
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
class IsNullTransform
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :source_column
|
6
|
+
def initialize(source_column )
|
7
|
+
self.source_column =source_column
|
8
|
+
self.name = "#{name}_is_null".to_sym
|
9
|
+
end
|
10
|
+
def transform(value)
|
11
|
+
value.nil?.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
|
4
|
+
class LazyLoadingText
|
5
|
+
attr_reader :is_dirty
|
6
|
+
attr_reader :has_loaded
|
7
|
+
def initialize(get_clob_proc)
|
8
|
+
@get_clob_proc=get_clob_proc
|
9
|
+
@has_loaded=false
|
10
|
+
@is_dirty=false
|
11
|
+
end
|
12
|
+
|
13
|
+
def value=(v)
|
14
|
+
@is_dirty=true
|
15
|
+
@has_loaded=true
|
16
|
+
@value=v
|
17
|
+
end
|
18
|
+
def value
|
19
|
+
if !@did_load
|
20
|
+
@value= @get_clob_proc.call
|
21
|
+
@has_loaded=true
|
22
|
+
end
|
23
|
+
return @value
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) +"/memory_storage.rb"
|
4
|
+
|
5
|
+
class MemoryRepository
|
6
|
+
attr_accessor :use_cache #this here just so interface matches sdb repo
|
7
|
+
attr_accessor :storage
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
sdb_domain= nil,
|
11
|
+
clob_bucket= nil,
|
12
|
+
aws_key_id= nil,
|
13
|
+
aws_secret_key= nil,
|
14
|
+
memcache_servers = nil ,
|
15
|
+
dummy=nil
|
16
|
+
)
|
17
|
+
@records={}
|
18
|
+
@storage=MemoryStorage.new
|
19
|
+
end
|
20
|
+
def clear_session_cache
|
21
|
+
|
22
|
+
end
|
23
|
+
def clear
|
24
|
+
@records={}
|
25
|
+
@storage=MemoryStorage.new
|
26
|
+
end
|
27
|
+
def save(table_name, primary_key, attributes)
|
28
|
+
key=make_cache_key(table_name,primary_key);
|
29
|
+
record=@records[key]
|
30
|
+
if !record
|
31
|
+
record={}
|
32
|
+
@records[key]=record
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
attributes.each do |description,value|
|
37
|
+
if description.is_clob
|
38
|
+
@storage.put("",make_clob_key(table_name,primary_key,description.name),value)
|
39
|
+
else
|
40
|
+
record[description.name]=value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
record["metadata%table_name"]=table_name
|
44
|
+
record["metadata%primary_key"]=primary_key
|
45
|
+
end
|
46
|
+
def query_ids(table_name,attribute_descriptions,options)
|
47
|
+
primary_key=nil
|
48
|
+
attribute_descriptions.each do |name,desc|
|
49
|
+
if desc.is_primary_key
|
50
|
+
primary_key= name.to_sym
|
51
|
+
break
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
objects=query(table_name,attribute_descriptions,options)
|
56
|
+
result=[]
|
57
|
+
objects.each do | o|
|
58
|
+
result<<o[primary_key]
|
59
|
+
end
|
60
|
+
result
|
61
|
+
end
|
62
|
+
|
63
|
+
def query(table_name,attribute_descriptions,options)
|
64
|
+
|
65
|
+
if options[:query]
|
66
|
+
raise 'query not supported yet'
|
67
|
+
end
|
68
|
+
|
69
|
+
result=[]
|
70
|
+
@records.each do |record_key,record|
|
71
|
+
ok=true
|
72
|
+
if record["metadata%table_name"]!=table_name
|
73
|
+
ok=false
|
74
|
+
else
|
75
|
+
if options.has_key?(:params)
|
76
|
+
|
77
|
+
options[:params].each do |param_key,param_value|
|
78
|
+
|
79
|
+
if param_value==:NOT_NULL
|
80
|
+
if record[param_key]==nil
|
81
|
+
ok=false
|
82
|
+
break
|
83
|
+
end
|
84
|
+
elsif param_value==:NULL
|
85
|
+
if record[param_key]!=nil
|
86
|
+
ok=false
|
87
|
+
break
|
88
|
+
end
|
89
|
+
elsif param_value.respond_to?(:matches?)
|
90
|
+
|
91
|
+
if !param_value.matches?(record[param_key])
|
92
|
+
ok=false
|
93
|
+
break
|
94
|
+
end
|
95
|
+
elsif !record[param_key] && !param_value
|
96
|
+
#ok
|
97
|
+
break
|
98
|
+
elsif record[param_key]!=param_value
|
99
|
+
ok=false
|
100
|
+
break
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
if options.has_key?(:conditions)
|
105
|
+
|
106
|
+
options[:conditions].each do |condition|
|
107
|
+
|
108
|
+
if !condition.matches?(record)
|
109
|
+
ok=false
|
110
|
+
break
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
if ok
|
116
|
+
result<<record
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
if options and options[:order_by]
|
122
|
+
result.sort! do |a,b|
|
123
|
+
a_value=a[options[:order_by]]
|
124
|
+
b_value=b[options[:order_by]]
|
125
|
+
if options[:order] && options[:order]!=:ascending
|
126
|
+
if b_value
|
127
|
+
b_value <=> a_value
|
128
|
+
else
|
129
|
+
-1
|
130
|
+
end
|
131
|
+
else
|
132
|
+
if a_value
|
133
|
+
a_value <=> b_value
|
134
|
+
else
|
135
|
+
-1
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
if options[:limit] and result.length>options[:limit]
|
141
|
+
result=result[0..options[:limit]-1]
|
142
|
+
end
|
143
|
+
return result
|
144
|
+
end
|
145
|
+
def find_one(table_name, primary_key,attribute_descriptions)#, non_clob_attribute_names, clob_attribute_names)
|
146
|
+
return @records[make_cache_key(table_name,primary_key)]
|
147
|
+
end
|
148
|
+
def get_clob(table_name,primary_key,clob_name)
|
149
|
+
return @storage.get("",make_clob_key(table_name,primary_key,clob_name))
|
150
|
+
|
151
|
+
end
|
152
|
+
def destroy(table_name, primary_key)
|
153
|
+
key=make_cache_key(table_name,primary_key);
|
154
|
+
|
155
|
+
if @records.has_key?(key)
|
156
|
+
@records.delete(key)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
def make_cache_key(table_name,primary_key)
|
162
|
+
return "cached_objects/#{table_name}/#{CGI.escape(primary_key.to_s)}"
|
163
|
+
end
|
164
|
+
def make_clob_key(table_name,primary_key,clob_name)
|
165
|
+
return "clobs/#{table_name}/#{CGI.escape(primary_key)}/#{clob_name}"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
|
4
|
+
class MemoryStorage
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@stuff={}
|
8
|
+
@attributes={}
|
9
|
+
end
|
10
|
+
def get(bucket,key)
|
11
|
+
return @stuff[bucket+"sdsdw555"+key]
|
12
|
+
|
13
|
+
end
|
14
|
+
def delete(bucket,key)
|
15
|
+
@attributes.delete(bucket+"sdsdw555"+key)
|
16
|
+
return @stuff.delete(bucket+"sdsdw555"+key)
|
17
|
+
|
18
|
+
end
|
19
|
+
def put(bucket,key,object,attributes=nil)
|
20
|
+
@stuff[bucket+"sdsdw555"+key]=object
|
21
|
+
@attributes[bucket+"sdsdw555"+key]=attributes if attributes
|
22
|
+
end
|
23
|
+
def get_content_type(bucket,key)
|
24
|
+
return @attributes[bucket+"sdsdw555"+key]['Content-Type'] if @attributes.has_key?(bucket+"sdsdw555"+key)
|
25
|
+
return nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
|
4
|
+
class OrCondition
|
5
|
+
attr_accessor :child_conditions
|
6
|
+
|
7
|
+
def initialize(child_conditions=[])
|
8
|
+
self.child_conditions=child_conditions
|
9
|
+
end
|
10
|
+
|
11
|
+
def add(child_condition)
|
12
|
+
self.child_conditions<<child_condition
|
13
|
+
end
|
14
|
+
|
15
|
+
def matches?(domain_object)
|
16
|
+
|
17
|
+
self.child_conditions.each do | condition|
|
18
|
+
if condition.respond_to?(:matches?)
|
19
|
+
if condition.matches?(domain_object)
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
def to_sdb_query
|
28
|
+
first =true
|
29
|
+
query=""
|
30
|
+
count=0
|
31
|
+
self.child_conditions.each do | condition|
|
32
|
+
count=count+1
|
33
|
+
if ! first
|
34
|
+
if count>4
|
35
|
+
query<< " ] union [ "
|
36
|
+
count=0
|
37
|
+
else
|
38
|
+
query<< " or "
|
39
|
+
end
|
40
|
+
end
|
41
|
+
first=false
|
42
|
+
|
43
|
+
if condition.respond_to?(:to_sdb_query)
|
44
|
+
|
45
|
+
query << condition.to_sdb_query
|
46
|
+
else
|
47
|
+
query << condition.to_s
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return query
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'cgi'
|
3
|
+
require 'openssl'
|
4
|
+
require 'digest/sha1'
|
5
|
+
require 'time'
|
6
|
+
module SdbDal
|
7
|
+
module S3
|
8
|
+
# This interface mirrors the AWSAuthConnection class, but instead
|
9
|
+
# of performing the operations, this class simply returns a url that can
|
10
|
+
# be used to perform the operation with the query string authentication
|
11
|
+
# parameters set.
|
12
|
+
# PLEASE NOTE - For security reasons, it is HIGHLY RECOMMENDED to avoid
|
13
|
+
# using product tokens in signed urls. Please see the README for
|
14
|
+
# further details.
|
15
|
+
class QueryStringAuthGenerator
|
16
|
+
attr_accessor :calling_format
|
17
|
+
attr_accessor :expires
|
18
|
+
attr_accessor :expires_in
|
19
|
+
attr_reader :server
|
20
|
+
attr_reader :port
|
21
|
+
|
22
|
+
# by default, expire in 1 minute
|
23
|
+
DEFAULT_EXPIRES_IN = 60
|
24
|
+
|
25
|
+
def initialize(aws_access_key_id, aws_secret_access_key, tokens=Array.new,
|
26
|
+
is_secure=true,
|
27
|
+
server=DEFAULT_HOST, port=PORTS_BY_SECURITY[is_secure],
|
28
|
+
format=CallingFormat::REGULAR)
|
29
|
+
@aws_access_key_id = aws_access_key_id
|
30
|
+
@aws_secret_access_key = aws_secret_access_key
|
31
|
+
@protocol = is_secure ? 'https' : 'http'
|
32
|
+
@server = server
|
33
|
+
@port = port
|
34
|
+
@calling_format = format
|
35
|
+
@tokens = tokens
|
36
|
+
# by default expire
|
37
|
+
@expires_in = DEFAULT_EXPIRES_IN
|
38
|
+
|
39
|
+
|
40
|
+
end
|
41
|
+
def tokens
|
42
|
+
@tokens
|
43
|
+
end
|
44
|
+
|
45
|
+
# set the expires value to be a fixed time. the argument can
|
46
|
+
# be either a Time object or else seconds since epoch.
|
47
|
+
def expires=(value)
|
48
|
+
@expires = value
|
49
|
+
@expires_in = nil
|
50
|
+
end
|
51
|
+
|
52
|
+
# set the expires value to expire at some point in the future
|
53
|
+
# relative to when the url is generated. value is in seconds.
|
54
|
+
def expires_in=(value)
|
55
|
+
@expires_in = value
|
56
|
+
@expires = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_bucket(bucket, headers={})
|
60
|
+
return generate_url('PUT', bucket, '', {}, headers)
|
61
|
+
end
|
62
|
+
|
63
|
+
# takes options :prefix, :marker, :max_keys, and :delimiter
|
64
|
+
def list_bucket(bucket, options={}, headers={})
|
65
|
+
path_args = {}
|
66
|
+
options.each { |k, v|
|
67
|
+
path_args[k] = v.to_s
|
68
|
+
}
|
69
|
+
return generate_url('GET', bucket, '', path_args, headers)
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_bucket(bucket, headers={})
|
73
|
+
return generate_url('DELETE', bucket, '', {}, headers)
|
74
|
+
end
|
75
|
+
|
76
|
+
# don't really care what object data is. it's just for conformance with the
|
77
|
+
# other interface. If this doesn't work, check tcpdump to see if the client is
|
78
|
+
# putting a Content-Type header on the wire.
|
79
|
+
def put(bucket, key, object=nil, headers={})
|
80
|
+
object = S3Object.new(object) if not object.instance_of? S3Object
|
81
|
+
return generate_url('PUT', bucket, CGI::escape(key), {}, merge_meta(headers, object))
|
82
|
+
end
|
83
|
+
|
84
|
+
def get(bucket, key, headers={})
|
85
|
+
return generate_url('GET', bucket, CGI::escape(key), {}, headers)
|
86
|
+
end
|
87
|
+
|
88
|
+
def delete(bucket, key, headers={})
|
89
|
+
return generate_url('DELETE', bucket, CGI::escape(key), {}, headers)
|
90
|
+
end
|
91
|
+
|
92
|
+
def get_bucket_logging(bucket, headers={})
|
93
|
+
return generate_url('GET', bucket, '', {'logging' => nil}, headers)
|
94
|
+
end
|
95
|
+
|
96
|
+
def put_bucket_logging(bucket, logging_xml_doc, headers={})
|
97
|
+
return generate_url('PUT', bucket, '', {'logging' => nil}, headers)
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_acl(bucket, key='', headers={})
|
101
|
+
return generate_url('GET', bucket, CGI::escape(key), {'acl' => nil}, headers)
|
102
|
+
end
|
103
|
+
|
104
|
+
def get_bucket_acl(bucket, headers={})
|
105
|
+
return get_acl(bucket, '', headers)
|
106
|
+
end
|
107
|
+
|
108
|
+
# don't really care what acl_xml_doc is.
|
109
|
+
# again, check the wire for Content-Type if this fails.
|
110
|
+
def put_acl(bucket, key, acl_xml_doc, headers={})
|
111
|
+
return generate_url('PUT', bucket, CGI::escape(key), {'acl' => nil}, headers)
|
112
|
+
end
|
113
|
+
|
114
|
+
def put_bucket_acl(bucket, acl_xml_doc, headers={})
|
115
|
+
return put_acl(bucket, '', acl_xml_doc, headers)
|
116
|
+
end
|
117
|
+
|
118
|
+
def list_all_my_buckets(headers={})
|
119
|
+
return generate_url('GET', '', '', {}, headers)
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
private
|
124
|
+
# generate a url with the appropriate query string authentication
|
125
|
+
# parameters set.
|
126
|
+
def generate_url(method, bucket="", key="", path_args={}, headers={})
|
127
|
+
expires = 0
|
128
|
+
if not @expires_in.nil?
|
129
|
+
expires = Time.now.to_i + @expires_in
|
130
|
+
elsif not @expires.nil?
|
131
|
+
expires = @expires
|
132
|
+
else
|
133
|
+
raise "invalid expires state"
|
134
|
+
end
|
135
|
+
if @tokens && !@tokens.empty?
|
136
|
+
headers[AMAZON_TOKEN_HEADER_PREFIX]=@tokens.join(',')
|
137
|
+
path_args[AMAZON_TOKEN_HEADER_PREFIX]=@tokens.join(',')
|
138
|
+
end
|
139
|
+
canonical_string =
|
140
|
+
S3::canonical_string(method, bucket, key, path_args, headers, expires)
|
141
|
+
encoded_canonical =
|
142
|
+
S3::encode(@aws_secret_access_key, canonical_string)
|
143
|
+
|
144
|
+
url = CallingFormat.build_url_base(@protocol, @server, @port, bucket, @calling_format)
|
145
|
+
|
146
|
+
path_args["Signature"] = encoded_canonical.to_s
|
147
|
+
path_args["Expires"] = expires.to_s
|
148
|
+
path_args["AWSAccessKeyId"] = @aws_access_key_id.to_s
|
149
|
+
|
150
|
+
arg_string = S3.path_args_hash_to_string(path_args)
|
151
|
+
|
152
|
+
return "#{url}/#{key}?#{arg_string}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def merge_meta(headers, object)
|
156
|
+
final_headers = headers.clone
|
157
|
+
if not object.nil? and not object.metadata.nil?
|
158
|
+
object.metadata.each do |k, v|
|
159
|
+
final_headers[METADATA_PREFIX + k] = v
|
160
|
+
end
|
161
|
+
end
|
162
|
+
return final_headers
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module SdbDal
|
2
|
+
|
3
|
+
|
4
|
+
class Reference
|
5
|
+
attr_accessor :target_class
|
6
|
+
attr_accessor :primary_key
|
7
|
+
attr_accessor :index
|
8
|
+
def initialize(options={})
|
9
|
+
if options.has_key?(:target)
|
10
|
+
self.target_class=options[:target].class.name.to_sym
|
11
|
+
self.primary_key=options[:target].primary_key
|
12
|
+
end
|
13
|
+
self.index=-1
|
14
|
+
if options.has_key?(:index)
|
15
|
+
self.index=options[:index]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def targets?(item)
|
19
|
+
return false unless item
|
20
|
+
self.target_class==item.class.name.to_sym and self.primary_key==item.primary_key
|
21
|
+
end
|
22
|
+
def get_target
|
23
|
+
the_class=Kernel.const_get(self.target_class)
|
24
|
+
the_class.find(self.primary_key)
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|