lafcadio 0.8.0 → 0.8.1

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,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