Class: SimpleRecord::Base

Inherits:
RightAws::ActiveSdb::Base
  • Object
show all
Includes:
Callbacks
Defined in:
lib/simple_record.rb

Defined Under Namespace

Classes: Attribute

Constant Summary collapse

@@cache_store =
nil
@@virtuals =
[]
@@offset =
9223372036854775808
@@padding =
20
@@date_format =

Time to second precision

"%Y-%m-%dT%H:%M:%S"
@@regex_no_id =
/.*Couldn't find.*with ID.*/
@@debug =
""

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Callbacks

included

Constructor Details

#initialize(*params) ⇒ Base

Returns a new instance of Base.



84
85
86
87
# File 'lib/simple_record.rb', line 84

def initialize(attrs={})
    super
    # 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
end

Class Attribute Details

.domain_prefixObject

Returns the value of attribute domain_prefix.



196
197
198
# File 'lib/simple_record.rb', line 196

def domain_prefix
  @domain_prefix
end

Instance Attribute Details

#errorsObject

Returns the value of attribute errors.



193
194
195
# File 'lib/simple_record.rb', line 193

def errors
  @errors
end

Class Method Details

.are_booleans(*args) ⇒ Object



342
343
344
345
346
# File 'lib/simple_record.rb', line 342

def self.are_booleans(*args)
    args.each do |arg|
        defined_attributes[arg].type = :boolean
    end
end

.are_dates(*args) ⇒ Object



336
337
338
339
340
# File 'lib/simple_record.rb', line 336

def self.are_dates(*args)
    args.each do |arg|
        defined_attributes[arg].type = :date
    end
end

.are_ints(*args) ⇒ Object



329
330
331
332
333
334
# File 'lib/simple_record.rb', line 329

def self.are_ints(*args)
    #    puts 'calling are_ints: ' + args.inspect
    args.each do |arg|
        defined_attributes[arg].type = :int
    end
end

.batch_save(objects, options = {}) ⇒ Object

Run pre_save on each object, then runs batch_put_attributes Returns



707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
# File 'lib/simple_record.rb', line 707

def self.batch_save(objects, options={})
    results = []
    to_save = []
    if objects && objects.size > 0
        objects.each do |o|
            ok = o.pre_save(options)
            raise "Pre save failed on object [" + o.inspect + "]" if !ok
            results << ok
            next if !ok
            o.pre_save2
            to_save << RightAws::SdbInterface::Item.new(o.id, o.attributes, true)
        end
    end
    connection.batch_put_attributes(domain, to_save)
    results
end

.belongs_to(association_id, options = {}) ⇒ Object

One belongs_to association per call. Call multiple times if there are more than one.

This method will also create an {association)_id method that will return the ID of the foreign object without actually materializing it.



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/simple_record.rb', line 361

def self.belongs_to(association_id, options = {})
    attribute = SimpleRecord::Base::Attribute.new(:belongs_to)
    defined_attributes[association_id] = attribute
    attribute.options = options
    #@@belongs_to_map[association_id] = options
    arg = association_id
    arg_s = arg.to_s
    arg_id = arg.to_s + '_id'

    # todo: should also handle foreign_key http://74.125.95.132/search?q=cache:KqLkxuXiBBQJ:wiki.rubyonrails.org/rails/show/belongs_to+rails+belongs_to&hl=en&ct=clnk&cd=1&gl=us
    #    puts "arg_id=#{arg}_id"
    #        puts "is defined? " + eval("(defined? #{arg}_id)").to_s
    #        puts 'atts=' + @attributes.inspect

    # Define reader method
    send(:define_method, arg) do
        attribute = defined_attributes_local[arg]
        options2 = attribute.options # @@belongs_to_map[arg]
        class_name = options2[:class_name] || arg.to_s[0...1].capitalize + arg.to_s[1...arg.to_s.length]

        # Camelize classnames with underscores (ie my_model.rb --> MyModel)
        class_name = class_name.camelize

        #      puts "attr=" + @attributes[arg_id].inspect
        #      puts 'val=' + @attributes[arg_id][0].inspect unless @attributes[arg_id].nil?
        ret = nil
        arg_id = arg.to_s + '_id'
        if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
            if !@@cache_store.nil?
                arg_id_val = @attributes[arg_id][0]
                cache_key = self.class.cache_key(class_name, arg_id_val)
