lafcadio 0.9.4 → 0.9.5

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.
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.9.4"
19
+ Version = "0.9.5"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
@@ -16,7 +16,7 @@
16
16
  # http://lafcadio.rubyforge.org/tutorial.html.
17
17
 
18
18
  module Lafcadio
19
- Version = "0.9.3"
19
+ Version = "0.9.4"
20
20
 
21
21
  require 'lafcadio/depend'
22
22
  require 'lafcadio/domain'
@@ -2,115 +2,127 @@ require 'lafcadio/objectStore'
2
2
  require 'lafcadio/util'
3
3
 
4
4
  module Lafcadio
5
- class MockDbBridge #:nodoc:
6
- attr_reader :last_pk_id_inserted
7
-
8
- def initialize
9
- @objects = {}
10
- @next_pk_ids = {}
11
- @queries = []
12
- @transaction = nil
13
- end
14
-
15
- def all( domain_class )
16
- @objects[domain_class] ? @objects[domain_class].values : []
17
- end
18
-
19
- def commit(db_object)
20
- if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
21
- raise ArgumentError
5
+ class ObjectStore
6
+ class MockDbBridge #:nodoc:
7
+ attr_reader :last_pk_id_inserted
8
+ attr_accessor :objects, :next_pk_ids, :queries
9
+
10
+ def initialize
11
+ @objects = {}
12
+ @next_pk_ids = {}
13
+ @queries = []
14
+ @transaction = nil
22
15
  end
23
- if @transaction
24
- @transaction << db_object
25
- else
26
- objects_by_domain_class = objects_by_domain_class db_object.domain_class
27
- if db_object.delete
28
- objects_by_domain_class.delete( db_object.pk_id )
16
+
17
+ def all( domain_class )
18
+ @objects[domain_class] ? @objects[domain_class].values : []
19
+ end
20
+
21
+ def commit(db_object)
22
+ if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
23
+ raise ArgumentError
24
+ end
25
+ if @transaction
26
+ @transaction << db_object
29
27
  else
30
- object_pk_id = pre_commit_pk_id( db_object )
31
- objects_by_domain_class[object_pk_id] = db_object
28
+ objects_by_domain_class = objects_by_domain_class(
29
+ db_object.domain_class
30
+ )
31
+ if db_object.delete
32
+ objects_by_domain_class.delete( db_object.pk_id )
33
+ else
34
+ object_pk_id = pre_commit_pk_id( db_object )
35
+ objects_by_domain_class[object_pk_id] = db_object
36
+ end
32
37
  end
33
38
  end
34
- end
35
-
36
- def group_query( query )
37
- query.collect objects_by_domain_class( query.domain_class ).values
38
- end
39
-
40
- def next_pk_id( domain_class )
41
- dobjs = objects_by_domain_class( domain_class ).values
42
- dobjs.inject( 0 ) { |memo, obj| memo > obj.pk_id ? memo : obj.pk_id } + 1
43
- end
44
-
45
- def objects_by_domain_class( domain_class )
46
- @objects[domain_class] = {} unless @objects[domain_class]
47
- @objects[domain_class]
48
- end
49
-
50
- def pre_commit_pk_id( domain_object )
51
- @next_pk_ids = {} unless @next_pk_ids
52
- if (next_pk_id = @next_pk_ids[domain_object.domain_class])
53
- @next_pk_ids[domain_object.domain_class] = nil
54
- @last_pk_id_inserted = next_pk_id
55
- elsif domain_object.pk_id
56
- domain_object.pk_id
57
- elsif ( next_pk_id = @next_pk_ids[domain_object.domain_class] )
58
- @last_pk_id_inserted = next_pk_id
59
- @next_pk_ids[domain_object.domain_class] = nil
60
- next_pk_id
61
- else
62
- pk_ids = objects_by_domain_class( domain_object.domain_class ).keys
63
- @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
39
+
40
+ def group_query( query )
41
+ query.collect objects_by_domain_class( query.domain_class ).values
64
42
  end
