simple_record 2.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/simple_record.rb CHANGED
@@ -46,412 +46,434 @@ require_relative 'simple_record/sharding'
46
46
 
47
47
  module SimpleRecord
48
48
 
49
- @@options = {}
50
- @@stats = SimpleRecord::Stats.new
51
- @@logging = false
52
- @@s3 = nil
53
- @@auto_close_s3 = false
54
- @@logger = Logger.new(STDOUT)
55
- @@logger.level = Logger::INFO
49
+ @@options = {}
50
+ @@stats = SimpleRecord::Stats.new
51
+ @@logging = false
52
+ @@s3 = nil
53
+ @@auto_close_s3 = false
54
+ @@logger = Logger.new(STDOUT)
55
+ @@logger.level = Logger::INFO
56
+
57
+ class << self;
58
+ attr_accessor :aws_access_key, :aws_secret_key
59
+
60
+ # Deprecated
61
+ def enable_logging
62
+ @@logging = true
63
+ @@logger.level = Logger::DEBUG
64
+ end
56
65
 
57
- class << self;
58
- attr_accessor :aws_access_key, :aws_secret_key
66
+ # Deprecated
67
+ def disable_logging
68
+ @@logging = false
69
+ end
59
70
 
60
- # Deprecated
61
- def enable_logging
62
- @@logging = true
63
- @@logger.level = Logger::DEBUG
64
- end
71
+ # Deprecated
72
+ def logging?
73
+ @@logging
74
+ end
65
75
 
66
- # Deprecated
67
- def disable_logging
68
- @@logging = false
69
- end
76
+ def logger
77
+ @@logger
78
+ end
70
79
 
71
- # Deprecated
72
- def logging?
73
- @@logging
74
- end
80
+ # This can be used to log queries and what not to a file.
81
+ # Params:
82
+ # :select=>{:filename=>"file_to_write_to", :format=>"csv"}
83
+ def log_usage(types={})
84
+ @usage_logging_options = {} unless @usage_logging_options
85
+ return if types.nil?
86
+ types.each_pair do |type, options|
87
+ options[:lines_between_flushes] = 100 unless options[:lines_between_flushes]
88
+ @usage_logging_options[type] = options
89
+ end
90
+ #puts 'SimpleRecord.usage_logging_options=' + SimpleRecord.usage_logging_options.inspect
91
+ end
75
92
 
76
- def logger
77
- @@logger
78
- end
93
+ def close_usage_log(type)
94
+ return unless @usage_logging_options[type]
95
+ @usage_logging_options[type][:file].close if @usage_logging_options[type][:file]
96
+ end
79
97
 
80
- # This can be used to log queries and what not to a file.
81
- # Params:
82
- # :select=>{:filename=>"file_to_write_to", :format=>"csv"}
83
- def log_usage(types={})
84
- @usage_logging_options = {} unless @usage_logging_options
85
- return if types.nil?
86
- types.each_pair do |type, options|
87
- options[:lines_between_flushes] = 100 unless options[:lines_between_flushes]
88
- @usage_logging_options[type] = options
89
- end
90
- #puts 'SimpleRecord.usage_logging_options=' + SimpleRecord.usage_logging_options.inspect
91
- end
98
+ def usage_logging_options
99
+ @usage_logging_options
100
+ end
92
101
 
93
- def close_usage_log(type)
94
- return unless @usage_logging_options[type]
95
- @usage_logging_options[type][:file].close if @usage_logging_options[type][:file]
96
- end
102
+ def stats
103
+ @@stats
104
+ end
97
105
 
98
- def usage_logging_options
99
- @usage_logging_options
100
- end
101
106
 
102
- def stats
103
- @@stats
104
- end
107
+ # Create a new handle to an Sdb account. All handles share the same per process or per thread
108
+ # HTTP connection to Amazon Sdb. Each handle is for a specific account.
109
+ # The +params+ are passed through as-is to Aws::SdbInterface.new
110
+ # Params:
111
+ # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
112
+ # :port => 443 # Amazon service port: 80(default) or 443
113
+ # :protocol => 'https' # Amazon service protocol: 'http'(default) or 'https'
114
+ # :signature_version => '0' # The signature version : '0' or '1'(default)
115
+ # :connection_mode => :default # options are
116
+ # :default (will use best known safe (as in won't need explicit close) option, may change in the future)
117
+ # :per_request (opens and closes a connection on every request to SDB)
118
+ # :single (one thread across entire app)
119
+ # :per_thread (one connection per thread)
120
+ # :pool (uses a connection pool with a maximum number of connections - NOT IMPLEMENTED YET)
121
+ # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
122
+ def establish_connection(aws_access_key=nil, aws_secret_key=nil, options={})
123
+ @aws_access_key = aws_access_key
124
+ @aws_secret_key = aws_secret_key
125
+ @@options.merge!(options)
126
+ #puts 'SimpleRecord.establish_connection with options: ' + @@options.inspect
127
+ SimpleRecord::ActiveSdb.establish_connection(aws_access_key, aws_secret_key, @@options)
128
+ if options[:connection_mode] == :per_thread
129
+ @@auto_close_s3 = true
130
+ # todo: should we init this only when needed?
131
+ end
132
+ s3_ops = {:connection_mode=>options[:connection_mode] || :default}
133
+ @@s3 = Aws::S3.new(SimpleRecord.aws_access_key, SimpleRecord.aws_secret_key, s3_ops)
134
+
135
+ if options[:created_col]
136
+ SimpleRecord::Base.has_dates options[:created_col]
137
+ end
138
+ if options[:updated_col]
139
+ SimpleRecord::Base.has_dates options[:updated_col]
140
+ end
105
141
 
106
142
 
107
- # Create a new handle to an Sdb account. All handles share the same per process or per thread
108
- # HTTP connection to Amazon Sdb. Each handle is for a specific account.
109
- # The +params+ are passed through as-is to Aws::SdbInterface.new
110
- # Params:
111
- # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
112
- # :port => 443 # Amazon service port: 80(default) or 443
113
- # :protocol => 'https' # Amazon service protocol: 'http'(default) or 'https'
114
- # :signature_version => '0' # The signature version : '0' or '1'(default)
115
- # :connection_mode => :default # options are
116
- # :default (will use best known safe (as in won't need explicit close) option, may change in the future)
117
- # :per_request (opens and closes a connection on every request to SDB)
118
- # :single (one thread across entire app)
119
- # :per_thread (one connection per thread)
120
- # :pool (uses a connection pool with a maximum number of connections - NOT IMPLEMENTED YET)
121
- # :logger => Logger Object # Logger instance: logs to STDOUT if omitted
122
- def establish_connection(aws_access_key=nil, aws_secret_key=nil, options={})
123
- @aws_access_key = aws_access_key
124
- @aws_secret_key = aws_secret_key
125
- @@options.merge!(options)
126
- #puts 'SimpleRecord.establish_connection with options: ' + @@options.inspect
127
- SimpleRecord::ActiveSdb.establish_connection(aws_access_key, aws_secret_key, @@options)
128
- if options[:connection_mode] == :per_thread
129
- @@auto_close_s3 = true
130
- # todo: should we init this only when needed?
131
- end
132
- s3_ops = {:connection_mode=>options[:connection_mode] || :default}
133
- @@s3 = Aws::S3.new(SimpleRecord.aws_access_key, SimpleRecord.aws_secret_key, s3_ops)
134
- end
135
-
136
- # Call this to close the connection to SimpleDB.
137
- # If you're using this in Rails with per_thread connection mode, you should do this in
138
- # an after_filter for each request.
139
- def close_connection()
140
- SimpleRecord::ActiveSdb.close_connection
141
- @@s3.close_connection if @@auto_close_s3
142
- end
143
+ end
143
144
 
144
- # If you'd like to specify the s3 connection to use for LOBs, you can pass it in here.
145
- # We recommend that this connection matches the type of connection you're using for SimpleDB,
146
- # at least if you're using per_thread connection mode.
147
- def s3=(s3)
148
- @@s3 = s3
149
- end
145
+ # Call this to close the connection to SimpleDB.
146
+ # If you're using this in Rails with per_thread connection mode, you should do this in
147
+ # an after_filter for each request.
148
+ def close_connection()
149
+ SimpleRecord::ActiveSdb.close_connection
150
+ @@s3.close_connection if @@auto_close_s3
151
+ end
150
152
 
