Class: ActionBlocks::FilterAdapter

Inherits:
Object
  • Object
show all
Defined in:
lib/action_blocks/data_engine/filter_adapter.rb

Overview

Data Engine

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(engine:, filter_reqs:, user:) ⇒ FilterAdapter

Returns a new instance of FilterAdapter.



6
7
8
9
10
11
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 6

def initialize(engine:, filter_reqs:, user:)
  @engine = engine
  @user = user
  @rls_scheme = filter_reqs
  @model_id = @engine.root_klass.to_s.underscore
end

Instance Attribute Details

#engineObject

Returns the value of attribute engine.



4
5
6
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 4

def engine
  @engine
end

#filter_reqsObject

Returns the value of attribute filter_reqs.



4
5
6
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 4

def filter_reqs
  @filter_reqs
end

#userObject

Returns the value of attribute user.



4
5
6
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 4

def user
  @user
end

Instance Method Details

#evaluate(expression) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 41

def evaluate(expression)
  # Convert Symbol to Arel Attribute
  return @arel_attributes[expression] if expression.class == Symbol

  # Convert Proc to it's result
  if expression.class == Proc
    proc_args = {}
    # debug expression.parameters
    if expression.parameters.include?([:keyreq, :user])
      proc_args[:user] = @user
    end
    return expression.call(**proc_args)
  end

  # Convert expression to Arel Predicate
  if expression.class == Array
    fn, *args = expression
    case fn
    when :user
      return @user.send(args[0])
    when :eq
      left, right = args
      return evaluate(left).eq(evaluate(right))
    when :not_eq
      left, right = args
      return evaluate(left).not_eq(evaluate(right))
    when :and
      return args.map {|x| evaluate(x)}.reduce(&:and)
    when :or
      return args.map {|x| evaluate(x)}.reduce(&:or)
    else
      raise "RLS function #{fn.inspect} not recognized"
    end
  end

  return expression
end

#get_arel_attributesObject

Convert all fields to arel nodes while building up needed @engine.joins



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 25

def get_arel_attributes()
  @fields = get_fields(@rls_scheme)
  @arel_attributes = {}
  [@fields].flatten.each do |f|
    f = ActionBlocks.find("field-#{@model_id}-#{f}")
    select_req = f.select_requirements
    if select_req[:type] == :summary
      raise "Summary fields not supported in authorizations"
    end
    field_name = select_req[:field_name]
    node, *rest = select_req[:path]
    @arel_attributes[field_name] = walk_path(@engine.root_klass, node, @engine.root_key, rest)
  end
  return @arel_attributes
end

#get_fields(expression) ⇒ Object

Extract fields from lisp/scheme



14
15
16
17
18
19
20
21
22
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 14

def get_fields(expression)
  if expression.class == Array
    fn, *args = expression
    return [] if fn == :user
    return args.map { |a| get_fields(a) }.flatten.uniq
  end
  return expression if expression.class == Symbol
  return []
end

#processObject



79
80
81
82
83
84
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 79

def process
  if (!@rls_scheme.empty?)
    @arel_attributes = get_arel_attributes()
    @engine.wheres << evaluate(@rls_scheme)
  end
end

#walk_path(klass, node, parent_key, col_path) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/action_blocks/data_engine/filter_adapter.rb', line 86

def walk_path(klass, node, parent_key, col_path)
  key = [parent_key, node].compact.join('_').to_sym
  return node if node.class != Symbol
  return @engine.tables[parent_key][node.to_sym] if col_path.empty?

  # Create Arel Table Alias
  relation = klass.reflections[node.to_s]
  klass = relation.klass
  @engine.tables[key] = klass.arel_table.alias(key) unless @engine.tables[key]
  # Create Join
  fk = relation.join_foreign_key
  pk = relation.join_primary_key
  join_on = @engine.tables[key].create_on(@engine.tables[parent_key][fk].eq(@engine.tables[key][pk]))
  @engine.joins[key] = @engine.tables[parent_key].create_join(@engine.tables[key], join_on, Arel::Nodes::OuterJoin)
  # Recurse
  next_node, *rest = col_path
  return walk_path(klass, next_node, key, rest)
end