65
- end
66
-
67
- def queries( domain_class = nil )
68
- @queries.select { |qry|
69
- domain_class ? qry.domain_class == domain_class : true
70
- }
71
- end
72
-
73
- def query_count( sql )
74
- @queries.select { |qry| qry.to_sql == sql }.size
75
- end
76
-
77
- def select_dobjs(query)
78
- @queries << query
79
- domain_class = query.domain_class
80
- objects = []
81
- all( domain_class ).each { |dbObj|
82
- objects << dbObj if query.dobj_satisfies?( dbObj )
83
- }
84
- query.order_and_limit_collection objects
85
- end
86
-
87
- def set_next_pk_id( domain_class, npi )
88
- @next_pk_ids = {} unless @next_pk_ids
89
- @next_pk_ids[ domain_class ] = npi
90
- end
91
-
92
- def transaction( action )
93
- tr = MockDbBridge::Transaction.new
94
- @transaction = tr
95
- begin
43
+
44
+ def next_pk_id( domain_class )
45
+ dobjs = objects_by_domain_class( domain_class ).values
46
+ dobjs.inject( 0 ) { |memo, obj|
47
+ memo > obj.pk_id ? memo : obj.pk_id
48
+ } + 1
49
+ end
50
+
51
+ def objects_by_domain_class( domain_class )
52
+ @objects[domain_class] = {} unless @objects[domain_class]
53
+ @objects[domain_class]
54
+ end
55
+
56
+ def pre_commit_pk_id( domain_object )
57
+ @next_pk_ids = {} unless @next_pk_ids
58
+ if (next_pk_id = @next_pk_ids[domain_object.domain_class])
59
+ @next_pk_ids[domain_object.domain_class] = nil
60
+ @last_pk_id_inserted = next_pk_id
61
+ elsif domain_object.pk_id
62
+ domain_object.pk_id
63
+ else
64
+ pk_ids = objects_by_domain_class( domain_object.domain_class ).keys
65
+ @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
66
+ end
67
+ end
68
+
69
+ def queries( domain_class = nil )
70
+ @queries.select { |qry|
71
+ domain_class ? qry.domain_class == domain_class : true
72
+ }
73
+ end
74
+
75
+ def query_count( sql )
76
+ @queries.select { |qry| qry.to_sql == sql }.size
77
+ end
78
+
79
+ def rollback; end
80
+
81
+ def select_dobjs( query )
82
+ @queries << query
83
+ domain_class = query.domain_class
84
+ all = all domain_class
85
+ if @transaction
86
+ from_tr = @transaction.select { |dobj|
87
+ dobj.domain_class == query.domain_class
88
+ }
89
+ all = all.concat from_tr
90
+ end
91
+ objects = all.select { |dobj| query.dobj_satisfies?( dobj ) }
92
+ query.order_and_limit_collection objects
93
+ end
94
+
95
+ def set_next_pk_id( domain_class, npi )
96
+ @next_pk_ids = {} unless @next_pk_ids
97
+ @next_pk_ids[ domain_class ] = npi
98
+ end
99
+
100
+ def transaction( action )
101
+ tr = MockDbBridge::Transaction.new
102
+ @transaction = tr
96
103
  action.call tr
97
104
  @transaction = nil
105
+ tr.uniq!
98
106
  tr.each do |dobj_to_commit| commit( dobj_to_commit ); end
99
- rescue RollbackError; end
100
- end
101
-
102
- class Transaction < Array
103
- def rollback; raise RollbackError; end
104
- end
105
-
106
- class RollbackError < StandardError #:nodoc:
107
+ end
108
+
109
+ def transactional_clone
110
+ tc = clone
111
+ tc.objects = objects.clone
112
+ tc.next_pk_ids = next_pk_ids.clone
113
+ tc.queries = queries.clone
114
+ tc
115
+ end
116
+
117
+ class Transaction < Array
118
+ def rollback; raise RollbackError; end
119
+ end
107
120
  end
108
121
  end
109
122
 
110
123
  # Externally, the MockObjectStore looks and acts exactly like the ObjectStore,
111
124
  # but stores all its data in memory. This makes it very useful for unit
112
- # testing, and in fact LafcadioTestCase#setup creates a new instance of
113
- # MockObjectStore for each test case. For example:
125
+ # testing. For example:
114
126
  #
115
127
  # class SomeTestCase < Test::Unit::TestCase
116
128
  # def setup
@@ -2,115 +2,130 @@ require 'lafcadio/objectStore'
2
2
  require 'lafcadio/util'
3
3
 
4
4
  module Lafcadio
