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.

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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

[View source]

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