pacer 0.9.1.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +8 -0
- data/.document +5 -0
- data/.gitignore +26 -0
- data/.rspec +1 -0
- data/.rvmrc +0 -0
- data/CONTRIBUTORS +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +24 -0
- data/README.md +187 -0
- data/Rakefile +49 -0
- data/autotest/discover.rb +1 -0
- data/bin/autospec +16 -0
- data/bin/autotest +16 -0
- data/bin/rake +16 -0
- data/bin/rcov +16 -0
- data/bin/rspec +16 -0
- data/bin/yard +16 -0
- data/bin/yardoc +16 -0
- data/lib/pacer/blueprints/extensions.rb +77 -0
- data/lib/pacer/blueprints/multi_graph.rb +121 -0
- data/lib/pacer/blueprints/ruby_graph.rb +199 -0
- data/lib/pacer/blueprints/tg.rb +100 -0
- data/lib/pacer/blueprints.rb +4 -0
- data/lib/pacer/core/graph/edges_route.rb +92 -0
- data/lib/pacer/core/graph/element_route.rb +171 -0
- data/lib/pacer/core/graph/graph_index_route.rb +48 -0
- data/lib/pacer/core/graph/graph_route.rb +55 -0
- data/lib/pacer/core/graph/mixed_route.rb +96 -0
- data/lib/pacer/core/graph/vertices_route.rb +220 -0
- data/lib/pacer/core/graph.rb +13 -0
- data/lib/pacer/core/route.rb +502 -0
- data/lib/pacer/core/side_effect.rb +11 -0
- data/lib/pacer/core.rb +8 -0
- data/lib/pacer/exceptions.rb +11 -0
- data/lib/pacer/extensions/block_filter_element.rb +22 -0
- data/lib/pacer/extensions.rb +6 -0
- data/lib/pacer/filter/block_filter.rb +31 -0
- data/lib/pacer/filter/collection_filter.rb +109 -0
- data/lib/pacer/filter/empty_filter.rb +70 -0
- data/lib/pacer/filter/future_filter.rb +68 -0
- data/lib/pacer/filter/index_filter.rb +30 -0
- data/lib/pacer/filter/loop_filter.rb +95 -0
- data/lib/pacer/filter/object_filter.rb +55 -0
- data/lib/pacer/filter/property_filter/edge_filters.rb +93 -0
- data/lib/pacer/filter/property_filter/filters.rb +269 -0
- data/lib/pacer/filter/property_filter.rb +111 -0
- data/lib/pacer/filter/random_filter.rb +13 -0
- data/lib/pacer/filter/range_filter.rb +104 -0
- data/lib/pacer/filter/uniq_filter.rb +12 -0
- data/lib/pacer/filter/where_filter/node_visitor.rb +280 -0
- data/lib/pacer/filter/where_filter.rb +47 -0
- data/lib/pacer/filter.rb +17 -0
- data/lib/pacer/function_resolver.rb +43 -0
- data/lib/pacer/graph/edge_mixin.rb +127 -0
- data/lib/pacer/graph/element_mixin.rb +202 -0
- data/lib/pacer/graph/graph_indices_mixin.rb +93 -0
- data/lib/pacer/graph/graph_mixin.rb +361 -0
- data/lib/pacer/graph/graph_transactions_mixin.rb +207 -0
- data/lib/pacer/graph/index_mixin.rb +30 -0
- data/lib/pacer/graph/vertex_mixin.rb +119 -0
- data/lib/pacer/graph.rb +14 -0
- data/lib/pacer/pipe/blackbox_pipeline.rb +48 -0
- data/lib/pacer/pipe/block_filter_pipe.rb +38 -0
- data/lib/pacer/pipe/collection_filter_pipe.rb +10 -0
- data/lib/pacer/pipe/cross_product_transform_pipe.rb +48 -0
- data/lib/pacer/pipe/enumerable_pipe.rb +30 -0
- data/lib/pacer/pipe/expandable_pipe.rb +63 -0
- data/lib/pacer/pipe/id_collection_filter_pipe.rb +33 -0
- data/lib/pacer/pipe/is_empty_pipe.rb +30 -0
- data/lib/pacer/pipe/is_unique_pipe.rb +61 -0
- data/lib/pacer/pipe/label_collection_filter_pipe.rb +21 -0
- data/lib/pacer/pipe/label_prefix_pipe.rb +21 -0
- data/lib/pacer/pipe/loop_pipe.rb +86 -0
- data/lib/pacer/pipe/map_pipe.rb +36 -0
- data/lib/pacer/pipe/never_pipe.rb +9 -0
- data/lib/pacer/pipe/process_pipe.rb +37 -0
- data/lib/pacer/pipe/property_comparison_pipe.rb +40 -0
- data/lib/pacer/pipe/ruby_pipe.rb +25 -0
- data/lib/pacer/pipe/simple_visitor_pipe.rb +43 -0
- data/lib/pacer/pipe/stream_sort_pipe.rb +84 -0
- data/lib/pacer/pipe/stream_uniq_pipe.rb +33 -0
- data/lib/pacer/pipe/type_filter_pipe.rb +22 -0
- data/lib/pacer/pipe/unary_transform_pipe.rb +59 -0
- data/lib/pacer/pipe/variable_store_iterator_wrapper.rb +26 -0
- data/lib/pacer/pipe/visitor_pipe.rb +67 -0
- data/lib/pacer/pipes.rb +61 -0
- data/lib/pacer/route/mixin/bulk_operations.rb +52 -0
- data/lib/pacer/route/mixin/route_operations.rb +107 -0
- data/lib/pacer/route/mixin/variable_route_module.rb +26 -0
- data/lib/pacer/route/mixins.rb +3 -0
- data/lib/pacer/route.rb +228 -0
- data/lib/pacer/routes.rb +6 -0
- data/lib/pacer/side_effect/aggregate.rb +31 -0
- data/lib/pacer/side_effect/counted.rb +30 -0
- data/lib/pacer/side_effect/group_count.rb +44 -0
- data/lib/pacer/side_effect/is_unique.rb +32 -0
- data/lib/pacer/side_effect/section.rb +25 -0
- data/lib/pacer/side_effect/visitor.rb +37 -0
- data/lib/pacer/side_effect.rb +11 -0
- data/lib/pacer/support/array_list.rb +28 -0
- data/lib/pacer/support/enumerable.rb +100 -0
- data/lib/pacer/support/hash.rb +9 -0
- data/lib/pacer/support/iterator_mixins.rb +110 -0
- data/lib/pacer/support/native_exception.rb +22 -0
- data/lib/pacer/support/proc.rb +16 -0
- data/lib/pacer/support.rb +10 -0
- data/lib/pacer/transform/cap.rb +50 -0
- data/lib/pacer/transform/gather.rb +9 -0
- data/lib/pacer/transform/has_count_cap.rb +41 -0
- data/lib/pacer/transform/join.rb +181 -0
- data/lib/pacer/transform/map.rb +23 -0
- data/lib/pacer/transform/path.rb +50 -0
- data/lib/pacer/transform/process.rb +23 -0
- data/lib/pacer/transform/scatter.rb +23 -0
- data/lib/pacer/transform/sort_section.rb +103 -0
- data/lib/pacer/transform/stream_sort.rb +21 -0
- data/lib/pacer/transform/stream_uniq.rb +21 -0
- data/lib/pacer/transform.rb +16 -0
- data/lib/pacer/utils/graph_analysis.rb +112 -0
- data/lib/pacer/utils/trie.rb +93 -0
- data/lib/pacer/utils/tsort.rb +65 -0
- data/lib/pacer/utils/y_files.rb +127 -0
- data/lib/pacer/utils.rb +10 -0
- data/lib/pacer/version.rb +13 -0
- data/lib/pacer/wrappers/edge_wrapper.rb +51 -0
- data/lib/pacer/wrappers/element_wrapper.rb +78 -0
- data/lib/pacer/wrappers/new_element.rb +106 -0
- data/lib/pacer/wrappers/vertex_wrapper.rb +51 -0
- data/lib/pacer/wrappers.rb +19 -0
- data/lib/pacer-0.9.1.1-standalone.jar +0 -0
- data/lib/pacer.rb +290 -0
- data/pacer.gemspec +30 -0
- data/pom/standalone.xml +22 -0
- data/pom.xml +124 -0
- data/samples/grateful-dead.xml +26380 -0
- data/samples/grateful_dead.rb +63 -0
- data/samples/profile.rb +15 -0
- data/spec/data/grateful-dead.xml +26380 -0
- data/spec/data/pacer.graphml +319 -0
- data/spec/pacer/blueprints/dex_spec.rb +172 -0
- data/spec/pacer/blueprints/neo4j_spec.rb +177 -0
- data/spec/pacer/blueprints/tg_spec.rb +128 -0
- data/spec/pacer/core/graph/edges_route_spec.rb +52 -0
- data/spec/pacer/core/graph/element_route_spec.rb +46 -0
- data/spec/pacer/core/graph/graph_route_spec.rb +94 -0
- data/spec/pacer/core/graph/vertices_route_spec.rb +169 -0
- data/spec/pacer/core/route_spec.rb +197 -0
- data/spec/pacer/filter/collection_filter_spec.rb +19 -0
- data/spec/pacer/filter/empty_filter_spec.rb +29 -0
- data/spec/pacer/filter/future_filter_spec.rb +97 -0
- data/spec/pacer/filter/loop_filter_spec.rb +31 -0
- data/spec/pacer/filter/property_filter_spec.rb +111 -0
- data/spec/pacer/filter/random_filter_spec.rb +17 -0
- data/spec/pacer/filter/uniq_filter_spec.rb +18 -0
- data/spec/pacer/filter/where_filter_spec.rb +93 -0
- data/spec/pacer/graph/edge_mixin_spec.rb +116 -0
- data/spec/pacer/graph/element_mixin_spec.rb +297 -0
- data/spec/pacer/graph/graph_mixin_spec.rb +538 -0
- data/spec/pacer/graph/index_mixin_spec.rb +0 -0
- data/spec/pacer/graph/vertex_mixin_spec.rb +192 -0
- data/spec/pacer/pipe/block_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/labels_filter_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/ruby_pipe_spec.rb +0 -0
- data/spec/pacer/pipe/type_filter_pipe_spec.rb +0 -0
- data/spec/pacer/route/mixin/base_spec.rb +419 -0
- data/spec/pacer/route/mixin/bulk_operations_spec.rb +30 -0
- data/spec/pacer/route/mixin/route_operations_spec.rb +127 -0
- data/spec/pacer/support/array_list_spec.rb +0 -0
- data/spec/pacer/support/enumerable_spec.rb +115 -0
- data/spec/pacer/transform/join_spec.rb +138 -0
- data/spec/pacer/transform/path_spec.rb +54 -0
- data/spec/pacer/utils/tsort_spec.rb +89 -0
- data/spec/pacer/wrapper/edge_wrapper_spec.rb +33 -0
- data/spec/pacer/wrapper/element_wrapper_spec.rb +169 -0
- data/spec/pacer/wrapper/vertex_wrapper_spec.rb +33 -0
- data/spec/pacer_spec.rb +0 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/support/contexts.rb +14 -0
- data/spec/support/graph_runner.rb +142 -0
- data/spec/support/matchers.rb +19 -0
- data/spec/support/use_transactions.rb +31 -0
- data/spec/tackle/simple_mixin.rb +21 -0
- data/spec/tackle/tinkerpop_graph_mixins.rb +60 -0
- metadata +364 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
class Route
|
|
3
|
+
class << self
|
|
4
|
+
# This method is useful for creating sideline routes that branch
|
|
5
|
+
# off of the current route.
|
|
6
|
+
#
|
|
7
|
+
# It creates a new route without any source based on the type,
|
|
8
|
+
# filters, function and extensions of the given route. The main
|
|
9
|
+
# thing about the returned route is that the pipeline that is
|
|
10
|
+
# built from it will not include any of the pipes that make up
|
|
11
|
+
# the route it's based on.
|
|
12
|
+
#
|
|
13
|
+
# @param [Route] back the route the new route is based on.
|
|
14
|
+
# @return [Route]
|
|
15
|
+
def empty(back)
|
|
16
|
+
Pacer::Route.new :filter => :empty, :back => back
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def block_branch(back, block, branch_start = nil)
|
|
20
|
+
if block.arity == 0
|
|
21
|
+
route = block.call rescue nil
|
|
22
|
+
else
|
|
23
|
+
unless branch_start
|
|
24
|
+
if back.is_a? Pacer::Graph
|
|
25
|
+
branch_start = back
|
|
26
|
+
else
|
|
27
|
+
branch_start = Pacer::Route.empty(back)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
route = block.call(branch_start) rescue nil
|
|
31
|
+
end
|
|
32
|
+
if route == branch_start
|
|
33
|
+
identity_branch(back).route
|
|
34
|
+
elsif route.is_a? Pacer::Route
|
|
35
|
+
route.route
|
|
36
|
+
else
|
|
37
|
+
empty(back).map(&block).route
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def identity_branch(back)
|
|
42
|
+
Pacer::Route.empty(back).chain_route(:pipe_class => Pacer::Pipes::IdentityPipe,
|
|
43
|
+
:route_name => '@').route
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
module Filter
|
|
51
|
+
module EmptyFilter
|
|
52
|
+
protected
|
|
53
|
+
|
|
54
|
+
def after_initialize
|
|
55
|
+
@back = @source = nil
|
|
56
|
+
super
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def build_pipeline
|
|
60
|
+
nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def inspect_class_name
|
|
64
|
+
s = "#{element_type.to_s.scan(/Elem|Obj|V|E/).last}"
|
|
65
|
+
s = "#{s} #{ @info }" if @info
|
|
66
|
+
s
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Routes
|
|
3
|
+
module RouteOperations
|
|
4
|
+
def lookahead(opts = {}, &block)
|
|
5
|
+
chain_route({ :filter => :future, :block => block }.merge(opts))
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def neg_lookahead(opts = {}, &block)
|
|
9
|
+
chain_route({ :filter => :future, :neg_block => block }.merge(opts))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Filter
|
|
15
|
+
module FutureFilter
|
|
16
|
+
import com.tinkerpop.pipes.filter.FutureFilterPipe
|
|
17
|
+
|
|
18
|
+
attr_accessor :min, :max
|
|
19
|
+
|
|
20
|
+
def block=(block)
|
|
21
|
+
@future_filter = [block, true]
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def neg_block=(block)
|
|
25
|
+
@future_filter = [block, false]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
|
|
30
|
+
def after_initialize
|
|
31
|
+
@future_filter = nil unless defined? @future_filter
|
|
32
|
+
@route = nil unless defined? @route
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def attach_pipe(end_pipe)
|
|
37
|
+
pipe = FutureFilterPipe.new(lookahead_pipe)
|
|
38
|
+
pipe.set_starts(end_pipe) if end_pipe
|
|
39
|
+
pipe
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def lookahead_route
|
|
43
|
+
if @future_filter
|
|
44
|
+
block, has_elements = @future_filter
|
|
45
|
+
@future_filter = nil
|
|
46
|
+
route = block.call(Pacer::Route.empty(self))
|
|
47
|
+
if min or max
|
|
48
|
+
route = route.has_count_route(:min => min, :max => max).is(true)
|
|
49
|
+
end
|
|
50
|
+
unless has_elements
|
|
51
|
+
route = route.chain_route(:element_type => :object, :pipe_class => Pacer::Pipes::IsEmptyPipe, :route_name => 'negate')
|
|
52
|
+
end
|
|
53
|
+
@route = route
|
|
54
|
+
elsif @route
|
|
55
|
+
@route
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def lookahead_pipe
|
|
60
|
+
Pacer::Route.pipeline(lookahead_route)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def inspect_string
|
|
64
|
+
"#{ inspect_class_name }(#{ lookahead_route.inspect })"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Filter
|
|
3
|
+
module IndexFilter
|
|
4
|
+
attr_accessor :index, :key, :value
|
|
5
|
+
|
|
6
|
+
def count
|
|
7
|
+
if @index and @key and @value
|
|
8
|
+
if @index.respond_to? :count
|
|
9
|
+
@index.count(@key, graph.encode_property(@value))
|
|
10
|
+
else
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
def source_iterator
|
|
21
|
+
src = index.get(key, graph.encode_property(value)) || java.util.ArrayList.new
|
|
22
|
+
src.iterator
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def inspect_string
|
|
26
|
+
"#{ inspect_class_name }(#{ key }: #{value.inspect})"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Core
|
|
3
|
+
module Route
|
|
4
|
+
def loop(&block)
|
|
5
|
+
chain_route :filter => :loop, :looping_route => block
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Apply the given path fragment multiple times in succession. If a Range
|
|
9
|
+
# or Array of numbers is given, the results are a combination of the
|
|
10
|
+
# results from all of the specified repetition levels. That is useful if
|
|
11
|
+
# a pattern may be nested to varying depths.
|
|
12
|
+
def repeat(arg, &block)
|
|
13
|
+
case arg
|
|
14
|
+
when Fixnum
|
|
15
|
+
range = arg..arg
|
|
16
|
+
arg.to_enum(:times).inject(self) do |route_end, count|
|
|
17
|
+
yield route_end
|
|
18
|
+
end
|
|
19
|
+
when Range
|
|
20
|
+
if arg.exclude_end?
|
|
21
|
+
range = arg.begin..(arg.end - 1)
|
|
22
|
+
else
|
|
23
|
+
range = arg
|
|
24
|
+
end
|
|
25
|
+
r = self.loop(&block).while do |e, depth, p|
|
|
26
|
+
if depth < range.begin
|
|
27
|
+
:loop
|
|
28
|
+
elsif depth < range.end
|
|
29
|
+
:loop_and_emit
|
|
30
|
+
elsif depth == range.end
|
|
31
|
+
:emit
|
|
32
|
+
else
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
r.while_description = "repeat #{ arg.inspect }"
|
|
37
|
+
r
|
|
38
|
+
else
|
|
39
|
+
raise "Invalid repeat range"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
module ElementMixin
|
|
46
|
+
def loop(&block)
|
|
47
|
+
chain_route :filter => :loop, :looping_route => block
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
module Filter
|
|
52
|
+
module LoopFilter
|
|
53
|
+
attr_reader :looping_route
|
|
54
|
+
attr_accessor :while_description
|
|
55
|
+
|
|
56
|
+
def looping_route=(route)
|
|
57
|
+
if route.is_a? Proc
|
|
58
|
+
@looping_route = Pacer::Route.block_branch(self, route)
|
|
59
|
+
else
|
|
60
|
+
@looping_route = route
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def while(yield_paths = false, &block)
|
|
65
|
+
@yield_paths = yield_paths
|
|
66
|
+
@control_block = block
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
protected
|
|
71
|
+
|
|
72
|
+
def attach_pipe(end_pipe)
|
|
73
|
+
unless @control_block
|
|
74
|
+
raise 'No loop control block specified. Use either #while or #until after #loop.'
|
|
75
|
+
end
|
|
76
|
+
pipe = Pacer::Pipes::LoopPipe.new(graph, looping_pipe, @control_block)
|
|
77
|
+
pipe.setStarts(end_pipe) if end_pipe
|
|
78
|
+
pipe
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def looping_pipe
|
|
82
|
+
Pacer::Route.pipeline(looping_route)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def inspect_string
|
|
86
|
+
s = "#{ inspect_class_name }(#{ @looping_route.inspect })"
|
|
87
|
+
if while_description
|
|
88
|
+
"#{ s }(#{ while_description })"
|
|
89
|
+
else
|
|
90
|
+
s
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Routes
|
|
3
|
+
module RouteOperations
|
|
4
|
+
def is(value)
|
|
5
|
+
if value.nil? and graph and defined? Pacer::DexGraph and graph.is_a? Pacer::DexGraph
|
|
6
|
+
# NOTE: This is a workaround for https://github.com/tinkerpop/blueprints/issues/178
|
|
7
|
+
only(value)
|
|
8
|
+
else
|
|
9
|
+
if value.is_a? Symbol
|
|
10
|
+
chain_route :filter => :property, :block => proc { |v| v.vars[value] == v }
|
|
11
|
+
else
|
|
12
|
+
chain_route({ :filter => :object, :value => value })
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def is_not(value)
|
|
18
|
+
if value.nil? and graph and defined? Pacer::DexGraph and graph.is_a? Pacer::DexGraph
|
|
19
|
+
# NOTE: This is a workaround for https://github.com/tinkerpop/blueprints/issues/178
|
|
20
|
+
except(value)
|
|
21
|
+
else
|
|
22
|
+
if value.is_a? Symbol
|
|
23
|
+
chain_route :filter => :property, :block => proc { |v| v.vars[value] != v }
|
|
24
|
+
else
|
|
25
|
+
chain_route({ :filter => :object, :value => value, :negate => true })
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
module Filter
|
|
33
|
+
module ObjectFilter
|
|
34
|
+
import com.tinkerpop.pipes.filter.ObjectFilterPipe
|
|
35
|
+
|
|
36
|
+
attr_accessor :value, :negate
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
|
|
40
|
+
def attach_pipe(end_pipe)
|
|
41
|
+
pipe = ObjectFilterPipe.new(value, negate ? Pacer::Pipes::NOT_EQUAL : Pacer::Pipes::EQUAL)
|
|
42
|
+
pipe.set_starts end_pipe if end_pipe
|
|
43
|
+
pipe
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def inspect_string
|
|
47
|
+
if negate
|
|
48
|
+
"is_not(#{ value.inspect })"
|
|
49
|
+
else
|
|
50
|
+
"is(#{ value.inspect })"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Filter
|
|
3
|
+
module PropertyFilter
|
|
4
|
+
class EdgeFilters < Filters
|
|
5
|
+
attr_accessor :labels
|
|
6
|
+
|
|
7
|
+
protected
|
|
8
|
+
|
|
9
|
+
attr_accessor :non_ext_labels
|
|
10
|
+
|
|
11
|
+
public
|
|
12
|
+
|
|
13
|
+
def initialize(filters)
|
|
14
|
+
@best_index = nil
|
|
15
|
+
self.labels = []
|
|
16
|
+
self.non_ext_labels = []
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def add_filter(filter, extension)
|
|
21
|
+
case filter
|
|
22
|
+
when String, Symbol
|
|
23
|
+
reset_properties
|
|
24
|
+
self.non_ext_labels << filter
|
|
25
|
+
self.labels << filter.to_s
|
|
26
|
+
else
|
|
27
|
+
super
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_pipeline(route, start_pipe = nil, pipe = nil)
|
|
32
|
+
pipe ||= start_pipe
|
|
33
|
+
if labels.any?
|
|
34
|
+
label_pipe = Pacer::Pipes::LabelCollectionFilterPipe.new labels
|
|
35
|
+
label_pipe.set_starts pipe if pipe
|
|
36
|
+
Pacer.debug_pipes << { :name => labels.inspect, :start => pipe, :end => block_pipe } if Pacer.debug_pipes
|
|
37
|
+
pipe = label_pipe
|
|
38
|
+
start_pipe ||= pipe
|
|
39
|
+
end
|
|
40
|
+
super(route, start_pipe, pipe)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def any?
|
|
44
|
+
labels.any? or super
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_s
|
|
48
|
+
if labels.any?
|
|
49
|
+
[labels.map { |l| l.to_sym.inspect }.join(', '), super].reject { |s| s == '' }.join ', '
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def best_index(route)
|
|
56
|
+
index, key, value = find_best_index(route)
|
|
57
|
+
if key == 'label'
|
|
58
|
+
labels.delete value
|
|
59
|
+
end
|
|
60
|
+
super
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
|
|
65
|
+
def reset_properties
|
|
66
|
+
@encoded_properties = nil
|
|
67
|
+
if @best_index
|
|
68
|
+
# put removed index label back...
|
|
69
|
+
i, k, v = @best_index
|
|
70
|
+
labels << v if k == 'label'
|
|
71
|
+
end
|
|
72
|
+
super
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def find_best_index(route)
|
|
76
|
+
super do |avail, index_options|
|
|
77
|
+
labels.each do |label|
|
|
78
|
+
if idxs = avail["key:label"]
|
|
79
|
+
if choose_best_index
|
|
80
|
+
idxs.each do |idx|
|
|
81
|
+
index_options << [idx.count('label', label), idx, k, v]
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
return @best_index = [idxs.first, 'label', label]
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
module Pacer
|
|
2
|
+
module Filter
|
|
3
|
+
module PropertyFilter
|
|
4
|
+
class Filters
|
|
5
|
+
attr_reader :properties, :extensions, :route_modules
|
|
6
|
+
attr_accessor :wrapper, :blocks
|
|
7
|
+
|
|
8
|
+
# Allow Pacer to use index counts to determine which index has
|
|
9
|
+
# the least number elements for the available keys in the query.
|
|
10
|
+
#
|
|
11
|
+
# @attr [Boolean] choose_best_index
|
|
12
|
+
attr_accessor :choose_best_index
|
|
13
|
+
|
|
14
|
+
# Allow Pacer to use manual indices without explicitly
|
|
15
|
+
# referencing them by name.
|
|
16
|
+
#
|
|
17
|
+
# @example Explicit manual index:
|
|
18
|
+
#
|
|
19
|
+
# graph.v(:index_name => { :index_key => value })
|
|
20
|
+
#
|
|
21
|
+
# @example Non-explicit index lookup:
|
|
22
|
+
#
|
|
23
|
+
# graph.v(:index_key => value)
|
|
24
|
+
#
|
|
25
|
+
# @attr [Boolean] search_manual_indices
|
|
26
|
+
attr_accessor :search_manual_indices
|
|
27
|
+
|
|
28
|
+
protected
|
|
29
|
+
|
|
30
|
+
attr_accessor :non_ext_props
|
|
31
|
+
|
|
32
|
+
public
|
|
33
|
+
|
|
34
|
+
def initialize(filters)
|
|
35
|
+
@properties = []
|
|
36
|
+
@blocks = []
|
|
37
|
+
@extensions = []
|
|
38
|
+
@wrapper = nil
|
|
39
|
+
@route_modules = []
|
|
40
|
+
@non_ext_props = []
|
|
41
|
+
@best_index_value = nil
|
|
42
|
+
add_filters filters, nil
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Set which graph this filter is currently operating on
|
|
46
|
+
#
|
|
47
|
+
# @note this is not threadsafe if you are reusing predefined
|
|
48
|
+
# routes on multiple graphs.
|
|
49
|
+
#
|
|
50
|
+
# @attr [GraphMixin] g a graph
|
|
51
|
+
attr_reader :graph
|
|
52
|
+
|
|
53
|
+
def graph=(g)
|
|
54
|
+
if graph != g
|
|
55
|
+
reset_properties
|
|
56
|
+
@graph = g
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Set which indices are available to be used to determine the
|
|
61
|
+
# best_index.
|
|
62
|
+
#
|
|
63
|
+
# @attr [Array<Pacer::IndexMixin>] i an array of indices
|
|
64
|
+
attr_reader :indices
|
|
65
|
+
|
|
66
|
+
def indices=(i)
|
|
67
|
+
if indices != i
|
|
68
|
+
reset_properties
|
|
69
|
+
@indices = i
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def add_filter(filter, extension)
|
|
74
|
+
case filter
|
|
75
|
+
when Hash
|
|
76
|
+
reset_properties
|
|
77
|
+
filter.each do |k, v|
|
|
78
|
+
self.non_ext_props << [k.to_s, v] unless extension
|
|
79
|
+
self.properties << [k.to_s, v]
|
|
80
|
+
end
|
|
81
|
+
when Module, Class
|
|
82
|
+
if filter.is_a? Class and filter.ancestors.include? Pacer::Wrappers::ElementWrapper
|
|
83
|
+
self.wrapper = filter
|
|
84
|
+
else
|
|
85
|
+
self.extensions << filter
|
|
86
|
+
end
|
|
87
|
+
if filter.respond_to? :route_conditions
|
|
88
|
+
add_filters filter.route_conditions, filter
|
|
89
|
+
end
|
|
90
|
+
if filter.respond_to? :route
|
|
91
|
+
self.route_modules << filter
|
|
92
|
+
end
|
|
93
|
+
when Array
|
|
94
|
+
add_filters(filter, extension)
|
|
95
|
+
when nil
|
|
96
|
+
else
|
|
97
|
+
raise "Unknown filter: #{ filter.class }: #{ filter.inspect }"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def add_filters(filters, extension)
|
|
102
|
+
if filters.is_a? Array
|
|
103
|
+
filters.each do |filter|
|
|
104
|
+
add_filter filter, extension
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
add_filter filters, extension
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def encode_value(value)
|
|
112
|
+
value = graph.encode_property(value)
|
|
113
|
+
if value.respond_to? :to_java
|
|
114
|
+
jvalue = value.to_java
|
|
115
|
+
elsif value.respond_to? :to_java_string
|
|
116
|
+
jvalue = value.to_java_string
|
|
117
|
+
else
|
|
118
|
+
jvalue = value
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def build_pipeline(route, start_pipe, pipe = nil)
|
|
123
|
+
self.graph = route.graph
|
|
124
|
+
pipe ||= start_pipe
|
|
125
|
+
route_modules.each do |mod|
|
|
126
|
+
extension_route = mod.route(Pacer::Route.empty(route))
|
|
127
|
+
s, e = extension_route.send :build_pipeline
|
|
128
|
+
s.setStarts(pipe) if pipe
|
|
129
|
+
start_pipe ||= s
|
|
130
|
+
pipe = e
|
|
131
|
+
end
|
|
132
|
+
encoded_properties.each do |key, value|
|
|
133
|
+
new_pipe = PropertyFilterPipe.new(key, value, Pacer::Pipes::EQUAL)
|
|
134
|
+
new_pipe.set_starts pipe if pipe
|
|
135
|
+
Pacer.debug_pipes << { :name => key, :start => pipe, :end => new_pipe } if Pacer.debug_pipes
|
|
136
|
+
pipe = new_pipe
|
|
137
|
+
start_pipe ||= pipe
|
|
138
|
+
end
|
|
139
|
+
blocks.each do |block|
|
|
140
|
+
block_pipe = Pacer::Pipes::BlockFilterPipe.new(route, block)
|
|
141
|
+
block_pipe.set_starts pipe if pipe
|
|
142
|
+
Pacer.debug_pipes << { :name => 'block', :start => pipe, :end => block_pipe } if Pacer.debug_pipes
|
|
143
|
+
pipe = block_pipe
|
|
144
|
+
start_pipe ||= pipe
|
|
145
|
+
end
|
|
146
|
+
[start_pipe, pipe]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def any?
|
|
150
|
+
properties.any? or blocks.any? or route_modules.any? or extensions.any?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def extensions_only?
|
|
154
|
+
properties.none? and blocks.none? and route_modules.none? and (extensions.any? or wrapper)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def to_s
|
|
158
|
+
strings = []
|
|
159
|
+
strings << [wrapper.name] if wrapper
|
|
160
|
+
strings.concat extensions.map { |e| e.name }
|
|
161
|
+
strings.concat((non_ext_props - [@best_index_value]).map { |k, v| "#{ k }==#{ v.inspect }" })
|
|
162
|
+
strings.concat blocks.map { '&block' }
|
|
163
|
+
strings.concat route_modules.map { |mod| mod.name }
|
|
164
|
+
strings.join ', '
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def best_index(element_type)
|
|
168
|
+
result = find_best_index(element_type)
|
|
169
|
+
# the call to find_best_index produces @best_index_value:
|
|
170
|
+
if properties.delete @best_index_value
|
|
171
|
+
@encoded_properties = nil
|
|
172
|
+
end
|
|
173
|
+
result
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
protected
|
|
177
|
+
|
|
178
|
+
def find_best_index(element_type)
|
|
179
|
+
return @best_index if @best_index
|
|
180
|
+
avail = available_indices(element_type)
|
|
181
|
+
return nil if avail.empty?
|
|
182
|
+
index_options = []
|
|
183
|
+
yield avail, index_options if block_given?
|
|
184
|
+
properties.each do |k, v|
|
|
185
|
+
if v.is_a? Hash
|
|
186
|
+
v.each do |k2, v2|
|
|
187
|
+
if (idxs = avail["name:#{k}"]).any?
|
|
188
|
+
if choose_best_index
|
|
189
|
+
idxs.each do |idx|
|
|
190
|
+
index_options << [idx.count(k2, encode_value(v2)), [idx, k2, v2], [k, v]]
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
@best_index_value = [k, v]
|
|
194
|
+
return @best_index = [idxs.first, k2, v2]
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
elsif (idxs = (avail["key:#{k}"] + avail[:all])).any?
|
|
199
|
+
if choose_best_index
|
|
200
|
+
idxs.each do |idx|
|
|
201
|
+
index_options << [idx.count(k, encode_value(v)), [idx, k, v], [k, v]]
|
|
202
|
+
end
|
|
203
|
+
else
|
|
204
|
+
@best_index_value = [k, v]
|
|
205
|
+
return @best_index = [idxs.first, k, v]
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
nil
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
index_options = index_options.sort_by do |a|
|
|
212
|
+
count = a.first
|
|
213
|
+
if count == 0 and search_manual_indices
|
|
214
|
+
# Only use 0 result indices if there is no alternative
|
|
215
|
+
# because most manual indices won't be populating the
|
|
216
|
+
# data in question.
|
|
217
|
+
java.lang.Integer::MAX_VALUE
|
|
218
|
+
else
|
|
219
|
+
count
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
_, @best_index, @best_index_value = index_options.first || [nil, [], []]
|
|
223
|
+
@best_index
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def reset_properties
|
|
227
|
+
@encoded_properties = nil
|
|
228
|
+
if @best_index_value
|
|
229
|
+
# put removed index property back...
|
|
230
|
+
properties << @best_index_value
|
|
231
|
+
end
|
|
232
|
+
@best_index = nil
|
|
233
|
+
@best_index_value = nil
|
|
234
|
+
@available_indices = nil
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def encoded_properties
|
|
238
|
+
@encoded_properties ||= properties.map do |k, v|
|
|
239
|
+
[k, encode_value(v)]
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def available_indices(element_type)
|
|
244
|
+
return @available_indices if @available_indices
|
|
245
|
+
@available_indices = Hash.new { |h, k| h[k] = [] }
|
|
246
|
+
return @available_indices unless indices
|
|
247
|
+
index_class = graph.index_class(element_type)
|
|
248
|
+
indices.each do |index|
|
|
249
|
+
next unless index.index_class == index_class
|
|
250
|
+
if index.index_type == Pacer.automatic_index
|
|
251
|
+
if keys = index.getAutoIndexKeys
|
|
252
|
+
keys.each do |key|
|
|
253
|
+
@available_indices["key:#{key}"] << index
|
|
254
|
+
end
|
|
255
|
+
else
|
|
256
|
+
@available_indices[:all] << index
|
|
257
|
+
end
|
|
258
|
+
else
|
|
259
|
+
@available_indices["name:#{index.index_name}"] = [index]
|
|
260
|
+
@available_indices[:all] << index if search_manual_indices
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
@available_indices
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|