5
- class MockDbBridge #:nodoc:
6
- attr_reader :last_pk_id_inserted
7
-
8
- def initialize
9
- @objects = {}
10
- @next_pk_ids = {}
11
- @queries = []
12
- @transaction = nil
13
- end
14
-
15
- def all( domain_class )
16
- @objects[domain_class] ? @objects[domain_class].values : []
17
- end
18
-
19
- def select_dobjs(query)
20
- @queries << query
21
- domain_class = query.domain_class
22
- objects = []
23
- all( domain_class ).each { |dbObj|
24
- objects << dbObj if query.dobj_satisfies?( dbObj )
25
- }
26
- query.order_and_limit_collection objects
27
- end
28
-
29
- def commit(db_object)
30
- if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
31
- raise ArgumentError
5
+ class ObjectStore
6
+ class MockDbBridge #:nodoc:
7
+ attr_reader :last_pk_id_inserted
8
+ attr_accessor :objects, :next_pk_ids, :queries
9
+
10
+ def initialize
11
+ @objects = {}
12
+ @next_pk_ids = {}
13
+ @queries = []
14
+ @transaction = nil
15
+ end
16
+
17
+ def all( domain_class )
18
+ @objects[domain_class] ? @objects[domain_class].values : []
32
19
  end
33
- if @transaction
34
- @transaction << db_object
35
- else
36
- objects_by_domain_class = objects_by_domain_class db_object.domain_class
37
- if db_object.delete
38
- objects_by_domain_class.delete( db_object.pk_id )
20
+
21
+ def commit(db_object)
22
+ if db_object.pk_id and !db_object.pk_id.is_a?( Integer )
23
+ raise ArgumentError
24
+ end
25
+ if @transaction
26
+ @transaction << db_object
39
27
  else
40
- object_pk_id = pre_commit_pk_id( db_object )
41
- objects_by_domain_class[object_pk_id] = db_object
28
+ objects_by_domain_class = objects_by_domain_class(
29
+ db_object.domain_class
30
+ )
31
+ if db_object.delete
32
+ objects_by_domain_class.delete( db_object.pk_id )
33
+ else
34
+ object_pk_id = pre_commit_pk_id( db_object )
35
+ objects_by_domain_class[object_pk_id] = db_object
36
+ end
42
37
  end
43
38
  end
44
- end
45
-
46
- def group_query( query )
47
- query.collect objects_by_domain_class( query.domain_class ).values
48
- end
49
-
50
- def next_pk_id( domain_class )
51
- dobjs = objects_by_domain_class( domain_class ).values
52
- dobjs.inject( 0 ) { |memo, obj| memo > obj.pk_id ? memo : obj.pk_id } + 1
53
- end
54
-
55
- def objects_by_domain_class( domain_class )
56
- @objects[domain_class] = {} unless @objects[domain_class]
57
- @objects[domain_class]
58
- end
59
-
60
- def pre_commit_pk_id( domain_object )
61
- @next_pk_ids = {} unless @next_pk_ids
62
- if (next_pk_id = @next_pk_ids[domain_object.domain_class])
63
- @next_pk_ids[domain_object.domain_class] = nil
64
- @last_pk_id_inserted = next_pk_id
65
- elsif domain_object.pk_id
66
- domain_object.pk_id
67
- elsif ( next_pk_id = @next_pk_ids[domain_object.domain_class] )
68
- @last_pk_id_inserted = next_pk_id
69
- @next_pk_ids[domain_object.domain_class] = nil
70
- next_pk_id
71
- else
72
- pk_ids = objects_by_domain_class( domain_object.domain_class ).keys
73
- @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
39
+
40
+ def group_query( query )
41
+ query.collect objects_by_domain_class( query.domain_class ).values
74
42
  end