#          puts 'cache_key=' + cache_key
                ret = @@cache_store.read(cache_key)
#          puts 'belongs_to incache=' + ret.inspect
            end
            if ret.nil?
                to_eval = "#{class_name}.find(@attributes['#{arg_id}'][0])"
#      puts 'to eval=' + to_eval
                begin
                    ret = eval(to_eval) # (defined? #{arg}_id)
                rescue RightAws::ActiveSdb::ActiveSdbError
                    if $!.message.include? "Couldn't find"
                        ret = nil
                    else
                        raise $!
                    end
                end

            end
        end
#      puts 'ret=' + ret.inspect
        return ret
    end


    # Define writer method
    send(:define_method, arg.to_s + "=") do |value|
        arg_id = arg.to_s + '_id'
        if value.nil?
            make_dirty(arg_id, nil)
            self[arg_id]=nil unless self[arg_id].nil? # if it went from something to nil, then we have to remember and remove attribute on save
        else
            make_dirty(arg_id, value.id)
            self[arg_id]=value.id
        end
    end


    # Define ID reader method for reading the associated objects id without getting the entire object
    send(:define_method, arg_id) do
        if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
            return @attributes[arg_id][0]
        end
        return nil
    end

    # Define writer method for setting the _id directly without the associated object
    send(:define_method, arg_id + "=") do |value|
        if value.nil?
            self[arg_id] = nil unless self[arg_id].nil? # if it went from something to nil, then we have to remember and remove attribute on save
        else
            self[arg_id] = value
        end
    end

    send(:define_method, "create_"+arg.to_s) do |*params|
        newsubrecord=eval(arg.to_s.classify).new(*params)
        newsubrecord.save
        arg_id = arg.to_s + '_id'
        self[arg_id]=newsubrecord.id
    end
end

.cache_key(class_name, id) ⇒ Object



920
921
922
# File 'lib/simple_record.rb', line 920

def self.cache_key(class_name, id)
    return class_name + "/" + id.to_s
end

.cache_results(results) ⇒ Object



906
907
908
909
910
911
912
913
914
915
916
917
918
# File 'lib/simple_record.rb', line 906

def self.cache_results(results)
    if !@@cache_store.nil? && !results.nil?
        if results.is_a?(Array)
            # todo: cache each result
        else
            class_name = results.class.name
            id = results.id
            cache_key = self.cache_key(class_name, id)
            #puts 'caching result at ' + cache_key + ': ' + results.inspect
            @@cache_store.write(cache_key, results, :expires_in =>30)
        end
    end
end

.cache_storeObject



205
206
207
# File 'lib/simple_record.rb', line 205

def self.cache_store
    return @@cache_store
end

.cache_store=(cache) ⇒ Object

Set the cache to use



202
203
204
# File 'lib/simple_record.rb', line 202

def self.cache_store=(cache)
    @@cache_store = cache
end

.convert_condition_params(options) ⇒ Object



894
895
896
897
898
899
900
901
902
903
904
# File 'lib/simple_record.rb', line 894

def self.convert_condition_params(options)
    return if options.nil?
    conditions = options[:conditions]
    if !conditions.nil? && conditions.size > 1
        # all after first are values
        conditions.collect! { |x|
            self.pad_and_offset(x)
        }
    end

end

.debugObject



925
926
927
# File 'lib/simple_record.rb', line 925

def self.debug
    @@debug
end

.delete(id) ⇒ Object

Usage: ClassName.delete id todo: move to RightAWS



728
729
730
# File 'lib/simple_record.rb', line 728

def self.delete(id)
    connection.delete_attributes(domain, id)
end

.domainObject



240
241
242
243
244
245
246
247
# File 'lib/simple_record.rb', line 240

