pacer 1.2.0-java → 1.3.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +14 -0
- data/lib/pacer/blueprints/ruby_graph.rb +0 -1
- data/lib/pacer/core/graph/graph_index_route.rb +2 -2
- data/lib/pacer/core/graph/path_route.rb +11 -5
- data/lib/pacer/filter/property_filter/filters.rb +46 -16
- data/lib/pacer/filter/where_filter/node_visitor.rb +2 -0
- data/lib/pacer/graph/graph_transactions_mixin.rb +9 -0
- data/lib/pacer/graph/pacer_graph.rb +39 -26
- data/lib/pacer/graph/simple_encoder.rb +3 -0
- data/lib/pacer/loader.rb +1 -1
- data/lib/pacer/pipes.rb +1 -1
- data/lib/pacer/transform/sort_section.rb +41 -7
- data/lib/pacer/version.rb +4 -4
- data/lib/pacer/wrappers/edge_wrapper.rb +13 -0
- data/lib/pacer/wrappers/element_wrapper.rb +4 -4
- data/lib/pacer/wrappers/index_wrapper.rb +9 -0
- data/pom.xml +4 -4
- data/spec/pacer/blueprints/neo4j_spec.rb +1 -1
- data/spec/pacer/filter/property_filter/filters_spec.rb +21 -0
- data/spec/pacer/filter/property_filter_spec.rb +14 -0
- data/spec/pacer/graph/pacer_graph_spec.rb +12 -0
- data/spec/pacer/route/mixin/base_spec.rb +3 -3
- data/spec/pacer/transform/sort_section_spec.rb +29 -0
- data/spec/pacer/wrapper/edge_wrapper_spec.rb +65 -2
- data/spec/pacer/wrapper/vertex_wrapper_spec.rb +2 -2
- metadata +11 -20
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 873067a94942616e42ecb659e821bdf1f13c6bd4
|
4
|
+
data.tar.gz: 91c4e71707fa23b969e6205d650a981464d2b4a5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bacb0e4e165bd10005d090cc7e1cd1fae2954b88901725078729c2fdd62e202c7f42237ed1d62b2d08aa5b1864b061eceb6638bc3900dbf9ccfbedfef32179fa
|
7
|
+
data.tar.gz: 687bc677f5ca3682ef2b012ed278731d2a2963f85f399ef4829b55a4dc35d6e82d504d4470e50a60c6dc5d19f8d2b19e93411801ef6ac60815b0ed22d84ed167
|
data/README.md
CHANGED
@@ -203,3 +203,17 @@ I'm aiming for 100% test coverage in Pacer and am currently nearly there in the
|
|
203
203
|
## Style Guide
|
204
204
|
|
205
205
|
Please follow Github's [Ruby style guide](https://github.com/styleguide/ruby) when contributing to make your patches more likely to be accepted!
|
206
|
+
|
207
|
+
## YourKit Profiler
|
208
|
+
|
209
|
+
One of the advantages of building Pacer on JRuby is that we can leverage
|
210
|
+
the incredible tools that exist in the JVM ecosystem. YourKit is a tool
|
211
|
+
that I found through glowing recommendation, and has been greatly useful
|
212
|
+
in profiling the performance of Pacer.
|
213
|
+
|
214
|
+
YourKit is kindly supporting the Pacer open source project with its full-featured Java Profiler.
|
215
|
+
YourKit, LLC is the creator of innovative and intelligent tools for profiling
|
216
|
+
Java and .NET applications. Take a look at YourKit's leading software products:
|
217
|
+
|
218
|
+
<a href="http://www.yourkit.com/java/profiler/index.jsp">YourKit Java Profiler</a> and
|
219
|
+
<a href="http://www.yourkit.com/.net/profiler/index.jsp">YourKit .NET Profiler</a>.
|
@@ -6,7 +6,7 @@ module Pacer::Core::Graph
|
|
6
6
|
# Returns a new route to all graph vertices. Standard filter options.
|
7
7
|
def v(*args, &block)
|
8
8
|
filters = Pacer::Route.filters(args)
|
9
|
-
if features.supportsIndices
|
9
|
+
if features.supportsKeyIndices or (search_manual_indices and features.supportsIndices)
|
10
10
|
route = indexed_route(:vertex, filters, block)
|
11
11
|
end
|
12
12
|
if route
|
@@ -19,7 +19,7 @@ module Pacer::Core::Graph
|
|
19
19
|
# Returns a new route to all graph edges. Standard filter options.
|
20
20
|
def e(*args, &block)
|
21
21
|
filters = Pacer::Route.edge_filters(args)
|
22
|
-
if features.supportsIndices
|
22
|
+
if features.supportsKeyIndices or (search_manual_indices and features.supportsIndices)
|
23
23
|
route = indexed_route(:edge, filters, block)
|
24
24
|
end
|
25
25
|
if route
|
@@ -55,11 +55,17 @@ HELP
|
|
55
55
|
|
56
56
|
def payloads
|
57
57
|
map element_type: :path, route_name: 'payloads' do |path|
|
58
|
-
path.
|
59
|
-
if e.is_a? Pacer::
|
60
|
-
|
61
|
-
|
62
|
-
e.
|
58
|
+
path.flat_map do |e|
|
59
|
+
e = e.element if e.is_a? Pacer::Wrappers::ElementWrapper
|
60
|
+
r = []
|
61
|
+
while e.is_a? Pacer::Payload::Element
|
62
|
+
r.unshift e.payload
|
63
|
+
e = e.element
|
64
|
+
end
|
65
|
+
if r == []
|
66
|
+
[nil]
|
67
|
+
else
|
68
|
+
r
|
63
69
|
end
|
64
70
|
end
|
65
71
|
end
|
@@ -34,6 +34,8 @@ module Pacer
|
|
34
34
|
|
35
35
|
module PropertyFilter
|
36
36
|
class Filters
|
37
|
+
NodeVisitor = Pacer::Filter::WhereFilter::NodeVisitor
|
38
|
+
|
37
39
|
attr_reader :properties, :extensions, :route_modules, :best_index_value
|
38
40
|
attr_accessor :wrapper, :blocks
|
39
41
|
|
@@ -112,11 +114,20 @@ module Pacer
|
|
112
114
|
pipe = e
|
113
115
|
end
|
114
116
|
encoded_properties.each do |key, value|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
case value
|
118
|
+
when NodeVisitor::Pipe
|
119
|
+
new_pipe = value.build
|
120
|
+
when NodeVisitor::Value
|
121
|
+
# no op
|
122
|
+
else
|
123
|
+
new_pipe = PropertyFilterPipe.new(key, value, Pacer::Pipes::EQUAL)
|
124
|
+
end
|
125
|
+
if new_pipe
|
126
|
+
new_pipe.set_starts pipe if pipe
|
127
|
+
Pacer.debug_pipes << { :name => key, :start => pipe, :end => new_pipe } if Pacer.debug_pipes
|
128
|
+
pipe = new_pipe
|
129
|
+
start_pipe ||= pipe
|
130
|
+
end
|
120
131
|
end
|
121
132
|
blocks.each do |block|
|
122
133
|
block_pipe = Pacer::Pipes::BlockFilterPipe.new(route, block)
|
@@ -140,7 +151,13 @@ module Pacer
|
|
140
151
|
strings = []
|
141
152
|
strings << [wrapper.name] if wrapper
|
142
153
|
strings.concat extensions.map { |e| e.name }
|
143
|
-
strings.concat((non_ext_props - [@best_index_value]).map { |k, v|
|
154
|
+
strings.concat((non_ext_props - [@best_index_value]).map { |k, v|
|
155
|
+
if v.is_a? Set
|
156
|
+
"#{ k } IN (#{ v.sort.map { |s| s.inspect }.join ', ' })"
|
157
|
+
else
|
158
|
+
"#{ k }==#{ v.inspect }"
|
159
|
+
end
|
160
|
+
})
|
144
161
|
strings.concat blocks.map { '&block' }
|
145
162
|
strings.concat route_modules.map { |mod| mod.name }
|
146
163
|
strings.join ', '
|
@@ -164,6 +181,7 @@ module Pacer
|
|
164
181
|
when Hash
|
165
182
|
reset_properties
|
166
183
|
filter.each do |k, v|
|
184
|
+
v = v.first if v.is_a? Set and v.length == 1
|
167
185
|
self.non_ext_props << [k.to_s, v] unless extension
|
168
186
|
self.properties << [k.to_s, v]
|
169
187
|
end
|
@@ -209,14 +227,22 @@ module Pacer
|
|
209
227
|
end
|
210
228
|
end
|
211
229
|
|
212
|
-
def encode_value(value)
|
213
|
-
value
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
230
|
+
def encode_value(key, value)
|
231
|
+
if value.is_a? Set
|
232
|
+
encoded = value.map.with_index { |v, i| graph.encode_property(v) }
|
233
|
+
str = encoded.map { |v| "`#{ key.to_s }` == #{ v.inspect }" }.join " or "
|
234
|
+
parsed = JRuby.parse str
|
235
|
+
visitor = NodeVisitor.new(nil, {})
|
236
|
+
parsed.accept visitor
|
218
237
|
else
|
219
|
-
|
238
|
+
value = graph.encode_property(value)
|
239
|
+
if value.respond_to? :to_java
|
240
|
+
value.to_java
|
241
|
+
elsif value.respond_to? :to_java_string
|
242
|
+
value.to_java_string
|
243
|
+
else
|
244
|
+
value
|
245
|
+
end
|
220
246
|
end
|
221
247
|
end
|
222
248
|
|
@@ -259,9 +285,13 @@ module Pacer
|
|
259
285
|
end
|
260
286
|
|
261
287
|
def check_index(index_options, idxs, k, v, index_value)
|
262
|
-
if
|
288
|
+
if v.is_a? Set
|
289
|
+
# By default we assume that indices can't do OR type operations, so Set values are ruled out. If
|
290
|
+
# the index can do that (i.e. Neo4j's lucene engine), the adapter needs to do its own index selection.
|
291
|
+
false
|
292
|
+
elsif choose_best_index
|
263
293
|
idxs.each do |idx|
|
264
|
-
index_options << [idx.count(k, encode_value(v)), [idx, k, v], index_value]
|
294
|
+
index_options << [idx.count(k, encode_value(k, v)), [idx, k, v], index_value]
|
265
295
|
end
|
266
296
|
false
|
267
297
|
else
|
@@ -284,7 +314,7 @@ module Pacer
|
|
284
314
|
|
285
315
|
def encoded_properties
|
286
316
|
@encoded_properties ||= properties.map do |k, v|
|
287
|
-
[k, encode_value(v)]
|
317
|
+
[k, encode_value(k, v)]
|
288
318
|
end
|
289
319
|
end
|
290
320
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Pacer
|
2
2
|
module Filter
|
3
3
|
module WhereFilter
|
4
|
+
# NOTE: the property filter also uses this to build { key: Set[v1, v2] }
|
5
|
+
# filters as or statements.
|
4
6
|
class NodeVisitor
|
5
7
|
import com.tinkerpop.pipes.filter.OrFilterPipe
|
6
8
|
import com.tinkerpop.pipes.filter.FilterPipe
|
@@ -82,6 +82,13 @@ module Pacer
|
|
82
82
|
blueprints_graph.stopTransaction TransactionalGraph::Conclusion::SUCCESS
|
83
83
|
end
|
84
84
|
|
85
|
+
attr_reader :on_commit_block
|
86
|
+
|
87
|
+
def on_commit(&block)
|
88
|
+
return unless block
|
89
|
+
@on_commit_block = block
|
90
|
+
end
|
91
|
+
|
85
92
|
private
|
86
93
|
|
87
94
|
def threadlocal_graph_info
|
@@ -128,6 +135,7 @@ module Pacer
|
|
128
135
|
end
|
129
136
|
puts "transaction committed" if Pacer.verbose == :very
|
130
137
|
blueprints_graph.stopTransaction TransactionalGraph::Conclusion::SUCCESS
|
138
|
+
on_commit_block.call if on_commit_block
|
131
139
|
end
|
132
140
|
rollback = ->(message = nil) do
|
133
141
|
puts ["transaction rolled back", message].compact.join(': ') if Pacer.verbose == :very
|
@@ -153,6 +161,7 @@ module Pacer
|
|
153
161
|
def mock_base_tx_finalizers
|
154
162
|
commit = -> do
|
155
163
|
puts "mock transaction committed" if Pacer.verbose == :very
|
164
|
+
on_commit_block.call if on_commit_block
|
156
165
|
end
|
157
166
|
rollback = ->(message = nil) do
|
158
167
|
puts ["mock transaction rolled back", message].compact.join(': ') if Pacer.verbose == :very
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module Pacer
|
2
|
+
import com.tinkerpop.blueprints.Parameter
|
3
|
+
|
2
4
|
class PacerGraph
|
3
5
|
include GraphTransactionsMixin
|
4
6
|
|
@@ -6,9 +8,9 @@ module Pacer
|
|
6
8
|
include Pacer::Core::Graph::GraphRoute
|
7
9
|
include Pacer::Core::Graph::GraphIndexRoute
|
8
10
|
|
9
|
-
attr_reader :blueprints_graph
|
11
|
+
attr_reader :blueprints_graph
|
10
12
|
|
11
|
-
attr_accessor :base_vertex_wrapper, :base_edge_wrapper
|
13
|
+
attr_accessor :encoder, :base_vertex_wrapper, :base_edge_wrapper
|
12
14
|
|
13
15
|
def initialize(encoder, open, shutdown = nil, graph_id = nil)
|
14
16
|
self.base_vertex_wrapper = Pacer::Wrappers::VertexWrapper
|
@@ -52,10 +54,6 @@ module Pacer
|
|
52
54
|
self
|
53
55
|
end
|
54
56
|
|
55
|
-
def copy_object
|
56
|
-
self.class.new @encoder, @reopen, @shutdown, graph_id
|
57
|
-
end
|
58
|
-
|
59
57
|
def use_wrapper(klass)
|
60
58
|
reopen = proc do
|
61
59
|
klass.new unwrap_graph(@reopen.call)
|
@@ -88,18 +86,7 @@ module Pacer
|
|
88
86
|
v = blueprints_graph.getVertex(id)
|
89
87
|
rescue java.lang.RuntimeException
|
90
88
|
end
|
91
|
-
|
92
|
-
wrapper = modules.detect { |obj| obj.ancestors.include? Pacer::Wrappers::VertexWrapper }
|
93
|
-
if wrapper
|
94
|
-
v = wrapper.new graph, v
|
95
|
-
modules.delete wrapper
|
96
|
-
else
|
97
|
-
v = base_vertex_wrapper.new graph, v
|
98
|
-
end
|
99
|
-
v.add_extensions modules
|
100
|
-
else
|
101
|
-
v
|
102
|
-
end
|
89
|
+
wrap_element v, base_vertex_wrapper, Pacer::Wrappers::VertexWrapper, modules
|
103
90
|
end
|
104
91
|
|
105
92
|
# Get an edge by id.
|
@@ -115,15 +102,23 @@ module Pacer
|
|
115
102
|
v = blueprints_graph.getEdge(id)
|
116
103
|
rescue Java::JavaLang::RuntimeException
|
117
104
|
end
|
105
|
+
wrap_element v, base_edge_wrapper, Pacer::Wrappers::EdgeWrapper, modules
|
106
|
+
end
|
107
|
+
|
108
|
+
def wrap_element(v, base, klass, modules)
|
118
109
|
if v
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
110
|
+
if modules
|
111
|
+
wrapper = modules.detect { |obj| obj.ancestors.include? klass }
|
112
|
+
if wrapper
|
113
|
+
v = wrapper.new graph, v
|
114
|
+
modules.delete wrapper
|
115
|
+
else
|
116
|
+
v = base.new graph, v
|
117
|
+
end
|
118
|
+
v.add_extensions modules
|
123
119
|
else
|
124
|
-
|
120
|
+
base.new graph, v
|
125
121
|
end
|
126
|
-
v.add_extensions modules
|
127
122
|
end
|
128
123
|
end
|
129
124
|
|
@@ -371,10 +366,21 @@ module Pacer
|
|
371
366
|
include Indices
|
372
367
|
|
373
368
|
module KeyIndices
|
374
|
-
def create_key_index(name, type)
|
369
|
+
def create_key_index(name, type = :vertex, opts = {})
|
370
|
+
params = build_key_index_parameters_from opts
|
375
371
|
if features.supportsKeyIndices
|
376
372
|
if element_type(type) == :vertex and features.supportsVertexKeyIndex
|
377
|
-
blueprints_graph.createKeyIndex name.to_s, index_class(:vertex)
|
373
|
+
blueprints_graph.createKeyIndex name.to_s, index_class(:vertex), *params
|
374
|
+
elsif element_type(type) == :edge and features.supportsEdgeKeyIndex
|
375
|
+
blueprints_graph.createKeyIndex name.to_s, index_class(:edge), *params
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
def drop_key_index(name, type = :vertex)
|
381
|
+
if features.supportsKeyIndices
|
382
|
+
if element_type(type) == :vertex and features.supportsVertexKeyIndex
|
383
|
+
blueprints_graph.dropKeyIndex name.to_s, index_class(:vertex)
|
378
384
|
elsif element_type(type) == :edge and features.supportsEdgeKeyIndex
|
379
385
|
blueprints_graph.createKeyIndex name.to_s, index_class(:edge)
|
380
386
|
end
|
@@ -413,7 +419,14 @@ module Pacer
|
|
413
419
|
fail ClientError, "The key #{ key } is not indexed"
|
414
420
|
end
|
415
421
|
end
|
422
|
+
|
423
|
+
def build_key_index_parameters_from(option_hash)
|
424
|
+
option_hash.each_with_object([]) do |(key, value), params|
|
425
|
+
params << Pacer::Parameter.new(key, value)
|
426
|
+
end
|
427
|
+
end
|
416
428
|
end
|
429
|
+
|
417
430
|
include KeyIndices
|
418
431
|
|
419
432
|
module ElementType
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Pacer
|
2
2
|
class SimpleEncoder
|
3
3
|
JBoolean = java.lang.Boolean
|
4
|
+
JDate = java.util.Date
|
4
5
|
JFalse = false.to_java
|
5
6
|
|
6
7
|
def self.encode_property(value)
|
@@ -17,6 +18,8 @@ module Pacer
|
|
17
18
|
def self.decode_property(value)
|
18
19
|
if value.is_a? JBoolean and value == JFalse
|
19
20
|
false
|
21
|
+
elsif value.is_a? JDate
|
22
|
+
Time.at value.getTime() / 1000.0
|
20
23
|
else
|
21
24
|
value
|
22
25
|
end
|
data/lib/pacer/loader.rb
CHANGED
@@ -70,6 +70,7 @@ require 'pacer/visitors/section'
|
|
70
70
|
require 'pacer/filter/collection_filter'
|
71
71
|
require 'pacer/filter/empty_filter'
|
72
72
|
require 'pacer/filter/future_filter'
|
73
|
+
require 'pacer/filter/where_filter'
|
73
74
|
require 'pacer/filter/property_filter'
|
74
75
|
require 'pacer/filter/range_filter'
|
75
76
|
require 'pacer/filter/uniq_filter'
|
@@ -77,7 +78,6 @@ require 'pacer/filter/index_filter'
|
|
77
78
|
require 'pacer/filter/loop_filter'
|
78
79
|
require 'pacer/filter/block_filter'
|
79
80
|
require 'pacer/filter/object_filter'
|
80
|
-
require 'pacer/filter/where_filter'
|
81
81
|
require 'pacer/filter/random_filter'
|
82
82
|
|
83
83
|
require 'pacer/transform/cap'
|
data/lib/pacer/pipes.rb
CHANGED
@@ -3,7 +3,7 @@ module Pacer
|
|
3
3
|
module Pipes
|
4
4
|
# TODO: move pipe imports to the modules that actually use them.
|
5
5
|
import com.tinkerpop.pipes.AbstractPipe
|
6
|
-
import com.tinkerpop.pipes.
|
6
|
+
import com.tinkerpop.pipes.IdentityPipe
|
7
7
|
import com.tinkerpop.pipes.util.Pipeline
|
8
8
|
import com.tinkerpop.pipes.util.PipeHelper
|
9
9
|
|
@@ -2,7 +2,11 @@ module Pacer
|
|
2
2
|
module Routes
|
3
3
|
module RouteOperations
|
4
4
|
def sort_section(section = nil, &block)
|
5
|
-
chain_route transform: :sort_section,
|
5
|
+
chain_route transform: :sort_section, sort_by_block: block, section: section
|
6
|
+
end
|
7
|
+
|
8
|
+
def custom_sort_section(section = nil, &block)
|
9
|
+
chain_route transform: :sort_section, custom_sort_block: block, section: section
|
6
10
|
end
|
7
11
|
end
|
8
12
|
end
|
@@ -15,26 +19,32 @@ module Pacer
|
|
15
19
|
# section_visitor
|
16
20
|
include Pacer::Visitors::VisitsSection
|
17
21
|
|
18
|
-
attr_accessor :
|
22
|
+
attr_accessor :sort_by_block
|
23
|
+
attr_accessor :custom_sort_block
|
19
24
|
|
20
25
|
protected
|
21
26
|
|
22
27
|
def attach_pipe(end_pipe)
|
23
|
-
|
24
|
-
|
28
|
+
if custom_sort_block
|
29
|
+
wrapper = Pacer::Wrappers::WrapperSelector.build graph, element_type, extensions
|
30
|
+
pipe = CustomSortPipe.new(self, section_visitor, custom_sort_block, graph, wrapper)
|
31
|
+
else # sort_by_block
|
32
|
+
pf = Pacer::Wrappers::WrappingPipeFunction.new self, sort_by_block if sort_by_block
|
33
|
+
pipe = SortBySectionPipe.new(self, section_visitor, pf)
|
34
|
+
end
|
25
35
|
pipe.setStarts end_pipe if end_pipe
|
26
36
|
pipe
|
27
37
|
end
|
28
38
|
|
29
|
-
|
30
|
-
|
31
|
-
attr_reader :pf_1, :pf_2, :to_sort, :to_emit, :section
|
39
|
+
class SortBySectionPipe < Pacer::Pipes::RubyPipe
|
40
|
+
attr_reader :pf_1, :pf_2, :to_sort, :to_emit, :section, :route
|
32
41
|
attr_reader :getPathToHere
|
33
42
|
|
34
43
|
def initialize(route, section, pipe_function)
|
35
44
|
super()
|
36
45
|
@to_emit = []
|
37
46
|
@section = section
|
47
|
+
@route = route
|
38
48
|
@to_sort = []
|
39
49
|
@paths = []
|
40
50
|
if section
|
@@ -105,6 +115,30 @@ module Pacer
|
|
105
115
|
end
|
106
116
|
end
|
107
117
|
end
|
118
|
+
|
119
|
+
class CustomSortPipe < SortBySectionPipe
|
120
|
+
attr_reader :sort_block
|
121
|
+
|
122
|
+
def initialize(route, section, sort_block, graph, wrapper)
|
123
|
+
super route, section, nil
|
124
|
+
@sort_block = sort_block
|
125
|
+
@graph = graph
|
126
|
+
@wrapper = wrapper
|
127
|
+
end
|
128
|
+
|
129
|
+
def after_element
|
130
|
+
if to_sort.any?
|
131
|
+
to_sort.map! { |e| [ @wrapper.new(@graph, e.first), e.last ] }
|
132
|
+
sorted = to_sort.sort { |a, b| @sort_block.call a.first, b.first }
|
133
|
+
if route.element_type == :vertex || route.element_type == :edge
|
134
|
+
to_emit.concat sorted.map { |e| [ e.first.element, e.last ] }
|
135
|
+
else
|
136
|
+
to_emit.concat sorted
|
137
|
+
end
|
138
|
+
@to_sort.clear
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
108
142
|
end
|
109
143
|
end
|
110
144
|
end
|
data/lib/pacer/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Pacer
|
2
2
|
unless const_defined? :VERSION
|
3
|
-
VERSION = "1.
|
3
|
+
VERSION = "1.3.1"
|
4
4
|
|
5
5
|
JAR = "pacer-#{ VERSION }-standalone.jar"
|
6
6
|
JAR_PATH = "lib/#{ JAR }"
|
7
7
|
|
8
8
|
START_TIME = Time.now
|
9
9
|
|
10
|
-
BLUEPRINTS_VERSION = "2.
|
11
|
-
PIPES_VERSION = "2.
|
12
|
-
GREMLIN_VERSION = "2.
|
10
|
+
BLUEPRINTS_VERSION = "2.3.0"
|
11
|
+
PIPES_VERSION = "2.3.0"
|
12
|
+
GREMLIN_VERSION = "2.3.0"
|
13
13
|
end
|
14
14
|
end
|
@@ -119,6 +119,19 @@ module Pacer::Wrappers
|
|
119
119
|
graph.remove_edge element
|
120
120
|
end
|
121
121
|
|
122
|
+
# Creates a new edge between the same elements with the same
|
123
|
+
# properties, but in the opposite direction and optionally with a
|
124
|
+
# new label. Attempts to reuse the edge id.
|
125
|
+
def reverse!(opts = {})
|
126
|
+
iv = out_vertex
|
127
|
+
ov = in_vertex
|
128
|
+
id = element_id if opts[:reuse_id]
|
129
|
+
new_label = opts.fetch(:label, label)
|
130
|
+
props = properties
|
131
|
+
delete!
|
132
|
+
graph.create_edge id, ov, iv, new_label, props
|
133
|
+
end
|
134
|
+
|
122
135
|
# Clones this edge into the target graph.
|
123
136
|
#
|
124
137
|
# This differs from the {#copy_into} in that it tries to set
|
@@ -113,12 +113,12 @@ module Pacer::Wrappers
|
|
113
113
|
value = graph.encode_property(value)
|
114
114
|
key = key.to_s
|
115
115
|
if value
|
116
|
-
|
117
|
-
element.setProperty(key, value)
|
118
|
-
end
|
116
|
+
element.setProperty(key, value)
|
119
117
|
else
|
120
|
-
element.removeProperty(key)
|
118
|
+
element.removeProperty(key)
|
121
119
|
end
|
120
|
+
rescue Exception => e
|
121
|
+
throw Pacer::ClientError.new "Unable to serialize #{ key }: #{ value.class }"
|
122
122
|
end
|
123
123
|
|
124
124
|
# Specialize result to return self for elements.
|
@@ -40,7 +40,16 @@ module Pacer::Wrappers
|
|
40
40
|
if element.is_a? ElementWrapper
|
41
41
|
element = element.element
|
42
42
|
end
|
43
|
+
|
43
44
|
index.put key.to_s, value, element
|
44
45
|
end
|
46
|
+
|
47
|
+
def remove(key, value, element)
|
48
|
+
if element.is_a? ElementWrapper
|
49
|
+
element = element.element
|
50
|
+
end
|
51
|
+
|
52
|
+
index.remove key.to_s, value, element
|
53
|
+
end
|
45
54
|
end
|
46
55
|
end
|
data/pom.xml
CHANGED
@@ -7,10 +7,10 @@
|
|
7
7
|
<artifactId>pacer</artifactId>
|
8
8
|
<!-- NOTE: the following properties are automatically updated based on the values in lib/pacer-neo4j/version.rb -->
|
9
9
|
<properties>
|
10
|
-
<blueprints.version>2.
|
11
|
-
<gem.version>1.
|
12
|
-
<pipes.version>2.
|
13
|
-
<gremlin.version>2.
|
10
|
+
<blueprints.version>2.3.0</blueprints.version>
|
11
|
+
<gem.version>1.3.1</gem.version>
|
12
|
+
<pipes.version>2.3.0</pipes.version>
|
13
|
+
<gremlin.version>2.3.0</gremlin.version>
|
14
14
|
</properties>
|
15
15
|
<!-- NOTE: the following properties are automatically updated based on the values in lib/pacer-neo4j/version.rb -->
|
16
16
|
<version>${gem.version}</version>
|
@@ -36,6 +36,27 @@ module Pacer::Filter::PropertyFilter
|
|
36
36
|
its(:properties) { should == [ %w[ name Darrick ], %w[ nickname pangloss ] ] }
|
37
37
|
end
|
38
38
|
|
39
|
+
context 'With a Set of properties' do
|
40
|
+
let(:filters) { Pacer::Route.send filter_method, [nickname: Set['pangloss', 'someone']] }
|
41
|
+
|
42
|
+
before { subject.graph = graph }
|
43
|
+
|
44
|
+
its(:any?) { should be_true }
|
45
|
+
its(:extensions_only?) { should be_false }
|
46
|
+
its(:extensions) { should be_empty }
|
47
|
+
its(:route_modules) { should be_empty }
|
48
|
+
its(:wrapper) { should be_nil }
|
49
|
+
its(:blocks) { should be_empty }
|
50
|
+
its(:properties) { should == [ ['nickname', Set['pangloss', 'someone'] ] ] }
|
51
|
+
its(:to_s) { should == 'nickname IN ("pangloss", "someone")' }
|
52
|
+
it 'should encode the Set property as an Or pipe' do
|
53
|
+
props = subject.send :encoded_properties
|
54
|
+
pipe = props.assoc('nickname').last
|
55
|
+
pipe.should be_a Pacer::Filter::WhereFilter::NodeVisitor::Pipe
|
56
|
+
pipe.build.should be_a Java::ComTinkerpopPipesFilter::OrFilterPipe
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
39
60
|
context 'with extensions' do
|
40
61
|
let(:filters) { Pacer::Route.send filter_method, [TP::Person, name: 'Darrick', nickname: 'pangloss'] }
|
41
62
|
|
@@ -34,6 +34,20 @@ Run.tg(:read_only) do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
context 'v(:type => "person", :name => Set["pangloss", "someone"])' do
|
38
|
+
subject { graph.v(:type => 'person', :name => Set['pangloss', 'someone']) }
|
39
|
+
its(:to_a) { should == graph.v('type' => 'person', 'name' => 'pangloss').to_a }
|
40
|
+
its(:to_a) { should == graph.v.where('type = "person" and (name == "pangloss" or name == "someone")').to_a }
|
41
|
+
its(:count) { should == 1 }
|
42
|
+
its(:extensions) { should == [] }
|
43
|
+
it 'should have the correct type' do
|
44
|
+
subject[:type].first.should == 'person'
|
45
|
+
end
|
46
|
+
it 'should have the correct name' do
|
47
|
+
subject[:name].first.should == 'pangloss'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
37
51
|
context 'v(TP::Person)' do
|
38
52
|
subject { graph.v(TP::Person) }
|
39
53
|
its(:count) { should == 2 }
|
@@ -94,6 +94,11 @@ Run.all :read_write do
|
|
94
94
|
describe '#create_vertex' do
|
95
95
|
let(:use_id) { rand 1000000 }
|
96
96
|
|
97
|
+
before do
|
98
|
+
c = example.metadata[:graph_commit]
|
99
|
+
c.call if c
|
100
|
+
end
|
101
|
+
|
97
102
|
context 'existing' do
|
98
103
|
it 'should raise an exception' do
|
99
104
|
unless graph.features.ignoresSuppliedIds
|
@@ -168,6 +173,11 @@ Run.all :read_write do
|
|
168
173
|
let(:from) { graph.vertex v0.element_id }
|
169
174
|
let(:to) { graph.vertex v1.element_id }
|
170
175
|
|
176
|
+
before do
|
177
|
+
c = example.metadata[:graph_commit]
|
178
|
+
c.call if c
|
179
|
+
end
|
180
|
+
|
171
181
|
context 'existing' do
|
172
182
|
it 'should raise an exception' do
|
173
183
|
if not graph.features.ignoresSuppliedIds
|
@@ -341,6 +351,8 @@ Run.all :read_write do
|
|
341
351
|
it 'should not load the data into a graph with conflicting vertex ids' do
|
342
352
|
unless graph.features.ignoresSuppliedIds
|
343
353
|
graph.create_vertex '0' unless graph.vertex '0'
|
354
|
+
c = example.metadata[:graph_commit]
|
355
|
+
c.call if c
|
344
356
|
expect { Pacer::GraphML.import graph, 'spec/data/pacer.graphml' }.to raise_error(Pacer::ElementExists)
|
345
357
|
end
|
346
358
|
end
|
@@ -30,7 +30,7 @@ Run.all do
|
|
30
30
|
|
31
31
|
its(:inspect) do
|
32
32
|
should be_one_of "#<V-Index(name: \"gremlin\") -> V-Section -> :grem -> inE(:wrote)>",
|
33
|
-
/#<V-Lucene\(name:gremlin\) ~ \d+ -> V-Section -> :grem -> inE\(:wrote\)>/,
|
33
|
+
/#<V-Lucene\(name:"gremlin"\) ~ \d+ -> V-Section -> :grem -> inE\(:wrote\)>/,
|
34
34
|
"#<GraphV -> V-Property(name==\"gremlin\") -> V-Section -> :grem -> inE(:wrote)>"
|
35
35
|
end
|
36
36
|
its(:out_v) { should_not be_nil }
|
@@ -87,7 +87,7 @@ Run.all do
|
|
87
87
|
use_simple_graph_data
|
88
88
|
before { setup_data }
|
89
89
|
subject { graph.v.element_ids.to_a }
|
90
|
-
its(:
|
90
|
+
its(:to_set) { should == [v0, v1].to_route(based_on: graph.v).element_ids.to_set }
|
91
91
|
end
|
92
92
|
end
|
93
93
|
end
|
@@ -107,7 +107,7 @@ Run.all(:read_only) do
|
|
107
107
|
r = r.in_v
|
108
108
|
r = r.is_not(:grem)
|
109
109
|
r.inspect.should be_one_of "#<V-Index(name: \"gremlin\") -> V-Section -> :grem -> inE(:wrote) -> outV -> outE(:wrote) -> E-Property(&block) -> inV -> V-Property(&block)>",
|
110
|
-
/#<V-Lucene\(name:gremlin\) ~ \d+ -> V-Section -> :grem -> inE\(:wrote\) -> outV -> outE\(:wrote\) -> E-Property\(&block\) -> inV -> V-Property\(&block\)>/,
|
110
|
+
/#<V-Lucene\(name:"gremlin"\) ~ \d+ -> V-Section -> :grem -> inE\(:wrote\) -> outV -> outE\(:wrote\) -> E-Property\(&block\) -> inV -> V-Property\(&block\)>/,
|
111
111
|
"#<GraphV -> V-Property(name==\"gremlin\") -> V-Section -> :grem -> inE(:wrote) -> outV -> outE(:wrote) -> E-Property(&block) -> inV -> V-Property(&block)>"
|
112
112
|
end
|
113
113
|
end
|
@@ -5,6 +5,35 @@ Run.tg :read_only do
|
|
5
5
|
|
6
6
|
let(:unsorted) { graph.v.out.out }
|
7
7
|
|
8
|
+
describe 'sort by custom sort' do
|
9
|
+
let(:by_custom) do
|
10
|
+
graph.v.section(:x).out.out.sort_section(:x) { |a, b| a[:name] <=> b[:name] }
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should have the same elements' do
|
14
|
+
by_custom.group_count.should == unsorted.group_count
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should have 3 elements in the path' do
|
18
|
+
by_custom.paths.each do |path|
|
19
|
+
path.length.should == 3
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should put groups into the correct order' do
|
24
|
+
# depends on the order of graph.v(type: 'project') ...
|
25
|
+
route = graph.v(type: 'project').section(:proj).out[:name].custom_sort_section(:proj) { |a, b| a <=> b }
|
26
|
+
route.to_a.should == %w[
|
27
|
+
blueprints
|
28
|
+
blueprints
|
29
|
+
gremlin
|
30
|
+
pipes
|
31
|
+
blueprints
|
32
|
+
pipes
|
33
|
+
]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
8
37
|
describe 'sort by name' do
|
9
38
|
let(:by_name) do
|
10
39
|
graph.v.section(:x).out.out.sort_section(:x) { |v| v[:name] }
|
@@ -100,6 +100,52 @@ describe Pacer::Wrappers::EdgeWrapper do
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
+
describe '#reverse!' do
|
104
|
+
it 'should remove the old element' do
|
105
|
+
id = e0.element_id
|
106
|
+
e0.reverse!
|
107
|
+
c = example.metadata[:graph_commit]
|
108
|
+
c.call if c
|
109
|
+
graph.edge(id).should be_nil
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should create a new element with the same label' do
|
113
|
+
label = e0.label
|
114
|
+
new_e = e0.reverse!
|
115
|
+
new_e.label.should == label
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should not have the same element_id' do
|
119
|
+
id = e0.element_id
|
120
|
+
new_e = e0.reverse!
|
121
|
+
new_e.element_id.should_not == id
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should reverse the direction' do
|
125
|
+
iv = e0.in_vertex
|
126
|
+
ov = e0.out_vertex
|
127
|
+
new_e = e0.reverse!
|
128
|
+
new_e.in_vertex.should == ov
|
129
|
+
new_e.out_vertex.should == iv
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should change the label' do
|
133
|
+
new_e = e0.reverse! label: 'hello!!'
|
134
|
+
new_e.label.should == 'hello!!'
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'should reuse the element id' do
|
138
|
+
unless graph.features.ignoresSuppliedIds
|
139
|
+
e0
|
140
|
+
c = example.metadata[:graph_commit]
|
141
|
+
c.call if c
|
142
|
+
id = e0.element_id
|
143
|
+
new_e = e0.reverse! reuse_id: true
|
144
|
+
new_e.element_id.should == id.to_s
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
103
149
|
contexts(
|
104
150
|
'into new tg' => proc {
|
105
151
|
let(:dest) { Pacer.tg }
|
@@ -115,7 +161,12 @@ describe Pacer::Wrappers::EdgeWrapper do
|
|
115
161
|
}) do
|
116
162
|
describe '#clone_into' do
|
117
163
|
context 'including vertices' do
|
118
|
-
subject
|
164
|
+
subject do
|
165
|
+
e0
|
166
|
+
c = example.metadata[:graph_commit]
|
167
|
+
c.call if c
|
168
|
+
e0.clone_into(dest, :create_vertices => true)
|
169
|
+
end
|
119
170
|
|
120
171
|
its('element_id.to_s') { should == e0.element_id.to_s unless graph.features.ignoresSuppliedIds }
|
121
172
|
its(:label) { should == 'links' }
|
@@ -132,6 +183,9 @@ describe Pacer::Wrappers::EdgeWrapper do
|
|
132
183
|
|
133
184
|
context 'existing' do
|
134
185
|
before do
|
186
|
+
v0; v1; e0
|
187
|
+
c = example.metadata[:graph_commit]
|
188
|
+
c.call if c
|
135
189
|
v0.clone_into(dest)
|
136
190
|
v1.clone_into(dest)
|
137
191
|
end
|
@@ -146,7 +200,16 @@ describe Pacer::Wrappers::EdgeWrapper do
|
|
146
200
|
end
|
147
201
|
|
148
202
|
describe '#copy_into' do
|
149
|
-
|
203
|
+
before do
|
204
|
+
v0; v1; e0
|
205
|
+
c = example.metadata[:graph_commit]
|
206
|
+
c.call if c
|
207
|
+
end
|
208
|
+
subject do
|
209
|
+
v0.clone_into(dest)
|
210
|
+
v1.clone_into(dest)
|
211
|
+
e0.copy_into(dest)
|
212
|
+
end
|
150
213
|
its(:label) { should == 'links' }
|
151
214
|
its(:graph) { should equal(dest) }
|
152
215
|
its('in_vertex.properties') { should == e0.in_vertex.properties }
|
@@ -195,13 +195,13 @@ shared_examples_for Pacer::Wrappers::VertexWrapper do
|
|
195
195
|
subject { v0 }
|
196
196
|
its(:graph) { should equal(graph) }
|
197
197
|
its(:display_name) { should be_nil }
|
198
|
-
its(:inspect) { should =~ /#<[VM]\[#{v0.element_id}\]>/ }
|
198
|
+
its(:inspect) { should =~ /#<[VM]\[#{Regexp.quote v0.element_id.to_s }\]>/ }
|
199
199
|
context 'with label proc' do
|
200
200
|
before do
|
201
201
|
graph.vertex_name = proc { |e| "some name" }
|
202
202
|
end
|
203
203
|
its(:display_name) { should == "some name" }
|
204
|
-
its(:inspect) { should =~ /#<[VM]\[#{ v0.element_id }\] some name>/ }
|
204
|
+
its(:inspect) { should =~ /#<[VM]\[#{ Regexp.quote v0.element_id.to_s }\] some name>/ }
|
205
205
|
end
|
206
206
|
it { should_not == v1 }
|
207
207
|
it { should == v0 }
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pacer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 1.2.0
|
4
|
+
version: 1.3.1
|
6
5
|
platform: java
|
7
6
|
authors:
|
8
7
|
- Darrick Wiebe
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-07-04 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
13
|
description: Pacer defines routes through a graph and then traverses them very quickly.
|
15
14
|
email: darrick@innatesoftware.com
|
@@ -218,39 +217,30 @@ files:
|
|
218
217
|
- spec/support/use_transactions.rb
|
219
218
|
- spec/tackle/simple_mixin.rb
|
220
219
|
- spec/tackle/tinkerpop_graph_mixins.rb
|
221
|
-
- lib/pacer-1.
|
220
|
+
- lib/pacer-1.3.1-standalone.jar
|
222
221
|
homepage: http://github.com/pangloss/pacer
|
223
222
|
licenses:
|
224
223
|
- MIT
|
224
|
+
metadata: {}
|
225
225
|
post_install_message:
|
226
226
|
rdoc_options: []
|
227
227
|
require_paths:
|
228
228
|
- lib
|
229
229
|
required_ruby_version: !ruby/object:Gem::Requirement
|
230
230
|
requirements:
|
231
|
-
- -
|
231
|
+
- - '>='
|
232
232
|
- !ruby/object:Gem::Version
|
233
|
-
|
234
|
-
- 0
|
235
|
-
hash: 2
|
236
|
-
version: !binary |-
|
237
|
-
MA==
|
238
|
-
none: false
|
233
|
+
version: '0'
|
239
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
240
235
|
requirements:
|
241
|
-
- -
|
236
|
+
- - '>='
|
242
237
|
- !ruby/object:Gem::Version
|
243
|
-
|
244
|
-
- 0
|
245
|
-
hash: 2
|
246
|
-
version: !binary |-
|
247
|
-
MA==
|
248
|
-
none: false
|
238
|
+
version: '0'
|
249
239
|
requirements: []
|
250
240
|
rubyforge_project:
|
251
|
-
rubygems_version:
|
241
|
+
rubygems_version: 2.0.3
|
252
242
|
signing_key:
|
253
|
-
specification_version:
|
243
|
+
specification_version: 4
|
254
244
|
summary: A very efficient and easy to use graph traversal engine.
|
255
245
|
test_files:
|
256
246
|
- spec/data/grateful-dead.xml
|
@@ -307,3 +297,4 @@ test_files:
|
|
307
297
|
- spec/support/use_transactions.rb
|
308
298
|
- spec/tackle/simple_mixin.rb
|
309
299
|
- spec/tackle/tinkerpop_graph_mixins.rb
|
300
|
+
has_rdoc:
|