appoxy-simple_record 1.0.23 → 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/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.
|