151
- def s3
152
- @@s3
153
- end
153
+ # If you'd like to specify the s3 connection to use for LOBs, you can pass it in here.
154
+ # We recommend that this connection matches the type of connection you're using for SimpleDB,
155
+ # at least if you're using per_thread connection mode.
156
+ def s3=(s3)
157
+ @@s3 = s3
158
+ end
154
159
 
155
- def options
156
- @@options
157
- end
160
+ def s3
161
+ @@s3
162
+ end
158
163
 
164
+ def options
165
+ @@options
159
166
  end
160
167
 
161
- class Base < SimpleRecord::ActiveSdb::Base
168
+ end
169
+
170
+ class Base < SimpleRecord::ActiveSdb::Base
162
171
 
163
172
 
164
173
  # puts 'Is ActiveModel defined? ' + defined?(ActiveModel).inspect
165
- if defined?(ActiveModel)
166
- extend ActiveModel::Naming
167
- include ActiveModel::Conversion
168
- include ActiveModel::Validations
169
- else
170
- attr_accessor :errors
171
- include SimpleRecord::Rails2
172
- end
174
+ if defined?(ActiveModel)
175
+ extend ActiveModel::Naming
176
+ include ActiveModel::Conversion
177
+ include ActiveModel::Validations
178
+ else
179
+ attr_accessor :errors
180
+ include SimpleRecord::Rails2
181
+ end
173
182
 
174
- include SimpleRecord::Translations
183
+ include SimpleRecord::Translations
175
184
  # include SimpleRecord::Attributes
176
- extend SimpleRecord::Attributes::ClassMethods
177
- include SimpleRecord::Attributes
178
- extend SimpleRecord::Sharding::ClassMethods
179
- include SimpleRecord::Sharding
180
- include SimpleRecord::Callbacks
181
- include SimpleRecord::Json
182
- include SimpleRecord::Logging
183
- extend SimpleRecord::Logging::ClassMethods
185
+ extend SimpleRecord::Attributes::ClassMethods
186
+ include SimpleRecord::Attributes
187
+ extend SimpleRecord::Sharding::ClassMethods
188
+ include SimpleRecord::Sharding
189
+ include SimpleRecord::Callbacks
190
+ include SimpleRecord::Json
191
+ include SimpleRecord::Logging
192
+ extend SimpleRecord::Logging::ClassMethods
184
193
 
185
- def self.extended(base)
194
+ def self.extended(base)
186
195
 
187
- end
196
+ end
188
197
 
189
- def initialize(attrs={})
190
- # todo: Need to deal with objects passed in. iterate through belongs_to perhaps and if in attrs, set the objects id rather than the object itself
198
+ def initialize(attrs={})
199
+ # todo: Need to deal with objects passed in. iterate through belongs_to perhaps and if in attrs, set the objects id rather than the object itself
191
200
 
192
- initialize_base(attrs)
201
+ initialize_base(attrs)
193
202
 
194
- # Convert attributes to sdb values
195
- attrs.each_pair do |name, value|
196
- set(name, value, true)
197
- end
198
- end
203
+ # Convert attributes to sdb values
204
+ attrs.each_pair do |name, value|
205
+ set(name, value, true)
206
+ end
207
+ end
199
208
 
200
- def initialize_base(attrs={})
209
+ def initialize_base(attrs={})
201
210
 
202
- #we have to handle the virtuals.
203
- Attributes.handle_virtuals(attrs)
211
+ #we have to handle the virtuals.
212
+ Attributes.handle_virtuals(attrs)
204
213
 
205
- @errors=SimpleRecord_errors.new if not (defined?(ActiveModel))
206
- @dirty = {}
214
+ clear_errors
207
215
 
208
- @attributes = {} # sdb values
209
- @attributes_rb = {} # ruby values
210
- @lobs = {}
211
- @new_record = true
216
+ @dirty = {}
212
217
 
213
- end
218
+ @attributes = {} # sdb values
219
+ @attributes_rb = {} # ruby values
220
+ @lobs = {}
221
+ @new_record = true
214
222
 
215
- def initialize_from_db(attrs={})
216
- initialize_base(attrs)
217
- attrs.each_pair do |k, v|
218
- @attributes[k.to_s] = v
219
- end
220
- end
223
+ end
224
+
225
+ def initialize_from_db(attrs={})
226
+ initialize_base(attrs)
227
+ attrs.each_pair do |k, v|
228
+ @attributes[k.to_s] = v
229
+ end
230
+ end
221
231
 
222
232
 
223
- def self.inherited(base)
224
- #puts 'SimpleRecord::Base is inherited by ' + base.inspect
225
- Callbacks.setup_callbacks(base)
233
+ def self.inherited(base)
234
+ # puts 'SimpleRecord::Base is inherited by ' + base.inspect
235
+ Callbacks.setup_callbacks(base)
226
236
 
227
237
  # base.has_strings :id
228
- base.has_dates :created, :updated
229
- base.before_create :set_created, :set_updated
230
- base.before_update :set_updated
238
+ base.has_dates :created, :updated
239
+ base.before_create :set_created, :set_updated
240
+ base.before_update :set_updated
231
241
 
232
- end
242
+ end
233
243
 
234
244
 
235
- def persisted?
236
- true
237
- end
245
+ def persisted?
246
+ !@new_record && !destroyed?
247
+ end
238
248
 
249
+ def destroyed?
250
+ @deleted
251
+ end
239
252
 
240
- def defined_attributes_local
241
- # todo: store this somewhere so it doesn't keep going through this
242
- ret = self.class.defined_attributes
243
- ret.merge!(self.class.superclass.defined_attributes) if self.class.superclass.respond_to?(:defined_attributes)
244
- end
253
+ def defined_attributes_local
254
+ # todo: store this somewhere so it doesn't keep going through this
255
+ ret = self.class.defined_attributes
256
+ ret.merge!(self.class.superclass.defined_attributes) if self.class.superclass.respond_to?(:defined_attributes)
257
+ end
245
258
 
246
259
 
247
- class << self;
248
- attr_accessor :domain_prefix
249
- end
260
+ class << self;
261
+ attr_accessor :domain_prefix
262
+ end
250
263
 
251
- #@domain_name_for_class = nil
264
+ #@domain_name_for_class = nil
252
265
 
253
- @@cache_store = nil
254
- # Set the cache to use
255
- def self.cache_store=(cache)
256
- @@cache_store = cache
257
- end
266
+ @@cache_store = nil
267
+ # Set the cache to use
268
+ def self.cache_store=(cache)
269
+ @@cache_store = cache
270
+ end
258
271
 
259
- def self.cache_store
260
- return @@cache_store
261
- end
272
+ def self.cache_store
273
+ return @@cache_store
274
+ end
262
275
 
263
- # If you want a domain prefix for all your models, set it here.
264
- def self.set_domain_prefix(prefix)
265
- #puts 'set_domain_prefix=' + prefix
266
- self.domain_prefix = prefix
267
- end
276
+ # If you want a domain prefix for all your models, set it here.
277
+ def self.set_domain_prefix(prefix)
278
+ #puts 'set_domain_prefix=' + prefix
279
+ self.domain_prefix = prefix
280
+ end
268
281
 
269
- # Same as set_table_name
270
- def self.set_table_name(table_name)
271
- set_domain_name table_name
272
- end
282
+ # Same as set_table_name
283
+ def self.set_table_name(table_name)
284
+ set_domain_name table_name
285
+ end
273
286
 
274
- # Sets the domain name for this class
275
- def self.set_domain_name(table_name)
276
- super
277
- end
287
+ # Sets the domain name for this class
288
+ def self.set_domain_name(table_name)
289
+ super
290
+ end
278
291
 
279
292
 
280
- def domain
281
- self.class.domain
282
- end
293
+ def domain
294
+ self.class.domain
295
+ end
283
296
 
284
- def self.domain
285
- unless @domain
286
- # This strips off the module if there is one.
287
- n2 = name.split('::').last || name
297
+ def self.domain
298
+ unless @domain
299
+ # This strips off the module if there is one.
300
+ n2 = name.split('::').last || name
288
301
  # puts 'n2=' + n2
289
- if n2.respond_to?(:tableize)
290
- @domain = n2.tableize
291
- else
292
- @domain = n2.downcase
293
- end
294
- set_domain_name @domain
295
- end
296
- domain_name_for_class = (SimpleRecord::Base.domain_prefix || "") + @domain.to_s
297
- domain_name_for_class
302
+ if n2.respond_to?(:tableize)
303
+ @domain = n2.tableize
304
+ else
305
+ @domain = n2.downcase
298
306
  end