75
- end
76
-
77
- def queries( domain_class = nil )
78
- @queries.select { |qry|
79
- domain_class ? qry.domain_class == domain_class : true
80
- }
81
- end
82
-
83
- def query_count( sql )
84
- @queries.select { |qry| qry.to_sql == sql }.size
85
- end
86
-
87
- def set_next_pk_id( domain_class, npi )
88
- @next_pk_ids = {} unless @next_pk_ids
89
- @next_pk_ids[ domain_class ] = npi
90
- end
91
-
92
- def transaction( action )
93
- tr = MockDbBridge::Transaction.new
94
- @transaction = tr
95
- begin
43
+
44
+ def next_pk_id( domain_class )
45
+ dobjs = objects_by_domain_class( domain_class ).values
46
+ dobjs.inject( 0 ) { |memo, obj|
47
+ memo > obj.pk_id ? memo : obj.pk_id
48
+ } + 1
49
+ end
50
+
51
+ def objects_by_domain_class( domain_class )
52
+ @objects[domain_class] = {} unless @objects[domain_class]
53
+ @objects[domain_class]
54
+ end
55
+
56
+ def pre_commit_pk_id( domain_object )
57
+ @next_pk_ids = {} unless @next_pk_ids
58
+ if (next_pk_id = @next_pk_ids[domain_object.domain_class])
59
+ @next_pk_ids[domain_object.domain_class] = nil
60
+ @last_pk_id_inserted = next_pk_id
61
+ elsif domain_object.pk_id
62
+ domain_object.pk_id
63
+ elsif ( next_pk_id = @next_pk_ids[domain_object.domain_class] )
64
+ @last_pk_id_inserted = next_pk_id
65
+ @next_pk_ids[domain_object.domain_class] = nil
66
+ next_pk_id
67
+ else
68
+ pk_ids = objects_by_domain_class( domain_object.domain_class ).keys
69
+ @last_pk_id_inserted = pk_ids.max ? pk_ids.max + 1 : 1
70
+ end
71
+ end
72
+
73
+ def queries( domain_class = nil )
74
+ @queries.select { |qry|
75
+ domain_class ? qry.domain_class == domain_class : true
76
+ }
77
+ end
78
+
79
+ def query_count( sql )
80
+ @queries.select { |qry| qry.to_sql == sql }.size
81
+ end
82
+
83
+ def rollback; end
84
+
85
+ def select_dobjs( query )
86
+ @queries << query
87
+ domain_class = query.domain_class
88
+ all = all domain_class
89
+ if @transaction
90
+ from_tr = @transaction.select { |dobj|
91
+ dobj.domain_class == query.domain_class
92
+ }
93
+ all = all.concat from_tr
94
+ end
95
+ objects = all.select { |dobj| query.dobj_satisfies?( dobj ) }
96
+ query.order_and_limit_collection objects
97
+ end
98
+
99
+ def set_next_pk_id( domain_class, npi )
100
+ @next_pk_ids = {} unless @next_pk_ids
101
+ @next_pk_ids[ domain_class ] = npi
102
+ end
103
+
104
+ def transaction( action )
105
+ tr = MockDbBridge::Transaction.new
106
+ @transaction = tr
96
107
  action.call tr
97
108
  @transaction = nil
98
109
  tr.each do |dobj_to_commit| commit( dobj_to_commit ); end
99
- rescue RollbackError; end
100
- end
101
-
102
- class Transaction < Array
103
- def rollback; raise RollbackError; end
104
- end
105
-
106
- class RollbackError < StandardError #:nodoc:
110
+ end
111
+
112
+ def transactional_clone
113
+ tc = clone
114
+ tc.objects = objects.clone
115
+ tc.next_pk_ids = next_pk_ids.clone
116
+ tc.queries = queries.clone
117
+ tc
118
+ end
119
+
120
+ class Transaction < Array
121
+ def rollback; raise RollbackError; end
122
+ end
107
123
  end
108
124
  end
109
125
 
110
126
  # Externally, the MockObjectStore looks and acts exactly like the ObjectStore,
111
127
  # but stores all its data in memory. This makes it very useful for unit
112
- # testing, and in fact LafcadioTestCase#setup creates a new instance of
113
- # MockObjectStore for each test case. For example:
128
+ # testing. For example:
114
129
  #
115
130
  # class SomeTestCase < Test::Unit::TestCase
116
131
  # def setup
@@ -265,12 +265,24 @@ module Lafcadio
265
265
  # Client.new( 'name' => 'Big Co.' ).commit
266
266
  # tr.rollback
267
267
  # end # the client will not be saved to the DB
268
- def transaction( &action ); @cache.transaction( action ); end
268
+ def transaction( &action )
269
+ old_cache = @cache
270
+ @cache = @cache.transactional_clone
271
+ begin
272
+ @cache.transaction action
273
+ rescue
274
+ err_to_raise = $!
275
+ @cache.rollback unless $!.is_a? RollbackError
276
+ @cache = old_cache
277
+ raise err_to_raise unless $!.is_a? RollbackError
278
+ end
279
+ end
269
280
 
