lafcadio 0.5.2 → 0.6.0

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.
@@ -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