307
+ set_domain_name @domain
308
+ end
309
+ domain_name_for_class = (SimpleRecord::Base.domain_prefix || "") + @domain.to_s
310
+ domain_name_for_class
311
+ end
299
312
 
300
- def has_id_on_end(name_s)
301
- name_s = name_s.to_s
302
- name_s.length > 3 && name_s[-3..-1] == "_id"
303
- end
313
+ def has_id_on_end(name_s)
314
+ name_s = name_s.to_s
315
+ name_s.length > 3 && name_s[-3..-1] == "_id"
316
+ end
304
317
 
305
- def get_att_meta(name)
306
- name_s = name.to_s
307
- att_meta = defined_attributes_local[name.to_sym]
308
- if att_meta.nil? && has_id_on_end(name_s)
309
- att_meta = defined_attributes_local[name_s[0..-4].to_sym]
310
- end
311
- return att_meta
312
- end
318
+ def get_att_meta(name)
319
+ name_s = name.to_s
320
+ att_meta = defined_attributes_local[name.to_sym]
321
+ if att_meta.nil? && has_id_on_end(name_s)
322
+ att_meta = defined_attributes_local[name_s[0..-4].to_sym]
323
+ end
324
+ return att_meta
325
+ end
313
326
 
314
- def sdb_att_name(name)
315
- att_meta = get_att_meta(name)
316
- if att_meta.type == :belongs_to && !has_id_on_end(name.to_s)
317
- return "#{name}_id"
318
- end
319
- name.to_s
320
- end
327
+ def sdb_att_name(name)
328
+ att_meta = get_att_meta(name)
329
+ if att_meta.type == :belongs_to && !has_id_on_end(name.to_s)
330
+ return "#{name}_id"
331
+ end
332
+ name.to_s
333
+ end
321
334
 
322
- def strip_array(arg)
323
- if arg.is_a? Array
324
- if arg.length==1
325
- ret = arg[0]
326
- else
327
- ret = arg
328
- end
329
- else
330
- ret = arg
331
- end
332
- return ret
335
+ def strip_array(arg)
336
+ if arg.is_a? Array
337
+ if arg.length==1
338
+ ret = arg[0]
339
+ else
340
+ ret = arg
333
341
  end
342
+ else
343
+ ret = arg
344
+ end
345
+ return ret
346
+ end
334
347
 
335
348
 
336
- def make_dirty(arg, value)
337
- sdb_att_name = sdb_att_name(arg)
338
- arg = arg.to_s
349
+ def make_dirty(arg, value)
350
+ sdb_att_name = sdb_att_name(arg)
351
+ arg = arg.to_s
339
352
 
340
353
  # puts "Marking #{arg} dirty with #{value}" if SimpleRecord.logging?
341
- if @dirty.include?(sdb_att_name)
342
- old = @dirty[sdb_att_name]
354
+ if @dirty.include?(sdb_att_name)
355
+ old = @dirty[sdb_att_name]
343
356
  # puts "#{sdb_att_name} was already dirty #{old}"
344
- @dirty.delete(sdb_att_name) if value == old
345
- else
346
- old = get_attribute(arg)
357
+ @dirty.delete(sdb_att_name) if value == old
358
+ else
359
+ old = get_attribute(arg)
347
360
  # puts "dirtifying #{sdb_att_name} old=#{old.inspect} to new=#{value.inspect}" if SimpleRecord.logging?
348
- @dirty[sdb_att_name] = old if value != old
349
- end
350
- end
361
+ @dirty[sdb_att_name] = old if value != old
362
+ end
363
+ end
351
364
 
352
- def clear_errors
353
- @errors=SimpleRecord_errors.new
354
- end
365
+ def clear_errors
366
+ # @errors=SimpleRecord_errors.new
367
+ if not (defined?(ActiveModel))
368
+ @errors=SimpleRecord_errors.new
369
+ else
370
+ @errors = ActiveModel::Errors.new(self)
371
+ end
372
+ end
355
373
 
356
- def []=(attribute, values)
357
- make_dirty(attribute, values)
358
- super
359
- end
374
+ def []=(attribute, values)
375
+ make_dirty(attribute, values)
376
+ super
377
+ end
360
378
 
361
- def [](attribute)
362
- super
363
- end
379
+ def [](attribute)
380
+ super
381
+ end
364
382
 
365
383
 
366
- def set_created
367
- set(:created, Time.now)
368
- end
384
+ def set_created
385
+ set(SimpleRecord.options[:created_col] || :created, Time.now)
386
+ end
369
387
 
370
- def set_updated
371
- set(:updated, Time.now)
372
- end
388
+ def set_updated
389
+ set(SimpleRecord.options[:updated_col] || :updated, Time.now)
390
+ end
373
391
 
374
- # an aliased method since many people use created_at/updated_at naming convention
375
- def created_at
376
- self.created
377
- end
392
+ # an aliased method since many people use created_at/updated_at naming convention
393
+ def created_at
394
+ self.created
395
+ end
378
396
 
379
- # an aliased method since many people use created_at/updated_at naming convention
380
- def updated_at
381
- self.updated
382
- end
397
+ # an aliased method since many people use created_at/updated_at naming convention
398
+ def updated_at
399
+ self.updated
400
+ end
383
401
 
384
- def cache_store
385
- @@cache_store
386
- end
402
+ def read_attribute_for_validation(key)
403
+ @attributes[key.to_s]
404
+ end
387
405
 
388
- def domain_ok(ex, options={})
389
- if (ex.message().index("NoSuchDomain") != nil)
390
- dom = options[:domain] || domain
391
- self.class.create_domain(dom)
392
- return true
393
- end
394
- return false
395
- end
406
+ def cache_store
407
+ @@cache_store
408
+ end
396
409
 
410
+ def domain_ok(ex, options={})
411
+ if (ex.message().index("NoSuchDomain") != nil)
412
+ dom = options[:domain] || domain
413
+ self.class.create_domain(dom)
414
+ return true
415
+ end
416
+ return false
417
+ end
397
418
 
398
- def new_record?
399
- # todo: new_record in activesdb should align with how we're defining a new record here, ie: if id is nil
400
- super
401
- end
419
+
420
+ def new_record?
421
+ # todo: new_record in activesdb should align with how we're defining a new record here, ie: if id is nil
422
+ super
423
+ end
402
424
 
403
425
 
404
- @create_domain_called = false
426
+ @create_domain_called = false
405
427
 
406
- # Options:
407
- # - :except => Array of attributes to NOT save
408
- # - :dirty => true - Will only store attributes that were modified. To make it save regardless and have it update the :updated value, include this and set it to false.
409
- # - :domain => Explicitly define domain to use.
410
- #
411
- def save(options={})
428
+ # Options:
429
+ # - :except => Array of attributes to NOT save
430
+ # - :dirty => true - Will only store attributes that were modified. To make it save regardless and have it update the :updated value, include this and set it to false.
431
+ # - :domain => Explicitly define domain to use.
432
+ #
433
+ def save(options={})
412
434
  # puts 'SAVING: ' + self.inspect if SimpleRecord.logging?
413
- # todo: Clean out undefined values in @attributes (in case someone set the attributes hash with values that they hadn't defined)
414
- clear_errors
415
- # todo: decide whether this should go before pre_save or after pre_save? pre_save dirties "updated" and perhaps other items due to callbacks
416
- if options[:dirty]
435
+ # todo: Clean out undefined values in @attributes (in case someone set the attributes hash with values that they hadn't defined)
436
+ clear_errors
437
+ # todo: decide whether this should go before pre_save or after pre_save? pre_save dirties "updated" and perhaps other items due to callbacks
438
+ if options[:dirty]
417
439
  # puts '@dirtyA=' + @dirty.inspect
418
- return true if @dirty.size == 0 # Nothing to save so skip it
419
- end
420
- is_create = self[:id].nil?
421
- ok = pre_save(options) # Validates and sets ID
422
- if ok
423
- begin
424
- dirty = @dirty
440
+ return true if @dirty.size == 0 # Nothing to save so skip it
441
+ end
442
+ is_create = self[:id].nil?
443
+ ok = pre_save(options) # Validates and sets ID
444
+ if ok
445
+ begin
446
+ dirty = @dirty
425
447
  # puts 'dirty before=' + @dirty.inspect