270
281
  class Cache #:nodoc:
271
282
  include MonitorMixin
272
283
 
273
- attr_reader :db_bridge
284
+ attr_reader :db_bridge
285
+ attr_accessor :domain_class_caches
274
286
 
275
287
  def initialize( db_bridge = DbBridge.new )
276
288
  super()
@@ -315,7 +327,9 @@ module Lafcadio
315
327
  if !collected and main_cache.queries.values
316
328
  newObjects = @db_bridge.select_dobjs query
317
329
  newObjects.each { |dbObj| main_cache.save dbObj }
318
- main_cache.queries[query] = newObjects.collect { |dobj| dobj.pk_id }
330
+ main_cache.queries[query] = newObjects.collect { |dobj|
331
+ dobj.pk_id
332
+ }
319
333
  end
320
334
  end
321
335
  main_cache.queries[query].map { |pk_id| main_cache[pk_id] }.compact
@@ -333,17 +347,29 @@ module Lafcadio
333
347
 
334
348
  def method_missing( meth, *args )
335
349
  simple_dispatch = [
336
- :queries, :save, :set_commit_time, :update_after_commit
350
+ :flush, :queries, :save, :set_commit_time, :update_after_commit
337
351
  ]
338
352
  if simple_dispatch.include?( meth )
339
353
  cache( args.first.domain_class ).send( meth, *args )
340
354
  elsif [ :[], :last_commit_time ].include?( meth )
341
355
  cache( args.first ).send( meth, *args[1..-1] )
342
- elsif [ :group_query, :transaction ].include?( meth )
356
+ elsif [ :group_query, :rollback, :transaction ].include?( meth )
343
357
  @db_bridge.send( meth, *args )
358
+ else
359
+ super
344
360
  end
345
361
  end
346
362
 
363
+ def transactional_clone
364
+ tc = Cache.new @db_bridge.transactional_clone
365
+ dcc_clones = {}
366
+ @domain_class_caches.each do |domain_class, dcc|
367
+ dcc_clones[domain_class] = dcc.transactional_clone
368
+ end
369
+ tc.domain_class_caches = dcc_clones
370
+ tc
371
+ end
372
+
347
373
  def update_dependent_domain_class( db_object, aClass, field )
348
374
  object_store = ObjectStore.get_object_store
349
375
  collection = aClass.get( db_object, field.name )
@@ -367,7 +393,8 @@ module Lafcadio
367
393
  end
368
394
 
369
395
  class DomainClassCache < Hash #:nodoc:
370
- attr_reader :commit_times, :domain_class, :queries
396
+ attr_reader :domain_class
397
+ attr_accessor :commit_times, :queries
371
398
 
372
399
  def initialize( domain_class, db_bridge )
373
400
  super()
@@ -423,6 +450,13 @@ module Lafcadio
423
450
  end
424
451
 
425
452
  def set_commit_time( d_obj ); commit_times[d_obj.pk_id] = Time.now; end
453
+
454
+ def transactional_clone
455
+ tc = clone
456
+ tc.commit_times = commit_times.clone
457
+ tc.queries = queries.clone
458
+ tc
459
+ end
426
460
 
427
461
  def update_after_commit( db_object ) #:nodoc:
428
462
  if [ :update, :insert ].include?(
@@ -547,9 +581,6 @@ module Lafcadio
547
581
  def initialize
548
582
  @db_conn = DbConnection.get_db_connection
549
583
  @transaction = nil
550
- ObjectSpace.define_finalizer( self, proc { |id|
551
- DbConnection.get_db_connection.disconnect
552
- } )
553
584
  end
554
585
 
555
586
  def _dump(aDepth)
@@ -610,6 +641,8 @@ module Lafcadio
610
641
  end
611
642
  end
612
643
 
644
+ def rollback; @transaction.rollback( false ) if @transaction; end
645
+
613
646
  def select_all(sql)
614
647
  maybe_log sql
615
648
  begin
@@ -646,8 +679,6 @@ module Lafcadio
646
679
  begin
647
680
  action.call @transaction
648
681
  @transaction.commit
649
- rescue RollbackError
650
- # rollback handled by Transaction
651
682
  rescue
652
683
  err_to_raise = $!
653
684
  @transaction.rollback false
@@ -656,6 +687,8 @@ module Lafcadio
656
687
  @transaction = nil
657
688
  end
658
689
 
690
+ def transactional_clone; clone; end
691
+
659
692
  class Transaction #:nodoc:
660
693
  def initialize( db_conn ); @db_conn = db_conn; end
661
694
 
@@ -666,9 +699,6 @@ module Lafcadio
666
699
  raise RollbackError if raise_error
667
700
  end
668
701
  end
669
-
670
- class RollbackError < StandardError #:nodoc:
671
- end
672
702
  end
673
703
 
674
704
  class DbConnection < ContextualService::Service #:nodoc:
@@ -679,7 +709,10 @@ module Lafcadio
679
709
 
680
710
  def self.db_name=( db_name ); @@db_name = db_name; end
681
711
 
682
- def initialize; @dbh = load_new_dbh; end
712
+ def initialize
713
+ @dbh = load_new_dbh
714
+ ObjectSpace.define_finalizer( self, proc { |id| disconnect } )
715
+ end
683
716
 
684
717
  def disconnect; @dbh.disconnect; end
685
718
 
@@ -812,6 +845,9 @@ module Lafcadio
812
845
  )
