Class: Masamune::DataPlan::Engine

Inherits:
Object
  • Object
show all
Includes:
HasEnvironment
Defined in:
lib/masamune/data_plan/engine.rb

Constant Summary collapse

MAX_DEPTH =
10

Instance Method Summary collapse

Methods included from HasEnvironment

#environment, #environment=

Constructor Details

#initializeEngine



33
34
35
36
37
38
39
40
41
# File 'lib/masamune/data_plan/engine.rb', line 33

def initialize
  @target_rules = {}
  @source_rules = {}
  @command_rules = {}
  @targets = Hash.new { |set, rule| set[rule] = Masamune::DataPlan::Set.new(@target_rules[rule]) }
  @sources = Hash.new { |set, rule| set[rule] = Masamune::DataPlan::Set.new(@source_rules[rule]) }
  @set_cache = Hash.new { |cache, level| cache[level] = {} }
  @current_depth = 0
end

Instance Method Details

#add_command_rule(rule, command) ⇒ Object



63
64
65
# File 'lib/masamune/data_plan/engine.rb', line 63

def add_command_rule(rule, command)
  @command_rules[rule] = command
end

#add_source_rule(rule, source_options = {}) ⇒ Object



55
56
57
# File 'lib/masamune/data_plan/engine.rb', line 55

def add_source_rule(rule, source_options = {})
  @source_rules[rule] = Masamune::DataPlan::Rule.new(self, rule, :source, source_options)
end

#add_target_rule(rule, target_options = {}) ⇒ Object



47
48
49
# File 'lib/masamune/data_plan/engine.rb', line 47

def add_target_rule(rule, target_options = {})
  @target_rules[rule] = Masamune::DataPlan::Rule.new(self, rule, :target, target_options)
end

#clear!Object



157
158
159
160
161
# File 'lib/masamune/data_plan/engine.rb', line 157

def clear!
  @set_cache.clear
  filesystem.clear!
  environment.postgres_helper.clear!
end

#constrain_max_depth(rule) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/masamune/data_plan/engine.rb', line 149

def constrain_max_depth(rule)
  @current_depth += 1
  raise "Max depth of #{MAX_DEPTH} exceeded for rule '#{rule}'" if @current_depth > MAX_DEPTH
  yield
ensure
  @current_depth -= 1
end

#execute(rule, options = {}) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/masamune/data_plan/engine.rb', line 134

def execute(rule, options = {})
  return if targets(rule).actionable.empty?

  if options.fetch(:resolve, true)
    constrain_max_depth(rule) do
      sources(rule).group_by { |source| rule_for_target(source.input) }.each do |derived_rule, _sources|
        execute(derived_rule, options) if derived_rule != Masamune::DataPlan::Rule::TERMINAL
      end
    end
  end

  @command_rules[rule].call(self, rule, options)
  clear!
end

#filesystemObject



43
44
45
# File 'lib/masamune/data_plan/engine.rb', line 43

def filesystem
  @filesystem ||= Masamune::CachedFilesystem.new(environment.filesystem)
end

#get_source_rule(rule) ⇒ Object



59
60
61
# File 'lib/masamune/data_plan/engine.rb', line 59

def get_source_rule(rule)
  @source_rules[rule]
end

#get_target_rule(rule) ⇒ Object



51
52
53
# File 'lib/masamune/data_plan/engine.rb', line 51

def get_target_rule(rule)
  @target_rules[rule]
end

#prepare(rule, options = {}) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/masamune/data_plan/engine.rb', line 118

def prepare(rule, options = {})
  @targets[rule].merge options.fetch(:targets, [])
  @sources[rule].merge options.fetch(:sources, [])
  @target_rules[rule].try(:prepare)
  @source_rules[rule].try(:prepare)

  if options.fetch(:resolve, true)
    constrain_max_depth(rule) do
      sources(rule).group_by { |source| rule_for_target(source.input) }.each do |derived_rule, sources|
        prepare(derived_rule, targets: sources.map(&:input)) if derived_rule != Masamune::DataPlan::Rule::TERMINAL
      end
    end
  end
  clear!
end

#rule_for_target(target) ⇒ Object

TODO: use constructed reference instead



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/masamune/data_plan/engine.rb', line 68

def rule_for_target(target)
  target_matches = @target_rules.select { |_rule, matcher| matcher.primary? && matcher.matches?(target) }
  source_matches = @source_rules.select { |_rule, matcher| matcher.matches?(target) }

  if target_matches.empty?
    raise "No rule matches target #{target}" if source_matches.empty?
    Masamune::DataPlan::Rule::TERMINAL
  else
    logger.error("Multiple rules match target #{target}") if target_matches.length > 1
    target_matches.map(&:first).first
  end
end

#sources(rule) ⇒ Object



114
115
116
# File 'lib/masamune/data_plan/engine.rb', line 114

def sources(rule)
  @set_cache[:sources_for_rule][rule] ||= @sources[rule].union(@targets[rule].sources).adjacent
end

#sources_for_target(rule, target) ⇒ Object



100
101
102
103
104
105
106
107
108
# File 'lib/masamune/data_plan/engine.rb', line 100

def sources_for_target(rule, target)
  return Masamune::DataPlan::Set.new(get_source_rule(rule), to_enum(:sources_for_target, rule, target)) unless block_given?
  source_template = @source_rules[rule]
  target_template = @target_rules[rule]
  target_instance = target_template.bind_input(target)
  target_template.generate_via_unify(target_instance, source_template).each do |source|
    yield source
  end
end

#targets(rule) ⇒ Object



110
111
112
# File 'lib/masamune/data_plan/engine.rb', line 110

def targets(rule)
  @set_cache[:targets_for_rule][rule] ||= @targets[rule].union(@sources[rule].targets)
end

#targets_for_date_range(rule, start, stop) ⇒ Object



81
82
83
84
85
86
87
88
# File 'lib/masamune/data_plan/engine.rb', line 81

def targets_for_date_range(rule, start, stop)
  return Masamune::DataPlan::Set.new(get_target_rule(rule), to_enum(:targets_for_date_range, rule, start, stop)) unless block_given?
  target_template = @target_rules[rule]
  return unless target_template
  target_template.generate(start.to_time.utc, stop.to_time.utc).each do |target|
    yield target
  end
end

#targets_for_source(rule, source) ⇒ Object



90
91
92
93
94
95
96
97
98
# File 'lib/masamune/data_plan/engine.rb', line 90

def targets_for_source(rule, source)
  return Masamune::DataPlan::Set.new(get_target_rule(rule), to_enum(:targets_for_source, rule, source)) unless block_given?
  source_template = @source_rules[rule]
  target_template = @target_rules[rule]
  source_instance = source_template.bind_input(source)
  source_template.generate_via_unify(source_instance, target_template).each do |target|
    yield target
  end
end