Class: Marty::BaseRule

Inherits:
Base show all
Defined in:
app/models/marty/base_rule.rb

Direct Known Subclasses

DeloreanRule

Constant Summary

Constants inherited from ActiveRecord::Base

ActiveRecord::Base::COUNT_SIG, ActiveRecord::Base::DISTINCT_SIG, ActiveRecord::Base::FIND_BY_SIG, ActiveRecord::Base::FIRST_SIG, ActiveRecord::Base::GROUP_SIG, ActiveRecord::Base::JOINS_SIG, ActiveRecord::Base::LAST_SIG, ActiveRecord::Base::LIMIT_SIG, ActiveRecord::Base::MCFLY_PT_SIG, ActiveRecord::Base::NOT_SIG, ActiveRecord::Base::ORDER_SIG, ActiveRecord::Base::PLUCK_SIG, ActiveRecord::Base::SELECT_SIG, ActiveRecord::Base::WHERE_SIG

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

get_final_attrs, get_struct_attrs, make_hash, make_openstruct, mcfly_pt

Methods inherited from ActiveRecord::Base

joins, old_joins

Class Method Details

.get_matches_(pt, attrs, params) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'app/models/marty/base_rule.rb', line 93

def self.get_matches_(pt, attrs, params)

  q = select("DISTINCT ON (name) *").where(attrs)

  params.each do |k, vraw|
    h = guard_info
    use_k = (h[k] && k) ||
            (h[k+"_array"] && k+"_array") ||
            (h[k+"_range"] && k+"_range")
    next unless use_k
    multi, type = h[use_k].values_at(:multi, :type)
    filts = [vraw].flatten.map do |v|
      qstr = get_subq('simple_guards', use_k, multi, type, v)
    end.join(" OR ")
    isn = "simple_guards->'#{use_k}' IS NULL OR"

    q = q.where("(#{isn} #{filts})")
  end
  #print q.to_sql
  q.order(:name)
end

.get_subq(field, subfield, multi, type, vraw) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
# File 'app/models/marty/base_rule.rb', line 80

def self.get_subq(field, subfield, multi, type, vraw)
  arrow = multi || ![:range, :string, :date, :datetime].include?(type) ?
            "->" : "->>"
  op = multi || type == :range ? "@>" : "="
  value0 = [:string, :date, :datetime].include?(type) ?
             ActiveRecord::Base.connection.quote(vraw) :
             type == :range ? vraw.to_f :
               "'#{vraw}'::jsonb"
  value = multi ? %Q('["%s"]') % value0[1..-2] : value0
  fieldcast = type == :range ? "::numrange" : ''
  "(#{field}#{arrow}'#{subfield}')#{fieldcast} #{op} #{value}"
end

.guard_infoObject



5
6
7
# File 'app/models/marty/base_rule.rb', line 5

def self.guard_info
  {}
end

Instance Method Details

#check(name, h) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'app/models/marty/base_rule.rb', line 23

def check(name, h)
  multi, type, enum, values, req = h.values_at(:multi, :type, :enum, :values,
                                               :required)
  ns = "'#{name}'"
  expmulti = multi ? 'multi' : 'single'
  errtype = :guards
  v = simple_guards[name]
  type ||= :string
  return errors[errtype] << "- Required field #{ns} is missing" if
    v.blank? && req
  return if v.blank?
  gotmulti = v.is_a?(Array) ? 'multi' : 'single'
  return errors[errtype] << "- Wrong arity for #{ns} (expected #{expmulti} "\
                            "got #{gotmulti})" if expmulti != gotmulti
  vs = [v].flatten.to_set
  vs.each do |vv|
    return errors[errtype] << "- Wrong type for #{ns}" unless
      gettypes(vv).member?(type)
  end
  return unless enum || values
  vals = enum && enum::VALUES || values.to_set
  bad = (vs - vals)
  p = bad.count > 1 ? 's' : ''
  return errors[errtype] <<
         %Q(- Bad value#{p} '#{bad.to_a.join("', '")}' for #{ns}) if bad.present?
end

#chkrange(v) ⇒ Object



9
10
11
# File 'app/models/marty/base_rule.rb', line 9

def chkrange(v)
  v.match(/\A(\[|\()([0-9\.-]*),([0-9\.-]*)(\]|\))\z/)
end

#gettypes(v) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
# File 'app/models/marty/base_rule.rb', line 12

def gettypes(v)
  types = []
  types << :string if v.is_a?(String)
  types += [:int, :integer] if Integer(v) rescue nil
  types << :float if Float(v) rescue nil
  types << :date if Date.parse(v) rescue nil
  types << :datetime if DateTime.parse(v) rescue nil
  types << :range if chkrange(v) rescue nil
  types << :boolean if [true, false, 'True', 'False'].include?(v)
  types
end

#validateObject



49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'app/models/marty/base_rule.rb', line 49

def validate
  self.class.guard_info.each { |name, h| check(name, h) }
  grids.each do |vn, gn|
    return errors[:grids] << "- Bad grid name '#{gn}' for '#{vn}'" unless
      gn.blank? || Marty::DataGrid.lookup('infinity', gn)
  end
  cg_err = computed_guards.delete("~~ERROR~~")
  errors[:computed] <<
    "- Error in rule '#{name}' field 'computed_guards': #{cg_err.capitalize}" if cg_err
  res_err = results.delete("~~ERROR~~")
  errors[:computed] <<
    "- Error in rule '#{name}' field 'results': #{res_err.capitalize}" if res_err
end