813
846
  end
814
847
  end
848
+
849
+ class RollbackError < StandardError #:nodoc:
850
+ end
815
851
 
816
852
  class SqlToRubyValues #:nodoc:
817
853
  attr_reader :domain_class, :row_hash
@@ -265,12 +265,20 @@ module Lafcadio
265
265
  # Client.new( 'name' => 'Big Co.' ).commit
266
266
  # tr.rollback
267
267
  # end # the client will not be saved to the DB
268
- def transaction( &action ); @cache.transaction( action ); end
268
+ def transaction( &action )
269
+ transactional_cache = @cache.transactional_clone
270
+ begin
271
+ transactional_cache.transaction action
272
+ @cache = transactional_cache
273
+ rescue RollbackError
274
+ end
275
+ end
269
276
 
270
277
  class Cache #:nodoc:
271
278
  include MonitorMixin
272
279
 
273
- attr_reader :db_bridge
280
+ attr_reader :db_bridge
281
+ attr_accessor :domain_class_caches
274
282
 
275
283
  def initialize( db_bridge = DbBridge.new )
276
284
  super()
@@ -305,17 +313,27 @@ module Lafcadio
305
313
  end
306
314
 
307
315
  def get_by_query( query )
316
+ puts "get_by_query #{ query.to_sql }"
317
+ puts 1
308
318
  main_cache = cache query.domain_class
309
319
  unless main_cache.queries[query]
320
+ puts 2
310
321
  if query.one_pk_id?
311
322
  collected = false
323
+ puts 3
312
324
  else
313
325
  collected = main_cache.collect_from_superset query
326
+ puts 4
314
327
  end
315
328
  if !collected and main_cache.queries.values
329
+ puts 5
316
330
  newObjects = @db_bridge.select_dobjs query
317
331
  newObjects.each { |dbObj| main_cache.save dbObj }
318
- main_cache.queries[query] = newObjects.collect { |dobj| dobj.pk_id }
332
+ puts 6
333
+ main_cache.queries[query] = newObjects.collect { |dobj|
334
+ dobj.pk_id
335
+ }
336
+ puts 8
319
337
  end
320
338
  end
321
339
  main_cache.queries[query].map { |pk_id| main_cache[pk_id] }.compact
@@ -341,8 +359,20 @@ module Lafcadio
341
359
  cache( args.first ).send( meth, *args[1..-1] )
342
360
  elsif [ :group_query, :transaction ].include?( meth )
343
361
  @db_bridge.send( meth, *args )
362
+ else
363
+ super
344
364
  end
345
365
  end
366
+
367
+ def transactional_clone
368
+ tc = Cache.new @db_bridge.transactional_clone
369
+ dcc_clones = {}
370
+ @domain_class_caches.each do |dcc|
371
+ dcc_clones[dcc.domain_class] = dcc.transactional_clone
372
+ end
373
+ tc.domain_class_caches = dcc_clones
374
+ tc
375
+ end
346
376
 
347
377
  def update_dependent_domain_class( db_object, aClass, field )
348
378
  object_store = ObjectStore.get_object_store
@@ -367,7 +397,8 @@ module Lafcadio
367
397
  end
368
398
 
369
399
  class DomainClassCache < Hash #:nodoc:
