sdb_dal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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