appoxy-simple_record 1.0.23 → 1.0.26
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/simple_record.rb +296 -166
- data/test/my_child_model.rb +30 -2
- data/test/my_model.rb +19 -2
- data/test/test_simple_record.rb +93 -35
- metadata +4 -3
data/lib/simple_record.rb
CHANGED
@@ -44,17 +44,137 @@ module SimpleRecord
|
|
44
44
|
# :per_thread (one connection per thread)
|
45
45
|
# :pool (uses a connection pool with a maximum number of connections - NOT IMPLEMENTED YET)
|
46
46
|
# :logger => Logger Object # Logger instance: logs to STDOUT if omitted
|
47
|
-
# :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
|
48
47
|
def self.establish_connection(aws_access_key=nil, aws_secret_key=nil, params={})
|
49
48
|
RightAws::ActiveSdb.establish_connection(aws_access_key, aws_secret_key, params)
|
50
49
|
end
|
51
50
|
|
52
51
|
def self.close_connection()
|
53
|
-
|
52
|
+
RightAws::ActiveSdb.close_connection
|
53
|
+
end
|
54
|
+
|
55
|
+
module Callbacks
|
56
|
+
#this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
|
57
|
+
#this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
|
58
|
+
#basically, this is how we recreate the callback functions
|
59
|
+
@@callbacks=["before_validation", "before_validation_on_create", "before_validation_on_update",
|
60
|
+
"after_validation", "after_validation_on_create", "after_validation_on_update",
|
61
|
+
"before_save", "before_create", "before_update",
|
62
|
+
"after_create", "after_update", "after_save",
|
63
|
+
"after_destroy"]
|
64
|
+
|
65
|
+
def self.included(base)
|
66
|
+
#puts 'Callbacks included in ' + base.inspect
|
67
|
+
|
68
|
+
end
|
54
69
|
end
|
55
70
|
|
56
71
|
class Base < RightAws::ActiveSdb::Base
|
57
72
|
|
73
|
+
include SimpleRecord::Callbacks
|
74
|
+
|
75
|
+
|
76
|
+
# todo: move into Callbacks module
|
77
|
+
#this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
|
78
|
+
#this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
|
79
|
+
#basically, this is how we recreate the callback functions
|
80
|
+
@@callbacks.each do |callback|
|
81
|
+
instance_eval <<-endofeval
|
82
|
+
|
83
|
+
#puts 'doing callback=' + callback + ' for ' + self.inspect
|
84
|
+
#we first have to make an initialized array for each of the callbacks, to prevent problems if they are not called
|
85
|
+
|
86
|
+
def #{callback}(*args)
|
87
|
+
#puts 'callback called in ' + self.inspect + ' with ' + args.inspect
|
88
|
+
|
89
|
+
#make_dirty(arg_s, value)
|
90
|
+
#self[arg.to_s]=value
|
91
|
+
#puts 'value in callback #{callback}=' + value.to_s
|
92
|
+
args.each do |arg|
|
93
|
+
cnames = callbacks['#{callback}']
|
94
|
+
#puts '\tcnames1=' + cnames.inspect + ' for class ' + self.inspect
|
95
|
+
cnames = [] if cnames.nil?
|
96
|
+
cnames << arg.to_s if cnames.index(arg.to_s).nil?
|
97
|
+
#puts '\tcnames2=' + cnames.inspect
|
98
|
+
callbacks['#{callback}'] = cnames
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
endofeval
|
103
|
+
end
|
104
|
+
#puts 'base methods=' + self.methods.inspect
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
def self.inherited(base)
|
109
|
+
puts 'SimpleRecord::Base is inherited by ' + base.inspect
|
110
|
+
setup_callbacks(base)
|
111
|
+
|
112
|
+
base.has_dates :created, :updated
|
113
|
+
base.before_create :set_created, :set_updated
|
114
|
+
base.before_update :set_updated
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.setup_callbacks(base)
|
119
|
+
instance_eval <<-endofeval
|
120
|
+
|
121
|
+
def callbacks
|
122
|
+
@callbacks ||= {}
|
123
|
+
@callbacks
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.defined_attributes
|
127
|
+
#puts 'class defined_attributes'
|
128
|
+
@attributes ||= {}
|
129
|
+
@attributes
|
130
|
+
end
|
131
|
+
|
132
|
+
endofeval
|
133
|
+
|
134
|
+
@@callbacks.each do |callback|
|
135
|
+
class_eval <<-endofeval
|
136
|
+
|
137
|
+
def run_#{callback}
|
138
|
+
#puts 'CLASS CALLBACKS for ' + self.inspect + ' = ' + self.class.callbacks.inspect
|
139
|
+
return true if self.class.callbacks.nil?
|
140
|
+
cnames = self.class.callbacks['#{callback}']
|
141
|
+
cnames = [] if cnames.nil?
|
142
|
+
#cnames += super.class.callbacks['#{callback}'] unless super.class.callbacks.nil?
|
143
|
+
# puts 'cnames XXX = ' + cnames.inspect
|
144
|
+
return true if cnames.nil?
|
145
|
+
cnames.each { |name|
|
146
|
+
#puts 'run_ #{name}'
|
147
|
+
unless eval(name)
|
148
|
+
return false
|
149
|
+
end
|
150
|
+
}
|
151
|
+
#super.run_#{callback}
|
152
|
+
return true
|
153
|
+
end
|
154
|
+
|
155
|
+
endofeval
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
# Holds information about an attribute
|
162
|
+
class Attribute
|
163
|
+
attr_accessor :type, :options
|
164
|
+
|
165
|
+
def initialize(type)
|
166
|
+
@type = type
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
def defined_attributes_local
|
173
|
+
#puts 'local defined_attributes'
|
174
|
+
self.class.defined_attributes
|
175
|
+
end
|
176
|
+
|
177
|
+
|
58
178
|
attr_accessor :errors
|
59
179
|
@@domain_prefix = ''
|
60
180
|
@domain_name_for_class = nil
|
@@ -103,57 +223,67 @@ module SimpleRecord
|
|
103
223
|
domain_name_for_class
|
104
224
|
end
|
105
225
|
|
106
|
-
#this bit of code creates a "run_blank" function for everything value in the @@callbacks array.
|
107
|
-
#this function can then be inserted in the appropriate place in the save, new, destroy, etc overrides
|
108
|
-
#basically, this is how we recreate the callback functions
|
109
|
-
@@callbacks=["before_save", "before_create", "after_create", "before_update", "after_update", "after_save", "after_destroy"]
|
110
|
-
@@callbacks.each do |callback|
|
111
|
-
#we first have to make an initialized array for each of the callbacks, to prevent problems if they are not called
|
112
|
-
eval %{
|
113
|
-
@@#{callback}_names=[]
|
114
226
|
|
115
|
-
def self.#{callback}(*args)
|
116
|
-
args.each do |arg|
|
117
|
-
@@#{callback}_names << arg.to_s if @@#{callback}_names.index(arg.to_s).nil?
|
118
|
-
end
|
119
|
-
# asdf @@#{callback}_names=args.map{|arg| arg.to_s}
|
120
|
-
end
|
121
227
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
228
|
+
# Since SimpleDB supports multiple attributes per value, the values are an array.
|
229
|
+
# This method will return the value unwrapped if it's the only, otherwise it will return the array.
|
230
|
+
def get_attribute(arg)
|
231
|
+
arg = arg.to_s
|
232
|
+
if self[arg].class==Array
|
233
|
+
if self[arg].length==1
|
234
|
+
ret = self[arg][0]
|
235
|
+
else
|
236
|
+
ret = self[arg]
|
237
|
+
end
|
238
|
+
else
|
239
|
+
ret = self[arg]
|
240
|
+
end
|
241
|
+
ret
|
129
242
|
end
|
130
|
-
|
243
|
+
|
244
|
+
def make_dirty(arg, value)
|
245
|
+
# todo: only set dirty if it changed
|
246
|
+
#puts 'making dirty ' + @dirty.inspect
|
247
|
+
@dirty[arg] = get_attribute(arg) # Store old value (not sure if we need it?)
|
248
|
+
#puts 'end making dirty ' + @dirty.inspect
|
131
249
|
end
|
132
250
|
|
133
|
-
@@attributes = []
|
134
251
|
def self.has_attributes(*args)
|
135
252
|
args.each do |arg|
|
136
|
-
|
253
|
+
defined_attributes[arg] = SimpleRecord::Base::Attribute.new(:string) if defined_attributes[arg].nil?
|
137
254
|
# define reader method
|
255
|
+
arg_s = arg.to_s # to get rid of all the to_s calls
|
138
256
|
send :define_method, arg do
|
139
257
|
ret = nil
|
140
|
-
|
141
|
-
if self[arg.to_s].length==1
|
142
|
-
ret = self[arg.to_s][0]
|
143
|
-
else
|
144
|
-
ret = self[arg.to_s]
|
145
|
-
end
|
146
|
-
else
|
147
|
-
ret = self[arg.to_s]
|
148
|
-
end
|
258
|
+
ret = get_attribute(arg)
|
149
259
|
return nil if ret.nil?
|
150
260
|
return un_offset_if_int(arg, ret)
|
151
261
|
end
|
152
262
|
|
153
263
|
# define writer method
|
154
|
-
method_name = (
|
264
|
+
method_name = (arg_s+"=")
|
155
265
|
send(:define_method, method_name) do |value|
|
156
|
-
|
266
|
+
make_dirty(arg_s, value)
|
267
|
+
self[arg.to_s]=value
|
268
|
+
end
|
269
|
+
|
270
|
+
# Now for dirty methods: http://api.rubyonrails.org/classes/ActiveRecord/Dirty.html
|
271
|
+
# define changed? method
|
272
|
+
send(:define_method, arg_s + "_changed?") do
|
273
|
+
!@dirty[arg_s].nil?
|
274
|
+
end
|
275
|
+
|
276
|
+
# define change method
|
277
|
+
send(:define_method, arg_s + "_change") do
|
278
|
+
old_val = @dirty[arg_s]
|
279
|
+
return nil if old_val.nil?
|
280
|
+
[old_val, get_attribute(arg_s)]
|
281
|
+
end
|
282
|
+
|
283
|
+
# define was method
|
284
|
+
send(:define_method, arg_s + "_was") do
|
285
|
+
old_val = @dirty[arg_s]
|
286
|
+
old_val
|
157
287
|
end
|
158
288
|
end
|
159
289
|
end
|
@@ -171,30 +301,22 @@ module SimpleRecord
|
|
171
301
|
are_booleans(*args)
|
172
302
|
end
|
173
303
|
|
174
|
-
@@ints = []
|
175
304
|
def self.are_ints(*args)
|
176
305
|
# puts 'calling are_ints: ' + args.inspect
|
177
306
|
args.each do |arg|
|
178
|
-
|
179
|
-
@@ints << arg if @@ints.index(arg).nil?
|
307
|
+
defined_attributes[arg].type = :int
|
180
308
|
end
|
181
|
-
# @@ints = args
|
182
|
-
# puts 'ints=' + @@ints.inspect
|
183
309
|
end
|
184
310
|
|
185
|
-
@@dates = []
|
186
311
|
def self.are_dates(*args)
|
187
312
|
args.each do |arg|
|
188
|
-
|
313
|
+
defined_attributes[arg].type = :date
|
189
314
|
end
|
190
|
-
# @@dates = args
|
191
|
-
# puts 'dates=' + @@dates.inspect
|
192
315
|
end
|
193
316
|
|
194
|
-
@@booleans = []
|
195
317
|
def self.are_booleans(*args)
|
196
318
|
args.each do |arg|
|
197
|
-
|
319
|
+
defined_attributes[arg].type = :boolean
|
198
320
|
end
|
199
321
|
end
|
200
322
|
|
@@ -207,14 +329,17 @@ module SimpleRecord
|
|
207
329
|
end
|
208
330
|
end
|
209
331
|
|
210
|
-
@@belongs_to_map = {}
|
211
332
|
# One belongs_to association per call. Call multiple times if there are more than one.
|
212
333
|
#
|
213
334
|
# This method will also create an {association)_id method that will return the ID of the foreign object
|
214
335
|
# without actually materializing it.
|
215
336
|
def self.belongs_to(association_id, options = {})
|
216
|
-
|
337
|
+
attribute = SimpleRecord::Base::Attribute.new(:belongs_to)
|
338
|
+
defined_attributes[association_id] = attribute
|
339
|
+
attribute.options = options
|
340
|
+
#@@belongs_to_map[association_id] = options
|
217
341
|
arg = association_id
|
342
|
+
arg_s = arg.to_s
|
218
343
|
arg_id = arg.to_s + '_id'
|
219
344
|
|
220
345
|
# 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
|
@@ -224,7 +349,8 @@ module SimpleRecord
|
|
224
349
|
|
225
350
|
# Define reader method
|
226
351
|
send(:define_method, arg) do
|
227
|
-
|
352
|
+
attribute = defined_attributes[arg]
|
353
|
+
options2 = attribute.options # @@belongs_to_map[arg]
|
228
354
|
class_name = options2[:class_name] || arg.to_s[0...1].capitalize + arg.to_s[1...arg.to_s.length]
|
229
355
|
|
230
356
|
# Camelize classnames with underscores (ie my_model.rb --> MyModel)
|
@@ -243,7 +369,7 @@ module SimpleRecord
|
|
243
369
|
# puts 'belongs_to incache=' + ret.inspect
|
244
370
|
end
|
245
371
|
if ret.nil?
|
246
|
-
to_eval = "#{class_name}.find(@attributes['#{arg_id}'][0]
|
372
|
+
to_eval = "#{class_name}.find(@attributes['#{arg_id}'][0])"
|
247
373
|
# puts 'to eval=' + to_eval
|
248
374
|
begin
|
249
375
|
ret = eval(to_eval) # (defined? #{arg}_id)
|
@@ -261,26 +387,28 @@ module SimpleRecord
|
|
261
387
|
return ret
|
262
388
|
end
|
263
389
|
|
264
|
-
# Define reader ID method
|
265
|
-
send(:define_method, arg_id) do
|
266
|
-
if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
|
267
|
-
return @attributes[arg_id][0]
|
268
|
-
end
|
269
|
-
return nil
|
270
|
-
end
|
271
|
-
|
272
390
|
|
273
391
|
# Define writer method
|
274
392
|
send(:define_method, arg.to_s + "=") do |value|
|
275
393
|
arg_id = arg.to_s + '_id'
|
276
394
|
if value.nil?
|
395
|
+
make_dirty(arg_id, nil)
|
277
396
|
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
|
278
397
|
else
|
398
|
+
make_dirty(arg_id, value.id)
|
279
399
|
self[arg_id]=value.id
|
280
400
|
end
|
281
401
|
end
|
282
402
|
|
283
403
|
|
404
|
+
# Define ID reader method for reading the associated objects id without getting the entire object
|
405
|
+
send(:define_method, arg_id) do
|
406
|
+
if !@attributes[arg_id].nil? && @attributes[arg_id].size > 0 && @attributes[arg_id][0] != nil && @attributes[arg_id][0] != ''
|
407
|
+
return @attributes[arg_id][0]
|
408
|
+
end
|
409
|
+
return nil
|
410
|
+
end
|
411
|
+
|
284
412
|
# Define writer method for setting the _id directly without the associated object
|
285
413
|
send(:define_method, arg_id + "=") do |value|
|
286
414
|
if value.nil?
|
@@ -318,27 +446,8 @@ module SimpleRecord
|
|
318
446
|
|
319
447
|
end
|
320
448
|
|
321
|
-
has_attributes :created, :updated
|
322
|
-
before_create :set_created, :set_updated
|
323
|
-
before_update :set_updated
|
324
|
-
are_dates :created, :updated
|
325
|
-
|
326
|
-
def set_created
|
327
|
-
# puts 'SETTING CREATED'
|
328
|
-
# @created = DateTime.now
|
329
|
-
self[:created] = DateTime.now
|
330
|
-
# @tester = 'some test value'
|
331
|
-
# self[:tester] = 'some test value'
|
332
|
-
end
|
333
|
-
|
334
|
-
def set_updated
|
335
|
-
# puts 'SETTING UPDATED'
|
336
|
-
# @updated = DateTime.now
|
337
|
-
self[:updated] = DateTime.now
|
338
|
-
# @tester = 'some test value updated'
|
339
|
-
end
|
340
|
-
|
341
449
|
def initialize(*params)
|
450
|
+
|
342
451
|
if params[0]
|
343
452
|
#we have to handle the virtuals. Right now, this assumes that all parameters are passed from inside an array
|
344
453
|
#this is the usually the case when the parameters are passed passed via POST and obtained from the params array
|
@@ -353,6 +462,34 @@ module SimpleRecord
|
|
353
462
|
super()
|
354
463
|
end
|
355
464
|
@errors=SimpleRecord_errors.new
|
465
|
+
@dirty = {}
|
466
|
+
|
467
|
+
|
468
|
+
end
|
469
|
+
|
470
|
+
def clear_errors
|
471
|
+
@errors=SimpleRecord_errors.new
|
472
|
+
end
|
473
|
+
|
474
|
+
def []=(attribute, values)
|
475
|
+
@dirty[attribute] = get_attribute(attribute)
|
476
|
+
super
|
477
|
+
end
|
478
|
+
|
479
|
+
|
480
|
+
def set_created
|
481
|
+
# puts 'SETTING CREATED'
|
482
|
+
# @created = DateTime.now
|
483
|
+
self[:created] = DateTime.now
|
484
|
+
# @tester = 'some test value'
|
485
|
+
# self[:tester] = 'some test value'
|
486
|
+
end
|
487
|
+
|
488
|
+
def set_updated
|
489
|
+
# puts 'SETTING UPDATED'
|
490
|
+
# @updated = DateTime.now
|
491
|
+
self[:updated] = DateTime.now
|
492
|
+
# @tester = 'some test value updated'
|
356
493
|
end
|
357
494
|
|
358
495
|
|
@@ -399,19 +536,27 @@ module SimpleRecord
|
|
399
536
|
|
400
537
|
@create_domain_called = false
|
401
538
|
|
402
|
-
|
539
|
+
# Options:
|
540
|
+
# - :except => Array of attributes to NOT save
|
541
|
+
# - :dirty => true - Will only store attributes that were modified
|
542
|
+
#
|
543
|
+
def save(options={})
|
403
544
|
# puts 'SAVING: ' + self.inspect
|
545
|
+
clear_errors
|
404
546
|
is_create = self[:id].nil?
|
405
|
-
ok = pre_save(
|
547
|
+
ok = pre_save(options)
|
406
548
|
if ok
|
407
549
|
begin
|
408
550
|
# puts 'is frozen? ' + self.frozen?.to_s + ' - ' + self.inspect
|
409
|
-
|
410
|
-
|
551
|
+
if options[:dirty] # Only used in simple_record right now
|
552
|
+
options[:dirty_atts] = @dirty
|
553
|
+
end
|
554
|
+
to_delete = get_atts_to_delete # todo: this should use the @dirty hash now
|
555
|
+
if super(options)
|
411
556
|
# puts 'SAVED super'
|
412
557
|
self.class.cache_results(self)
|
413
558
|
delete_niled(to_delete)
|
414
|
-
if
|
559
|
+
if is_create ? run_after_create : run_after_update && run_after_save
|
415
560
|
return true
|
416
561
|
else
|
417
562
|
#I thought about calling destroy here, but rails doesn't behave that way, so neither will I
|
@@ -425,7 +570,7 @@ module SimpleRecord
|
|
425
570
|
if (domain_ok($!))
|
426
571
|
if !@create_domain_called
|
427
572
|
@create_domain_called = true
|
428
|
-
save(
|
573
|
+
save(options)
|
429
574
|
else
|
430
575
|
raise $!
|
431
576
|
end
|
@@ -440,45 +585,46 @@ module SimpleRecord
|
|
440
585
|
end
|
441
586
|
|
442
587
|
def pad_and_offset_ints_to_sdb()
|
443
|
-
|
444
|
-
|
588
|
+
|
589
|
+
defined_attributes_local.each_pair do |name, att_meta|
|
445
590
|
# puts 'int encoding: ' + i.to_s
|
446
|
-
|
591
|
+
if att_meta.type == :int && !self[name.to_s].nil?
|
447
592
|
# puts 'before: ' + self[i.to_s].inspect
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
593
|
+
# puts @attributes.inspect
|
594
|
+
# puts @attributes[i.to_s].inspect
|
595
|
+
arr = @attributes[name.to_s]
|
596
|
+
arr.collect!{ |x| self.class.pad_and_offset(x) }
|
597
|
+
@attributes[name.to_s] = arr
|
453
598
|
# puts 'after: ' + @attributes[i.to_s].inspect
|
454
|
-
else
|
455
|
-
# puts 'was nil'
|
456
|
-
end
|
457
599
|
end
|
458
600
|
end
|
459
601
|
end
|
460
602
|
|
461
603
|
def convert_dates_to_sdb()
|
462
|
-
|
463
|
-
|
604
|
+
|
605
|
+
defined_attributes_local.each_pair do |name, att_meta|
|
464
606
|
# puts 'int encoding: ' + i.to_s
|
465
|
-
|
607
|
+
if att_meta.type == :date && !self[name.to_s].nil?
|
466
608
|
# puts 'before: ' + self[i.to_s].inspect
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
609
|
+
# puts @attributes.inspect
|
610
|
+
# puts @attributes[i.to_s].inspect
|
611
|
+
arr = @attributes[name.to_s]
|
612
|
+
#puts 'padding date=' + i.to_s
|
613
|
+
arr.collect!{ |x| self.class.pad_and_offset(x) }
|
614
|
+
@attributes[name.to_s] = arr
|
473
615
|
# puts 'after: ' + @attributes[i.to_s].inspect
|
474
|
-
|
475
|
-
|
476
|
-
end
|
616
|
+
else
|
617
|
+
# puts 'was nil'
|
477
618
|
end
|
478
619
|
end
|
479
620
|
end
|
480
621
|
|
481
|
-
def pre_save(
|
622
|
+
def pre_save(options)
|
623
|
+
|
624
|
+
is_create = self[:id].nil?
|
625
|
+
ok = run_before_validation && is_create ? run_before_validation_on_create : run_before_validation_on_update
|
626
|
+
return false unless ok
|
627
|
+
|
482
628
|
if respond_to?('validate')
|
483
629
|
validate
|
484
630
|
# puts 'AFTER VALIDATIONS, ERRORS=' + errors.inspect
|
@@ -488,7 +634,9 @@ module SimpleRecord
|
|
488
634
|
end
|
489
635
|
end
|
490
636
|
|
491
|
-
|
637
|
+
ok = run_after_validation && is_create ? run_after_validation_on_create : run_after_validation_on_update
|
638
|
+
return false unless ok
|
639
|
+
|
492
640
|
ok = respond_to?('before_save') ? before_save : true
|
493
641
|
if ok
|
494
642
|
if is_create && respond_to?('before_create')
|
@@ -518,6 +666,7 @@ module SimpleRecord
|
|
518
666
|
end
|
519
667
|
|
520
668
|
def get_atts_to_delete
|
669
|
+
# todo: this should use the @dirty hash now
|
521
670
|
to_delete = []
|
522
671
|
@attributes.each do |key, value|
|
523
672
|
# puts 'value=' + value.inspect
|
@@ -530,12 +679,12 @@ module SimpleRecord
|
|
530
679
|
|
531
680
|
# Run pre_save on each object, then runs batch_put_attributes
|
532
681
|
# Returns
|
533
|
-
def self.batch_save(objects)
|
682
|
+
def self.batch_save(objects, options={})
|
534
683
|
results = []
|
535
684
|
to_save = []
|
536
685
|
if objects && objects.size > 0
|
537
686
|
objects.each do |o|
|
538
|
-
ok = o.pre_save
|
687
|
+
ok = o.pre_save(options)
|
539
688
|
raise "Pre save failed on object [" + o.inspect + "]" if !ok
|
540
689
|
results << ok
|
541
690
|
next if !ok
|
@@ -563,51 +712,14 @@ module SimpleRecord
|
|
563
712
|
end
|
564
713
|
|
565
714
|
def un_offset_if_int(arg, x)
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
end
|
575
|
-
end
|
576
|
-
if !@@dates.nil?
|
577
|
-
for d in @@dates
|
578
|
-
# puts 'converting created: ' + self['created'].inspect
|
579
|
-
if d == arg
|
580
|
-
x = to_date(x)
|
581
|
-
end
|
582
|
-
# if !self[d].nil?
|
583
|
-
# self[d].collect!{ |d2|
|
584
|
-
# if d2.is_a?(String)
|
585
|
-
# DateTime.parse(d2)
|
586
|
-
# else
|
587
|
-
# d2
|
588
|
-
# end
|
589
|
-
# }
|
590
|
-
# end
|
591
|
-
# puts 'after=' + self['created'].inspect
|
592
|
-
end
|
593
|
-
end
|
594
|
-
if !@@booleans.nil?
|
595
|
-
for b in @@booleans
|
596
|
-
# puts 'converting created: ' + self['created'].inspect
|
597
|
-
if b == arg
|
598
|
-
x = to_bool(x)
|
599
|
-
end
|
600
|
-
# if !self[d].nil?
|
601
|
-
# self[d].collect!{ |d2|
|
602
|
-
# if d2.is_a?(String)
|
603
|
-
# DateTime.parse(d2)
|
604
|
-
# else
|
605
|
-
# d2
|
606
|
-
# end
|
607
|
-
# }
|
608
|
-
# end
|
609
|
-
# puts 'after=' + self['created'].inspect
|
610
|
-
end
|
715
|
+
att_meta = defined_attributes_local[arg]
|
716
|
+
# puts 'int encoding: ' + i.to_s
|
717
|
+
if att_meta.type == :int
|
718
|
+
x = un_offset_int(x)
|
719
|
+
elsif att_meta.type == :date
|
720
|
+
x = to_date(x)
|
721
|
+
elsif att_meta.type == :boolean
|
722
|
+
x = to_bool(x)
|
611
723
|
end
|
612
724
|
x
|
613
725
|
end
|
@@ -659,12 +771,9 @@ module SimpleRecord
|
|
659
771
|
end
|
660
772
|
|
661
773
|
def unpad_self
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
# unpad and unoffset
|
666
|
-
|
667
|
-
unpad(i, @attributes)
|
774
|
+
defined_attributes_local.each_pair do |name, att_meta|
|
775
|
+
if att_meta.type == :int
|
776
|
+
unpad(name, @attributes)
|
668
777
|
end
|
669
778
|
end
|
670
779
|
end
|
@@ -746,9 +855,9 @@ This is done on getters now
|
|
746
855
|
|
747
856
|
# Pad and Offset number attributes
|
748
857
|
options = params[1]
|
749
|
-
#
|
858
|
+
#puts 'options=' + options.inspect
|
750
859
|
convert_condition_params(options)
|
751
|
-
#
|
860
|
+
#puts 'after collect=' + options.inspect
|
752
861
|
|
753
862
|
results = all ? [] : nil
|
754
863
|
begin
|
@@ -842,6 +951,26 @@ This is done on getters now
|
|
842
951
|
return @@domain_prefix + self.class.name.tableize
|
843
952
|
end
|
844
953
|
|
954
|
+
def changed
|
955
|
+
return @dirty.keys
|
956
|
+
end
|
957
|
+
|
958
|
+
def changed?
|
959
|
+
return @dirty.size > 0
|
960
|
+
end
|
961
|
+
|
962
|
+
def changes
|
963
|
+
ret = {}
|
964
|
+
#puts 'in CHANGES=' + @dirty.inspect
|
965
|
+
@dirty.each_pair {|key, value| ret[key] = [value, get_attribute(key)]}
|
966
|
+
return ret
|
967
|
+
end
|
968
|
+
|
969
|
+
def mark_as_old
|
970
|
+
super
|
971
|
+
@dirty = {}
|
972
|
+
end
|
973
|
+
|
845
974
|
end
|
846
975
|
|
847
976
|
class SimpleRecord_errors
|
@@ -950,3 +1079,4 @@ This is done on getters now
|
|
950
1079
|
|
951
1080
|
end
|
952
1081
|
end
|
1082
|
+
|
data/test/my_child_model.rb
CHANGED
@@ -1,6 +1,34 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
|
2
|
+
require 'my_model'
|
2
3
|
|
3
4
|
class MyChildModel < SimpleRecord::Base
|
4
5
|
belongs_to :my_model
|
5
|
-
has_attributes :name
|
6
|
-
|
6
|
+
has_attributes :name, :child_attr
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
=begin
|
12
|
+
|
13
|
+
|
14
|
+
puts 'word'
|
15
|
+
|
16
|
+
mm = MyModel.new
|
17
|
+
puts 'word2'
|
18
|
+
|
19
|
+
mcm = MyChildModel.new
|
20
|
+
|
21
|
+
puts 'mcm instance methods=' + MyChildModel.instance_methods(true).inspect
|
22
|
+
#puts 'mcm=' + mcm.instance_methods(false)
|
23
|
+
puts 'mcm class vars = ' + mcm.class.class_variables.inspect
|
24
|
+
puts mcm.class == MyChildModel
|
25
|
+
puts 'saved? ' + mm.save.to_s
|
26
|
+
puts mm.errors.inspect
|
27
|
+
|
28
|
+
puts "mm attributes=" + MyModel.defined_attributes.inspect
|
29
|
+
puts "mcm attributes=" + MyChildModel.defined_attributes.inspect
|
30
|
+
|
31
|
+
mcm2 = MyChildModel.new
|
32
|
+
puts "mcm2 attributes=" + MyChildModel.defined_attributes.inspect
|
33
|
+
|
34
|
+
=end
|
data/test/my_model.rb
CHANGED
@@ -2,10 +2,27 @@ require File.expand_path(File.dirname(__FILE__) + "/../lib/simple_record")
|
|
2
2
|
|
3
3
|
class MyModel < SimpleRecord::Base
|
4
4
|
|
5
|
-
has_attributes :name
|
5
|
+
has_attributes :name, :nickname
|
6
6
|
has_ints :age
|
7
7
|
has_booleans :cool
|
8
|
-
has_dates :
|
8
|
+
has_dates :birthday
|
9
9
|
|
10
10
|
|
11
|
+
#callbacks
|
12
|
+
before_create :set_nickname
|
13
|
+
|
14
|
+
def set_nickname
|
15
|
+
self.nickname = name if self.nickname.blank?
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate
|
19
|
+
errors.add("name", "can't be empty.") if name.blank?
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
def atts
|
25
|
+
@@attributes
|
26
|
+
end
|
27
|
+
|
11
28
|
end
|
data/test/test_simple_record.rb
CHANGED
@@ -24,15 +24,27 @@ class TestSimpleRecord < Test::Unit::TestCase
|
|
24
24
|
mm.age = 32
|
25
25
|
mm.cool = true
|
26
26
|
mm.save
|
27
|
+
|
28
|
+
assert !mm.created.nil?
|
29
|
+
assert !mm.updated.nil?
|
30
|
+
assert !mm.id.nil?
|
31
|
+
assert mm.age == 32
|
32
|
+
assert mm.cool = true
|
33
|
+
assert mm.name = "Travis"
|
34
|
+
|
27
35
|
id = mm.id
|
28
36
|
puts 'id=' + id.to_s
|
29
37
|
# Get the object back
|
30
38
|
mm2 = MyModel.find(id)
|
31
|
-
puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
|
32
|
-
puts mm2.cool.class.name
|
39
|
+
#puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
|
40
|
+
#puts mm2.cool.class.name
|
33
41
|
assert mm2.id == mm.id
|
34
42
|
assert mm2.age == mm.age
|
35
43
|
assert mm2.cool == mm.cool
|
44
|
+
assert mm2.age == 32
|
45
|
+
assert mm2.cool = true
|
46
|
+
assert mm2.name = "Travis"
|
47
|
+
assert mm2.created.is_a? DateTime
|
36
48
|
end
|
37
49
|
|
38
50
|
def test_bad_query
|
@@ -83,39 +95,85 @@ class TestSimpleRecord < Test::Unit::TestCase
|
|
83
95
|
end
|
84
96
|
|
85
97
|
def test_callbacks
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
98
|
+
|
99
|
+
|
100
|
+
mm = MyModel.new
|
101
|
+
assert !mm.save
|
102
|
+
assert mm.errors.count == 1 # name is required
|
103
|
+
|
104
|
+
# test queued callback before_create
|
105
|
+
mm.name = "Travis"
|
106
|
+
assert mm.save
|
107
|
+
# now nickname should be set on before_create
|
108
|
+
assert mm.nickname == mm.name
|
109
|
+
|
110
|
+
mm2 = MyModel.find(mm.id)
|
111
|
+
assert mm2.nickname = mm.nickname
|
112
|
+
assert mm2.name = mm.name
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_dirty
|
119
|
+
mm = MyModel.new
|
120
|
+
mm.name = "Travis"
|
121
|
+
mm.age = 32
|
122
|
+
mm.cool = true
|
123
|
+
mm.save
|
124
|
+
id = mm.id
|
125
|
+
puts 'id=' + id.to_s
|
126
|
+
# Get the object back
|
127
|
+
mm2 = MyModel.find(id)
|
128
|
+
puts 'got=' + mm2.name + ' and he/she is ' + mm2.age.to_s + ' years old and he/she is cool? ' + mm2.cool.to_s
|
129
|
+
assert mm2.id == mm.id
|
130
|
+
assert mm2.age == mm.age
|
131
|
+
assert mm2.cool == mm.cool
|
132
|
+
|
133
|
+
mm2.name = "Travis 2"
|
134
|
+
mm2.save(:dirty=>true)
|
135
|
+
|
136
|
+
# todo: how do we assert this?
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
# http://api.rubyonrails.org/classes/ActiveRecord/Dirty.html#M002136
|
141
|
+
def test_changed
|
142
|
+
mm = MyModel.new
|
143
|
+
mm.name = "Travis"
|
144
|
+
mm.age = 32
|
145
|
+
mm.cool = true
|
146
|
+
mm.save
|
147
|
+
|
148
|
+
puts 'changed?=' + mm.changed?.to_s
|
149
|
+
assert !mm.changed?
|
150
|
+
assert mm.changed.size == 0
|
151
|
+
assert mm.changes.size == 0
|
152
|
+
assert !mm.name_changed?
|
153
|
+
|
154
|
+
mm.name = "Jim"
|
155
|
+
assert mm.changed?
|
156
|
+
assert mm.changed.size == 1
|
157
|
+
assert mm.changed[0] == "name"
|
158
|
+
|
159
|
+
assert mm.changes.size == 1
|
160
|
+
puts 'CHANGES=' + mm.changes.inspect
|
161
|
+
assert mm.changes["name"][0] == "Travis"
|
162
|
+
assert mm.changes["name"][1] == "Jim"
|
163
|
+
|
164
|
+
assert mm.name_changed?
|
165
|
+
assert mm.name_was == "Travis"
|
166
|
+
assert mm.name_change[0] == "Travis"
|
167
|
+
assert mm.name_change[1] == "Jim"
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_attributes_correct
|
172
|
+
|
173
|
+
#MyModel.defined_attributes.each do |a|
|
105
174
|
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
|
109
|
-
# cb_names = self.instance_variable_get(:@#{callback}_names)
|
110
|
-
# cb_names.each { |name|
|
111
|
-
# unless eval(name)
|
112
|
-
# return false
|
113
|
-
# end
|
114
|
-
# }
|
115
|
-
# return true
|
116
|
-
# end
|
117
|
-
# }
|
118
|
-
# end
|
119
|
-
# end
|
175
|
+
#end
|
176
|
+
#MyChildModel.defined_attributes.inspect
|
177
|
+
|
120
178
|
end
|
121
179
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appoxy-simple_record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.26
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Travis Reeder
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-07-
|
13
|
+
date: 2009-07-30 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
@@ -27,6 +27,7 @@ files:
|
|
27
27
|
- README.markdown
|
28
28
|
has_rdoc: true
|
29
29
|
homepage: http://github.com/appoxy/simple_record/
|
30
|
+
licenses:
|
30
31
|
post_install_message:
|
31
32
|
rdoc_options:
|
32
33
|
- --charset=UTF-8
|
@@ -47,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
47
48
|
requirements: []
|
48
49
|
|
49
50
|
rubyforge_project:
|
50
|
-
rubygems_version: 1.
|
51
|
+
rubygems_version: 1.3.5
|
51
52
|
signing_key:
|
52
53
|
specification_version: 2
|
53
54
|
summary: Drop in replacement for ActiveRecord to Amazon SimpleDB instead.
|