def self.domain
    #return self.get_domain_name unless self.get_domain_name.nil?
    d = super
    #puts 'in self.domain, d=' + d.to_s + ' domain_prefix=' + SimpleRecord::Base.domain_prefix.to_s
    domain_name_for_class = SimpleRecord::Base.domain_prefix + d.to_s
    #self.set_domain_name(domain_name_for_class)
    domain_name_for_class
end

.find(*params) ⇒ Object



847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
# File 'lib/simple_record.rb', line 847

def self.find(*params)
    #puts 'params=' + params.inspect
    q_type = :all
    select_attributes=[]

    if params.size > 0
        q_type = params[0]
    end

    # Pad and Offset number attributes
    options = {}
    if params.size > 1
        options = params[1]
        #puts 'options=' + options.inspect
        #puts 'after collect=' + options.inspect
        convert_condition_params(options)
    end
    #puts 'params2=' + params.inspect

    results = q_type == :all ? [] : nil
    begin
        results=super(*params)
        #puts 'params3=' + params.inspect
        SimpleRecord.stats.selects += 1
        if q_type != :count
            cache_results(results)
            if results.is_a?(Array)
                results = SimpleRecord::ResultsArray.new(self, params, results, next_token)
            end
        end
    rescue RightAws::AwsError, RightAws::ActiveSdb::ActiveSdbError
        puts "RESCUED: " + $!.message
        if ($!.message().index("NoSuchDomain") != nil)
            # this is ok
        elsif ($!.message() =~ @@regex_no_id)
            results = nil
        else
            raise $!
        end
    end
    return results
end

.has_attributes(*args) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/simple_record.rb', line 274

def self.has_attributes(*args)
    args.each do |arg|
        defined_attributes[arg] = SimpleRecord::Base::Attribute.new(:string) if defined_attributes[arg].nil?
        # define reader method
        arg_s = arg.to_s # to get rid of all the to_s calls
        send(:define_method, arg) do
            ret = nil
            ret = get_attribute(arg)
            return nil if ret.nil?
            return un_offset_if_int(arg, ret)
        end

        # define writer method
        send(:define_method, arg_s+"=") do |value|
            make_dirty(arg_s, value)
            self[arg_s]=value
        end

        # Now for dirty methods: http://api.rubyonrails.org/classes/ActiveRecord/Dirty.html
        # define changed? method
        send(:define_method, arg_s + "_changed?") do
            @dirty.has_key?(arg_s)
        end

        # define change method
        send(:define_method, arg_s + "_change") do
            old_val = @dirty[arg_s]
            return nil if old_val.nil?
            [old_val, get_attribute(arg_s)]
        end

        # define was method
        send(:define_method, arg_s + "_was") do
            old_val = @dirty[arg_s]
            old_val
        end
    end
end

.has_booleans(*args) ⇒ Object



324
325
326
327
# File 'lib/simple_record.rb', line 324

def self.has_booleans(*args)
    has_attributes(*args)
    are_booleans(*args)
end

.has_dates(*args) ⇒ Object



320
321
322
323
# File 'lib/simple_record.rb', line 320

def self.has_dates(*args)
    has_attributes(*args)
    are_dates(*args)
end

.has_ints(*args) ⇒ Object



316
317
318
319
# File 'lib/simple_record.rb', line 316

def self.has_ints(*args)
    has_attributes(*args)
    are_ints(*args)
end

.has_many(*args) ⇒ Object



454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/simple_record.rb', line 454

def self.has_many(*args)
    args.each do |arg|
        #okay, this creates an instance method with the pluralized name of the symbol passed to belongs_to
        send(:define_method, arg) do
            #when called, the method creates a new, very temporary instance of the Activerecordtosdb_subrecord class
            #It is passed the three initializers it needs:
            #note the first parameter is just a string by time new gets it, like "user"
            #the second and third parameters are still a variable when new gets it, like user_id
            return eval(%{Activerecordtosdb_subrecord_array.new('#{arg}', self.class.name ,id)})
        end
    end
    #Disclaimer: this whole funciton just seems crazy to me, and a bit inefficient. But it was the clearest way I could think to do it code wise.
    #It's bad programming form (imo) to have a class method require something that isn't passed to it through it's variables.
    #I couldn't pass the id when calling find, since the original find doesn't work that way, so I was left with this.
