lafcadio 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/lafcadio.rb +1 -1
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/domain.rb +9 -8
- data/lib/lafcadio/domain.rb~ +221 -84
- data/lib/lafcadio/query.rb +1 -1
- data/lib/lafcadio/query.rb~ +211 -94
- metadata +106 -111
data/lib/lafcadio.rb
CHANGED
data/lib/lafcadio.rb~
CHANGED
data/lib/lafcadio/domain.rb
CHANGED
@@ -652,14 +652,15 @@ module Lafcadio
|
|
652
652
|
|
653
653
|
def self.try_load_xml_parser # :nodoc:
|
654
654
|
require 'lafcadio/domain'
|
655
|
-
dirName = LafcadioConfig.new['classDefinitionDir']
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
655
|
+
if ( dirName = LafcadioConfig.new['classDefinitionDir'] )
|
656
|
+
xmlFileName = self.basename + '.xml'
|
657
|
+
xmlPath = File.join( dirName, xmlFileName )
|
658
|
+
begin
|
659
|
+
xml = File.open( xmlPath ) do |f| f.gets( nil ); end
|
660
|
+
ClassDefinitionXmlParser.new( self, xml )
|
661
|
+
rescue Errno::ENOENT
|
662
|
+
# no xml file, so no @xmlParser
|
663
|
+
end
|
663
664
|
end
|
664
665
|
end
|
665
666
|
|
data/lib/lafcadio/domain.rb~
CHANGED
@@ -17,7 +17,7 @@ module Lafcadio
|
|
17
17
|
if className != ''
|
18
18
|
fieldClass = Class.by_name( 'Lafcadio::' + className )
|
19
19
|
register_name( name )
|
20
|
-
field = fieldClass.
|
20
|
+
field = fieldClass.create_from_xml( @domain_class, fieldElt )
|
21
21
|
set_field_attributes( field, fieldElt )
|
22
22
|
else
|
23
23
|
msg = "Couldn't find field class '#{ className }' for field " +
|
@@ -44,7 +44,7 @@ module Lafcadio
|
|
44
44
|
fieldAttr = []
|
45
45
|
fieldAttr << FieldAttribute.new( 'size', FieldAttribute::INTEGER )
|
46
46
|
fieldAttr << FieldAttribute.new( 'unique', FieldAttribute::BOOLEAN )
|
47
|
-
fieldAttr << FieldAttribute.new( '
|
47
|
+
fieldAttr << FieldAttribute.new( 'not_nil', FieldAttribute::BOOLEAN )
|
48
48
|
fieldAttr << FieldAttribute.new( 'enum_type', FieldAttribute::ENUM,
|
49
49
|
BooleanField )
|
50
50
|
fieldAttr << FieldAttribute.new( 'enums', FieldAttribute::HASH )
|
@@ -120,6 +120,8 @@ module Lafcadio
|
|
120
120
|
class InvalidDataError < ArgumentError; end
|
121
121
|
end
|
122
122
|
|
123
|
+
# DomainComparable is used by DomainObject and DomainObjectProxy to define
|
124
|
+
# comparisons.
|
123
125
|
module DomainComparable
|
124
126
|
include Comparable
|
125
127
|
|
@@ -137,6 +139,8 @@ module Lafcadio
|
|
137
139
|
end
|
138
140
|
end
|
139
141
|
|
142
|
+
# Two DomainObjects or DomainObjectProxies are eql? if they have the same
|
143
|
+
# +domain_class+ and the same +pk_id+.
|
140
144
|
def eql?( otherObj ); self == otherObj; end
|
141
145
|
|
142
146
|
def hash; "#{ self.class.name } #{ pk_id }".hash; end
|
@@ -146,24 +150,37 @@ module Lafcadio
|
|
146
150
|
# of DomainObject.
|
147
151
|
#
|
148
152
|
# = Defining fields
|
149
|
-
# There are
|
150
|
-
# 1.
|
151
|
-
#
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
153
|
+
# There are three ways to define the fields of a DomainObject subclass.
|
154
|
+
# 1. <b>One-line field definitions</b>: When defining the class, add fields
|
155
|
+
# with class methods like so:
|
156
|
+
# class User < Lafcadio::DomainObject
|
157
|
+
# string 'lastName'
|
158
|
+
# email 'email'
|
159
|
+
# string 'password'
|
160
|
+
# date 'birthday'
|
161
|
+
# end
|
162
|
+
# These can also be pluralized:
|
163
|
+
# class User < Lafcadio::DomainObject
|
164
|
+
# strings 'lastName', 'password'
|
165
|
+
# email 'email'
|
166
|
+
# date 'birthday'
|
167
|
+
# end
|
168
|
+
# The class methods you can use are +blob+, +boolean+, +date+,
|
169
|
+
# +date_time+, +domain_object+, +email+, +enum+, +float+, +integer+,
|
170
|
+
# +month+, +state+, +string+, +text_list+. These correspond to BlobField,
|
171
|
+
# BooleanField, DateField, DateTimeField, DomainObjectField, EmailField,
|
172
|
+
# EnumField, FloatField, IntegerField, MonthField, StateField,
|
173
|
+
# StringField, and TextListField, respectively. Consult their individual
|
174
|
+
# RDoc entries for more on how to parameterize them through the class
|
175
|
+
# methods.
|
176
|
+
# 2. <b>Overriding DomainObject.get_class_fields</b>: The method should
|
177
|
+
# return an Array of instances of ObjectField or its children. If you use
|
178
|
+
# this method, make sure to call the superclass (this is needed to define
|
179
|
+
# the primary key field). The order of fields in the Array is unimportant.
|
163
180
|
# For example:
|
164
181
|
# class User < DomainObject
|
165
182
|
# def User.get_class_fields
|
166
|
-
# fields =
|
183
|
+
# fields = super
|
167
184
|
# fields << StringField.new(self, 'firstName')
|
168
185
|
# fields << StringField.new(self, 'lastName')
|
169
186
|
# fields << StringField.new(self, 'email')
|
@@ -172,63 +189,89 @@ module Lafcadio
|
|
172
189
|
# fields
|
173
190
|
# end
|
174
191
|
# end
|
192
|
+
# This method is probably not worth the trouble unless you end up defining
|
193
|
+
# your own field classes for some reason.
|
194
|
+
# 3. <b>Defining fields in an XML file</b>: Note that this method may be
|
195
|
+
# removed in the future. To do this:
|
196
|
+
# 1. Set one directory to contain all your XML files, by setting
|
197
|
+
# +classDefinitionDir+ in your LafcadioConfig file.
|
198
|
+
# 2. Write one XML file per domain class. For example, a User.xml file
|
199
|
+
# might look like:
|
200
|
+
# <lafcadio_class_definition name="User">
|
201
|
+
# <field name="lastName" class="StringField"/>
|
202
|
+
# <field name="email" class="StringField"/>
|
203
|
+
# <field name="password" class="StringField"/>
|
204
|
+
# <field name="birthday" class="DateField"/>
|
205
|
+
# </lafcadio_class_definition>
|
175
206
|
#
|
176
207
|
# = Setting and retrieving fields
|
177
208
|
# Once your fields are defined, you can create an instance by passing in a
|
178
209
|
# hash of field names and values.
|
179
|
-
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
210
|
+
#
|
211
|
+
# john = User.new(
|
212
|
+
# :firstName => 'John', :lastName => 'Doe',
|
213
|
+
# :email => 'john.doe@email.com', :password => 'my_password',
|
214
|
+
# :birthday => Date.new( 1979, 1, 15 )
|
215
|
+
# )
|
183
216
|
#
|
184
217
|
# You can read and write these fields like normal instance attributes.
|
185
|
-
# john.email => 'john.doe@email.com'
|
218
|
+
# john.email # => 'john.doe@email.com'
|
186
219
|
# john.email = 'john.doe@mail.email.com'
|
187
220
|
#
|
188
221
|
# If your domain class has fields that refer to other domain classes, or even
|
189
|
-
# to another row in the same table, you can use a DomainObjectField to
|
190
|
-
# relation.
|
191
|
-
#
|
192
|
-
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
198
|
-
|
199
|
-
# msg = Message.new(
|
200
|
-
|
201
|
-
|
202
|
-
#
|
222
|
+
# to another row in the same table, you can use a DomainObjectField to
|
223
|
+
# express the relation.
|
224
|
+
#
|
225
|
+
# class Message < Lafcadio::DomainObject
|
226
|
+
# strings 'subject', 'body'
|
227
|
+
# domain_object User, 'author'
|
228
|
+
# domain_object User, 'recipient'
|
229
|
+
# date 'date_sent'
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# msg = Message.new(
|
233
|
+
# :subject => 'hi there',
|
234
|
+
# :body => 'You wanna go to the movies on Saturday?',
|
235
|
+
# :author => john, :recipient => jane, :dateSent => Date.today
|
236
|
+
# )
|
203
237
|
#
|
204
238
|
# = pk_id and committing
|
205
|
-
# Lafcadio requires that each table has a numeric primary key. It assumes
|
206
|
-
# this key is named +pk_id+ in the database, though that can be
|
239
|
+
# Lafcadio requires that each table has a numeric primary key. It assumes
|
240
|
+
# that this key is named +pk_id+ in the database, though that can be
|
241
|
+
# overridden.
|
207
242
|
#
|
208
|
-
# When you create a domain object by calling new, you should not
|
209
|
-
# +pk_id+ to the new instance. The pk_id will automatically be set
|
210
|
-
# commit the object by calling DomainObject#commit.
|
243
|
+
# When you create a domain object by calling DomainObject.new, you should not
|
244
|
+
# assign a +pk_id+ to the new instance. The pk_id will automatically be set
|
245
|
+
# when you commit the object by calling DomainObject#commit.
|
211
246
|
#
|
212
|
-
# However, you may want to manually set +pk_id+ when setting up a test case,
|
213
|
-
# you can ensure that a domain object has a given primary key.
|
247
|
+
# However, you may want to manually set +pk_id+ when setting up a test case,
|
248
|
+
# so you can ensure that a domain object has a given primary key.
|
214
249
|
#
|
215
250
|
# = Naming assumptions, and how to override them
|
216
251
|
# By default, Lafcadio assumes that every domain object is indexed by the
|
217
252
|
# field +pk_id+ in the database schema. If you're dealing with a table that
|
218
|
-
# uses a different field name,
|
253
|
+
# uses a different field name, call DomainObject.sql_primary_key_name.
|
219
254
|
# However, you will always use +pk_id+ in your Ruby code.
|
220
255
|
#
|
221
|
-
# Lafcadio assumes that a domain class corresponds to a table whose name is
|
222
|
-
# the
|
223
|
-
# class is assumed to be stored in a "users" table, while a ProductCategory
|
224
|
-
# class is assumed to be stored in a "
|
256
|
+
# Lafcadio assumes that a domain class corresponds to a table whose name is
|
257
|
+
# the pluralized, lower-case, underscored version of the class name. A User
|
258
|
+
# class is assumed to be stored in a "users" table, while a ProductCategory
|
259
|
+
# class is assumed to be stored in a "product_categories" table. Call
|
225
260
|
# DomainObject.table_name to override this behavior.
|
226
261
|
#
|
262
|
+
# class LegacyThing < Lafcadio::DomainObject
|
263
|
+
# string 'some_field'
|
264
|
+
# sql_primary_key_name 'some_legacy_id'
|
265
|
+
# table_name 'some_legacy_table'
|
266
|
+
# end
|
267
|
+
# thing = LegacyThing[9909]
|
268
|
+
# thing.pk_id # => 9909
|
269
|
+
#
|
227
270
|
# = Inheritance
|
228
271
|
# Domain classes can inherit from other domain classes; they have all the
|
229
272
|
# fields of any concrete superclasses plus any new fields defined for
|
230
273
|
# themselves. You can use normal inheritance to define this:
|
231
|
-
# class User < DomainObject
|
274
|
+
# class User < Lafcadio::DomainObject
|
232
275
|
# ...
|
233
276
|
# end
|
234
277
|
#
|
@@ -248,6 +291,9 @@ module Lafcadio
|
|
248
291
|
|
249
292
|
include DomainComparable
|
250
293
|
|
294
|
+
# Shortcut method for retrieving one domain object.
|
295
|
+
#
|
296
|
+
# User[7356] # => user with the pk_id 7536
|
251
297
|
def self.[]( pk_id ); get( pk_id ); end
|
252
298
|
|
253
299
|
def self.abstract_subclass?( a_class ) #:nodoc:
|
@@ -258,11 +304,12 @@ module Lafcadio
|
|
258
304
|
[ MapObject ]
|
259
305
|
end
|
260
306
|
|
261
|
-
|
307
|
+
# Returns every committed instance of the domain class.
|
308
|
+
#
|
309
|
+
# User.all # => all users
|
310
|
+
def self.all; ObjectStore.get_object_store.all( self ); end
|
262
311
|
|
263
|
-
|
264
|
-
# superclasses.
|
265
|
-
def self.all_fields
|
312
|
+
def self.all_fields # :nodoc:
|
266
313
|
self_and_concrete_superclasses.map { |a_class|
|
267
314
|
a_class.class_fields
|
268
315
|
}.flatten
|
@@ -286,7 +333,7 @@ module Lafcadio
|
|
286
333
|
subclass_record.fields
|
287
334
|
end
|
288
335
|
|
289
|
-
def self.create_field( field_class, *args )
|
336
|
+
def self.create_field( field_class, *args ) #:nodoc:
|
290
337
|
subclass_record.maybe_init_fields
|
291
338
|
att_hash = create_field_att_hash( field_class, *args )
|
292
339
|
field = field_class.create_with_args( self, att_hash )
|
@@ -328,6 +375,20 @@ module Lafcadio
|
|
328
375
|
create_field( field_class, arg ) unless arg.nil?
|
329
376
|
end
|
330
377
|
|
378
|
+
# Sets a default setup hash for a field of a certain class. Useful for
|
379
|
+
# mapping domain classes with lots of fields and unusual field
|
380
|
+
# configurations.
|
381
|
+
#
|
382
|
+
# class LotsOfBooleans < Lafcadio::DomainObject
|
383
|
+
# default_field_setup_hash(
|
384
|
+
# Lafcadio::BooleanField,
|
385
|
+
# {
|
386
|
+
# 'enum_type' => Lafcadio::BooleanField::ENUMS_CAPITAL_YES_NO
|
387
|
+
# }
|
388
|
+
# )
|
389
|
+
# booleans 'this', 'that', 'the_other', 'and_another_one',
|
390
|
+
# 'this_one_too'
|
391
|
+
# end
|
331
392
|
def self.default_field_setup_hash( field_class, hash )
|
332
393
|
subclass_record.default_field_setup_hash[field_class] = hash
|
333
394
|
end
|
@@ -357,11 +418,16 @@ module Lafcadio
|
|
357
418
|
end
|
358
419
|
end
|
359
420
|
|
421
|
+
# Tests whether a given domain object exists.
|
422
|
+
#
|
423
|
+
# User.exist?( 8280 ) # => returns true iff there's a User 8280
|
424
|
+
# User.exist?( 'Hwang', :lastName ) # => returns true iff there's a User
|
425
|
+
# # with the last name 'Hwang'
|
360
426
|
def self.exist?( search_term, field_name = :pk_id )
|
361
427
|
query = Query.infer( self ) { |dobj|
|
362
428
|
dobj.send( field_name ).equals( search_term )
|
363
429
|
}
|
364
|
-
!ObjectStore.get_object_store.
|
430
|
+
!ObjectStore.get_object_store.query( query ).empty?
|
365
431
|
end
|
366
432
|
|
367
433
|
def self.field( fieldName ) #:nodoc:
|
@@ -374,27 +440,53 @@ module Lafcadio
|
|
374
440
|
field
|
375
441
|
end
|
376
442
|
|
443
|
+
# Returns the first domain object it can find.
|
444
|
+
#
|
445
|
+
# very_first_user = User.first
|
377
446
|
def self.first; all.first; end
|
378
|
-
|
447
|
+
|
448
|
+
# This class method has a few uses, depending on how you use it.
|
449
|
+
# 1. Pass DomainObject.get a block in order to run a complex query:
|
450
|
+
# adult_hwangs = User.get { |user|
|
451
|
+
# user.lastName.equals( 'Hwang' ) &
|
452
|
+
# user.birthday.lte( Date.today - ( 365 * 18 ) )
|
453
|
+
# }
|
454
|
+
# See query.rb for more information about how to form these
|
455
|
+
# queries.
|
456
|
+
# 2. Pass it a simple search term and a field name to retrieve every domain
|
457
|
+
# object matching the term. The field name will default to +pk_id+.
|
458
|
+
# hwangs = User.get( 'Hwang', :lastName )
|
459
|
+
# user123 = User.get( 123 ).first
|
460
|
+
# 3. Pass it a { :group => :count } hash to retrieve a count result hash.
|
461
|
+
# This interface is fairly new and may be refined (that is, changed) in
|
462
|
+
# the future.
|
463
|
+
# num_users = User.get( :group => :count ).first[:count]
|
379
464
|
def self.get( *args )
|
380
465
|
if block_given?
|
381
466
|
query = Query.infer( self ) { |dobj| yield( dobj ) }
|
382
|
-
ObjectStore.get_object_store.
|
467
|
+
ObjectStore.get_object_store.query( query )
|
383
468
|
elsif args.size == 1
|
384
469
|
arg = args.first
|
385
470
|
if arg.is_a? Fixnum
|
386
471
|
ObjectStore.get_object_store.get( self, *args )
|
387
472
|
else
|
388
473
|
qry = Query.new( self, nil, { :group_functions => [ :count ] } )
|
389
|
-
ObjectStore.get_object_store.
|
474
|
+
ObjectStore.get_object_store.group_query qry
|
390
475
|
end
|
391
476
|
else
|
392
|
-
|
477
|
+
search_term = args.shift
|
478
|
+
field_name = (
|
479
|
+
args.shift or link_field( search_term.domain_class ).name
|
480
|
+
)
|
481
|
+
qry = Query::Equals.new( field_name, search_term, self )
|
482
|
+
ObjectStore.get_object_store.query qry
|
393
483
|
end
|
394
484
|
end
|
395
485
|
|
396
486
|
# Returns an Array of ObjectField instances for this domain class, parsing
|
397
|
-
# them from XML if necessary.
|
487
|
+
# them from XML if necessary. You can override this to define a domain
|
488
|
+
# class' fields, though it will probably just be simpler to use one-line
|
489
|
+
# class methods instead.
|
398
490
|
def self.get_class_fields
|
399
491
|
if self.methods( false ).include?( 'get_class_fields' )
|
400
492
|
[ subclass_record.pk_field ]
|
@@ -416,6 +508,9 @@ module Lafcadio
|
|
416
508
|
superclass != DomainObject and !abstract_subclass?( superclass )
|
417
509
|
end
|
418
510
|
|
511
|
+
# Returns the last domain object.
|
512
|
+
#
|
513
|
+
# last_msg = Message.last
|
419
514
|
def self.last; all.last; end
|
420
515
|
|
421
516
|
def self.link_field( linked_domain_class ) # :nodoc:
|
@@ -457,9 +552,13 @@ module Lafcadio
|
|
457
552
|
end
|
458
553
|
end
|
459
554
|
|
555
|
+
# Returns the only committed instance of the domain class. Will raise an
|
556
|
+
# IndexError if there are 0, or more than 1, domain objects.
|
557
|
+
#
|
558
|
+
# the_one_user = User.only
|
460
559
|
def self.only; all.only; end
|
461
560
|
|
462
|
-
def self.require_domain_file( typeString )
|
561
|
+
def self.require_domain_file( typeString ) # :nodoc:
|
463
562
|
typeString =~ /([^\:]*)$/
|
464
563
|
fileName = $1
|
465
564
|
domain_dirs.each { |domainDir|
|
@@ -485,7 +584,7 @@ module Lafcadio
|
|
485
584
|
classes
|
486
585
|
end
|
487
586
|
|
488
|
-
def self.singleton_method_added( symbol )
|
587
|
+
def self.singleton_method_added( symbol ) # :nodoc:
|
489
588
|
if symbol.id2name == 'sql_primary_key_name' && self < DomainObject
|
490
589
|
begin
|
491
590
|
field( 'pk_id' ).db_field_name = self.send( symbol )
|
@@ -495,23 +594,47 @@ module Lafcadio
|
|
495
594
|
end
|
496
595
|
end
|
497
596
|
|
498
|
-
#
|
499
|
-
#
|
597
|
+
# If +set_db_field_name+ is nil, this will return the sql name of the
|
598
|
+
# primary key. If +set_db_field_name+ isn't nil, it will set the sql name.
|
599
|
+
#
|
600
|
+
# class User < Lafcadio::DomainObject
|
601
|
+
# string 'firstNames'
|
602
|
+
# end
|
603
|
+
# User.sql_primary_key_name # => 'pk_id'
|
604
|
+
# class User < Lafcadio::DomainObject
|
605
|
+
# sql_primary_key_name 'some_other_id'
|
606
|
+
# end
|
607
|
+
# User.sql_primary_key_name # => 'some_other_id'
|
500
608
|
def self.sql_primary_key_name( set_db_field_name = nil )
|
501
609
|
field( 'pk_id' ).db_field_name = set_db_field_name if set_db_field_name
|
502
610
|
field( 'pk_id' ).db_field_name
|
503
611
|
end
|
504
612
|
|
505
|
-
def self.subclass_record
|
613
|
+
def self.subclass_record # :nodoc:
|
614
|
+
@@subclass_records[self]
|
615
|
+
end
|
506
616
|
|
507
617
|
def self.subclasses #:nodoc:
|
508
618
|
@@subclass_records.keys
|
509
619
|
end
|
510
620
|
|
511
|
-
#
|
512
|
-
#
|
513
|
-
#
|
514
|
-
# assumed to be stored in a "
|
621
|
+
# If +set_table_name+ is nil, DomainObject.table_name will return the table
|
622
|
+
# name. Lafcadio assumes that a domain class corresponds to a table whose
|
623
|
+
# name is the pluralized, lower-case, underscored version of the class
|
624
|
+
# name. A User class is assumed to be stored in a "users" table, while a
|
625
|
+
# ProductCategory class is assumed to be stored in a "product_categories"
|
626
|
+
# table.
|
627
|
+
#
|
628
|
+
# If +set_table_name+ is not nil, this will set the table name.
|
629
|
+
#
|
630
|
+
# class User < Lafcadio::DomainObject
|
631
|
+
# string 'firstNames'
|
632
|
+
# end
|
633
|
+
# User.table_name # => 'users'
|
634
|
+
# class User < Lafcadio::DomainObject
|
635
|
+
# table_name 'some_table'
|
636
|
+
# end
|
637
|
+
# User.table_name # => 'some_table'
|
515
638
|
def self.table_name( set_table_name = nil )
|
516
639
|
if set_table_name
|
517
640
|
@table_name = set_table_name
|
@@ -527,7 +650,7 @@ module Lafcadio
|
|
527
650
|
end
|
528
651
|
end
|
529
652
|
|
530
|
-
def self.try_load_xml_parser
|
653
|
+
def self.try_load_xml_parser # :nodoc:
|
531
654
|
require 'lafcadio/domain'
|
532
655
|
dirName = LafcadioConfig.new['classDefinitionDir']
|
533
656
|
xmlFileName = self.basename + '.xml'
|
@@ -544,12 +667,14 @@ module Lafcadio
|
|
544
667
|
attr_reader :delete
|
545
668
|
protected :fields_set, :field_values
|
546
669
|
|
547
|
-
#
|
670
|
+
# +field_hash+ should contain key-value associations for the different
|
548
671
|
# fields of this domain class. For example, instantiating a User class
|
549
672
|
# might look like:
|
550
673
|
#
|
551
|
-
# User.new(
|
552
|
-
#
|
674
|
+
# User.new(
|
675
|
+
# 'firstNames' => 'John', 'lastName' => 'Doe',
|
676
|
+
# 'email' => 'john.doe@email.com', 'password' => 'l33t'
|
677
|
+
# )
|
553
678
|
#
|
554
679
|
# In normal usage any code you write that creates a domain object will not
|
555
680
|
# define the +pk_id+ field. The system assumes that a domain object with an
|
@@ -558,11 +683,11 @@ module Lafcadio
|
|
558
683
|
#
|
559
684
|
# If you're creating mock objects for unit tests, you can explicitly set
|
560
685
|
# the +pk_id+ to represent objects that already exist in the database.
|
561
|
-
def initialize(
|
562
|
-
|
686
|
+
def initialize( field_hash )
|
687
|
+
field_hash = preprocess_field_hash field_hash
|
563
688
|
@field_values = {}
|
564
689
|
@fields_set = []
|
565
|
-
|
690
|
+
reset_original_values_hash @fieldHash
|
566
691
|
check_fields = LafcadioConfig.new()['checkFields']
|
567
692
|
verify if %w( onInstantiate onAllStates ).include?( check_fields )
|
568
693
|
end
|
@@ -589,6 +714,8 @@ module Lafcadio
|
|
589
714
|
@delete = value
|
590
715
|
end
|
591
716
|
|
717
|
+
# Deletes a domain object, committing the delete to the database
|
718
|
+
# immediately.
|
592
719
|
def delete!
|
593
720
|
self.delete = true
|
594
721
|
commit
|
@@ -618,11 +745,10 @@ module Lafcadio
|
|
618
745
|
elsif ( field = getter_field( methId ) )
|
619
746
|
field_value( field )
|
620
747
|
else
|
621
|
-
new_symbol = ( 'get_' + methId.id2name ).to_sym
|
622
748
|
object_store = ObjectStore.get_object_store
|
623
|
-
if object_store.respond_to?
|
749
|
+
if object_store.respond_to? methId
|
624
750
|
args = [ self ].concat args
|
625
|
-
object_store.send(
|
751
|
+
object_store.send( methId, *args )
|
626
752
|
else
|
627
753
|
super( methId, *args )
|
628
754
|
end
|
@@ -635,7 +761,7 @@ module Lafcadio
|
|
635
761
|
nil
|
636
762
|
end
|
637
763
|
|
638
|
-
def preprocess_field_hash( fieldHash )
|
764
|
+
def preprocess_field_hash( fieldHash ) # :nodoc:
|
639
765
|
if fieldHash.is_a? Hash
|
640
766
|
fieldHash.keys.each { |key|
|
641
767
|
if self.class.field( key.to_s ).nil?
|
@@ -655,6 +781,10 @@ module Lafcadio
|
|
655
781
|
nil
|
656
782
|
end
|
657
783
|
|
784
|
+
def reset_original_values_hash( f = @field_values ) #:nodoc:
|
785
|
+
@original_values = ReadOnlyHash.new( f.clone )
|
786
|
+
end
|
787
|
+
|
658
788
|
def set_field_value( field, value ) #:nodoc:
|
659
789
|
if (
|
660
790
|
field.is_a?( DomainObjectField ) and
|
@@ -678,11 +808,18 @@ module Lafcadio
|
|
678
808
|
end
|
679
809
|
end
|
680
810
|
|
811
|
+
# Updates a domain object and commits the changes to the database
|
812
|
+
# immediately.
|
813
|
+
#
|
814
|
+
# user99 = User[99]
|
815
|
+
# user99.update!( :firstNames => 'Bill', :password => 'n3wp4ssw0rd' )
|
681
816
|
def update!( changes )
|
682
817
|
changes.each do |sym, value| self.send( sym.to_s + '=', value ); end
|
683
818
|
commit
|
684
819
|
end
|
685
820
|
|
821
|
+
# If you're running against a MockObjectStore, this will verify each field
|
822
|
+
# and raise an error if there's any invalid fields.
|
686
823
|
def verify
|
687
824
|
if ObjectStore.mock?
|
688
825
|
self.class.get_class_fields.each { |field|
|
@@ -691,11 +828,11 @@ module Lafcadio
|
|
691
828
|
end
|
692
829
|
end
|
693
830
|
|
694
|
-
class ReadOnlyHash < DelegateClass( Hash )
|
831
|
+
class ReadOnlyHash < DelegateClass( Hash ) # :nodoc:
|
695
832
|
def []=( key, val ); raise NoMethodError; end
|
696
833
|
end
|
697
834
|
|
698
|
-
class SubclassRecord
|
835
|
+
class SubclassRecord # :nodoc:
|
699
836
|
attr_accessor :default_field_setup_hash, :fields, :sql_primary_key
|
700
837
|
|
701
838
|
def initialize( subclass )
|
@@ -720,11 +857,11 @@ module Lafcadio
|
|
720
857
|
|
721
858
|
# Any domain class that is used mostly to map between two other domain
|
722
859
|
# classes should be a subclass of MapObject. Subclasses of MapObject should
|
723
|
-
# override MapObject.
|
860
|
+
# override MapObject.mapped_classes, returning a two-element array containing
|
724
861
|
# the domain classes that the map object maps between.
|
725
862
|
class MapObject < DomainObject
|
726
863
|
def self.other_mapped_type(firstType) #:nodoc:
|
727
|
-
mt =
|
864
|
+
mt = mapped_classes.clone
|
728
865
|
mt.delete firstType
|
729
866
|
mt.only
|
730
867
|
end
|