lafcadio 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,746 +0,0 @@
1
- require 'rubygems'
2
- require 'dbi'
3
- require_gem 'log4r'
4
- require 'lafcadio/domain'
5
- require 'lafcadio/query'
6
- require 'lafcadio/util'
7
-
8
- module Lafcadio
9
- class Committer #:nodoc:
10
- INSERT = 1
11
- UPDATE = 2
12
- DELETE = 3
13
-
14
- attr_reader :commit_type, :db_object
15
-
16
- def initialize(db_object, dbBridge)
17
- @db_object = db_object
18
- @dbBridge = dbBridge
19
- @objectStore = ObjectStore.get_object_store
20
- @commit_type = nil
21
- end
22
-
23
- def execute
24
- @db_object.verify if LafcadioConfig.new()['checkFields'] == 'onCommit'
25
- set_commit_type
26
- @db_object.last_commit = get_last_commit
27
- @db_object.pre_commit_trigger
28
- update_dependent_domain_objects if @db_object.delete
29
- @dbBridge.commit @db_object
30
- unless @db_object.pk_id
31
- @db_object.pk_id = @dbBridge.last_pk_id_inserted
32
- end
33
- @db_object.post_commit_trigger
34
- end
35
-
36
- def get_last_commit
37
- if @db_object.delete
38
- DomainObject::COMMIT_DELETE
39
- elsif @db_object.pk_id
40
- DomainObject::COMMIT_EDIT
41
- else
42
- DomainObject::COMMIT_ADD
43
- end
44
- end
45
-
46
- def set_commit_type
47
- if @db_object.delete
48
- @commit_type = DELETE
49
- elsif @db_object.pk_id
50
- @commit_type = UPDATE
51
- else
52
- @commit_type = INSERT
53
- end
54
- end
55
-
56
- def update_dependent_domain_objects
57
- dependent_classes = @db_object.object_type.dependent_classes
58
- dependent_classes.keys.each { |aClass|
59
- field = dependent_classes[aClass]
60
- collection = @objectStore.get_filtered( aClass.name, @db_object,
61
- field.name )
62
- collection.each { |dependentObject|
63
- if field.delete_cascade
64
- dependentObject.delete = true
65
- else
66
- dependentObject.send( field.name + '=', nil )
67
- end
68
- @objectStore.commit(dependentObject)
69
- }
70
- }
71
- end
72
- end
73
-
74
- class CouldntMatchObjectTypeError < RuntimeError #:nodoc:
75
- end
76
-
77
- class DbBridge #:nodoc:
78
- @@dbh = nil
79
- @@last_pk_id_inserted = nil
80
-
81
- def self._load(aString)
82
- aString =~ /dbh:/
83
- dbString = $'
84
- begin
85
- dbh = Marshal.load(dbString)
86
- rescue TypeError
87
- dbh = nil
88
- end
89
- new dbh
90
- end
91
-
92
- def initialize
93
- @db_conn = DbConnection.get_db_connection
94
- ObjectSpace.define_finalizer( self, proc { |id|
95
- DbConnection.get_db_connection.disconnect
96
- } )
97
- end
98
-
99
- def _dump(aDepth)
100
- dbDump = @dbh.respond_to?( '_dump' ) ? @dbh._dump : @dbh.class.to_s
101
- "dbh:#{dbDump}"
102
- end
103
-
104
- def commit(db_object)
105
- sqlMaker = DomainObjectSqlMaker.new(db_object)
106
- sqlMaker.sql_statements.each { |sql, binds| execute_commit( sql, binds ) }
107
- if sqlMaker.sql_statements[0].first =~ /insert/
108
- sql = 'select last_insert_id()'
109
- result = execute_select( sql )
110
- @@last_pk_id_inserted = result[0]['last_insert_id()'].to_i
111
- end
112
- end
113
-
114
- def execute_commit( sql, binds ); @db_conn.do( sql, *binds ); end
115
-
116
- def execute_select(sql)
117
- maybe_log sql
118
- begin
119
- @db_conn.select_all( sql )
120
- rescue DBI::DatabaseError => e
121
- raise $!.to_s + ": #{ e.errstr }"
122
- end
123
- end
124
-
125
- def get_collection_by_query(query)
126
- object_type = query.object_type
127
- execute_select( query.to_sql ).collect { |row_hash|
128
- object_type.new( SqlValueConverter.new( object_type, row_hash ) )
129
- }
130
- end
131
-
132
- def group_query( query )
133
- execute_select( query.to_sql )[0].collect { |val|
134
- if query.field_name != query.object_type.sql_primary_key_name
135
- a_field = query.object_type.get_field( query.field_name )
136
- a_field.value_from_sql( val )
137
- else
138
- val.to_i
139
- end
140
- }
141
- end
142
-
143
- def last_pk_id_inserted; @@last_pk_id_inserted; end
144
-
145
- def maybe_log(sql)
146
- config = LafcadioConfig.new
147
- if config['logSql'] == 'y'
148
- sqllog = Log4r::Logger['sql'] || Log4r::Logger.new( 'sql' )
149
- filename = File.join( config['logdir'], config['sqlLogFile'] || 'sql' )
150
- outputter = Log4r::FileOutputter.new( 'outputter',
151
- { :filename => filename } )
152
- sqllog.outputters = outputter
153
- sqllog.info sql
154
- end
155
- end
156
- end
157
-
158
- class DbConnection < ContextualService
159
- @@connectionClass = DBI
160
- @@db_name = nil
161
- @@dbh = nil
162
-
163
- def self.flush
164
- DbConnection.set_db_connection( nil )
165
- @@dbh = nil
166
- end
167
-
168
- def self.set_connection_class( aClass ); @@connectionClass = aClass; end
169
-
170
- def self.set_db_name( db_name ); @@db_name = db_name; end
171
-
172
- def self.set_dbh( dbh ); @@dbh = dbh; end
173
-
174
- def initialize
175
- @@dbh = load_new_dbh if @@dbh.nil?
176
- @dbh = @@dbh
177
- end
178
-
179
- def disconnect; @dbh.disconnect if @dbh; end
180
-
181
- def load_new_dbh
182
- config = LafcadioConfig.new
183
- dbName = @@db_name || config['dbname']
184
- dbAndHost = nil
185
- if dbName && config['dbhost']
186
- dbAndHost = "dbi:Mysql:#{ dbName }:#{ config['dbhost'] }"
187
- else
188
- dbAndHost = "dbi:#{config['dbconn']}"
189
- end
190
- @@dbh = @@connectionClass.connect( dbAndHost, config['dbuser'],
191
- config['dbpassword'] )
192
- end
193
-
194
- def method_missing( symbol, *args )
195
- @dbh.send( symbol, *args )
196
- end
197
- end
198
-
199
- class DomainObjectInitError < RuntimeError #:nodoc:
200
- attr_reader :messages
201
-
202
- def initialize(messages)
203
- @messages = messages
204
- end
205
- end
206
-
207
- class DomainObjectNotFoundError < RuntimeError #:nodoc:
208
- end
209
-
210
- # The DomainObjectProxy is used when retrieving domain objects that are
211
- # linked to other domain objects with LinkFields. In terms of +object_type+ and
212
- # +pk_id+, a DomainObjectProxy instance looks to the outside world like the
213
- # domain object it's supposed to represent. It only retrieves its domain
214
- # object from the database when member data is requested.
215
- #
216
- # In normal usage you will probably never manipulate a DomainObjectProxy
217
- # directly, but you may discover it by accident by calling
218
- # DomainObjectProxy#class (or DomainObject#class) instead of
219
- # DomainObjectProxy#object_type (or DomainObjectProxy#object_type).
220
- class DomainObjectProxy
221
- include DomainComparable
222
-
223
- attr_accessor :object_type, :pk_id
224
-
225
- def initialize(object_typeOrDbObject, pk_id = nil)
226
- if pk_id
227
- @object_type = object_typeOrDbObject
228
- @pk_id = pk_id
229
- elsif object_typeOrDbObject.class < DomainObject
230
- @db_object = object_typeOrDbObject
231
- @d_obj_retrieve_time = Time.now
232
- @object_type = @db_object.class
233
- @pk_id = @db_object.pk_id
234
- else
235
- raise ArgumentError
236
- end
237
- @db_object = nil
238
- end
239
-
240
- def get_db_object
241
- object_store = ObjectStore.get_object_store
242
- if @db_object.nil? || needs_refresh?
243
- @db_object = object_store.get(@object_type, @pk_id)
244
- @d_obj_retrieve_time = Time.now
245
-
246
- end
247
- @db_object
248
- end
249
-
250
- def hash
251
- get_db_object.hash
252
- end
253
-
254
- def method_missing(methodId, *args)
255
- get_db_object.send(methodId.id2name, *args)
256
- end
257
-
258
- def needs_refresh?
259
- object_store = ObjectStore.get_object_store
260
- last_commit_time = object_store.last_commit_time( @object_type, @pk_id )
261
- !last_commit_time.nil? && last_commit_time > @d_obj_retrieve_time
262
- end
263
-
264
- def to_s
265
- get_db_object.to_s
266
- end
267
- end
268
-
269
- class DomainObjectSqlMaker #:nodoc:
270
- attr_reader :bind_values
271
-
272
- def initialize(obj); @obj = obj; end
273
-
274
- def delete_sql(object_type)
275
- "delete from #{ object_type.table_name} " +
276
- "where #{ object_type.sql_primary_key_name }=#{ @obj.pk_id }"
277
- end
278
-
279
- def get_name_value_pairs(object_type)
280
- nameValues = []
281
- object_type.class_fields.each { |field|
282
- unless field.instance_of?( PrimaryKeyField )
283
- value = @obj.send(field.name)
284
- unless field.db_will_automatically_write
285
- nameValues << field.name_for_sql
286
- nameValues <<(field.value_for_sql(value))
287
- end
288
- if field.bind_write?
289
- @bind_values << value
290
- end
291
- end
292
- }
293
- QueueHash.new( *nameValues )
294
- end
295
-
296
- def insert_sql(object_type)
297
- fields = object_type.class_fields
298
- nameValuePairs = get_name_value_pairs(object_type)
299
- if object_type.is_based_on?
300
- nameValuePairs[object_type.sql_primary_key_name] = 'LAST_INSERT_ID()'
301
- end
302
- fieldNameStr = nameValuePairs.keys.join ", "
303
- fieldValueStr = nameValuePairs.values.join ", "
304
- "insert into #{ object_type.table_name}(#{fieldNameStr}) " +
305
- "values(#{fieldValueStr})"
306
- end
307
-
308
- def sql_statements
309
- statements = []
310
- if @obj.error_messages.size > 0
311
- raise DomainObjectInitError, @obj.error_messages, caller
312
- end
313
- @obj.class.self_and_concrete_superclasses.each { |object_type|
314
- statements << statement_bind_value_pair( object_type )
315
- }
316
- statements.reverse
317
- end
318
-
319
- def statement_bind_value_pair( object_type )
320
- @bind_values = []
321
- if @obj.pk_id == nil
322
- statement = insert_sql(object_type)
323
- else
324
- if @obj.delete
325
- statement = delete_sql(object_type)
326
- else
327
- statement = update_sql(object_type)
328
- end
329
- end
330
- [statement, @bind_values]
331
- end
332
-
333
- def update_sql(object_type)
334
- nameValueStrings = []
335
- nameValuePairs = get_name_value_pairs(object_type)
336
- nameValuePairs.each { |key, value|
337
- nameValueStrings << "#{key}=#{ value }"
338
- }
339
- allNameValues = nameValueStrings.join ', '
340
- "update #{ object_type.table_name} set #{allNameValues} " +
341
- "where #{ object_type.sql_primary_key_name}=#{@obj.pk_id}"
342
- end
343
- end
344
-
345
- class FieldMatchError < StandardError; end
346
-
347
- # The ObjectStore represents the database in a Lafcadio application.
348
- #
349
- # = Configuring the ObjectStore
350
- # The ObjectStore depends on a few values being set correctly in the
351
- # LafcadioConfig file:
352
- # [dbuser] The database username.
353
- # [dbpassword] The database password.
354
- # [dbname] The database name.
355
- # [dbhost] The database host.
356
- #
357
- # = Instantiating ObjectStore
358
- # The ObjectStore is a ContextualService, meaning you can't get an instance by
359
- # calling ObjectStore.new. Instead, you should call
360
- # ObjectStore.get_object_store. (Using a ContextualService makes it easier to
361
- # make out the ObjectStore for unit tests: See ContextualService for more.)
362
- #
363
- # = Dynamic method calls
364
- # ObjectStore uses reflection to provide a lot of convenience methods for
365
- # querying domain objects in a number of ways.
366
- # [ObjectStore#get< domain class > (pk_id)]
367
- # Retrieves one domain object by pk_id. For example,
368
- # ObjectStore#getUser( 100 )
369
- # will return User 100.
370
- # [ObjectStore#get< domain class >s (searchTerm, fieldName = nil)]
371
- # Returns a collection of all instances of that domain class matching that
372
- # search term. For example,
373
- # ObjectStore#getProducts( aProductCategory )
374
- # queries MySQL for all products that belong to that product category. You
375
- # can omit +fieldName+ if +searchTerm+ is a non-nil domain object, and the
376
- # field connecting the first domain class to the second is named after the
377
- # domain class. (For example, the above line assumes that Product has a
378
- # field named "productCategory".) Otherwise, it's best to include
379
- # +fieldName+:
380
- # ObjectStore#getUsers( "Jones", "lastName" )
381
- #
382
- # = Querying
383
- # ObjectStore can also be used to generate complex, ad-hoc queries which
384
- # emulate much of the functionality you'd get from writing the SQL yourself.
385
- # Furthermore, these queries can be run against in-memory data stores, which
386
- # is particularly useful for tests.
387
- # date = Date.new( 2003, 1, 1 )
388
- # ObjectStore#getInvoices { |invoice|
389
- # Query.And( invoice.date.gte( date ), invoice.rate.equals( 10 ),
390
- # invoice.hours.equals( 10 ) )
391
- # }
392
- # is the same as
393
- # select * from invoices
394
- # where (date >= '2003-01-01' and rate = 10 and hours = 10)
395
- # See lafcadio/query.rb for more.
396
- #
397
- # = SQL Logging
398
- # Lafcadio uses log4r to log all of its SQL statements. The simplest way to
399
- # turn on logging is to set the following values in the LafcadioConfig file:
400
- # [logSql] Should be set to "y" to turn on logging.
401
- # [logdir] The directory where log files should be written. Required if
402
- # +logSql+ is "y"
403
- # [sqlLogFile] The name of the file (not including its directory) where SQL
404
- # should be logged. Default is "sql".
405
- #
406
- # = Triggers
407
- # Domain classes can be set to fire triggers either before or after commits.
408
- # Since these triggers are executed in Ruby, they're easy to test. See
409
- # DomainObject#pre_commit_trigger and DomainObject#post_commit_trigger for more.
410
- class ObjectStore < ContextualService
411
- def self.set_db_name(dbName) #:nodoc:
412
- DbConnection.set_db_name dbName
413
- end
414
-
415
- def initialize( dbBridge = nil ) #:nodoc:
416
- @dbBridge = dbBridge == nil ? DbBridge.new : dbBridge
417
- @cache = ObjectStore::Cache.new( @dbBridge )
418
- end
419
-
420
- # Commits a domain object to the database. You can also simply call
421
- # myDomainObject.commit
422
- def commit(db_object)
423
- @cache.commit( db_object )
424
- db_object
425
- end
426
-
427
- # Flushes one domain object from its cache.
428
- def flush(db_object)
429
- @cache.flush db_object
430
- end
431
-
432
- # Returns the domain object corresponding to the domain class and pk_id.
433
- def get(object_type, pk_id)
434
- query = Query.new object_type, pk_id
435
- @cache.get_by_query( query )[0] ||
436
- ( raise( DomainObjectNotFoundError,
437
- "Can't find #{object_type} #{pk_id}", caller ) )
438
- end
439
-
440
- # Returns all domain objects for the given domain class.
441
- def get_all(object_type); @cache.get_by_query( Query.new( object_type ) ); end
442
-
443
- # Returns the DbBridge; this is useful in case you need to use raw SQL for a
444
- # specific query.
445
- def get_db_bridge; @dbBridge; end
446
-
447
- def get_field_name( domain_object )
448
- domain_object.object_type.bare_name.decapitalize
449
- end
450
-
451
- def get_filtered(object_typeName, searchTerm, fieldName = nil) #:nodoc:
452
- object_type = DomainObject.get_object_type_from_string object_typeName
453
- fieldName = get_field_name( searchTerm ) unless fieldName
454
- if searchTerm.class <= DomainObject
455
- cond_class = Query::Link
456
- else
457
- cond_class = Query::Equals
458
- end
459
- get_subset( cond_class.new( fieldName, searchTerm, object_type ) )
460
- end
461
-
462
- def get_map_match(object_type, mapped) #:nodoc:
463
- Query::Equals.new( get_field_name( mapped ), mapped, object_type )
464
- end
465
-
466
- def get_map_object(object_type, map1, map2) #:nodoc:
467
- unless map1 && map2
468
- raise ArgumentError,
469
- "ObjectStore#get_map_object needs two non-nil keys", caller
470
- end
471
- mapMatch1 = get_map_match object_type, map1
472
- mapMatch2 = get_map_match object_type, map2
473
- condition = Query::CompoundCondition.new mapMatch1, mapMatch2
474
- get_subset(condition)[0]
475
- end
476
-
477
- def get_mapped(searchTerm, resultTypeName) #:nodoc:
478
- resultType = DomainObject.get_object_type_from_string resultTypeName
479
- firstTypeName = searchTerm.class.bare_name
480
- secondTypeName = resultType.bare_name
481
- mapTypeName = firstTypeName + secondTypeName
482
- get_filtered( mapTypeName, searchTerm ).collect { |mapObj|
483
- mapObj.send( resultType.name.decapitalize )
484
- }
485
- end
486
-
487
- # Retrieves the maximum value across all instances of one domain class.
488
- # ObjectStore#get_max( Client )
489
- # returns the highest +pk_id+ in the +clients+ table.
490
- # ObjectStore#get_max( Invoice, "rate" )
491
- # will return the highest rate for all invoices.
492
- def get_max( domain_class, field_name = 'pk_id' )
493
- @dbBridge.group_query( Query::Max.new( domain_class, field_name ) ).only
494
- end
495
-
496
- # Retrieves a collection of domain objects by +pk_id+.
497
- # ObjectStore#get_objects( Clients, [ 1, 2, 3 ] )
498
- def get_objects(object_type, pk_ids)
499
- get_subset Query::In.new('pk_id', pk_ids, object_type)
500
- end
501
-
502
- def get_subset(conditionOrQuery) #:nodoc:
503
- if conditionOrQuery.class <= Query::Condition
504
- condition = conditionOrQuery
505
- query = Query.new condition.object_type, condition
506
- else
507
- query = conditionOrQuery
508
- end
509
- @cache.get_by_query( query )
510
- end
511
-
512
- def last_commit_time( domain_class, pk_id ) #:nodoc:
513
- @cache.last_commit_time( domain_class, pk_id )
514
- end
515
-
516
- def method_missing(methodId, *args) #:nodoc:
517
- proc = block_given? ? ( proc { |obj| yield( obj ) } ) : nil
518
- dispatch = MethodDispatch.new( methodId, proc, *args )
519
- self.send( dispatch.symbol, *dispatch.args )
520
- end
521
-
522
- def respond_to?( symbol, include_private = false )
523
- begin
524
- dispatch = MethodDispatch.new( symbol )
525
- rescue NoMethodError
526
- super
527
- end
528
- end
529
-
530
- class Cache #:nodoc:
531
- def initialize( dbBridge )
532
- @dbBridge = dbBridge
533
- @objects = {}
534
- @collections_by_query = {}
535
- @commit_times = {}
536
- end
537
-
538
- def commit( db_object )
539
- committer = Committer.new db_object, @dbBridge
540
- committer.execute
541
- update_after_commit( committer )
542
- end
543
-
544
- # Flushes a domain object.
545
- def flush(db_object)
546
- hash_by_object_type(db_object.object_type).delete db_object.pk_id
547
- flush_collection_cache( db_object.object_type )
548
- end
549
-
550
- def flush_collection_cache( object_type )
551
- @collections_by_query.keys.each { |query|
552
- if query.object_type == object_type
553
- @collections_by_query.delete( query )
554
- end
555
- }
556
- end
557
-
558
- # Returns a cached domain object, or nil if none is found.
559
- def get(object_type, pk_id)
560
- hash_by_object_type(object_type)[pk_id].clone
561
- end
562
-
563
- # Returns an array of all domain objects of a given type.
564
- def get_all(object_type)
565
- hash_by_object_type(object_type).values.collect { |d_obj| d_obj.clone }
566
- end
567
-
568
- def get_by_query( query )
569
- unless @collections_by_query[query]
570
- newObjects = @dbBridge.get_collection_by_query(query)
571
- newObjects.each { |dbObj| save dbObj }
572
- @collections_by_query[query] = newObjects.collect { |dobj|
573
- dobj.pk_id
574
- }
575
- end
576
- collection = []
577
- @collections_by_query[query].each { |pk_id|
578
- dobj = get( query.object_type, pk_id )
579
- collection << dobj if dobj
580
- }
581
- collection
582
- end
583
-
584
- def hash_by_object_type(object_type)
585
- unless @objects[object_type]
586
- @objects[object_type] = {}
587
- end
588
- @objects[object_type]
589
- end
590
-
591
- def last_commit_time( domain_class, pk_id )
592
- by_domain_class = @commit_times[domain_class]
593
- by_domain_class ? by_domain_class[pk_id] : nil
594
- end
595
-
596
- def set_commit_time( d_obj )
597
- by_domain_class = @commit_times[d_obj.object_type]
598
- if by_domain_class.nil?
599
- by_domain_class = {}
600
- @commit_times[d_obj.object_type] = by_domain_class
601
- end
602
- by_domain_class[d_obj.pk_id] = Time.now
603
- end
604
-
605
- # Saves a domain object.
606
- def save(db_object)
607
- hash_by_object_type(db_object.object_type)[db_object.pk_id] = db_object
608
- flush_collection_cache( db_object.object_type )
609
- end
610
-
611
- def update_after_commit( committer ) #:nodoc:
612
- if committer.commit_type == Committer::UPDATE ||
613
- committer.commit_type == Committer::INSERT
614
- save( committer.db_object )
615
- elsif committer.commit_type == Committer::DELETE
616
- flush( committer.db_object )
617
- end
618
- set_commit_time( committer.db_object )
619
- end
620
- end
621
-
622
- class MethodDispatch #:nodoc:
623
- attr_reader :symbol, :args
624
-
625
- def initialize( orig_method, *other_args )
626
- @orig_method = orig_method
627
- @orig_args = other_args
628
- if @orig_args.size > 0
629
- @maybe_proc = @orig_args.shift
630
- end
631
- @methodName = orig_method.id2name
632
- if @methodName =~ /^get(.*)$/
633
- dispatch_get_method
634
- else
635
- raise_no_method_error
636
- end
637
- end
638
-
639
- def dispatch_get_plural
640
- if @orig_args.size == 0 && @maybe_proc.nil?
641
- @symbol = :get_all
642
- @args = [ @domain_class ]
643
- else
644
- searchTerm = @orig_args[0]
645
- fieldName = @orig_args[1]
646
- if searchTerm.nil? && @maybe_proc.nil? && fieldName.nil?
647
- msg = "ObjectStore\##{ @orig_method } needs a field name as its " +
648
- "second argument if its first argument is nil"
649
- raise( ArgumentError, msg, caller )
650
- end
651
- dispatch_get_plural_by_query_block_or_search_term( searchTerm,
652
- fieldName )
653
- end
654
- end
655
-
656
- def dispatch_get_plural_by_query_block
657
- inferrer = Query::Inferrer.new( @domain_class ) { |obj|
658
- @maybe_proc.call( obj )
659
- }
660
- @symbol = :get_subset
661
- @args = [ inferrer.execute ]
662
- end
663
-
664
- def dispatch_get_plural_by_query_block_or_search_term( searchTerm,
665
- fieldName )
666
- if !@maybe_proc.nil? && searchTerm.nil?
667
- dispatch_get_plural_by_query_block
668
- elsif @maybe_proc.nil? && ( !( searchTerm.nil? && fieldName.nil? ) )
669
- @symbol = :get_filtered
670
- @args = [ @domain_class.name, searchTerm, fieldName ]
671
- else
672
- raise( ArgumentError,
673
- "Shouldn't send both a query block and a search term",
674
- caller )
675
- end
676
- end
677
-
678
- def dispatch_get_method
679
- begin
680
- dispatch_get_singular
681
- rescue CouldntMatchObjectTypeError
682
- object_typeName = English.singular( camel_case_method_name_after_get
683
- )
684
- begin
685
- @domain_class = DomainObject.
686
- get_object_type_from_string( object_typeName )
687
- dispatch_get_plural
688
- rescue CouldntMatchObjectTypeError
689
- raise_no_method_error
690
- end
691
- end
692
- end
693
-
694
- def dispatch_get_singular
695
- object_type = DomainObject.get_object_type_from_string(
696
- camel_case_method_name_after_get
697
- )
698
- if @orig_args[0].class <= Integer
699
- @symbol = :get
700
- @args = [ object_type, @orig_args[0] ]
701
- elsif @orig_args[0].class <= DomainObject
702
- @symbol = :get_map_object
703
- @args = [ object_type, @orig_args[0], @orig_args[1] ]
704
- end
705
- end
706
-
707
- def camel_case_method_name_after_get
708
- @orig_method.id2name =~ /^get(.*)$/
709
- $1.underscore_to_camel_case
710
- end
711
-
712
- def raise_no_method_error
713
- raise( NoMethodError, "undefined method '#{ @methodName }'", caller )
714
- end
715
- end
716
- end
717
-
718
- class SqlValueConverter #:nodoc:
719
- attr_reader :object_type, :row_hash
720
-
721
- def initialize(object_type, row_hash)
722
- @object_type = object_type
723
- @row_hash = row_hash
724
- end
725
-
726
- def []( key )
727
- begin
728
- field = @object_type.get_field( key )
729
- val = field.value_from_sql( @row_hash[ field.db_field_name ] )
730
- if field.instance_of?( PrimaryKeyField ) && val.nil?
731
- raise FieldMatchError, error_msg, caller
732
- else
733
- val
734
- end
735
- rescue MissingError
736
- nil
737
- end
738
- end
739
-
740
- def error_msg
741
- "The field \"" + @object_type.sql_primary_key_name +
742
- "\" can\'t be found in the table \"" +
743
- @object_type.table_name + "\"."
744
- end
745
- end
746
- end