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