426
- if options[:dirty]
448
+ if options[:dirty]
427
449
  # puts '@dirty=' + @dirty.inspect
428
- return true if @dirty.size == 0 # This should probably never happen because after pre_save, created/updated dates are changed
429
- options[:dirty_atts] = @dirty
430
- end
431
- to_delete = get_atts_to_delete
432
- SimpleRecord.stats.saves += 1
433
-
434
- if self.class.is_sharded?
435
- options[:domain] = sharded_domain
436
- end
437
-
438
- if super(options)
439
- self.class.cache_results(self)
440
- delete_niled(to_delete)
441
- save_lobs(dirty)
442
- after_save_cleanup
443
- if (is_create ? run_after_create : run_after_update) && run_after_save
450
+ return true if @dirty.size == 0 # This should probably never happen because after pre_save, created/updated dates are changed
451
+ options[:dirty_atts] = @dirty
452
+ end
453
+ to_delete = get_atts_to_delete
454
+ SimpleRecord.stats.saves += 1
455
+
456
+ if self.class.is_sharded?
457
+ options[:domain] = sharded_domain
458
+ end
459
+
460
+ if super(options)
461
+ self.class.cache_results(self)
462
+ delete_niled(to_delete)
463
+ save_lobs(dirty)
464
+ after_save_cleanup
465
+ if (is_create ? run_after_create : run_after_update) && run_after_save
444
466
  # puts 'all good?'
445
- return true
446
- else
447
- return false
448
- end
449
- else
450
- return false
451
- end
452
- rescue Aws::AwsError => ex
453
- # puts "RESCUED in save: " + $!
454
- # Domain is created in aws lib now using :create_domain=>true
467
+ return true
468
+ else
469
+ return false
470
+ end
471
+ else
472
+ return false
473
+ end
474
+ rescue Aws::AwsError => ex
475
+ # puts "RESCUED in save: " + $!
476
+ # Domain is created in aws lib now using :create_domain=>true
455
477
  # if (domain_ok(ex, options))
456
478
  # if !@create_domain_called
457
479
  # @create_domain_called = true
@@ -462,201 +484,218 @@ module SimpleRecord
462
484
  # else
463
485
  # raise $!
464
486
  # end
465
- raise ex
466
- end
467
- else
468
- #@debug = "not saved"
469
- return false
470
- end
487
+ raise ex
471
488
  end
489
+ else
490
+ #@debug = "not saved"
491
+ return false
492
+ end
493
+ end
472
494
 
473
- def save_lobs(dirty=nil)
495
+ def save_lobs(dirty=nil)
474
496
  # puts 'dirty.inspect=' + dirty.inspect
475
- dirty = @dirty if dirty.nil?
476
- all_clobs = {}
477
- dirty_clobs = {}
478
- defined_attributes_local.each_pair do |k, v|
479
- # collect up the clobs in case it's a single put
480
- if v.type == :clob
481
- val = @lobs[k]
482
- all_clobs[k] = val
483
- if dirty.include?(k.to_s)
484
- dirty_clobs[k] = val
485
- else
497
+ dirty = @dirty if dirty.nil?
498
+ all_clobs = {}
499
+ dirty_clobs = {}
500
+ defined_attributes_local.each_pair do |k, v|
501
+ # collect up the clobs in case it's a single put
502
+ if v.type == :clob
503
+ val = @lobs[k]
504
+ all_clobs[k] = val
505
+ if dirty.include?(k.to_s)
506
+ dirty_clobs[k] = val
507
+ else
486
508
  # puts 'NOT DIRTY'
487
- end
509
+ end
488
510
 
489
- end
490
- end
491
- if dirty_clobs.size > 0
492
- if self.class.get_sr_config[:single_clob]
493
- # all clobs in one chunk
494
- # using json for now, could change later
495
- val = all_clobs.to_json
496
- puts 'val=' + val.inspect
497
- put_lob(single_clob_id, val, :new_bucket=>true)
498
- else
499
- dirty_clobs.each_pair do |k, val|
500
- put_lob(s3_lob_id(k), val)
501
- end
502
- end
503
- end
504
511
  end
505
-
506
- def delete_lobs
507
- defined_attributes_local.each_pair do |k, v|
508
- if v.type == :clob
509
- if self.class.get_sr_config[:single_clob]
510
- s3_bucket(false, :new_bucket=>true).delete_key(single_clob_id)
511
- SimpleRecord.stats.s3_deletes += 1
512
- return
513
- else
514
- s3_bucket.delete_key(s3_lob_id(k))
515
- SimpleRecord.stats.s3_deletes += 1
516
- end
517
- end
518
- end
512
+ end
513
+ if dirty_clobs.size > 0
514
+ if self.class.get_sr_config[:single_clob]
515
+ # all clobs in one chunk
516
+ # using json for now, could change later
517
+ val = all_clobs.to_json
518
+ puts 'val=' + val.inspect
519
+ put_lob(single_clob_id, val, :s3_bucket=>:new)
520
+ else
521
+ dirty_clobs.each_pair do |k, val|
522
+ put_lob(s3_lob_id(k), val)
523
+ end
519
524
  end
525
+ end
526
+ end
520
527
 
528
+ def delete_lobs
529
+ defined_attributes_local.each_pair do |k, v|
530
+ if v.type == :clob
531
+ if self.class.get_sr_config[:single_clob]
532
+ s3_bucket(false, :s3_bucket=>:new).delete_key(single_clob_id)
533
+ SimpleRecord.stats.s3_deletes += 1
534
+ return
535
+ else
536
+ s3_bucket.delete_key(s3_lob_id(k))
537
+ SimpleRecord.stats.s3_deletes += 1
538
+ end
539
+ end
540
+ end
541
+ end
521
542
 
522
- def put_lob(k, val, options={})
523
- begin
524
- s3_bucket(false, options).put(k, val)
525
- rescue Aws::AwsError => ex
526
- if ex.include? /NoSuchBucket/
527
- s3_bucket(true, options).put(k, val)
528
- else
529
- raise ex
530
- end
531
- end
532
- SimpleRecord.stats.s3_puts += 1
543
+
544
+ def put_lob(k, val, options={})
545
+ begin
546
+ s3_bucket(false, options).put(k, val)
547
+ rescue Aws::AwsError => ex
548
+ if ex.include? /NoSuchBucket/
549
+ s3_bucket(true, options).put(k, val)
550
+ else
551
+ raise ex
533
552
  end
553
+ end
554
+ SimpleRecord.stats.s3_puts += 1
555
+ end
534
556
 
535
557
 
536
- def is_dirty?(name)
537
- # todo: should change all the dirty stuff to symbols?
558
+ def is_dirty?(name)
559
+ # todo: should change all the dirty stuff to symbols?
538
560
  # puts '@dirty=' + @dirty.inspect
539
561
  # puts 'name=' +name.to_s
540
- @dirty.include? name.to_s
541
- end
562
+ @dirty.include? name.to_s
563
+ end
542
564
 
543
- def s3
565
+ def s3
544
566
 
545
- return SimpleRecord.s3 if SimpleRecord.s3
546
- # todo: should optimize this somehow, like use the same connection_mode as used in SR
547
- # or keep open while looping in ResultsArray.
548
- Aws::S3.new(SimpleRecord.aws_access_key, SimpleRecord.aws_secret_key)
549
- end
567
+ return SimpleRecord.s3 if SimpleRecord.s3
568
+ # todo: should optimize this somehow, like use the same connection_mode as used in SR
569
+ # or keep open while looping in ResultsArray.
570
+ Aws::S3.new(SimpleRecord.aws_access_key, SimpleRecord.aws_secret_key)
571
+ end
550
572
 
551
- # options:
552
- # :new_bucket => true/false. True if want to use new bucket. Defaults to false for backwards compatability.
553
- def s3_bucket(create=false, options={})
554
- s3.bucket(options[:new_bucket] || SimpleRecord.options[:new_bucket] ? s3_bucket_name2 : s3_bucket_name, create)
555
- end
573
+ # options:
574
+ # :s3_bucket => :old/:new/"#{any_bucket_name}". :new if want to use new bucket. Defaults to :old for backwards compatability.
575
+ def s3_bucket(create=false, options={})
576
+ s3.bucket(s3_bucket_name(options[:s3_bucket]), create)
577
+ end
556
578
 
