Can you please tell me how Data Mapper's auto upgrade thing works?
For example:
include 'data_mapper'
DataMapper.setup :default, "sqlite://#{Dir.pwd}/base.db"
class User
include DataMapper::Resource
property :id, Serial
property :name, String
end
DataMapper.auto_upgrade!
Here, how does that Data Mapper's auto upgrade understand that they have to create a Data Base
First of all, the User class is not a database, it is a model, which is linked to a table in a database.
When you include DataMapper::Resource
, it will automatically call extend DataMapper::Model
:
# https://github.com/datamapper/dm-core/blob/master/lib/dm-core/resource.rb#L55-L58
module DataMapper
module Resource
# ...
def self.included(model)
model.extend Model
super
end
# ...
end
end
this call to extend is intercepted by another hook in DataMapper::Model
, which keeps track of the module's descendants:
# https://github.com/datamapper/dm-core/blob/master/lib/dm-core/model.rb#L209-L223
module DataMapper
module Model
# ...
def self.descendants
@descendants ||= DescendantSet.new
end
# ...
def self.extended(descendant)
descendants << descendant
# ...
super
end
# ...
end
end
later, DataMapper can find all models via DataMapper::Model.descendants
:
# https://github.com/datamapper/dm-migrations/blob/8bfcec08286a12ceee1bc3e5a01da3b5b7d4a74d/lib/dm-migrations/auto_migration.rb#L43-L50
module DataMapper
module Migrations
module SingletonMethods
# ...
def auto_upgrade!(repository_name = nil)
repository_execute(:auto_upgrade!, repository_name)
end
# ...
def repository_execute(method, repository_name)
models = DataMapper::Model.descendants
models = models.select { |m| m.default_repository_name == repository_name } if repository_name
models.each do |model|
model.send(method, model.default_repository_name)
end
end
# ...
end
end
end
Here's a minimal example:
module Model
def self.descendants
@descendants ||= []
end
def self.extended(base)
descendants << base
super
end
end
module Resource
def self.included(base)
base.extend(Model)
end
end
class Car
include Resource
end
class Bike
include Resource
end
class Train
include Resource
end
Model.descendants
#=> [Car, Bike, Train]