lafcadio 0.8.0 → 0.8.1

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