module ViewModel::MigratableView

Public Instance Methods

inherited(base) click to toggle source
Calls superclass method
# File lib/view_model/migratable_view.rb, line 13
def inherited(base)
  super
  base.initialize_as_migratable_view
end
initialize_as_migratable_view() click to toggle source
# File lib/view_model/migratable_view.rb, line 18
def initialize_as_migratable_view
  @migrations_lock   = Monitor.new
  @migration_classes = {}
  @migration_paths   = {}
  @realized_migration_paths = true
end
migrates(from:, to:, &block) click to toggle source

Define a migration on this viewmodel

# File lib/view_model/migratable_view.rb, line 40
def migrates(from:, to:, &block)
  @migrations_lock.synchronize do
    builder = ViewModel::Migration::Builder.new
    builder.instance_exec(&block)
    @migration_classes[[from, to]] = builder.build!
    @realized_migration_paths = false
  end
end
migration_path(from:, to:) click to toggle source
# File lib/view_model/migratable_view.rb, line 25
def migration_path(from:, to:)
  @migrations_lock.synchronize do
    realize_paths! unless @realized_migration_paths

    migrations = @migration_paths.fetch([from, to]) do
      raise ViewModel::Migration::NoPathError.new(self, from, to)
    end

    migrations
  end
end
realize_paths!() click to toggle source

Internal: find and record possible paths to the current schema version.

# File lib/view_model/migratable_view.rb, line 50
def realize_paths!
  @migration_paths.clear

  graph = RGL::DirectedAdjacencyGraph.new

  # Add a vertex for the current version, in case no edges reach it
  graph.add_vertex(self.schema_version)

  # Add edges backwards, as we care about paths from the latest version
  @migration_classes.each_key do |from, to|
    graph.add_edge(to, from)
  end

  paths = graph.dijkstra_shortest_paths(Hash.new { 1 }, self.schema_version)

  paths.each do |target_version, path|
    next if path.nil? || path.length == 1

    # Store the path forwards rather than backwards
    path_migration_classes = path.reverse.each_cons(2).map do |from, to|
      @migration_classes.fetch([from, to])
    end

    key = [target_version, schema_version]

    @migration_paths[key] = path_migration_classes.map(&:new)
  end

  @realized_paths = true
end