pacer 1.2.0-java → 1.3.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.
- 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:
|