370
- attr_reader :commit_times, :domain_class, :queries
400
+ attr_reader :domain_class
401
+ attr_accessor :commit_times, :queries
371
402
 
372
403
  def initialize( domain_class, db_bridge )
373
404
  super()
@@ -423,6 +454,13 @@ module Lafcadio
423
454
  end
424
455
 
425
456
  def set_commit_time( d_obj ); commit_times[d_obj.pk_id] = Time.now; end
457
+
458
+ def transactional_clone
459
+ tc = clone
460
+ tc.commit_times = commit_times.clone
461
+ tc.queries = queries.clone
462
+ tc
463
+ end
426
464
 
427
465
  def update_after_commit( db_object ) #:nodoc:
428
466
  if [ :update, :insert ].include?(
@@ -562,6 +600,7 @@ module Lafcadio
562
600
  db_object
563
601
  )
564
602
  statements_and_binds.each do |sql, binds|
603
+ maybe_log sql
565
604
  @db_conn.do( sql, *binds )
566
605
  end
567
606
  if statements_and_binds[0].first =~ /insert/
@@ -596,13 +635,15 @@ module Lafcadio
596
635
  config = LafcadioConfig.new
597
636
  if config['logSql'] == 'y'
598
637
  sqllog = Log4r::Logger['sql'] || Log4r::Logger.new( 'sql' )
599
- filename = File.join(
600
- config['logdir'], config['sqlLogFile'] || 'sql'
601
- )
602
- outputter = Log4r::FileOutputter.new(
603
- 'outputter', { :filename => filename }
604
- )
605
- sqllog.outputters = outputter
638
+ if sqllog.outputters.empty?
639
+ filename = File.join(
640
+ config['logdir'], config['sqlLogFile'] || 'sql'
641
+ )
642
+ outputter = Log4r::FileOutputter.new(
643
+ 'outputter', { :filename => filename }
644
+ )
645
+ sqllog.outputters = outputter
646
+ end
606
647
  sqllog.info sql
607
648
  end
608
649
  end
@@ -643,8 +684,6 @@ module Lafcadio
643
684
  begin
644
685
  action.call @transaction
645
686
  @transaction.commit
646
- rescue RollbackError
647
- # rollback handled by Transaction
648
687
  rescue
649
688
  err_to_raise = $!
650
689
  @transaction.rollback false
@@ -653,6 +692,8 @@ module Lafcadio
653
692
  @transaction = nil
654
693
  end
655
694
 
695
+ def transactional_clone; clone; end
696
+
656
697
  class Transaction #:nodoc:
657
698
  def initialize( db_conn ); @db_conn = db_conn; end
658
699
 
@@ -663,9 +704,6 @@ module Lafcadio
663
704
  raise RollbackError if raise_error
664
705
  end
665
706
  end
666
-
667
- class RollbackError < StandardError #:nodoc:
668
- end
669
707
  end
670
708
 
671
709
  class DbConnection < ContextualService::Service #:nodoc:
@@ -809,6 +847,9 @@ module Lafcadio
809
847
  )
810
848
  end
811
849
  end
850
+
851
+ class RollbackError < StandardError #:nodoc:
852
+ end
812
853
 
813
854
  class SqlToRubyValues #:nodoc:
814
855
  attr_reader :domain_class, :row_hash
@@ -1,39 +1,6 @@
1
1
  require 'lafcadio/depend'
2
2
  require 'lafcadio/mock'
3
3
  require 'lafcadio/util'
4
- require 'test/unit'
5
-
6
- # A test case that sets up a number of mock services. In writing an application
7
- # that uses Lafcadio you may find it convenient to inherit from this class.
8
- class LafcadioTestCase < Test::Unit::TestCase
9
- include Lafcadio
10
-
11
- def setup
12
- context = ContextualService::Context.instance
13
- context.flush
14
- @mockObjectStore = MockObjectStore.new
15
- ObjectStore.set_object_store @mockObjectStore
16
- LafcadioConfig.set_values(
17
- 'classDefinitionDir' => '../test/testData', 'dbhost' => 'localhost',
18
- 'dbname' => 'test', 'dbpassword' => 'password', 'dbuser' => 'test',
19
- 'domainFiles' => %w( ../test/mock/domain ),
20
- 'logdir' => '../test/testOutput/', 'logSql' => 'n'
21
- )
22
- end
23
-
24
- # Asserts that for each key-value pair in +att_values+, sending the key to
25
- # +object+ will return the value.
26
- # u = User.new( 'fname' => 'Francis', 'lname' => 'Hwang' )
27
- # assert_attributes( u, { 'fname' => 'Francis', 'lname' => 'Hwang' } )
28
- def assert_attributes( object, att_values )
29
- att_values.each { |method, expected|
30
- assert_equal( expected, object.send( method ), method.to_s )
31
- }
32
- end
33
-
34
- def default_test #:nodoc:
35
- end
36
- end
37
4
 