579
+ def s3_bucket_name(s3_bucket_option=:old)
580
+ if s3_bucket_option == :new || SimpleRecord.options[:s3_bucket] == :new
557
581
  # this is the bucket that will be used going forward for anything related to s3
558
- def s3_bucket_name2
559
- "simple_record_#{SimpleRecord.aws_access_key}"
560
- end
582
+ ret = "simple_record_#{SimpleRecord.aws_access_key}"
583
+ elsif !SimpleRecord.options[:s3_bucket].nil? && SimpleRecord.options[:s3_bucket] != :old
584
+ ret = SimpleRecord.options[:s3_bucket]
585
+ else
586
+ ret = SimpleRecord.aws_access_key + "_lobs"
587
+ end
588
+ ret
589
+ end
561
590
 
562
- def s3_bucket_name
563
- SimpleRecord.aws_access_key + "_lobs"
564
- end
591
+ def s3_lob_id(name)
592
+ # if s3_bucket is not nil and not :old, then we use the new key.
593
+ if !SimpleRecord.options[:s3_bucket].nil? && SimpleRecord.options[:s3_bucket] != :old
594
+ "lobs/#{self.id}_#{name}"
595
+ else
596
+ self.id + "_" + name.to_s
597
+ end
598
+ end
565
599
 
566
- def s3_lob_id(name)
567
- if SimpleRecord.options[:new_bucket]
568
- "lobs/#{self.id}_#{name}"
569
- else
570
- self.id + "_" + name.to_s
571
- end
572
- end
600
+ def single_clob_id
601
+ "lobs/#{self.id}_single_clob"
602
+ end
573
603
 
574
- def single_clob_id
575
- "lobs/#{self.id}_single_clob"
576
- end
604
+ def save!(options={})
605
+ save(options) || raise(RecordNotSaved)
606
+ end
577
607
 
578
- def save!(options={})
579
- save(options) || raise(RecordNotSaved)
580
- end
608
+ def self.create(attributes={})
609
+ # puts "About to create in domain #{domain}"
610
+ super
611
+ end
581
612
 
582
- def save_with_validation!(options={})
583
- if valid?
584
- save
585
- else
586
- raise RecordInvalid.new(self)
587
- end
588
- end
613
+ def self.create!(attributes={})
614
+ item = self.new(attributes)
615
+ item.save!
616
+ item
617
+ end
618
+
619
+ def save_with_validation!(options={})
620
+ if valid?
621
+ save
622
+ else
623
+ raise RecordInvalid.new(self)
624
+ end
625
+ end
589
626
 
590
627
 
591
- def self.get_encryption_key()
592
- key = SimpleRecord.options[:encryption_key]
628
+ def self.get_encryption_key()
629
+ key = SimpleRecord.options[:encryption_key]
593
630
  # if key.nil?
594
631
  # puts 'WARNING: Encrypting attributes with your AWS Access Key. You should use your own :encryption_key so it doesn\'t change'
595
632
  # key = connection.aws_access_key_id # default to aws access key. NOT recommended in case you start using a new key
596
633
  # end
597
- return key
598
- end
599
-
600
-
601
- def validate
602
- true
603
- end
604
-
605
- def validate_on_create
606
- true
607
- end
608
-
609
- def validate_on_update
610
- true
611
- end
634
+ return key
635
+ end
612
636
 
637
+ def validate
638
+ true
639
+ end
613
640
 
614
- def pre_save(options)
641
+ def validate_on_create
642
+ true
643
+ end
615
644
 
616
- is_create = self[:id].nil?
617
- ok = run_before_validation && (is_create ? run_before_validation_on_create : run_before_validation_on_update)
618
- return false unless ok
645
+ def validate_on_update
646
+ true
647
+ end
619
648
 
620
- validate()
621
649
 
622
- is_create ? validate_on_create : validate_on_update
623
- # puts 'AFTER VALIDATIONS, ERRORS=' + errors.inspect
624
- if (!errors.nil? && errors.size > 0)
625
- # puts 'THERE ARE ERRORS, returning false'
626
- return false
627
- end
650
+ def pre_save(options)
628
651
 
629
- ok = run_after_validation && (is_create ? run_after_validation_on_create : run_after_validation_on_update)
630
- return false unless ok
652
+ is_create = self[:id].nil?
653
+ ok = run_before_validation && (is_create ? run_before_validation_on_create : run_before_validation_on_update)
654
+ return false unless ok
631
655
 
632
- ok = respond_to?('before_save') ? before_save : true
633
- if ok
634
- if is_create && respond_to?('before_create')
635
- ok = before_create
636
- elsif !is_create && respond_to?('before_update')
637
- ok = before_update
638
- end
639
- end
640
- if ok
641
- ok = run_before_save && (is_create ? run_before_create : run_before_update)
642
- end
643
- if ok
644
- # Now translate all fields into SimpleDB friendly strings
656
+ # validate()
657
+ # is_create ? validate_on_create : validate_on_update
658
+ if !valid?
659
+ return false
660
+ end
661
+ #
662
+ ## puts 'AFTER VALIDATIONS, ERRORS=' + errors.inspect
663
+ # if (!errors.nil? && errors.size > 0)
664
+ ## puts 'THERE ARE ERRORS, returning false'
665
+ # return false
666
+ # end
667
+
668
+ ok = run_after_validation && (is_create ? run_after_validation_on_create : run_after_validation_on_update)
669
+ return false unless ok
670
+
671
+ ok = respond_to?('before_save') ? before_save : true
672
+ if ok
673
+ if is_create && respond_to?('before_create')
674
+ ok = before_create
675
+ elsif !is_create && respond_to?('before_update')
676
+ ok = before_update
677
+ end
678
+ end
679
+ if ok
680
+ ok = run_before_save && (is_create ? run_before_create : run_before_update)
681
+ end
682
+ if ok
683
+ # Now translate all fields into SimpleDB friendly strings
645
684
  # convert_all_atts_to_sdb()
646
- end
647
- prepare_for_update
648
- ok
649
- end
685
+ end
686
+ prepare_for_update
687
+ ok
688
+ end
650
689
 
651
690
 
652
- def get_atts_to_delete
653
- to_delete = []
654
- changes.each_pair do |key, v|
655
- if v[1].nil?
656
- to_delete << key
657
- @attributes.delete(key)
658
- end
659
- end
691
+ def get_atts_to_delete
692
+ to_delete = []
693
+ changes.each_pair do |key, v|
694
+ if v[1].nil?
695
+ to_delete << key
696
+ @attributes.delete(key)
697
+ end
698
+ end
660
699
  # @attributes.each do |key, value|
661
700
  ## puts 'key=' + key.inspect + ' value=' + value.inspect
662
701
  # if value.nil? || (value.is_a?(Array) && value.size == 0) || (value.is_a?(Array) && value.size == 1 && value[0] == nil)
@@ -664,437 +703,436 @@ module SimpleRecord
664
703
  # @attributes.delete(key)
665
704
  # end
666
705
  # end
667
- return to_delete
668
- end
706
+ return to_delete
707
+ end
669
708
 
670
- # Run pre_save on each object, then runs batch_put_attributes
671
- # Returns
672
- def self.batch_save(objects, options={})
673
- options[:create_domain] = true if options[:create_domain].nil?
674
- results = []
675
- to_save = []
676
- if objects && objects.size > 0
677
- objects.each do |o|
678
- ok = o.pre_save(options)
679
- raise "Pre save failed on object [" + o.inspect + "]" if !ok
680
- results << ok
681
- next if !ok # todo: this shouldn't be here should it? raises above
682
- o.pre_save2
683
- to_save << Aws::SdbInterface::Item.new(o.id, o.attributes, true)
684
- if to_save.size == 25 # Max amount SDB will accept
685
- connection.batch_put_attributes(domain, to_save, options)
686
- to_save.clear
687
- end
688
- end
689
- end
690
- connection.batch_put_attributes(domain, to_save, options) if to_save.size > 0
691
- objects.each do |o|
692
- o.save_lobs(nil)
693
- end
694
- results
695
- end
709
+ # Run pre_save on each object, then runs batch_put_attributes
710
+ # Returns
711
+ def self.batch_save(objects, options={})
712
+ options[:create_domain] = true if options[:create_domain].nil?
713
+ results = []
714
+ to_save = []
715
+ if objects && objects.size > 0
716
+ objects.each do |o|
717
+ ok = o.pre_save(options)
718
+ raise "Pre save failed on object [" + o.inspect + "]" if !ok
719
+ results << ok
720
+ next if !ok # todo: this shouldn't be here should it? raises above
721
+ o.pre_save2
722
+ to_save << Aws::SdbInterface::Item.new(o.id, o.attributes, true)
723
+ if to_save.size == 25 # Max amount SDB will accept
724
+ connection.batch_put_attributes(domain, to_save, options)
725
+ to_save.clear
726
+ end
727
+ end
728
+ end
729
+ connection.batch_put_attributes(domain, to_save, options) if to_save.size > 0
730
+ objects.each do |o|
731
+ o.save_lobs(nil)
732
+ end
733
+ results
734
+ end
696
735
 
