Class: Pacer::Filter::PropertyFilter::Filters

Inherits:
Object
  • Object
show all
Defined in:
lib/pacer/filter/property_filter/filters.rb

Direct Known Subclasses

EdgeFilters

Constant Summary collapse

NodeVisitor =
Pacer::Filter::WhereFilter::NodeVisitor

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(graph, filters) ⇒ Filters

Returns a new instance of Filters.



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/pacer/filter/property_filter/filters.rb', line 62

def initialize(graph, filters)
  if graph.is_a? Pacer::Wrappers::ElementWrapper
    # this can happen if the starting route is actually a single element.
    @graph = graph.graph
  else
    @graph = graph
  end
  @properties = []
  @blocks = []
  @extensions = []
  @wrapper = nil
  @route_modules = []
  @non_ext_props = []
  @best_index_value = nil
  add_filters filters, nil
  combine_sets
end

Instance Attribute Details

#best_index_valueObject (readonly)

Returns the value of attribute best_index_value.



39
40
41
# File 'lib/pacer/filter/property_filter/filters.rb', line 39

def best_index_value
  @best_index_value
end

#blocksObject

Returns the value of attribute blocks.



40
41
42
# File 'lib/pacer/filter/property_filter/filters.rb', line 40

def blocks
  @blocks
end

#choose_best_indexObject

Allow Pacer to use index counts to determine which index has the least number elements for the available keys in the query.



46
47
48
# File 'lib/pacer/filter/property_filter/filters.rb', line 46

def choose_best_index
  @choose_best_index
end

#extensionsObject (readonly)

Returns the value of attribute extensions.



39
40
41
# File 'lib/pacer/filter/property_filter/filters.rb', line 39

def extensions
  @extensions
end

#graphObject

Note:

this is not threadsafe if you are reusing predefined routes on multiple graphs.

Set which graph this filter is currently operating on



106
107
108
# File 'lib/pacer/filter/property_filter/filters.rb', line 106

def graph
  @graph
end

#indicesObject

Set which indices are available to be used to determine the best_index.



128
129
130
# File 'lib/pacer/filter/property_filter/filters.rb', line 128

def indices
  @indices
end

#propertiesObject (readonly)

Returns the value of attribute properties.



39
40
41
# File 'lib/pacer/filter/property_filter/filters.rb', line 39

def properties
  @properties
end

#route_modulesObject (readonly)

Returns the value of attribute route_modules.



39
40
41
# File 'lib/pacer/filter/property_filter/filters.rb', line 39

def route_modules
  @route_modules
end

#search_manual_indicesObject

Allow Pacer to use manual indices without explicitly referencing them by name.

Examples:

Explicit manual index:


graph.v(:index_name => { :index_key => value })

Non-explicit index lookup:


graph.v(:index_key => value)


60
61
62
# File 'lib/pacer/filter/property_filter/filters.rb', line 60

def search_manual_indices
  @search_manual_indices
end

#wrapperObject

Returns the value of attribute wrapper.



40
41
42
# File 'lib/pacer/filter/property_filter/filters.rb', line 40

def wrapper
  @wrapper
end

Instance Method Details

#any?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/pacer/filter/property_filter/filters.rb', line 189

def any?
  properties.any? or blocks.any? or route_modules.any? or extensions.any?
end

#best_index(element_type) ⇒ Object



213
214
215
216
217
218
219
220
# File 'lib/pacer/filter/property_filter/filters.rb', line 213

def best_index(element_type)
  result = find_best_index(element_type)
  # the call to find_best_index produces @best_index_value:
  if properties.delete @best_index_value
    @encoded_properties = nil
  end
  result
end

#build_pipeline(route, start_pipe, pipe = nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/pacer/filter/property_filter/filters.rb', line 150