end

.has_one(*args) ⇒ Object



470
471
472
# File 'lib/simple_record.rb', line 470

def self.has_one(*args)

end

.has_strings(*args) ⇒ Object



313
314
315
# File 'lib/simple_record.rb', line 313

def self.has_strings(*args)
    has_attributes(*args)
end

.has_virtuals(*args) ⇒ Object



349
350
351
352
353
354
355
# File 'lib/simple_record.rb', line 349

def self.has_virtuals(*args)
    @@virtuals = args
    args.each do |arg|
        #we just create the accessor functions here, the actual instance variable is created during initialize
        attr_accessor(arg)
    end
end

.inherited(base) ⇒ Object



122
123
124
125
126
127
128
129
130
# File 'lib/simple_record.rb', line 122

def self.inherited(base)
    #puts 'SimpleRecord::Base is inherited by ' + base.inspect
    setup_callbacks(base)

    base.has_dates :created, :updated
    base.before_create :set_created, :set_updated
    base.before_update :set_updated

end

.pad_and_offset(x) ⇒ Object



525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
# File 'lib/simple_record.rb', line 525

def self.pad_and_offset(x)
    # todo: add Float, etc
    #    puts 'padding=' + x.class.name + " -- " + x.inspect
    if x.kind_of? Integer
        x += @@offset
        x_str = x.to_s
        # pad
        x_str = '0' + x_str while x_str.size < 20
        return x_str
    elsif x.respond_to?(:iso8601)
        #  puts x.class.name + ' responds to iso8601'
        #
        # There is an issue here where Time.iso8601 on an incomparable value to DateTime.iso8601.
        # Amazon suggests: 2008-02-10T16:52:01.000-05:00
        #                  "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
        #
        if x.is_a? DateTime
            x_str = x.new_offset(0).strftime(@@date_format)
        else
            x_str = x.getutc.strftime(@@date_format)
        end
        #  puts 'utc=' + x_str
        return x_str
    else
        return x
    end
end

.quote_regexp(a, re) ⇒ Object



826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
# File 'lib/simple_record.rb', line 826