697
- # Pass in an array of objects
698
- def self.batch_delete(objects, options={})
699
- if objects
700
- # 25 item limit, we should maybe handle this limit in here.
701
- connection.batch_delete_attributes @domain, objects.collect { |x| x.id }
702
- end
703
- end
736
+ # Pass in an array of objects
737
+ def self.batch_delete(objects, options={})
738
+ if objects
739
+ # 25 item limit, we should maybe handle this limit in here.
740
+ connection.batch_delete_attributes @domain, objects.collect { |x| x.id }
741
+ end
742
+ end
704
743
 
705
- #
706
- # Usage: ClassName.delete id
707
- #
708
- def self.delete(id)
709
- connection.delete_attributes(domain, id)
710
- end
744
+ #
745
+ # Usage: ClassName.delete id
746
+ #
747
+ def self.delete(id)
748
+ connection.delete_attributes(domain, id)
749
+ @deleted = true
750
+ end
711
751
 
712
- # Pass in the same OPTIONS you'd pass into a find(:all, OPTIONS)
713
- def self.delete_all(options)
714
- # could make this quicker by just getting item_names and deleting attributes rather than creating objects
715
- obs = self.find(:all, options)
716
- i = 0
717
- obs.each do |a|
718
- a.delete
719
- i+=1
720
- end
721
- return i
722
- end
752
+ # Pass in the same OPTIONS you'd pass into a find(:all, OPTIONS)
753
+ def self.delete_all(options)
754
+ # could make this quicker by just getting item_names and deleting attributes rather than creating objects
755
+ obs = self.find(:all, options)
756
+ i = 0
757
+ obs.each do |a|
758
+ a.delete
759
+ i+=1
760
+ end
761
+ return i
762
+ end
723
763
 
724
- # Pass in the same OPTIONS you'd pass into a find(:all, OPTIONS)
725
- def self.destroy_all(options)
726
- obs = self.find(:all, options)
727
- i = 0
728
- obs.each do |a|
729
- a.destroy
730
- i+=1
731
- end
732
- return i
733
- end
764
+ # Pass in the same OPTIONS you'd pass into a find(:all, OPTIONS)
765
+ def self.destroy_all(options)
766
+ obs = self.find(:all, options)
767
+ i = 0
768
+ obs.each do |a|
769
+ a.destroy
770
+ i+=1
771
+ end
772
+ return i
773
+ end
734
774
 
735
- def delete(options={})
736
- if self.class.is_sharded?
737
- options[:domain] = sharded_domain
738
- end
739
- super(options)
775
+ def delete(options={})
776
+ if self.class.is_sharded?
777
+ options[:domain] = sharded_domain
778
+ end
779
+ super(options)
740
780
 
741
- # delete lobs now too
742
- delete_lobs
743
- end
781
+ # delete lobs now too
782
+ delete_lobs
783
+ end
744
784
 
745
- def destroy
746
- return run_before_destroy && delete && run_after_destroy
747
- end
785
+ def destroy
786
+ return run_before_destroy && delete && run_after_destroy
787
+ end
748
788
 
749
789
 
750
- def delete_niled(to_delete)
790
+ def delete_niled(to_delete)
751
791
  # puts 'to_delete=' + to_delete.inspect
752
- if to_delete.size > 0
792
+ if to_delete.size > 0
753
793
  # puts 'Deleting attributes=' + to_delete.inspect
754
- SimpleRecord.stats.deletes += 1
755
- delete_attributes to_delete
756
- to_delete.each do |att|
757
- att_meta = get_att_meta(att)
758
- if att_meta.type == :clob
759
- s3_bucket.key(s3_lob_id(att)).delete
760
- end
761
- end
762
- end
763
- end
794
+ SimpleRecord.stats.deletes += 1
795
+ delete_attributes to_delete
796
+ to_delete.each do |att|
797
+ att_meta = get_att_meta(att)
798
+ if att_meta.type == :clob
799
+ s3_bucket.key(s3_lob_id(att)).delete
800
+ end
801
+ end
802
+ end
803
+ end
764
804
 
765
- def reload
766
- super()
767
- end
805
+ def reload
806
+ super()
807
+ end
768
808
 
769
809
 
770
- def update_attributes(atts)
771
- set_attributes(atts)
772
- save
773
- end
810
+ def update_attributes(atts)
811
+ set_attributes(atts)
812
+ save
813
+ end
774
814
 
775
- def update_attributes!(atts)
776
- set_attributes(atts)
777
- save!
778
- end
815
+ def update_attributes!(atts)
816
+ set_attributes(atts)
817
+ save!
818
+ end
779
819
 
780
820
 
781
- def self.quote_regexp(a, re)
782
- a =~ re
783
- #was there a match?
784
- if $&
785
- before=$`
786
- middle=$&
787
- after =$'
788
-
789
- before =~ /'$/ #is there already a quote immediately before the match?
790
- unless $&
791
- return "#{before}'#{middle}'#{quote_regexp(after, re)}" #if not, put quotes around the match
792
- else
793
- return "#{before}#{middle}#{quote_regexp(after, re)}" #if so, assume it is quoted already and move on
794
- end
795
- else
796
- #no match, just return the string
797
- return a
798
- end
799
- end
821
+ def self.quote_regexp(a, re)
822
+ a =~ re
823
+ #was there a match?
824
+ if $&
825
+ before=$`
826
+ middle=$&
827
+ after =$'
800
828
 
801
- def self.create(attributes={})
802
- # puts "About to create in domain #{domain}"
803
- super
829
+ before =~ /'$/ #is there already a quote immediately before the match?
830
+ unless $&
831
+ return "#{before}'#{middle}'#{quote_regexp(after, re)}" #if not, put quotes around the match
832
+ else
833
+ return "#{before}#{middle}#{quote_regexp(after, re)}" #if so, assume it is quoted already and move on
804
834
  end
835
+ else
836
+ #no match, just return the string
837
+ return a
838
+ end
839
+ end
805
840
 
