lafcadio 0.9.1 → 0.9.2
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/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
|