sam-dm-core 0.9.6
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 +26 -0
- data/CONTRIBUTING +51 -0
- data/FAQ +92 -0
- data/History.txt +145 -0
- data/MIT-LICENSE +22 -0
- data/Manifest.txt +125 -0
- data/QUICKLINKS +12 -0
- data/README.txt +143 -0
- data/Rakefile +30 -0
- data/SPECS +63 -0
- data/TODO +1 -0
- data/lib/dm-core.rb +224 -0
- data/lib/dm-core/adapters.rb +4 -0
- data/lib/dm-core/adapters/abstract_adapter.rb +202 -0
- data/lib/dm-core/adapters/data_objects_adapter.rb +707 -0
- data/lib/dm-core/adapters/mysql_adapter.rb +136 -0
- data/lib/dm-core/adapters/postgres_adapter.rb +188 -0
- data/lib/dm-core/adapters/sqlite3_adapter.rb +105 -0
- data/lib/dm-core/associations.rb +199 -0
- data/lib/dm-core/associations/many_to_many.rb +147 -0
- data/lib/dm-core/associations/many_to_one.rb +107 -0
- data/lib/dm-core/associations/one_to_many.rb +309 -0
- data/lib/dm-core/associations/one_to_one.rb +61 -0
- data/lib/dm-core/associations/relationship.rb +218 -0
- data/lib/dm-core/associations/relationship_chain.rb +81 -0
- data/lib/dm-core/auto_migrations.rb +113 -0
- data/lib/dm-core/collection.rb +638 -0
- data/lib/dm-core/dependency_queue.rb +31 -0
- data/lib/dm-core/hook.rb +11 -0
- data/lib/dm-core/identity_map.rb +45 -0
- data/lib/dm-core/is.rb +16 -0
- data/lib/dm-core/logger.rb +232 -0
- data/lib/dm-core/migrations/destructive_migrations.rb +17 -0
- data/lib/dm-core/migrator.rb +29 -0
- data/lib/dm-core/model.rb +471 -0
- data/lib/dm-core/naming_conventions.rb +84 -0
- data/lib/dm-core/property.rb +673 -0
- data/lib/dm-core/property_set.rb +162 -0
- data/lib/dm-core/query.rb +625 -0
- data/lib/dm-core/repository.rb +159 -0
- data/lib/dm-core/resource.rb +637 -0
- data/lib/dm-core/scope.rb +58 -0
- data/lib/dm-core/support.rb +7 -0
- data/lib/dm-core/support/array.rb +13 -0
- data/lib/dm-core/support/assertions.rb +8 -0
- data/lib/dm-core/support/errors.rb +23 -0
- data/lib/dm-core/support/kernel.rb +7 -0
- data/lib/dm-core/support/symbol.rb +41 -0
- data/lib/dm-core/transaction.rb +267 -0
- data/lib/dm-core/type.rb +160 -0
- data/lib/dm-core/type_map.rb +80 -0
- data/lib/dm-core/types.rb +19 -0
- data/lib/dm-core/types/boolean.rb +7 -0
- data/lib/dm-core/types/discriminator.rb +34 -0
- data/lib/dm-core/types/object.rb +24 -0
- data/lib/dm-core/types/paranoid_boolean.rb +34 -0
- data/lib/dm-core/types/paranoid_datetime.rb +33 -0
- data/lib/dm-core/types/serial.rb +9 -0
- data/lib/dm-core/types/text.rb +10 -0
- data/lib/dm-core/version.rb +3 -0
- data/script/all +5 -0
- data/script/performance.rb +203 -0
- data/script/profile.rb +87 -0
- data/spec/integration/association_spec.rb +1371 -0
- data/spec/integration/association_through_spec.rb +203 -0
- data/spec/integration/associations/many_to_many_spec.rb +449 -0
- data/spec/integration/associations/many_to_one_spec.rb +163 -0
- data/spec/integration/associations/one_to_many_spec.rb +151 -0
- data/spec/integration/auto_migrations_spec.rb +398 -0
- data/spec/integration/collection_spec.rb +1069 -0
- data/spec/integration/data_objects_adapter_spec.rb +32 -0
- data/spec/integration/dependency_queue_spec.rb +58 -0
- data/spec/integration/model_spec.rb +127 -0
- data/spec/integration/mysql_adapter_spec.rb +85 -0
- data/spec/integration/postgres_adapter_spec.rb +731 -0
- data/spec/integration/property_spec.rb +233 -0
- data/spec/integration/query_spec.rb +506 -0
- data/spec/integration/repository_spec.rb +57 -0
- data/spec/integration/resource_spec.rb +475 -0
- data/spec/integration/sqlite3_adapter_spec.rb +352 -0
- data/spec/integration/sti_spec.rb +208 -0
- data/spec/integration/strategic_eager_loading_spec.rb +138 -0
- data/spec/integration/transaction_spec.rb +75 -0
- data/spec/integration/type_spec.rb +271 -0
- data/spec/lib/logging_helper.rb +18 -0
- data/spec/lib/mock_adapter.rb +27 -0
- data/spec/lib/model_loader.rb +91 -0
- data/spec/lib/publicize_methods.rb +28 -0
- data/spec/models/vehicles.rb +34 -0
- data/spec/models/zoo.rb +47 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/unit/adapters/abstract_adapter_spec.rb +133 -0
- data/spec/unit/adapters/adapter_shared_spec.rb +15 -0
- data/spec/unit/adapters/data_objects_adapter_spec.rb +628 -0
- data/spec/unit/adapters/postgres_adapter_spec.rb +133 -0
- data/spec/unit/associations/many_to_many_spec.rb +17 -0
- data/spec/unit/associations/many_to_one_spec.rb +152 -0
- data/spec/unit/associations/one_to_many_spec.rb +393 -0
- data/spec/unit/associations/one_to_one_spec.rb +7 -0
- data/spec/unit/associations/relationship_spec.rb +71 -0
- data/spec/unit/associations_spec.rb +242 -0
- data/spec/unit/auto_migrations_spec.rb +111 -0
- data/spec/unit/collection_spec.rb +182 -0
- data/spec/unit/data_mapper_spec.rb +35 -0
- data/spec/unit/identity_map_spec.rb +126 -0
- data/spec/unit/is_spec.rb +80 -0
- data/spec/unit/migrator_spec.rb +33 -0
- data/spec/unit/model_spec.rb +339 -0
- data/spec/unit/naming_conventions_spec.rb +36 -0
- data/spec/unit/property_set_spec.rb +83 -0
- data/spec/unit/property_spec.rb +753 -0
- data/spec/unit/query_spec.rb +530 -0
- data/spec/unit/repository_spec.rb +93 -0
- data/spec/unit/resource_spec.rb +626 -0
- data/spec/unit/scope_spec.rb +142 -0
- data/spec/unit/transaction_spec.rb +493 -0
- data/spec/unit/type_map_spec.rb +114 -0
- data/spec/unit/type_spec.rb +119 -0
- data/tasks/ci.rb +68 -0
- data/tasks/dm.rb +63 -0
- data/tasks/doc.rb +20 -0
- data/tasks/gemspec.rb +23 -0
- data/tasks/hoe.rb +46 -0
- data/tasks/install.rb +20 -0
- metadata +216 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Associations
|
3
|
+
module OneToOne
|
4
|
+
extend Assertions
|
5
|
+
|
6
|
+
# Setup one to one relationship between two models
|
7
|
+
# -
|
8
|
+
# @api private
|
9
|
+
def self.setup(name, model, options = {})
|
10
|
+
assert_kind_of 'name', name, Symbol
|
11
|
+
assert_kind_of 'model', model, Model
|
12
|
+
assert_kind_of 'options', options, Hash
|
13
|
+
|
14
|
+
repository_name = model.repository.name
|
15
|
+
|
16
|
+
model.class_eval <<-EOS, __FILE__, __LINE__
|
17
|
+
def #{name}
|
18
|
+
#{name}_association.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def #{name}=(child_resource)
|
22
|
+
#{name}_association.replace(child_resource.nil? ? [] : [ child_resource ])
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def #{name}_association
|
28
|
+
@#{name}_association ||= begin
|
29
|
+
unless relationship = model.relationships(#{repository_name.inspect})[:#{name}]
|
30
|
+
raise ArgumentError, "Relationship #{name.inspect} does not exist in \#{model}"
|
31
|
+
end
|
32
|
+
association = Associations::OneToMany::Proxy.new(relationship, self)
|
33
|
+
parent_associations << association
|
34
|
+
association
|
35
|
+
end
|
36
|
+
end
|
37
|
+
EOS
|
38
|
+
|
39
|
+
model.relationships(repository_name)[name] = if options.has_key?(:through)
|
40
|
+
RelationshipChain.new(
|
41
|
+
:child_model => options.fetch(:class_name, Extlib::Inflection.classify(name)),
|
42
|
+
:parent_model => model,
|
43
|
+
:repository_name => repository_name,
|
44
|
+
:near_relationship_name => options[:through],
|
45
|
+
:remote_relationship_name => options.fetch(:remote_name, name),
|
46
|
+
:parent_key => options[:parent_key],
|
47
|
+
:child_key => options[:child_key]
|
48
|
+
)
|
49
|
+
else
|
50
|
+
Relationship.new(
|
51
|
+
name,
|
52
|
+
repository_name,
|
53
|
+
options.fetch(:class_name, Extlib::Inflection.classify(name)),
|
54
|
+
model,
|
55
|
+
options
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end # module HasOne
|
60
|
+
end # module Associations
|
61
|
+
end # module DataMapper
|
@@ -0,0 +1,218 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Associations
|
3
|
+
class Relationship
|
4
|
+
include Assertions
|
5
|
+
|
6
|
+
OPTIONS = [ :class_name, :child_key, :parent_key, :min, :max, :through ]
|
7
|
+
|
8
|
+
# @api private
|
9
|
+
attr_reader :name, :options, :query
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
def child_key
|
13
|
+
@child_key ||= begin
|
14
|
+
child_key = nil
|
15
|
+
child_model.repository.scope do |r|
|
16
|
+
model_properties = child_model.properties(r.name)
|
17
|
+
|
18
|
+
child_key = parent_key.zip(@child_properties || []).map do |parent_property,property_name|
|
19
|
+
# TODO: use something similar to DM::NamingConventions to determine the property name
|
20
|
+
parent_name = Extlib::Inflection.underscore(Extlib::Inflection.demodulize(parent_model.base_model.name))
|
21
|
+
property_name ||= "#{parent_name}_#{parent_property.name}".to_sym
|
22
|
+
|
23
|
+
if model_properties.has_property?(property_name)
|
24
|
+
model_properties[property_name]
|
25
|
+
else
|
26
|
+
options = {}
|
27
|
+
|
28
|
+
[ :length, :precision, :scale ].each do |option|
|
29
|
+
options[option] = parent_property.send(option)
|
30
|
+
end
|
31
|
+
|
32
|
+
# NOTE: hack to make each many to many child_key a true key,
|
33
|
+
# until I can figure out a better place for this check
|
34
|
+
if child_model.respond_to?(:many_to_many)
|
35
|
+
options[:key] = true
|
36
|
+
end
|
37
|
+
|
38
|
+
child_model.property(property_name, parent_property.primitive, options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
PropertySet.new(child_key)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @api private
|
47
|
+
def parent_key
|
48
|
+
@parent_key ||= begin
|
49
|
+
parent_key = nil
|
50
|
+
parent_model.repository.scope do |r|
|
51
|
+
parent_key = if @parent_properties
|
52
|
+
parent_model.properties(r.name).slice(*@parent_properties)
|
53
|
+
else
|
54
|
+
parent_model.key
|
55
|
+
end
|
56
|
+
end
|
57
|
+
PropertySet.new(parent_key)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @api private
|
62
|
+
def parent_model
|
63
|
+
Class === @parent_model ? @parent_model : (Class === @child_model ? @child_model.find_const(@parent_model) : Object.find_const(@parent_model))
|
64
|
+
rescue NameError
|
65
|
+
raise NameError, "Cannot find the parent_model #{@parent_model} for #{@child_model}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# @api private
|
69
|
+
def child_model
|
70
|
+
Class === @child_model ? @child_model : (Class === @parent_model ? @parent_model.find_const(@child_model) : Object.find_const(@child_model))
|
71
|
+
rescue NameError
|
72
|
+
raise NameError, "Cannot find the child_model #{@child_model} for #{@parent_model}"
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def get_children(parent, options = {}, finder = :all, *args)
|
77
|
+
bind_values = parent_key.get(parent)
|
78
|
+
parent_values = bind_values.dup
|
79
|
+
|
80
|
+
with_repository(child_model) do |r|
|
81
|
+
parent_identity_map = parent.repository.identity_map(parent_model)
|
82
|
+
child_identity_map = r.identity_map(child_model)
|
83
|
+
|
84
|
+
query_values = parent_identity_map.keys.flatten
|
85
|
+
query_values.reject! { |k| child_identity_map[[k]] }
|
86
|
+
|
87
|
+
bind_values = query_values unless query_values.empty?
|
88
|
+
query = child_key.map { |k| [ k, bind_values ] }.to_hash
|
89
|
+
|
90
|
+
collection = child_model.send(finder, *(args.dup << @query.merge(options).merge(query)))
|
91
|
+
return collection unless collection.kind_of?(Collection) && collection.any?
|
92
|
+
|
93
|
+
grouped_collection = Hash.new { |h,k| h[k] = [] }
|
94
|
+
collection.each do |resource|
|
95
|
+
grouped_collection[get_parent(resource, parent)] << resource
|
96
|
+
end
|
97
|
+
|
98
|
+
association_accessor = "#{self.name}_association"
|
99
|
+
|
100
|
+
ret = nil
|
101
|
+
grouped_collection.each do |parent, children|
|
102
|
+
association = parent.send(association_accessor)
|
103
|
+
|
104
|
+
query = collection.query.dup
|
105
|
+
query.conditions.map! do |operator, property, bind_value|
|
106
|
+
if operator != :raw && child_key.has_property?(property.name)
|
107
|
+
bind_value = *children.map { |child| property.get(child) }.uniq
|
108
|
+
end
|
109
|
+
[ operator, property, bind_value ]
|
110
|
+
end
|
111
|
+
|
112
|
+
parents_children = Collection.new(query)
|
113
|
+
children.each { |child| parents_children.send(:add, child) }
|
114
|
+
|
115
|
+
if parent_key.get(parent) == parent_values
|
116
|
+
ret = parents_children
|
117
|
+
else
|
118
|
+
association.instance_variable_set(:@children, parents_children)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
ret || child_model.send(finder, *(args.dup << @query.merge(options).merge(child_key.zip(parent_values).to_hash)))
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @api private
|
127
|
+
def get_parent(child, parent = nil)
|
128
|
+
child_value = child_key.get(child)
|
129
|
+
return nil unless child_value.nitems == child_value.size
|
130
|
+
|
131
|
+
with_repository(parent || parent_model) do
|
132
|
+
parent_identity_map = (parent || parent_model).repository.identity_map(parent_model)
|
133
|
+
child_identity_map = child.repository.identity_map(child_model)
|
134
|
+
|
135
|
+
if parent = parent_identity_map[child_value]
|
136
|
+
return parent
|
137
|
+
end
|
138
|
+
|
139
|
+
children = child_identity_map.values | [child]
|
140
|
+
|
141
|
+
bind_values = children.map { |c| child_key.get(c) }.uniq
|
142
|
+
query_values = bind_values.reject { |k| parent_identity_map[k] }
|
143
|
+
|
144
|
+
bind_values = query_values unless query_values.empty?
|
145
|
+
query = parent_key.zip(bind_values.transpose).to_hash
|
146
|
+
association_accessor = "#{self.name}_association"
|
147
|
+
|
148
|
+
collection = parent_model.send(:all, query)
|
149
|
+
unless collection.empty?
|
150
|
+
collection.send(:lazy_load)
|
151
|
+
children.each do |c|
|
152
|
+
c.send(association_accessor).instance_variable_set(:@parent, collection.get(*child_key.get(c)))
|
153
|
+
end
|
154
|
+
child.send(association_accessor).instance_variable_get(:@parent)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @api private
|
160
|
+
def with_repository(object = nil, &block)
|
161
|
+
other_model = object.model == child_model ? parent_model : child_model if object.respond_to?(:model)
|
162
|
+
other_model = object == child_model ? parent_model : child_model if object.kind_of?(DataMapper::Resource)
|
163
|
+
|
164
|
+
if other_model && other_model.repository == object.repository && object.repository.name != @repository_name
|
165
|
+
object.repository.scope(&block)
|
166
|
+
else
|
167
|
+
repository(@repository_name, &block)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# @api private
|
172
|
+
def attach_parent(child, parent)
|
173
|
+
child_key.set(child, parent && parent_key.get(parent))
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
|
178
|
+
# +child_model_name and child_properties refers to the FK, parent_model_name
|
179
|
+
# and parent_properties refer to the PK. For more information:
|
180
|
+
# http://edocs.bea.com/kodo/docs41/full/html/jdo_overview_mapping_join.html
|
181
|
+
# I wash my hands of it!
|
182
|
+
def initialize(name, repository_name, child_model, parent_model, options = {})
|
183
|
+
assert_kind_of 'name', name, Symbol
|
184
|
+
assert_kind_of 'repository_name', repository_name, Symbol
|
185
|
+
assert_kind_of 'child_model', child_model, String, Class
|
186
|
+
assert_kind_of 'parent_model', parent_model, String, Class
|
187
|
+
|
188
|
+
if child_properties = options[:child_key]
|
189
|
+
assert_kind_of 'options[:child_key]', child_properties, Array
|
190
|
+
end
|
191
|
+
|
192
|
+
if parent_properties = options[:parent_key]
|
193
|
+
assert_kind_of 'options[:parent_key]', parent_properties, Array
|
194
|
+
end
|
195
|
+
|
196
|
+
@name = name
|
197
|
+
@repository_name = repository_name
|
198
|
+
@child_model = child_model
|
199
|
+
@child_properties = child_properties # may be nil
|
200
|
+
@query = options.reject { |k,v| OPTIONS.include?(k) }
|
201
|
+
@parent_model = parent_model
|
202
|
+
@parent_properties = parent_properties # may be nil
|
203
|
+
@options = options
|
204
|
+
|
205
|
+
# attempt to load the child_key if the parent and child model constants are defined
|
206
|
+
if model_defined?(@child_model) && model_defined?(@parent_model)
|
207
|
+
child_key
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# @api private
|
212
|
+
def model_defined?(model)
|
213
|
+
# TODO: figure out other ways to see if the model is loaded
|
214
|
+
model.kind_of?(Class)
|
215
|
+
end
|
216
|
+
end # class Relationship
|
217
|
+
end # module Associations
|
218
|
+
end # module DataMapper
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Associations
|
3
|
+
class RelationshipChain < Relationship
|
4
|
+
OPTIONS = [
|
5
|
+
:repository_name, :near_relationship_name, :remote_relationship_name,
|
6
|
+
:child_model, :parent_model, :parent_key, :child_key,
|
7
|
+
:min, :max
|
8
|
+
]
|
9
|
+
|
10
|
+
undef_method :get_parent
|
11
|
+
undef_method :attach_parent
|
12
|
+
|
13
|
+
# @api private
|
14
|
+
def child_model
|
15
|
+
near_relationship.child_model
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def get_children(parent, options = {}, finder = :all, *args)
|
20
|
+
query = @query.merge(options).merge(child_key.to_query(parent_key.get(parent)))
|
21
|
+
|
22
|
+
query[:links] = links
|
23
|
+
query[:unique] = true
|
24
|
+
|
25
|
+
with_repository(parent) do
|
26
|
+
results = grandchild_model.send(finder, *(args << query))
|
27
|
+
# FIXME: remove the need for the uniq.freeze
|
28
|
+
finder == :all ? (@mutable ? results : results.freeze) : results
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @api private
|
35
|
+
def initialize(options)
|
36
|
+
if (missing_options = OPTIONS - [ :min, :max ] - options.keys ).any?
|
37
|
+
raise ArgumentError, "The options #{missing_options * ', '} are required", caller
|
38
|
+
end
|
39
|
+
|
40
|
+
@repository_name = options.fetch(:repository_name)
|
41
|
+
@near_relationship_name = options.fetch(:near_relationship_name)
|
42
|
+
@remote_relationship_name = options.fetch(:remote_relationship_name)
|
43
|
+
@child_model = options.fetch(:child_model)
|
44
|
+
@parent_model = options.fetch(:parent_model)
|
45
|
+
@parent_properties = options.fetch(:parent_key)
|
46
|
+
@child_properties = options.fetch(:child_key)
|
47
|
+
@mutable = options.delete(:mutable) || false
|
48
|
+
|
49
|
+
@name = near_relationship.name
|
50
|
+
@query = options.reject{ |key,val| OPTIONS.include?(key) }
|
51
|
+
@extra_links = []
|
52
|
+
@options = options
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def near_relationship
|
57
|
+
parent_model.relationships[@near_relationship_name]
|
58
|
+
end
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
def links
|
62
|
+
if remote_relationship.kind_of?(RelationshipChain)
|
63
|
+
remote_relationship.instance_eval { links } + [remote_relationship.instance_eval { near_relationship } ]
|
64
|
+
else
|
65
|
+
[ remote_relationship ]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# @api private
|
70
|
+
def remote_relationship
|
71
|
+
near_relationship.child_model.relationships[@remote_relationship_name] ||
|
72
|
+
near_relationship.child_model.relationships[@remote_relationship_name.to_s.singularize.to_sym]
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
def grandchild_model
|
77
|
+
Class === @child_model ? @child_model : (Class === @parent_model ? @parent_model.find_const(@child_model) : Object.find_const(@child_model))
|
78
|
+
end
|
79
|
+
end # class Relationship
|
80
|
+
end # module Associations
|
81
|
+
end # module DataMapper
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# TODO: move to dm-more/dm-migrations
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
class AutoMigrator
|
5
|
+
##
|
6
|
+
# Destructively automigrates the data-store to match the model.
|
7
|
+
# First migrates all models down and then up.
|
8
|
+
# REPEAT: THIS IS DESTRUCTIVE
|
9
|
+
#
|
10
|
+
# @param Symbol repository_name the repository to be migrated
|
11
|
+
def self.auto_migrate(repository_name = nil, *descendants)
|
12
|
+
auto_migrate_down(repository_name, *descendants)
|
13
|
+
auto_migrate_up(repository_name, *descendants)
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Destructively automigrates the data-store down
|
18
|
+
# REPEAT: THIS IS DESTRUCTIVE
|
19
|
+
#
|
20
|
+
# @param Symbol repository_name the repository to be migrated
|
21
|
+
# @calls DataMapper::Resource#auto_migrate_down!
|
22
|
+
# @api private
|
23
|
+
def self.auto_migrate_down(repository_name = nil, *descendants)
|
24
|
+
descendants = DataMapper::Resource.descendants.to_a if descendants.empty?
|
25
|
+
descendants.reverse.each do |model|
|
26
|
+
model.auto_migrate_down!(repository_name)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Automigrates the data-store up
|
32
|
+
#
|
33
|
+
# @param Symbol repository_name the repository to be migrated
|
34
|
+
# @calls DataMapper::Resource#auto_migrate_up!
|
35
|
+
# @api private
|
36
|
+
def self.auto_migrate_up(repository_name = nil, *descendants)
|
37
|
+
descendants = DataMapper::Resource.descendants.to_a if descendants.empty?
|
38
|
+
descendants.each do |model|
|
39
|
+
model.auto_migrate_up!(repository_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Safely migrates the data-store to match the model
|
45
|
+
# preserving data already in the data-store
|
46
|
+
#
|
47
|
+
# @param Symbol repository_name the repository to be migrated
|
48
|
+
# @calls DataMapper::Resource#auto_upgrade!
|
49
|
+
def self.auto_upgrade(repository_name = nil)
|
50
|
+
DataMapper::Resource.descendants.each do |model|
|
51
|
+
model.auto_upgrade!(repository_name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end # class AutoMigrator
|
55
|
+
|
56
|
+
module AutoMigrations
|
57
|
+
##
|
58
|
+
# Destructively automigrates the data-store to match the model
|
59
|
+
# REPEAT: THIS IS DESTRUCTIVE
|
60
|
+
#
|
61
|
+
# @param Symbol repository_name the repository to be migrated
|
62
|
+
def auto_migrate!(repository_name = self.repository_name)
|
63
|
+
auto_migrate_down!(repository_name)
|
64
|
+
auto_migrate_up!(repository_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Destructively migrates the data-store down, which basically
|
69
|
+
# deletes all the models.
|
70
|
+
# REPEAT: THIS IS DESTRUCTIVE
|
71
|
+
#
|
72
|
+
# @param Symbol repository_name the repository to be migrated
|
73
|
+
# @api private
|
74
|
+
def auto_migrate_down!(repository_name = self.repository_name)
|
75
|
+
# repository_name ||= default_repository_name
|
76
|
+
if self.superclass != Object
|
77
|
+
self.superclass.auto_migrate!(repository_name)
|
78
|
+
else
|
79
|
+
repository(repository_name) do |r|
|
80
|
+
r.adapter.destroy_model_storage(r, self)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# Auto migrates the data-store to match the model
|
87
|
+
#
|
88
|
+
# @param Symbol repository_name the repository to be migrated
|
89
|
+
# @api private
|
90
|
+
def auto_migrate_up!(repository_name = self.repository_name)
|
91
|
+
if self.superclass != Object
|
92
|
+
self.superclass.auto_migrate!(repository_name)
|
93
|
+
else
|
94
|
+
repository(repository_name) do |r|
|
95
|
+
r.adapter.create_model_storage(r, self)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# Safely migrates the data-store to match the model
|
102
|
+
# preserving data already in the data-store
|
103
|
+
#
|
104
|
+
# @param Symbol repository_name the repository to be migrated
|
105
|
+
def auto_upgrade!(repository_name = self.repository_name)
|
106
|
+
repository(repository_name) do |r|
|
107
|
+
r.adapter.upgrade_model_storage(r, self)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Model.send(:include, self)
|
112
|
+
end # module AutoMigrations
|
113
|
+
end # module DataMapper
|