806
- @@regex_no_id = /.*Couldn't find.*with ID.*/
807
-
808
- #
809
- # Usage:
810
- # Find by ID:
811
- # MyModel.find(ID)
812
- #
813
- # Query example:
814
- # MyModel.find(:all, :conditions=>["name = ?", name], :order=>"created desc", :limit=>10)
815
- #
816
- # Extra options:
817
- # :per_token => the number of results to return per next_token, max is 2500.
818
- # :consistent_read => true/false -- as per http://developer.amazonwebservices.com/connect/entry.jspa?externalID=3572
819
- # :retries => maximum number of times to retry this query on an error response.
820
- # :shard => shard name or array of shard names to use on this query.
821
- def self.find(*params)
822
- #puts 'params=' + params.inspect
823
-
824
- q_type = :all
825
- select_attributes=[]
826
- if params.size > 0
827
- q_type = params[0]
828
- end
829
- options = {}
830
- if params.size > 1
831
- options = params[1]
832
- end
833
-
834
- if !options[:shard_find] && is_sharded?
835
- # then break off and get results across all shards
836
- return find_sharded(*params)
837
- end
838
-
839
- # Pad and Offset number attributes
840
- params_dup = params.dup
841
- if params.size > 1
842
- options = params[1]
843
- #puts 'options=' + options.inspect
844
- #puts 'after collect=' + options.inspect
845
- convert_condition_params(options)
846
- per_token = options[:per_token]
847
- consistent_read = options[:consistent_read]
848
- if per_token || consistent_read then
849
- op_dup = options.dup
850
- op_dup[:limit] = per_token # simpledb uses Limit as a paging thing, not what is normal
851
- op_dup[:consistent_read] = consistent_read
852
- params_dup[1] = op_dup
853
- end
854
- end
841
+ @@regex_no_id = /.*Couldn't find.*with ID.*/
842
+
843
+ #
844
+ # Usage:
845
+ # Find by ID:
846
+ # MyModel.find(ID)
847
+ #
848
+ # Query example:
849
+ # MyModel.find(:all, :conditions=>["name = ?", name], :order=>"created desc", :limit=>10)
850
+ #
851
+ # Extra options:
852
+ # :per_token => the number of results to return per next_token, max is 2500.
853
+ # :consistent_read => true/false -- as per http://developer.amazonwebservices.com/connect/entry.jspa?externalID=3572
854
+ # :retries => maximum number of times to retry this query on an error response.
855
+ # :shard => shard name or array of shard names to use on this query.
856
+ def self.find(*params)
857
+ #puts 'params=' + params.inspect
858
+
859
+ q_type = :all
860
+ select_attributes=[]
861
+ if params.size > 0
862
+ q_type = params[0]
863
+ end
864
+ options = {}
865
+ if params.size > 1
866
+ options = params[1]
867
+ end
868
+
869
+ if !options[:shard_find] && is_sharded?
870
+ # then break off and get results across all shards
871
+ return find_sharded(*params)
872
+ end
873
+
874
+ # Pad and Offset number attributes
875
+ params_dup = params.dup
876
+ if params.size > 1
877
+ options = params[1]
878
+ #puts 'options=' + options.inspect
879
+ #puts 'after collect=' + options.inspect
880
+ convert_condition_params(options)
881
+ per_token = options[:per_token]
882
+ consistent_read = options[:consistent_read]
883
+ if per_token || consistent_read then
884
+ op_dup = options.dup
885
+ op_dup[:limit] = per_token # simpledb uses Limit as a paging thing, not what is normal
886
+ op_dup[:consistent_read] = consistent_read
887
+ params_dup[1] = op_dup
888
+ end
889
+ end
855
890
  # puts 'params2=' + params.inspect
856
891
 
857
- ret = q_type == :all ? [] : nil
858
- begin
859
-
860
- results=find_with_metadata(*params_dup)
892
+ ret = q_type == :all ? [] : nil
893
+ begin
894
+ results=find_with_metadata(*params_dup)
861
895
  # puts "RESULT=" + results.inspect
862
- write_usage(:select, domain, q_type, options, results)
863
- #puts 'params3=' + params.inspect
864
- SimpleRecord.stats.selects += 1
865
- if q_type == :count
866
- ret = results[:count]
867
- elsif q_type == :first
868
- ret = results[:items].first
869
- # todo: we should store request_id and box_usage with the object maybe?
870
- cache_results(ret)
871
- elsif results[:single]
872
- ret = results[:single]
873
- cache_results(ret)
874
- else
875
- if results[:items] #.is_a?(Array)
876
- cache_results(results[:items])
877
- ret = SimpleRecord::ResultsArray.new(self, params, results, next_token)
878
- end
879
- end
880
- rescue Aws::AwsError, SimpleRecord::ActiveSdb::ActiveSdbError => ex
896
+ write_usage(:select, domain, q_type, options, results)
897
+ #puts 'params3=' + params.inspect
898
+ SimpleRecord.stats.selects += 1
899
+ if q_type == :count
900
+ ret = results[:count]
901
+ elsif q_type == :first
902
+ ret = results[:items].first
903
+ # todo: we should store request_id and box_usage with the object maybe?
904
+ cache_results(ret)
905
+ elsif results[:single]
906
+ ret = results[:single]
907
+ cache_results(ret)
908
+ else
909
+ if results[:items] #.is_a?(Array)
910
+ cache_results(results[:items])
911
+ ret = SimpleRecord::ResultsArray.new(self, params, results, next_token)
912
+ end
913
+ end
914
+ rescue Aws::AwsError, SimpleRecord::ActiveSdb::ActiveSdbError => ex
881
915
  # puts "RESCUED: " + ex.message
882
- if (ex.message().index("NoSuchDomain") != nil)
883
- # this is ok
884
- elsif (ex.message() =~ @@regex_no_id)
885
- ret = nil
886
- else
887
- raise ex
888
- end
889
- end
890
- # puts 'single2=' + ret.inspect
891
- return ret
916
+ if (ex.message().index("NoSuchDomain") != nil)
917
+ # this is ok
918
+ elsif (ex.message() =~ @@regex_no_id)
919
+ ret = nil
920
+ else
921
+ raise ex
892
922
  end
923
+ end
924
+ # puts 'single2=' + ret.inspect
925
+ return ret
926
+ end
893
927
 
894
- def self.select(*params)
895
- return find(*params)
896
- end
928
+ def self.select(*params)
929
+ return find(*params)
930
+ end
897
931
 
898
- def self.all(*args)
899
- find(:all, *args)
900
- end
932
+ def self.all(*args)
933
+ find(:all, *args)
934
+ end
901
935
 
902
- def self.first(*args)
903
- find(:first, *args)
904
- end
936
+ def self.first(*args)
937
+ find(:first, *args)
938
+ end
905
939
 
906
- def self.count(*args)
907
- find(:count, *args)
908
- end
940
+ def self.count(*args)
941
+ find(:count, *args)
942
+ end
909
943
 
910
- # This gets less and less efficient the higher the page since SimpleDB has no way
911
- # to start at a specific row. So it will iterate from the first record and pull out the specific pages.
912
- def self.paginate(options={})
944
+ # This gets less and less efficient the higher the page since SimpleDB has no way
945
+ # to start at a specific row. So it will iterate from the first record and pull out the specific pages.
946
+ def self.paginate(options={})
913
947
  # options = args.pop
914
948
  # puts 'paginate options=' + options.inspect if SimpleRecord.logging?
915
- page = options[:page] || 1
916
- per_page = options[:per_page] || 50
949
+ page = options[:page] || 1
950
+ per_page = options[:per_page] || 50
917
951
  # total = options[:total_entries].to_i
918
- options[:page] = page.to_i # makes sure it's to_i
919
- options[:per_page] = per_page.to_i
920
- options[:limit] = options[:page] * options[:per_page]
952
+ options[:page] = page.to_i # makes sure it's to_i
953
+ options[:per_page] = per_page.to_i
954
+ options[:limit] = options[:page] * options[:per_page]
921
955
  # puts 'paging options=' + options.inspect
922
- fr = find(:all, options)
923
- return fr
956
+ fr = find(:all, options)
957
+ return fr
924
958
 
925
- end
959
+ end
926
960
 
927
961
 
928
- def self.convert_condition_params(options)
929
- return if options.nil?
930
- conditions = options[:conditions]
931
- if !conditions.nil? && conditions.size > 1
932
- # all after first are values
933
- conditions.collect! { |x|
934
- Translations.pad_and_offset(x)
935
- }
936
- end
962
+ def self.convert_condition_params(options)
963
+ return if options.nil?
964
+ conditions = options[:conditions]
965
+ if !conditions.nil? && conditions.size > 1
966
+ # all after first are values
967
+ conditions.collect! { |x|
968
+ Translations.pad_and_offset(x)
969
+ }
970
+ end
937
971
 
938
- end
972
+ end
939
973
 
940
- def self.cache_results(results)
941
- if !cache_store.nil? && !results.nil?
942
- if results.is_a?(Array)
943
- # todo: cache each result
944
- results.each do |item|
945
- class_name = item.class.name
946
- id = item.id
947
- cache_key = self.cache_key(class_name, id)
948
- #puts 'caching result at ' + cache_key + ': ' + results.inspect
949
- cache_store.write(cache_key, item, :expires_in =>30)
950
- end
951
- else
952
- class_name = results.class.name
953
- id = results.id
954
- cache_key = self.cache_key(class_name, id)
955
- #puts 'caching result at ' + cache_key + ': ' + results.inspect
956
- cache_store.write(cache_key, results, :expires_in =>30)
957
- end
958
- end
974
+ def self.cache_results(results)
975
+ if !cache_store.nil? && !results.nil?
976
+ if results.is_a?(Array)
977
+ # todo: cache each result
978
+ results.each do |item|
979
+ class_name = item.class.name
980
+ id = item.id
981
+ cache_key = self.cache_key(class_name, id)
982
+ #puts 'caching result at ' + cache_key + ': ' + results.inspect
983
+ cache_store.write(cache_key, item, :expires_in =>30)
984
+ end
985
+ else
986
+ class_name = results.class.name
987
+ id = results.id
988
+ cache_key = self.cache_key(class_name, id)
989
+ #puts 'caching result at ' + cache_key + ': ' + results.inspect
990
+ cache_store.write(cache_key, results, :expires_in =>30)
959
991
  end
