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.
- data/lib/lafcadio.rb +1 -1
- data/lib/lafcadio.rb~ +1 -1
- data/lib/lafcadio/mock.rb +108 -96
- data/lib/lafcadio/mock.rb~ +111 -96
- data/lib/lafcadio/objectStore.rb +51 -15
- data/lib/lafcadio/objectStore.rb~ +57 -16
- data/lib/lafcadio/test.rb +0 -33
- data/lib/lafcadio/test.rb~ +33 -7
- metadata +2 -2
data/lib/lafcadio.rb
CHANGED
data/lib/lafcadio.rb~
CHANGED
data/lib/lafcadio/mock.rb
CHANGED
@@ -2,115 +2,127 @@ require 'lafcadio/objectStore'
|
|
2
2
|
require 'lafcadio/util'
|
3
3
|
|
4
4
|
module Lafcadio
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
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
|
data/lib/lafcadio/mock.rb~
CHANGED
@@ -2,115 +2,130 @@ require 'lafcadio/objectStore'
|
|
2
2
|
require 'lafcadio/util'
|
3
3
|
|
4
4
|
module Lafcadio
|
5
|
-
class
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
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
|
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
|
data/lib/lafcadio/objectStore.rb
CHANGED
@@ -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 )
|
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
|
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|
|
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
|
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
|
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 )
|
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
|
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
|
-
|
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
|
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
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
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
|
data/lib/lafcadio/test.rb
CHANGED
@@ -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:
|
data/lib/lafcadio/test.rb~
CHANGED
@@ -48,9 +48,35 @@ module Lafcadio
|
|
48
48
|
Time.now
|
49
49
|
end
|
50
50
|
|
51
|
-
module
|
52
|
-
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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
|
-
#
|
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.
|
7
|
-
date: 2006-
|
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
|