def build_pipeline(route, start_pipe, pipe = nil)
  pipe ||= start_pipe
  if route
    self.graph = route.graph
    route_modules.each do |mod|
      extension_route = mod.route(Pacer::Route.empty(route))
      s, e = extension_route.send :build_pipeline
      s.setStarts(pipe) if pipe
      start_pipe ||= s
      pipe = e
    end
  end
  encoded_properties.each do |key, value|
    case value
    when NodeVisitor::Pipe
      new_pipe = value.build
    when NodeVisitor::Value
      # no op
    else
      new_pipe = PropertyFilterPipe.new(key, Pacer::Pipes::EQUAL, value)
    end
    if new_pipe
      new_pipe.set_starts pipe if pipe
      Pacer.debug_pipes << { :name => key, :start => pipe, :end => new_pipe } if Pacer.debug_pipes
      pipe = new_pipe
      start_pipe ||= pipe
    end
  end
  blocks.each do |block|
    # Will work if route is nil.
    block_pipe = Pacer::Pipes::BlockFilterPipe.new(route, block)
    block_pipe.set_starts pipe if pipe
    Pacer.debug_pipes << { :name => 'block', :start => pipe, :end => block_pipe } if Pacer.debug_pipes
    pipe = block_pipe
    start_pipe ||= pipe
  end
  [start_pipe, pipe]
end

#combine_setsObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/pacer/filter/property_filter/filters.rb', line 80

def combine_sets
  is_set = properties.group_by { |p| p[1].is_a? Set }
  sets = is_set[true] # [["x", Set[]] ...]
  if sets
    is_multi = sets.group_by { |a| a.count > 1 }
    multi = is_multi[true]
    if multi
      multi = multi.group_by { |m| m.first } # {"x": [["x", Set[]], ...]}
      result = multi.map do |multi_set|
        multi_set[1].reduce do |result, pair|
          [result[0], result[1].intersection(pair[1])]
        end
      end
      result = result.concat(is_multi[false]) if is_multi[false]
      result = result.concat(is_set[false]) if is_set[false]
      @properties = result
    end
  end
end

#extensions_only?Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/pacer/filter/property_filter/filters.rb', line 193

def extensions_only?
  properties.none? and blocks.none? and route_modules.none? and (extensions.any? or wrapper)
end

#property_keysObject



120
121
122
# File 'lib/pacer/filter/property_filter/filters.rb', line 120

def property_keys
  properties.map(&:first).uniq
end

#remove_property_keys(keys) ⇒ Object



115
116
117
118
# File 'lib/pacer/filter/property_filter/filters.rb', line 115

def remove_property_keys(keys)
  properties.delete_if { |a| keys.include? a.first }
  non_ext_props.delete_if { |a| keys.include? a.first }
end

#to_predicateObject

Not used for regular filtering, but useful to test an element against a complex set of conditions without having to build a route.

Returns a proc that can be called with an element to test and returns true if the element matches the conditions.



142
143
144
145
146
147
148
# File 'lib/pacer/filter/property_filter/filters.rb', line 142

def to_predicate
  expando, pipe = build_pipeline(nil, com.tinkerpop.pipes.util.iterators.ExpandableIterator.new)
  proc do |e|
    expando.add e
    pipe.next if pipe.hasNext
  end
end

#to_sObject



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/pacer/filter/property_filter/filters.rb', line 197

def to_s
  strings = []
  strings << [wrapper.name] if wrapper
  strings.concat extensions.map { |e| e.name }
  strings.concat((non_ext_props - [@best_index_value]).map { |k, v|
    if v.is_a? Set
      "#{ k } IN (#{ v.sort.map { |s| s.inspect }.join ', ' })"
    else
      "#{ k }==#{ v.inspect }"
    end
  })
  strings.concat blocks.map { '&block' }
  strings.concat route_modules.map { |mod| mod.name }
  strings.join ', '
end

#use_lookup!Object

Check #lookup in extensions, in preerence to #route_conditions for filters to apply.

Designed to allow filters to be defined in extensions that will not be used on every appearance of the extension (too many property filters in a traversal can impose a serious performance penalty. It is expected that lookup filters will only be used for index lookups.



230
231
232
233
234
235
236
237
238
239
# File 'lib/pacer/filter/property_filter/filters.rb', line 230

def use_lookup!
  extensions.each do |ext|
    if ext.respond_to? :lookup
      add_filters ext.lookup(graph), ext
    end
  end
  if wrapper and wrapper.respond_to? :lookup
    add_filters wrapper.lookup(graph), nil
  end
end