datamapper-dm-core 0.9.11 → 0.10.0
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/.autotest +17 -14
- data/.gitignore +3 -1
- data/FAQ +6 -5
- data/History.txt +5 -39
- data/Manifest.txt +67 -76
- data/QUICKLINKS +1 -1
- data/README.txt +21 -15
- data/Rakefile +16 -15
- data/SPECS +2 -29
- data/TODO +1 -1
- data/dm-core.gemspec +11 -15
- data/lib/dm-core/adapters/abstract_adapter.rb +182 -185
- data/lib/dm-core/adapters/data_objects_adapter.rb +482 -534
- data/lib/dm-core/adapters/in_memory_adapter.rb +90 -69
- data/lib/dm-core/adapters/mysql_adapter.rb +22 -115
- data/lib/dm-core/adapters/oracle_adapter.rb +249 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +7 -173
- data/lib/dm-core/adapters/sqlite3_adapter.rb +4 -97
- data/lib/dm-core/adapters/yaml_adapter.rb +116 -0
- data/lib/dm-core/adapters.rb +135 -16
- data/lib/dm-core/associations/many_to_many.rb +372 -90
- data/lib/dm-core/associations/many_to_one.rb +220 -73
- data/lib/dm-core/associations/one_to_many.rb +319 -255
- data/lib/dm-core/associations/one_to_one.rb +66 -53
- data/lib/dm-core/associations/relationship.rb +560 -158
- data/lib/dm-core/collection.rb +1104 -381
- data/lib/dm-core/core_ext/kernel.rb +12 -0
- data/lib/dm-core/core_ext/symbol.rb +10 -0
- data/lib/dm-core/identity_map.rb +4 -34
- data/lib/dm-core/migrations.rb +1283 -0
- data/lib/dm-core/model/descendant_set.rb +81 -0
- data/lib/dm-core/model/hook.rb +45 -0
- data/lib/dm-core/model/is.rb +32 -0
- data/lib/dm-core/model/property.rb +248 -0
- data/lib/dm-core/model/relationship.rb +335 -0
- data/lib/dm-core/model/scope.rb +90 -0
- data/lib/dm-core/model.rb +570 -369
- data/lib/dm-core/property.rb +753 -280
- data/lib/dm-core/property_set.rb +141 -98
- data/lib/dm-core/query/conditions/comparison.rb +814 -0
- data/lib/dm-core/query/conditions/operation.rb +247 -0
- data/lib/dm-core/query/direction.rb +43 -0
- data/lib/dm-core/query/operator.rb +42 -0
- data/lib/dm-core/query/path.rb +102 -0
- data/lib/dm-core/query/sort.rb +45 -0
- data/lib/dm-core/query.rb +974 -492
- data/lib/dm-core/repository.rb +147 -107
- data/lib/dm-core/resource.rb +644 -429
- data/lib/dm-core/spec/adapter_shared_spec.rb +294 -0
- data/lib/dm-core/spec/data_objects_adapter_shared_spec.rb +106 -0
- data/lib/dm-core/support/chainable.rb +20 -0
- data/lib/dm-core/support/deprecate.rb +12 -0
- data/lib/dm-core/support/equalizer.rb +23 -0
- data/lib/dm-core/support/logger.rb +13 -0
- data/lib/dm-core/{naming_conventions.rb → support/naming_conventions.rb} +6 -6
- data/lib/dm-core/transaction.rb +333 -92
- data/lib/dm-core/type.rb +98 -60
- data/lib/dm-core/types/boolean.rb +1 -1
- data/lib/dm-core/types/discriminator.rb +34 -20
- data/lib/dm-core/types/object.rb +7 -4
- data/lib/dm-core/types/paranoid_boolean.rb +11 -9
- data/lib/dm-core/types/paranoid_datetime.rb +11 -9
- data/lib/dm-core/types/serial.rb +3 -3
- data/lib/dm-core/types/text.rb +3 -4
- data/lib/dm-core/version.rb +1 -1
- data/lib/dm-core.rb +106 -110
- data/script/performance.rb +102 -109
- data/script/profile.rb +169 -38
- data/spec/lib/adapter_helpers.rb +105 -0
- data/spec/lib/collection_helpers.rb +18 -0
- data/spec/lib/counter_adapter.rb +34 -0
- data/spec/lib/pending_helpers.rb +27 -0
- data/spec/lib/rspec_immediate_feedback_formatter.rb +53 -0
- data/spec/public/associations/many_to_many_spec.rb +193 -0
- data/spec/public/associations/many_to_one_spec.rb +73 -0
- data/spec/public/associations/one_to_many_spec.rb +77 -0
- data/spec/public/associations/one_to_one_spec.rb +156 -0
- data/spec/public/collection_spec.rb +65 -0
- data/spec/public/model/relationship_spec.rb +924 -0
- data/spec/public/model_spec.rb +159 -0
- data/spec/public/property_spec.rb +829 -0
- data/spec/public/resource_spec.rb +71 -0
- data/spec/public/sel_spec.rb +44 -0
- data/spec/public/setup_spec.rb +145 -0
- data/spec/public/shared/association_collection_shared_spec.rb +317 -0
- data/spec/public/shared/collection_shared_spec.rb +1723 -0
- data/spec/public/shared/finder_shared_spec.rb +1619 -0
- data/spec/public/shared/resource_shared_spec.rb +924 -0
- data/spec/public/shared/sel_shared_spec.rb +112 -0
- data/spec/public/transaction_spec.rb +129 -0
- data/spec/public/types/discriminator_spec.rb +130 -0
- data/spec/semipublic/adapters/abstract_adapter_spec.rb +30 -0
- data/spec/semipublic/adapters/in_memory_adapter_spec.rb +12 -0
- data/spec/semipublic/adapters/mysql_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/oracle_adapter_spec.rb +194 -0
- data/spec/semipublic/adapters/postgres_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/sqlite3_adapter_spec.rb +17 -0
- data/spec/semipublic/adapters/yaml_adapter_spec.rb +12 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +53 -0
- data/spec/semipublic/associations/relationship_spec.rb +194 -0
- data/spec/semipublic/associations_spec.rb +177 -0
- data/spec/semipublic/collection_spec.rb +142 -0
- data/spec/semipublic/property_spec.rb +61 -0
- data/spec/semipublic/query/conditions_spec.rb +528 -0
- data/spec/semipublic/query/path_spec.rb +443 -0
- data/spec/semipublic/query_spec.rb +2626 -0
- data/spec/semipublic/resource_spec.rb +47 -0
- data/spec/semipublic/shared/resource_shared_spec.rb +126 -0
- data/spec/spec.opts +3 -1
- data/spec/spec_helper.rb +80 -57
- data/tasks/ci.rb +19 -31
- data/tasks/dm.rb +43 -48
- data/tasks/doc.rb +8 -11
- data/tasks/gemspec.rb +5 -5
- data/tasks/hoe.rb +15 -16
- data/tasks/install.rb +8 -10
- metadata +72 -93
- data/lib/dm-core/associations/relationship_chain.rb +0 -81
- data/lib/dm-core/associations.rb +0 -207
- data/lib/dm-core/auto_migrations.rb +0 -105
- data/lib/dm-core/dependency_queue.rb +0 -32
- data/lib/dm-core/hook.rb +0 -11
- data/lib/dm-core/is.rb +0 -16
- data/lib/dm-core/logger.rb +0 -232
- data/lib/dm-core/migrations/destructive_migrations.rb +0 -17
- data/lib/dm-core/migrator.rb +0 -29
- data/lib/dm-core/scope.rb +0 -58
- data/lib/dm-core/support/array.rb +0 -13
- data/lib/dm-core/support/assertions.rb +0 -8
- data/lib/dm-core/support/errors.rb +0 -23
- data/lib/dm-core/support/kernel.rb +0 -11
- data/lib/dm-core/support/symbol.rb +0 -41
- data/lib/dm-core/support.rb +0 -7
- data/lib/dm-core/type_map.rb +0 -80
- data/lib/dm-core/types.rb +0 -19
- data/script/all +0 -4
- data/spec/integration/association_spec.rb +0 -1382
- data/spec/integration/association_through_spec.rb +0 -203
- data/spec/integration/associations/many_to_many_spec.rb +0 -449
- data/spec/integration/associations/many_to_one_spec.rb +0 -163
- data/spec/integration/associations/one_to_many_spec.rb +0 -188
- data/spec/integration/auto_migrations_spec.rb +0 -413
- data/spec/integration/collection_spec.rb +0 -1073
- data/spec/integration/data_objects_adapter_spec.rb +0 -32
- data/spec/integration/dependency_queue_spec.rb +0 -46
- data/spec/integration/model_spec.rb +0 -197
- data/spec/integration/mysql_adapter_spec.rb +0 -85
- data/spec/integration/postgres_adapter_spec.rb +0 -731
- data/spec/integration/property_spec.rb +0 -253
- data/spec/integration/query_spec.rb +0 -514
- data/spec/integration/repository_spec.rb +0 -61
- data/spec/integration/resource_spec.rb +0 -513
- data/spec/integration/sqlite3_adapter_spec.rb +0 -352
- data/spec/integration/sti_spec.rb +0 -273
- data/spec/integration/strategic_eager_loading_spec.rb +0 -156
- data/spec/integration/transaction_spec.rb +0 -75
- data/spec/integration/type_spec.rb +0 -275
- data/spec/lib/logging_helper.rb +0 -18
- data/spec/lib/mock_adapter.rb +0 -27
- data/spec/lib/model_loader.rb +0 -100
- data/spec/lib/publicize_methods.rb +0 -28
- data/spec/models/content.rb +0 -16
- data/spec/models/vehicles.rb +0 -34
- data/spec/models/zoo.rb +0 -48
- data/spec/unit/adapters/abstract_adapter_spec.rb +0 -133
- data/spec/unit/adapters/adapter_shared_spec.rb +0 -15
- data/spec/unit/adapters/data_objects_adapter_spec.rb +0 -632
- data/spec/unit/adapters/in_memory_adapter_spec.rb +0 -98
- data/spec/unit/adapters/postgres_adapter_spec.rb +0 -133
- data/spec/unit/associations/many_to_many_spec.rb +0 -32
- data/spec/unit/associations/many_to_one_spec.rb +0 -159
- data/spec/unit/associations/one_to_many_spec.rb +0 -393
- data/spec/unit/associations/one_to_one_spec.rb +0 -7
- data/spec/unit/associations/relationship_spec.rb +0 -71
- data/spec/unit/associations_spec.rb +0 -242
- data/spec/unit/auto_migrations_spec.rb +0 -111
- data/spec/unit/collection_spec.rb +0 -182
- data/spec/unit/data_mapper_spec.rb +0 -35
- data/spec/unit/identity_map_spec.rb +0 -126
- data/spec/unit/is_spec.rb +0 -80
- data/spec/unit/migrator_spec.rb +0 -33
- data/spec/unit/model_spec.rb +0 -321
- data/spec/unit/naming_conventions_spec.rb +0 -36
- data/spec/unit/property_set_spec.rb +0 -90
- data/spec/unit/property_spec.rb +0 -753
- data/spec/unit/query_spec.rb +0 -571
- data/spec/unit/repository_spec.rb +0 -93
- data/spec/unit/resource_spec.rb +0 -649
- data/spec/unit/scope_spec.rb +0 -142
- data/spec/unit/transaction_spec.rb +0 -493
- data/spec/unit/type_map_spec.rb +0 -114
- data/spec/unit/type_spec.rb +0 -119
data/lib/dm-core/transaction.rb
CHANGED
|
@@ -1,141 +1,170 @@
|
|
|
1
|
-
# TODO: move to dm-more/dm-
|
|
1
|
+
# TODO: move to dm-more/dm-transaction
|
|
2
2
|
|
|
3
3
|
module DataMapper
|
|
4
4
|
class Transaction
|
|
5
|
+
extend Chainable
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
# Create a new DataMapper::Transaction
|
|
7
|
+
# Create a new Transaction
|
|
10
8
|
#
|
|
11
|
-
# @see
|
|
9
|
+
# @see Transaction#link
|
|
12
10
|
#
|
|
13
11
|
# In fact, it just calls #link with the given arguments at the end of the
|
|
14
12
|
# constructor.
|
|
15
13
|
#
|
|
14
|
+
# @api public
|
|
16
15
|
def initialize(*things)
|
|
17
16
|
@transaction_primitives = {}
|
|
18
17
|
@state = :none
|
|
19
18
|
@adapters = {}
|
|
20
19
|
link(*things)
|
|
21
|
-
|
|
20
|
+
if block_given?
|
|
21
|
+
warn "Passing block to #{self.class.name}.new is deprecated (#{caller[0]})"
|
|
22
|
+
commit { |*block_args| yield(*block_args) }
|
|
23
|
+
end
|
|
22
24
|
end
|
|
23
25
|
|
|
24
|
-
#
|
|
25
26
|
# Associate this Transaction with some things.
|
|
26
27
|
#
|
|
27
|
-
# @param
|
|
28
|
-
# associated with
|
|
29
|
-
#
|
|
30
|
-
#
|
|
28
|
+
# @param [Object] things
|
|
29
|
+
# the things you want this Transaction associated with:
|
|
30
|
+
#
|
|
31
|
+
# Adapters::AbstractAdapter subclasses will be added as
|
|
31
32
|
# adapters as is.
|
|
32
33
|
# Arrays will have their elements added.
|
|
33
|
-
#
|
|
34
|
-
#
|
|
34
|
+
# Repository will have it's own @adapters added.
|
|
35
|
+
# Resource subclasses will have all the repositories of all
|
|
35
36
|
# their properties added.
|
|
36
|
-
#
|
|
37
|
+
# Resource instances will have all repositories of all their
|
|
37
38
|
# properties added.
|
|
38
|
-
#
|
|
39
|
-
#
|
|
39
|
+
#
|
|
40
|
+
# @param [Proc] block
|
|
41
|
+
# a block (taking one argument, the Transaction) to execute within
|
|
42
|
+
# this transaction. The transaction will begin and commit around
|
|
40
43
|
# the block, and rollback if an exception is raised.
|
|
41
44
|
#
|
|
45
|
+
# @api private
|
|
42
46
|
def link(*things)
|
|
43
|
-
|
|
47
|
+
unless @state == :none
|
|
48
|
+
raise "Illegal state for link: #{@state}"
|
|
49
|
+
end
|
|
50
|
+
|
|
44
51
|
things.each do |thing|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
case thing
|
|
53
|
+
when DataMapper::Adapters::AbstractAdapter
|
|
54
|
+
@adapters[thing] = :none
|
|
55
|
+
when DataMapper::Repository
|
|
56
|
+
link(thing.adapter)
|
|
57
|
+
when DataMapper::Model
|
|
58
|
+
link(*thing.repositories)
|
|
59
|
+
when DataMapper::Resource
|
|
60
|
+
link(thing.model)
|
|
61
|
+
when Array
|
|
62
|
+
link(*thing)
|
|
63
|
+
else
|
|
64
|
+
raise "Unknown argument to #{self.class}#link: #{thing.inspect} (#{thing.class})"
|
|
57
65
|
end
|
|
58
66
|
end
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
|
|
68
|
+
if block_given?
|
|
69
|
+
commit { |*block_args| yield(*block_args) }
|
|
70
|
+
else
|
|
71
|
+
self
|
|
72
|
+
end
|
|
61
73
|
end
|
|
62
74
|
|
|
63
|
-
#
|
|
64
75
|
# Begin the transaction
|
|
65
76
|
#
|
|
66
77
|
# Before #begin is called, the transaction is not valid and can not be used.
|
|
67
78
|
#
|
|
79
|
+
# @api private
|
|
68
80
|
def begin
|
|
69
|
-
|
|
81
|
+
unless @state == :none
|
|
82
|
+
raise "Illegal state for begin: #{@state}"
|
|
83
|
+
end
|
|
84
|
+
|
|
70
85
|
each_adapter(:connect_adapter, [:log_fatal_transaction_breakage])
|
|
71
86
|
each_adapter(:begin_adapter, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
|
|
72
87
|
@state = :begin
|
|
73
88
|
end
|
|
74
89
|
|
|
75
|
-
#
|
|
76
90
|
# Commit the transaction
|
|
77
91
|
#
|
|
92
|
+
# If no block is given, it will simply commit any changes made since the
|
|
93
|
+
# Transaction did #begin.
|
|
94
|
+
#
|
|
78
95
|
# @param block<Block> a block (taking the one argument, the Transaction) to
|
|
79
96
|
# execute within this transaction. The transaction will begin and commit
|
|
80
97
|
# around the block, and roll back if an exception is raised.
|
|
81
98
|
#
|
|
82
|
-
# @
|
|
83
|
-
# If no block is given, it will simply commit any changes made since the
|
|
84
|
-
# Transaction did #begin.
|
|
85
|
-
#
|
|
99
|
+
# @api private
|
|
86
100
|
def commit
|
|
87
101
|
if block_given?
|
|
88
|
-
|
|
102
|
+
unless @state == :none
|
|
103
|
+
raise "Illegal state for commit with block: #{@state}"
|
|
104
|
+
end
|
|
105
|
+
|
|
89
106
|
begin
|
|
90
107
|
self.begin
|
|
91
108
|
rval = within { |*block_args| yield(*block_args) }
|
|
92
|
-
|
|
109
|
+
if @state == :begin
|
|
110
|
+
self.commit
|
|
111
|
+
end
|
|
93
112
|
return rval
|
|
94
|
-
rescue Exception =>
|
|
95
|
-
|
|
96
|
-
|
|
113
|
+
rescue Exception => exception
|
|
114
|
+
if @state == :begin
|
|
115
|
+
self.rollback
|
|
116
|
+
end
|
|
117
|
+
raise exception
|
|
97
118
|
end
|
|
98
119
|
else
|
|
99
|
-
|
|
100
|
-
|
|
120
|
+
unless @state == :begin
|
|
121
|
+
raise "Illegal state for commit without block: #{@state}"
|
|
122
|
+
end
|
|
101
123
|
each_adapter(:commit_adapter, [:log_fatal_transaction_breakage])
|
|
102
124
|
each_adapter(:close_adapter, [:log_fatal_transaction_breakage])
|
|
103
125
|
@state = :commit
|
|
104
126
|
end
|
|
105
127
|
end
|
|
106
128
|
|
|
107
|
-
#
|
|
108
129
|
# Rollback the transaction
|
|
109
130
|
#
|
|
110
131
|
# Will undo all changes made during the transaction.
|
|
111
132
|
#
|
|
133
|
+
# @api private
|
|
112
134
|
def rollback
|
|
113
|
-
|
|
135
|
+
unless @state == :begin
|
|
136
|
+
raise "Illegal state for rollback: #{@state}"
|
|
137
|
+
end
|
|
114
138
|
each_adapter(:rollback_adapter_if_begin, [:rollback_and_close_adapter_if_begin, :close_adapter_if_none])
|
|
115
|
-
each_adapter(:rollback_prepared_adapter_if_prepare, [:rollback_prepared_and_close_adapter_if_begin, :close_adapter_if_none])
|
|
116
139
|
each_adapter(:close_adapter_if_open, [:log_fatal_transaction_breakage])
|
|
117
140
|
@state = :rollback
|
|
118
141
|
end
|
|
119
142
|
|
|
120
|
-
#
|
|
121
143
|
# Execute a block within this Transaction.
|
|
122
144
|
#
|
|
123
|
-
#
|
|
145
|
+
# No #begin, #commit or #rollback is performed in #within, but this
|
|
146
|
+
# Transaction will pushed on the per thread stack of transactions for each
|
|
147
|
+
# adapter it is associated with, and it will ensures that it will pop the
|
|
148
|
+
# Transaction away again after the block is finished.
|
|
124
149
|
#
|
|
125
|
-
# @
|
|
126
|
-
# No #begin, #commit or #rollback is performed in #within, but this
|
|
127
|
-
# Transaction will pushed on the per thread stack of transactions for each
|
|
128
|
-
# adapter it is associated with, and it will ensures that it will pop the
|
|
129
|
-
# Transaction away again after the block is finished.
|
|
150
|
+
# @param block<Block> the block of code to execute.
|
|
130
151
|
#
|
|
152
|
+
# @api private
|
|
131
153
|
def within
|
|
132
|
-
|
|
133
|
-
|
|
154
|
+
unless block_given?
|
|
155
|
+
raise 'No block provided'
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
unless @state == :begin
|
|
159
|
+
raise "Illegal state for within: #{@state}"
|
|
160
|
+
end
|
|
161
|
+
|
|
134
162
|
@adapters.each do |adapter, state|
|
|
135
163
|
adapter.push_transaction(self)
|
|
136
164
|
end
|
|
165
|
+
|
|
137
166
|
begin
|
|
138
|
-
|
|
167
|
+
yield self
|
|
139
168
|
ensure
|
|
140
169
|
@adapters.each do |adapter, state|
|
|
141
170
|
adapter.pop_transaction
|
|
@@ -143,17 +172,23 @@ module DataMapper
|
|
|
143
172
|
end
|
|
144
173
|
end
|
|
145
174
|
|
|
175
|
+
# TODO: document
|
|
176
|
+
# @api private
|
|
146
177
|
def method_missing(meth, *args, &block)
|
|
147
|
-
if args.size == 1 && args.first.
|
|
148
|
-
if (match = meth.to_s.match(/^(.*)_if_(none|begin|
|
|
178
|
+
if args.size == 1 && args.first.kind_of?(Adapters::AbstractAdapter)
|
|
179
|
+
if (match = meth.to_s.match(/^(.*)_if_(none|begin|rollback|commit)$/))
|
|
149
180
|
if self.respond_to?(match[1], true)
|
|
150
|
-
|
|
181
|
+
if state_for(args.first).to_s == match[2]
|
|
182
|
+
self.send(match[1], args.first)
|
|
183
|
+
end
|
|
151
184
|
else
|
|
152
185
|
super
|
|
153
186
|
end
|
|
154
|
-
elsif (match = meth.to_s.match(/^(.*)_unless_(none|begin|
|
|
187
|
+
elsif (match = meth.to_s.match(/^(.*)_unless_(none|begin|rollback|commit)$/))
|
|
155
188
|
if self.respond_to?(match[1], true)
|
|
156
|
-
|
|
189
|
+
unless state_for(args.first).to_s == match[2]
|
|
190
|
+
self.send(match[1], args.first)
|
|
191
|
+
end
|
|
157
192
|
else
|
|
158
193
|
super
|
|
159
194
|
end
|
|
@@ -165,103 +200,309 @@ module DataMapper
|
|
|
165
200
|
end
|
|
166
201
|
end
|
|
167
202
|
|
|
203
|
+
# TODO: document
|
|
204
|
+
# @api private
|
|
168
205
|
def primitive_for(adapter)
|
|
169
|
-
|
|
170
|
-
|
|
206
|
+
unless @adapters.include?(adapter)
|
|
207
|
+
raise "Unknown adapter #{adapter}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
unless @transaction_primitives.include?(adapter)
|
|
211
|
+
raise "No primitive for #{adapter}"
|
|
212
|
+
end
|
|
213
|
+
|
|
171
214
|
@transaction_primitives[adapter]
|
|
172
215
|
end
|
|
173
216
|
|
|
174
217
|
private
|
|
175
218
|
|
|
219
|
+
# TODO: document
|
|
220
|
+
# @api private
|
|
176
221
|
def validate_primitive(primitive)
|
|
177
|
-
[:close, :begin, :
|
|
178
|
-
|
|
222
|
+
[:close, :begin, :rollback, :commit].each do |meth|
|
|
223
|
+
unless primitive.respond_to?(meth)
|
|
224
|
+
raise "Invalid primitive #{primitive}: doesnt respond_to?(#{meth.inspect})"
|
|
225
|
+
end
|
|
179
226
|
end
|
|
180
|
-
|
|
227
|
+
|
|
228
|
+
primitive
|
|
181
229
|
end
|
|
182
230
|
|
|
231
|
+
# TODO: document
|
|
232
|
+
# @api private
|
|
183
233
|
def each_adapter(method, on_fail)
|
|
184
234
|
begin
|
|
185
235
|
@adapters.each do |adapter, state|
|
|
186
236
|
self.send(method, adapter)
|
|
187
237
|
end
|
|
188
|
-
rescue Exception =>
|
|
238
|
+
rescue Exception => exception
|
|
189
239
|
@adapters.each do |adapter, state|
|
|
190
240
|
on_fail.each do |fail_handler|
|
|
191
241
|
begin
|
|
192
242
|
self.send(fail_handler, adapter)
|
|
193
|
-
rescue Exception =>
|
|
194
|
-
DataMapper.logger.fatal("#{self}#each_adapter(#{method.inspect}, #{on_fail.inspect}) failed with #{
|
|
243
|
+
rescue Exception => inner_exception
|
|
244
|
+
DataMapper.logger.fatal("#{self}#each_adapter(#{method.inspect}, #{on_fail.inspect}) failed with #{exception.inspect}: #{exception.backtrace.join("\n")} - and when sending #{fail_handler} to #{adapter} we failed again with #{inner_exception.inspect}: #{inner_exception.backtrace.join("\n")}")
|
|
195
245
|
end
|
|
196
246
|
end
|
|
197
247
|
end
|
|
198
|
-
raise
|
|
248
|
+
raise exception
|
|
199
249
|
end
|
|
200
250
|
end
|
|
201
251
|
|
|
252
|
+
# TODO: document
|
|
253
|
+
# @api private
|
|
202
254
|
def state_for(adapter)
|
|
203
|
-
|
|
255
|
+
unless @adapters.include?(adapter)
|
|
256
|
+
raise "Unknown adapter #{adapter}"
|
|
257
|
+
end
|
|
258
|
+
|
|
204
259
|
@adapters[adapter]
|
|
205
260
|
end
|
|
206
261
|
|
|
262
|
+
# TODO: document
|
|
263
|
+
# @api private
|
|
207
264
|
def do_adapter(adapter, what, prerequisite)
|
|
208
|
-
|
|
209
|
-
|
|
265
|
+
unless @transaction_primitives.include?(adapter)
|
|
266
|
+
raise "No primitive for #{adapter}"
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
unless state_for(adapter) == prerequisite
|
|
270
|
+
raise "Illegal state for #{what}: #{state_for(adapter)}"
|
|
271
|
+
end
|
|
272
|
+
|
|
210
273
|
DataMapper.logger.debug("#{adapter.name}: #{what}")
|
|
211
274
|
@transaction_primitives[adapter].send(what)
|
|
212
275
|
@adapters[adapter] = what
|
|
213
276
|
end
|
|
214
277
|
|
|
278
|
+
# TODO: document
|
|
279
|
+
# @api private
|
|
215
280
|
def log_fatal_transaction_breakage(adapter)
|
|
216
281
|
DataMapper.logger.fatal("#{self} experienced a totally broken transaction execution. Presenting member #{adapter.inspect}.")
|
|
217
282
|
end
|
|
218
283
|
|
|
284
|
+
# TODO: document
|
|
285
|
+
# @api private
|
|
219
286
|
def connect_adapter(adapter)
|
|
220
|
-
|
|
287
|
+
if @transaction_primitives.key?(adapter)
|
|
288
|
+
raise "Already a primitive for adapter #{adapter}"
|
|
289
|
+
end
|
|
290
|
+
|
|
221
291
|
@transaction_primitives[adapter] = validate_primitive(adapter.transaction_primitive)
|
|
222
292
|
end
|
|
223
293
|
|
|
294
|
+
# TODO: document
|
|
295
|
+
# @api private
|
|
224
296
|
def close_adapter_if_open(adapter)
|
|
225
297
|
if @transaction_primitives.include?(adapter)
|
|
226
298
|
close_adapter(adapter)
|
|
227
299
|
end
|
|
228
300
|
end
|
|
229
301
|
|
|
302
|
+
# TODO: document
|
|
303
|
+
# @api private
|
|
230
304
|
def close_adapter(adapter)
|
|
231
|
-
|
|
305
|
+
unless @transaction_primitives.include?(adapter)
|
|
306
|
+
raise 'No primitive for adapter'
|
|
307
|
+
end
|
|
308
|
+
|
|
232
309
|
@transaction_primitives[adapter].close
|
|
233
310
|
@transaction_primitives.delete(adapter)
|
|
234
311
|
end
|
|
235
312
|
|
|
313
|
+
# TODO: document
|
|
314
|
+
# @api private
|
|
236
315
|
def begin_adapter(adapter)
|
|
237
316
|
do_adapter(adapter, :begin, :none)
|
|
238
317
|
end
|
|
239
318
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
end
|
|
243
|
-
|
|
319
|
+
# TODO: document
|
|
320
|
+
# @api private
|
|
244
321
|
def commit_adapter(adapter)
|
|
245
|
-
do_adapter(adapter, :commit, :
|
|
322
|
+
do_adapter(adapter, :commit, :begin)
|
|
246
323
|
end
|
|
247
324
|
|
|
325
|
+
# TODO: document
|
|
326
|
+
# @api private
|
|
248
327
|
def rollback_adapter(adapter)
|
|
249
328
|
do_adapter(adapter, :rollback, :begin)
|
|
250
329
|
end
|
|
251
330
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
def rollback_prepared_and_close_adapter(adapter)
|
|
257
|
-
rollback_prepared_adapter(adapter)
|
|
258
|
-
close_adapter(adapter)
|
|
259
|
-
end
|
|
260
|
-
|
|
331
|
+
# TODO: document
|
|
332
|
+
# @api private
|
|
261
333
|
def rollback_and_close_adapter(adapter)
|
|
262
334
|
rollback_adapter(adapter)
|
|
263
335
|
close_adapter(adapter)
|
|
264
336
|
end
|
|
265
337
|
|
|
338
|
+
module Adapter
|
|
339
|
+
extend Chainable
|
|
340
|
+
|
|
341
|
+
# TODO: document
|
|
342
|
+
# @api private
|
|
343
|
+
def self.included(base)
|
|
344
|
+
[ :Repository, :Model, :Resource ].each do |name|
|
|
345
|
+
DataMapper.const_get(name).send(:include, Transaction.const_get(name))
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
# Produces a fresh transaction primitive for this Adapter
|
|
350
|
+
#
|
|
351
|
+
# Used by Transaction to perform its various tasks.
|
|
352
|
+
#
|
|
353
|
+
# @return [Object]
|
|
354
|
+
# a new Object that responds to :close, :begin, :commit,
|
|
355
|
+
# and :rollback,
|
|
356
|
+
#
|
|
357
|
+
# @api private
|
|
358
|
+
def transaction_primitive
|
|
359
|
+
DataObjects::Transaction.create_for_uri(normalized_uri)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Pushes the given Transaction onto the per thread Transaction stack so
|
|
363
|
+
# that everything done by this Adapter is done within the context of said
|
|
364
|
+
# Transaction.
|
|
365
|
+
#
|
|
366
|
+
# @param [Transaction] transaction
|
|
367
|
+
# a Transaction to be the 'current' transaction until popped.
|
|
368
|
+
#
|
|
369
|
+
# @return [Array(Transaction)]
|
|
370
|
+
# the stack of active transactions for the current thread
|
|
371
|
+
#
|
|
372
|
+
# @api private
|
|
373
|
+
def push_transaction(transaction)
|
|
374
|
+
transactions << transaction
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# Pop the 'current' Transaction from the per thread Transaction stack so
|
|
378
|
+
# that everything done by this Adapter is no longer necessarily within the
|
|
379
|
+
# context of said Transaction.
|
|
380
|
+
#
|
|
381
|
+
# @return [Transaction]
|
|
382
|
+
# the former 'current' transaction.
|
|
383
|
+
#
|
|
384
|
+
# @api private
|
|
385
|
+
def pop_transaction
|
|
386
|
+
transactions.pop
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Retrieve the current transaction for this Adapter.
|
|
390
|
+
#
|
|
391
|
+
# Everything done by this Adapter is done within the context of this
|
|
392
|
+
# Transaction.
|
|
393
|
+
#
|
|
394
|
+
# @return [Transaction]
|
|
395
|
+
# the 'current' transaction for this Adapter.
|
|
396
|
+
#
|
|
397
|
+
# @api private
|
|
398
|
+
def current_transaction
|
|
399
|
+
transactions.last
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
chainable do
|
|
403
|
+
protected
|
|
404
|
+
|
|
405
|
+
# TODO: document
|
|
406
|
+
# @api semipublic
|
|
407
|
+
def open_connection
|
|
408
|
+
current_connection || super
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# TODO: document
|
|
412
|
+
# @api semipublic
|
|
413
|
+
def close_connection(connection)
|
|
414
|
+
unless current_connection == connection
|
|
415
|
+
super
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
private
|
|
421
|
+
|
|
422
|
+
# TODO: document
|
|
423
|
+
# @api private
|
|
424
|
+
def transactions
|
|
425
|
+
Thread.current[:dm_transactions] ||= []
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
# Retrieve the current connection for this Adapter.
|
|
429
|
+
#
|
|
430
|
+
# @return [Transaction]
|
|
431
|
+
# the 'current' connection for this Adapter.
|
|
432
|
+
#
|
|
433
|
+
# @api private
|
|
434
|
+
def current_connection
|
|
435
|
+
if transaction = current_transaction
|
|
436
|
+
transaction.primitive_for(self).connection
|
|
437
|
+
end
|
|
438
|
+
end
|
|
439
|
+
end # module Adapter
|
|
440
|
+
|
|
441
|
+
# alias the MySQL, PostgreSQL, Sqlite3 and Oracle adapters to use transactions
|
|
442
|
+
MysqlAdapter = PostgresAdapter = Sqlite3Adapter = OracleAdapter = Adapter
|
|
443
|
+
|
|
444
|
+
module Repository
|
|
445
|
+
|
|
446
|
+
# Produce a new Transaction for this Repository
|
|
447
|
+
#
|
|
448
|
+
# @return [Adapters::Transaction]
|
|
449
|
+
# a new Transaction (in state :none) that can be used
|
|
450
|
+
# to execute code #with_transaction
|
|
451
|
+
#
|
|
452
|
+
# @api public
|
|
453
|
+
def transaction
|
|
454
|
+
Transaction.new(self)
|
|
455
|
+
end
|
|
456
|
+
end # module Repository
|
|
457
|
+
|
|
458
|
+
module Model
|
|
459
|
+
# TODO: document
|
|
460
|
+
# @api private
|
|
461
|
+
def self.included(mod)
|
|
462
|
+
mod.descendants.each { |model| model.extend self }
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Produce a new Transaction for this Resource class
|
|
466
|
+
#
|
|
467
|
+
# @return <Adapters::Transaction
|
|
468
|
+
# a new Adapters::Transaction with all Repositories
|
|
469
|
+
# of the class of this Resource added.
|
|
470
|
+
#
|
|
471
|
+
# @api public
|
|
472
|
+
def transaction
|
|
473
|
+
transaction = Transaction.new(self)
|
|
474
|
+
transaction.commit { |block_args| yield(*block_args) }
|
|
475
|
+
end
|
|
476
|
+
end # module Model
|
|
477
|
+
|
|
478
|
+
module Resource
|
|
479
|
+
|
|
480
|
+
# Produce a new Transaction for the class of this Resource
|
|
481
|
+
#
|
|
482
|
+
# @return [Adapters::Transaction]
|
|
483
|
+
# a new Adapters::Transaction for the Repository
|
|
484
|
+
# of the class of this Resource added.
|
|
485
|
+
#
|
|
486
|
+
# @api public
|
|
487
|
+
def transaction
|
|
488
|
+
model.transaction { |*block_args| yield(*block_args) }
|
|
489
|
+
end
|
|
490
|
+
end # module Resource
|
|
266
491
|
end # class Transaction
|
|
492
|
+
|
|
493
|
+
module Adapters
|
|
494
|
+
extendable do
|
|
495
|
+
|
|
496
|
+
# TODO: document
|
|
497
|
+
# @api private
|
|
498
|
+
def const_added(const_name)
|
|
499
|
+
if Transaction.const_defined?(const_name)
|
|
500
|
+
adapter = const_get(const_name)
|
|
501
|
+
adapter.send(:include, Transaction.const_get(const_name))
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
super
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
end # module Adapters
|
|
267
508
|
end # module DataMapper
|