992
+ end
993
+ end
960
994
 
961
- def self.cache_key(class_name, id)
962
- return class_name + "/" + id.to_s
963
- end
995
+ def self.cache_key(class_name, id)
996
+ return class_name + "/" + id.to_s
997
+ end
964
998
 
965
- @@debug=""
999
+ @@debug=""
966
1000
 
967
- def self.debug
968
- @@debug
969
- end
1001
+ def self.debug
1002
+ @@debug
1003
+ end
970
1004
 
971
- def self.sanitize_sql(*params)
972
- return ActiveRecord::Base.sanitize_sql(*params)
973
- end
1005
+ def self.sanitize_sql(*params)
1006
+ return ActiveRecord::Base.sanitize_sql(*params)
1007
+ end
974
1008
 
975
- def self.table_name
976
- return domain
977
- end
1009
+ def self.table_name
1010
+ return domain
1011
+ end
978
1012
 
979
- def changed
980
- return @dirty.keys
981
- end
1013
+ def changed
1014
+ return @dirty.keys
1015
+ end
982
1016
 
983
- def changed?
984
- return @dirty.size > 0
985
- end
1017
+ def changed?
1018
+ return @dirty.size > 0
1019
+ end
986
1020
 
987
- def changes
988
- ret = {}
989
- #puts 'in CHANGES=' + @dirty.inspect
990
- @dirty.each_pair { |key, value| ret[key] = [value, get_attribute(key)] }
991
- return ret
992
- end
1021
+ def changes
1022
+ ret = {}
1023
+ #puts 'in CHANGES=' + @dirty.inspect
1024
+ @dirty.each_pair { |key, value| ret[key] = [value, get_attribute(key)] }
1025
+ return ret
1026
+ end
993
1027
 
994
- def after_save_cleanup
995
- @dirty = {}
996
- end
1028
+ def after_save_cleanup
1029
+ @dirty = {}
1030
+ end
997
1031
 
998
- def hash
999
- # same as ActiveRecord
1000
- id.hash
1001
- end
1032
+ def hash
1033
+ # same as ActiveRecord
1034
+ id.hash
1035
+ end
1002
1036
 
1003
1037
 
1004
- end
1038
+ end
1005
1039
 
1006
1040
 
1007
- class Activerecordtosdb_subrecord_array
1008
- def initialize(subname, referencename, referencevalue)
1009
- @subname =subname.classify
1010
- @referencename =referencename.tableize.singularize + "_id"
1011
- @referencevalue=referencevalue
1012
- end
1041
+ class Activerecordtosdb_subrecord_array
1042
+ def initialize(subname, referencename, referencevalue)
1043
+ @subname =subname.classify
1044
+ @referencename =referencename.tableize.singularize + "_id"
1045
+ @referencevalue=referencevalue
1046
+ end
1013
1047
 
1014
- # Performance optimization if you know the array should be empty
1048
+ # Performance optimization if you know the array should be empty
1015
1049
 
1016
- def init_empty
1017
- @records = []
1018
- end
1050
+ def init_empty
1051
+ @records = []
1052
+ end
1019
1053
 
1020
- def load
1021
- if @records.nil?
1022
- @records = find_all
1023
- end
1024
- return @records
1025
- end
1054
+ def load
1055
+ if @records.nil?
1056
+ @records = find_all
1057
+ end
1058
+ return @records
1059
+ end
1026
1060
 
1027
- def [](key)
1028
- return load[key]
1029
- end
1061
+ def [](key)
1062
+ return load[key]
1063
+ end
1030
1064
 
1031
- def <<(ob)
1032
- return load << ob
1033
- end
1065
+ def first
1066
+ load[0]
1067
+ end
1034
1068
 
1035
- def count
1036
- return load.count
1037
- end
1069
+ def <<(ob)
1070
+ return load << ob
1071
+ end
1038
1072
 
1039
- def size
1040
- return count
1041
- end
1073
+ def count
1074
+ return load.count
1075
+ end
1042
1076
 
1043
- def each(*params, &block)
1044
- return load.each(*params) { |record| block.call(record) }
1045
- end
1077
+ def size
1078
+ return count
1079
+ end
1046
1080
 
1047
- def find_all(*params)
1048
- find(:all, *params)
1049
- end
1081
+ def each(*params, &block)
1082
+ return load.each(*params) { |record| block.call(record) }
1083
+ end
1050
1084
 
1051
- def empty?
1052
- return load.empty?
1053
- end
1085
+ def find_all(*params)
1086
+ find(:all, *params)
1087
+ end
1054
1088
 
1055
- def build(*params)
1056
- params[0][@referencename]=@referencevalue
1057
- eval(@subname).new(*params)
1058
- end
1089
+ def empty?
1090
+ return load.empty?
1091
+ end
1059
1092
 
1060
- def create(*params)
1061
- params[0][@referencename]=@referencevalue
1062
- record = eval(@subname).new(*params)
1063
- record.save
1064
- end
1093
+ def build(*params)
1094
+ params[0][@referencename]=@referencevalue
1095
+ eval(@subname).new(*params)
1096
+ end
1065
1097
 
1066
- def find(*params)
1067
- query=[:first, {}]
1068
- #{:conditions=>"id=>1"}
1069
- if params[0]
1070
- if params[0]==:all
1071
- query[0]=:all
1072
- end
1073
- end
1098
+ def create(*params)
1099
+ params[0][@referencename]=@referencevalue
1100
+ record = eval(@subname).new(*params)
1101
+ record.save
1102
+ end
1074
1103
 
1075
- if params[1]
1076
- query[1]=params[1]
1077
- if query[1][:conditions]
1078
- query[1][:conditions]=SimpleRecord::Base.sanitize_sql(query[1][:conditions])+" AND "+ SimpleRecord::Base.sanitize_sql(["#{@referencename} = ?", @referencevalue])
1079
- #query[1][:conditions]=Activerecordtosdb.sanitize_sql(query[1][:conditions])+" AND id='#{@id}'"
1080
- else
1081
- query[1][:conditions]=["#{@referencename} = ?", @referencevalue]
1082
- #query[1][:conditions]="id='#{@id}'"
1083
- end
1084
- else
1085
- query[1][:conditions]=["#{@referencename} = ?", @referencevalue]
1086
- #query[1][:conditions]="id='#{@id}'"
1087
- end
1104
+ def find(*params)
1105
+ query=[:first, {}]
1106
+ #{:conditions=>"id=>1"}
1107
+ if params[0]
1108
+ if params[0]==:all
1109
+ query[0]=:all
1110
+ end
1111
+ end
1088
1112
 
1089
- return eval(@subname).find(*query)
1113
+ if params[1]
1114
+ query[1]=params[1]
1115
+ if query[1][:conditions]
1116
+ query[1][:conditions]=SimpleRecord::Base.sanitize_sql(query[1][:conditions])+" AND "+ SimpleRecord::Base.sanitize_sql(["#{@referencename} = ?", @referencevalue])
1117
+ #query[1][:conditions]=Activerecordtosdb.sanitize_sql(query[1][:conditions])+" AND id='#{@id}'"
1118
+ else
1119
+ query[1][:conditions]=["#{@referencename} = ?", @referencevalue]
1120
+ #query[1][:conditions]="id='#{@id}'"
1090
1121
  end
1122
+ else
1123
+ query[1][:conditions]=["#{@referencename} = ?", @referencevalue]
1124
+ #query[1][:conditions]="id='#{@id}'"
1125
+ end
1091
1126
 
1127
+ return eval(@subname).find(*query)
1092
1128
  end
1093
1129
 
1094
- # This is simply a place holder so we don't keep doing gets to s3 or simpledb if already checked.
1095
- class RemoteNil
1130
+ end
1096
1131
 
1097
- end
1132
+ # This is simply a place holder so we don't keep doing gets to s3 or simpledb if already checked.
1133
+ class RemoteNil
1134
+
1135
+ end
1098
1136
 
1099
1137
 
1100
1138
  end