def self.quote_regexp(a, re)
    a =~ re
    #was there a match?
    if $&
        before=$`
        middle=$&
        after=$'

        before =~ /'$/ #is there already a quote immediately before the match?
        unless $&
            return "#{before}'#{middle}'#{quote_regexp(after, re)}" #if not, put quotes around the match
        else
            return "#{before}#{middle}#{quote_regexp(after, re)}" #if so, assume it is quoted already and move on
        end
    else
        #no match, just return the string
        return a
    end
end

.sanitize_sql(*params) ⇒ Object



929
930
931
# File 'lib/simple_record.rb', line 929

def self.sanitize_sql(*params)
    return ActiveRecord::Base.sanitize_sql(*params)
end

.select(*params) ⇒ Object



890
891
892
# File 'lib/simple_record.rb', line 890

def self.select(*params)
    return find(*params)
end

.set_domain_name(table_name) ⇒ Object

Sets the domain name for this class



221
222
223
224
225
# File 'lib/simple_record.rb', line 221

def self.set_domain_name(table_name)
    # puts 'setting domain name for class ' + self.inspect + '=' + table_name
    #@domain_name_for_class = table_name
    super
end

.set_domain_prefix(prefix) ⇒ Object

If you want a domain prefix for all your models, set it here.



210
211
212
213
# File 'lib/simple_record.rb', line 210

def self.set_domain_prefix(prefix)
    #puts 'set_domain_prefix=' + prefix
    self.domain_prefix = prefix
end

.set_table_name(table_name) ⇒ Object

Same as set_table_name



216
217
218
# File 'lib/simple_record.rb', line 216

def self.set_table_name(table_name)
    set_domain_name table_name
end

.setup_callbacks(base) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/simple_record.rb', line 132

def self.setup_callbacks(base)
    instance_eval "\n        def callbacks\n            @callbacks ||= {}\n            @callbacks\n        end\n\n       def self.defined_attributes\n            #puts 'class defined_attributes'\n            @attributes ||= {}\n            @attributes\n        end\n\n    endofeval\n\n    @@callbacks.each do |callback|\n        class_eval <<-endofeval\n\n     def run_\#{callback}\n        #puts 'CLASS CALLBACKS for ' + self.inspect + ' = ' + self.class.callbacks.inspect\n        return true if self.class.callbacks.nil?\n        cnames = self.class.callbacks['\#{callback}']\n        cnames = [] if cnames.nil?\n        #cnames += super.class.callbacks['\#{callback}'] unless super.class.callbacks.nil?\n        # puts 'cnames XXX = ' + cnames.inspect\n        return true if cnames.nil?\n        cnames.each { |name|\n            #puts 'run_  \#{name}'\n          unless eval(name)\n            return false\n          end\n      }\n        #super.run_\#{callback}\n      return true\n    end\n\n        endofeval\n    end\nend\n"

.table_nameObject



933
934
935
# File 'lib/simple_record.rb', line 933

def self.table_name
    return domain
end

Instance Method Details

#[]=(attribute, values) ⇒ Object



499
500
501
502
# File 'lib/simple_record.rb', line 499

def []=(attribute, values)
    make_dirty(attribute, values)
    super
end

#changedObject



937
938
939
# File 'lib/simple_record.rb', line 937

def changed
    return @dirty.keys
end

#changed?Boolean

Returns:

  • (Boolean)


941
942
943
# File 'lib/simple_record.rb', line 941

def changed?
    return @dirty.size > 0
end

#changesObject



945
946
947
948
949
950
# File 'lib/simple_record.rb', line 945

def changes
    ret = {}
    #puts 'in CHANGES=' + @dirty.inspect
    @dirty.each_pair {|key, value| ret[key] = [value, get_attribute(key)]}
    return ret
end

#clear_errorsObject



495
496
497
# File 'lib/simple_record.rb', line 495

def clear_errors
    @errors=SimpleRecord_errors.new
end

#convert_dates_to_sdbObject



628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# File 'lib/simple_record.rb', line 628

def convert_dates_to_sdb()

    defined_attributes_local.each_pair do |name, att_meta|
#          puts 'int encoding: ' + i.to_s
        if att_meta.type == :date && !self[name.to_s].nil?
#            puts 'before: ' + self[i.to_s].inspect
            #            puts @attributes.inspect
            #            puts @attributes[i.to_s].inspect
            arr = @attributes[name.to_s]
            #puts 'padding date=' + i.to_s
            arr.collect!{ |x| self.class.pad_and_offset(x) }
            @attributes[name.to_s] = arr
#            puts 'after: ' + @attributes[i.to_s].inspect
        else
            #            puts 'was nil'
        end
    end
end

#defined_attributes_localObject



186
187
188
189
190
# File 'lib/simple_record.rb', line 186

def defined_attributes_local
    #puts 'local defined_attributes'
    ret = self.class.defined_attributes
    ret.merge!(self.class.superclass.defined_attributes) if self.class.superclass.respond_to?(:defined_attributes)
end

#delete_niled(to_delete) ⇒ Object



732
733
734
735
736
737
# File 'lib/simple_record.rb', line 732

def delete_niled(to_delete)
    if to_delete.size > 0
#      puts 'Deleting attributes=' + to_delete.inspect
        delete_attributes to_delete
    end
end

#destroy(*params) ⇒ Object



814
815
816
817
818
819
820
821
822
823
824
# File 'lib/simple_record.rb', line 814

def destroy(*params)
    if super(*params)
        if run_after_destroy
            return true
        else
            return false
        end
    else
        return false
    end
end

#domainObject

def self.get_domain_name

    # puts 'returning domain_name=' + @domain_name_for_class.to_s
    #return @domain_name_for_class
    return self.domain
end


236
237
238
# File 'lib/simple_record.rb', line 236

def domain
    super # super.domain
end

#domain_ok(ex) ⇒ Object



553
554
555
556
557
558
559
560
# File 'lib/simple_record.rb', line 553

def domain_ok(ex)
    if (ex.message().index("NoSuchDomain") != nil)
        puts "Creating new SimpleDB Domain: " + domain
        self.class.create_domain
        return true
    end
    return false
end

#get_attribute(arg) ⇒ Object

Since SimpleDB supports multiple attributes per value, the values are an array. This method will return the value unwrapped if it’s the only, otherwise it will return the array.



253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/simple_record.rb', line 253

def get_attribute(arg)
    arg = arg.to_s
    if self[arg].class==Array
        if self[arg].length==1
            ret = self[arg][0]
        else
            ret = self[arg]
        end
    else
        ret = self[arg]
    end
    ret
end

#get_atts_to_deleteObject



693
694
695
696
697
698
699
700
701
702
703
# File 'lib/simple_record.rb', line 693

def get_atts_to_delete
    # todo: this should use the @dirty hash now
    to_delete = []
    @attributes.each do |key, value|
        #      puts 'value=' + value.inspect
        if value.nil? || (value.is_a?(Array) && value.size == 0)
            to_delete << key
        end
    end
    return to_delete
end

#make_dirty(arg, value) ⇒ Object



267
268
269
270
271
272
# File 'lib/simple_record.rb', line 267

def make_dirty(arg, value)
    # todo: only set dirty if it changed
    #puts 'making dirty arg=' + arg.to_s + ' --- ' + @dirty.inspect
    @dirty[arg] = get_attribute(arg) # Store old value (not sure if we need it?)
    #puts 'end making dirty ' + @dirty.inspect
end

#mark_as_oldObject



952
953
954
955
# File 'lib/simple_record.rb', line 952

def mark_as_old
    super
    @dirty = {}
end

#pad_and_offset_ints_to_sdbObject



612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
# File 'lib/simple_record.rb', line 612

def pad_and_offset_ints_to_sdb()

    defined_attributes_local.each_pair do |name, att_meta|
#          puts 'int encoding: ' + i.to_s
        if att_meta.type == :int && !self[name.to_s].nil?
#            puts 'before: ' + self[i.to_s].inspect
            #            puts @attributes.inspect
            #            puts @attributes[i.to_s].inspect
            arr = @attributes[name.to_s]
            arr.collect!{ |x| self.class.pad_and_offset(x) }
            @attributes[name.to_s] = arr
#            puts 'after: ' + @attributes[i.to_s].inspect
        end
    end
end

#pre_save(options) ⇒ Object



647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
# File 'lib/simple_record.rb', line 647

def pre_save(options)

    is_create = self[:id].nil?
    ok = run_before_validation && is_create ? run_before_validation_on_create : run_before_validation_on_update
    return false unless ok

    if respond_to?('validate')
        validate
#      puts 'AFTER VALIDATIONS, ERRORS=' + errors.inspect
        if (!@errors.nil? && @errors.length > 0 )
#        puts 'THERE ARE ERRORS, returning false'
            return false
        end
    end

    ok = run_after_validation && is_create ? run_after_validation_on_create : run_after_validation_on_update
    return false unless ok

    ok = respond_to?('before_save') ? before_save : true
    if ok
        if is_create && respond_to?('before_create')
            ok = before_create
        elsif !is_create && respond_to?('before_update')
            ok = before_update
        end
    end
    if ok
        ok = run_before_save && is_create ? run_before_create : run_before_update
    end
    if ok
#      puts 'ABOUT TO SAVE: ' + self.inspect
        # First we gotta pad and offset
        pad_and_offset_ints_to_sdb()
        convert_dates_to_sdb()
    end
    ok
end

#reloadObject



806
807
808
# File 'lib/simple_record.rb', line 806

def reload
    super()
end

#save(options = {}) ⇒ Object

Options:

- :except => Array of attributes to NOT save
- :dirty => true - Will only store attributes that were modified


568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
# File 'lib/simple_record.rb', line 568

def save(options={})
    #    puts 'SAVING: ' + self.inspect
    clear_errors
    is_create = self[:id].nil?
    ok = pre_save(options)
    if ok
        begin
            #        puts 'is frozen? ' + self.frozen?.to_s + ' - ' + self.inspect
            if options[:dirty] # Only used in simple_record right now
                options[:dirty_atts] = @dirty
            end
            to_delete = get_atts_to_delete # todo: this should use the @dirty hash now
            if super(options)
#          puts 'SAVED super'
                self.class.cache_results(self)
                delete_niled(to_delete)
                if is_create ? run_after_create : run_after_update && run_after_save
                    return true
                else
                    #I thought about calling destroy here, but rails doesn't behave that way, so neither will I
                    return false
                end
            else
                return false
            end
        rescue RightAws::AwsError
            # puts "RESCUED in save: " + $!
            if (domain_ok($!))
                if !@create_domain_called
                    @create_domain_called = true
                    save(options)
                else
                    raise $!
                end
            else
                raise $!
            end
        end
    else
        #@debug = "not saved"
        return false
    end
end

#save_attributes(*params) ⇒ Object



685
686
687
688
689
690
691
# File 'lib/simple_record.rb', line 685

def save_attributes(*params)
    ret = super(*params)
    if ret
        self.class.cache_results(self)
    end
    ret
end

#set_createdObject



505
506
507
508
509
510
511
# File 'lib/simple_record.rb', line 505

def set_created
#    puts 'SETTING CREATED'
    #    @created = DateTime.now
    self[:created] = DateTime.now
#    @tester = 'some test value'
    #    self[:tester] = 'some test value'
end

#set_updatedObject



513
514
515
516
517
518
# File 'lib/simple_record.rb', line 513

def set_updated
#    puts 'SETTING UPDATED'
    #    @updated = DateTime.now
    self[:updated] = DateTime.now
#    @tester = 'some test value updated'
end

#to_bool(x) ⇒ Object



762
763
764
765
766
767
768
# File 'lib/simple_record.rb', line 762

def to_bool(x)
    if x.is_a?(String)
        x == "true"
    else
        x
    end
end

#to_date(x) ⇒ Object



753
754
755
756
757
758
759
760
# File 'lib/simple_record.rb', line 753

def to_date(x)
    if x.is_a?(String)
        DateTime.parse(x)
    else
        x
    end

end

#un_offset_if_int(arg, x) ⇒ Object



739
740
741
742
743
744
745
746
747
748
749
750
# File 'lib/simple_record.rb', line 739

def un_offset_if_int(arg, x)
    att_meta =  defined_attributes_local[arg]
#          puts 'int encoding: ' + i.to_s
    if att_meta.type == :int
        x = un_offset_int(x)
    elsif att_meta.type == :date
        x = to_date(x)
    elsif att_meta.type == :boolean
        x = to_bool(x)
    end
    x
end

#un_offset_int(x) ⇒ Object



771
772
773
774
775
776
777
778
779
780
781
# File 'lib/simple_record.rb', line 771

def un_offset_int(x)
    if x.is_a?(String)
        x2 = x.to_i
#            puts 'to_i=' + x2.to_s
        x2 -= @@offset
#            puts 'after subtracting offset='+ x2.to_s
        x2
    else
        x
    end
end

#unpad(i, attributes) ⇒ Object



783
784
785
786
787
788
789
790
791
792
793
794
795
796
# File 'lib/simple_record.rb', line 783

def unpad(i, attributes)
    if !attributes[i].nil?
#          puts 'before=' + self[i].inspect
        attributes[i].collect!{ |x|
            un_offset_int(x)

        }
#          for x in self[i]
        #            x = self[i][0].to_i
        #            x -= @@offset
        #            self[i] = x
        #          end
    end
end

#unpad_selfObject



798
799
800
801
802
803
804
# File 'lib/simple_record.rb', line 798

def unpad_self
    defined_attributes_local.each_pair do |name, att_meta|
        if att_meta.type == :int
            unpad(name, @attributes)
        end
    end
end

#update_attributes(*params) ⇒ Object



810
811
812
# File 'lib/simple_record.rb', line 810

def update_attributes(*params)
    return save_attributes(*params)
end