38
5
  module Lafcadio
39
6
  def BooleanField.mock_value #:nodoc:
@@ -48,9 +48,35 @@ module Lafcadio
48
48
  Time.now
49
49
  end
50
50
 
51
- module DomainMock #:nodoc:
52
- Version = '0.1.0'
53
-
51
+ # A convenience module for test-cases of Lafcadio-dependent applications.
52
+ # Include this module in a test-case, and you automatically get the
53
+ # class-level method <tt>setup_mock_dobjs</tt>. This calls
54
+ # DomainObject.default_mock, and assigns the result to an instance variable
55
+ # named after the domain class. Note that if your test case also defines a
56
+ # <tt>setup</tt>, you should make sure to call <tt>super</tt> in that setup
57
+ # method to make <tt>setup_mock_dobjs</tt> work.
58
+ #
59
+ # class User < Lafcadio::DomainObject
60
+ # strings :fname, :lname, :email
61
+ # end
62
+ #
63
+ # class TestSendMessage < Test::Unit::TestCase
64
+ # include Lafcadio::DomainMock
65
+ # setup_mock_dobjs User
66
+ # def test_send_to_self
67
+ # SendMessage.new( 'sender' => @user, 'recipient' => @user )
68
+ # assert_equal( 1, Message.all.size )
69
+ # end
70
+ # end
71
+ #
72
+ # <tt>setup_mock_dobjs</tt> can handle plural domain classes:
73
+ #
74
+ # setup_mock_dobjs User, Message
75
+ #
76
+ # It can also handle assignments to different instance variables:
77
+ #
78
+ # setup_mock_dobjs User, '@sender'
79
+ module DomainMock
54
80
  def self.included( includer )
55
81
  def includer.setup_mock_dobjs( *domain_classes_or_symbol_names )
56
82
  domain_classes = DomainClassSymbolMapper.new
@@ -158,7 +184,7 @@ module Lafcadio
158
184
  # <tt>lafcadio/test.rb</tt>.
159
185
  #
160
186
  # class User < Lafcadio::DomainObject
161
- # string :fname, :lname, :email
187
+ # strings :fname, :lname, :email
162
188
  # end
163
189
  # u1 = User.custom_mock
164
190
  # u1.fname # => 'test text'
@@ -225,7 +251,7 @@ module Lafcadio
225
251
  # <tt>lafcadio/test.rb</tt>.
226
252
  #
227
253
  # class User < Lafcadio::DomainObject
228
- # string :fname, :lname, :email
254
+ # strings :fname, :lname, :email
229
255
  # end
230
256
  # u1 = User.default_mock
231
257
  # u1.fname # => 'test text'
@@ -269,7 +295,7 @@ module Lafcadio
269
295
  # <tt>lafcadio/test.rb</tt>.
270
296
  #
271
297
  # class User < Lafcadio::DomainObject
272
- # string :fname, :lname, :email
298
+ # strings :fname, :lname, :email
273
299
  # end
274
300
  # User.mock_value :fname, 'Bill'
275
301
  # User.mock_value :lname, 'Smith'
@@ -289,7 +315,7 @@ module Lafcadio
289
315
  # <tt>lafcadio/test.rb</tt>.
290
316
  #
291
317
  # class User < Lafcadio::DomainObject
292
- # string :fname, :lname, :email
318
+ # strings :fname, :lname, :email
293
319
  # end
294
320
  # User.mock_values { :fname => 'Bill', :lname => 'Smith' }
295
321
  # u1 = User.default_mock
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: lafcadio
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.9.4
7
- date: 2006-05-01 00:00:00 -04:00
6
+ version: 0.9.5
7
+ date: 2006-07-03 00:00:00 -04:00
8
8
  summary: Lafcadio is an object-relational mapping layer
9
9
  require_paths:
10
10
  - lib