sdb_dal 0.0.1
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/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
|