pacer 1.4.2-java → 1.5.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 +4 -4
- data/Gemfile +20 -1
- data/README.md +29 -15
- data/Rakefile +0 -1
- data/lib/pacer/core/graph/edges_route.rb +5 -5
- data/lib/pacer/core/graph/vertices_route.rb +7 -7
- data/lib/pacer/core/route.rb +39 -23
- data/lib/pacer/filter/collection_filter.rb +6 -5
- data/lib/pacer/filter/empty_filter.rb +1 -0
- data/lib/pacer/filter/loop_filter.rb +13 -2
- data/lib/pacer/filter/property_filter.rb +1 -1
- data/lib/pacer/filter/property_filter/filters.rb +1 -1
- data/lib/pacer/filter/uniq_section.rb +56 -0
- data/lib/pacer/filter/where_filter/node_visitor.rb +13 -12
- data/lib/pacer/graph/graph_ml.rb +4 -2
- data/lib/pacer/graph/graph_transactions_mixin.rb +26 -0
- data/lib/pacer/graph/pacer_graph.rb +1 -1
- data/lib/pacer/loader.rb +2 -1
- data/lib/pacer/pipe/collection_filter_pipe.rb +2 -0
- data/lib/pacer/pipe/id_collection_filter_pipe.rb +12 -2
- data/lib/pacer/pipe/loop_pipe.rb +1 -1
- data/lib/pacer/pipe/property_comparison_pipe.rb +6 -6
- data/lib/pacer/pipes.rb +5 -4
- data/lib/pacer/route/mixin/bulk_operations.rb +22 -21
- data/lib/pacer/support/enumerable.rb +0 -4
- data/lib/pacer/transform/identity.rb +10 -0
- data/lib/pacer/transform/lookup_ids.rb +2 -2
- data/lib/pacer/version.rb +3 -4
- data/lib/pacer/wrappers/edge_wrapper.rb +3 -1
- data/lib/pacer/wrappers/element_wrapper.rb +5 -3
- data/lib/pacer/wrappers/vertex_wrapper.rb +8 -2
- data/pom.xml +3 -30
- data/spec/pacer/blueprints/neo4j2_spec.rb +62 -0
- data/spec/pacer/blueprints/neo4j_spec.rb +6 -4
- data/spec/pacer/core/graph/graph_route_spec.rb +11 -3
- data/spec/pacer/core/route_spec.rb +1 -1
- data/spec/pacer/filter/empty_filter_spec.rb +1 -1
- data/spec/pacer/route/mixin/bulk_operations_spec.rb +11 -3
- data/spec/pacer/wrapper/element_wrapper_spec.rb +15 -15
- data/spec/pacer/wrapper/vertex_wrapper_spec.rb +4 -4
- data/spec/spec_helper.rb +5 -4
- data/spec/support/graph_runner.rb +11 -0
- data/spec/support/use_transactions.rb +4 -0
- metadata +7 -4
- data/lib/pacer/support/array.rb +0 -18
data/lib/pacer/graph/graph_ml.rb
CHANGED
@@ -17,8 +17,10 @@ module Pacer
|
|
17
17
|
rescue java.net.MalformedURLException
|
18
18
|
stream = java.io.FileInputStream.new path
|
19
19
|
end
|
20
|
-
graph.
|
21
|
-
|
20
|
+
graph.transaction(nesting: true) do
|
21
|
+
graph.send :creating_elements do
|
22
|
+
com.tinkerpop.blueprints.util.io.graphml.GraphMLReader.input_graph graph.blueprints_graph, stream
|
23
|
+
end
|
22
24
|
end
|
23
25
|
true
|
24
26
|
ensure
|
@@ -6,6 +6,10 @@ module Pacer
|
|
6
6
|
threadlocal_graph_info.fetch(:tx_depth, 0) > 0
|
7
7
|
end
|
8
8
|
|
9
|
+
def in_read_transaction?
|
10
|
+
threadlocal_graph_info.fetch(:read_tx_depth, 0) > 0
|
11
|
+
end
|
12
|
+
|
9
13
|
# Basic usage:
|
10
14
|
#
|
11
15
|
# graph.transaction do |commit, rollback|
|
@@ -47,6 +51,24 @@ module Pacer
|
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
def read_transaction
|
55
|
+
tgi = threadlocal_graph_info
|
56
|
+
read_tx_depth = tgi[:read_tx_depth] ||= 0
|
57
|
+
tgi[:read_tx_depth] += 1
|
58
|
+
# Blueprints auto-starts the transaction
|
59
|
+
yield
|
60
|
+
ensure
|
61
|
+
rtd = tgi[:read_tx_depth] -= 1
|
62
|
+
if rtd == 0 and tgi[:tx_depth] == 0 and blueprints_graph.is_a? TransactionalGraph
|
63
|
+
# rollback after the bottom read transaction (no changes outside a real transaction block should have been possible)
|
64
|
+
blueprints_graph.stopTransaction TransactionalGraph::Conclusion::FAILURE
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def reopen_read_transaction
|
69
|
+
# override this implementation-specific hook if needed (see pacer-neo4j)
|
70
|
+
end
|
71
|
+
|
50
72
|
# Set this to true if you don't want to use transactions.
|
51
73
|
#
|
52
74
|
# By default, transactions are enabled.
|
@@ -71,6 +93,8 @@ module Pacer
|
|
71
93
|
commit_implicit_transaction
|
72
94
|
when :rollback
|
73
95
|
rollback_implicit_transaction
|
96
|
+
else
|
97
|
+
fail Pacer::ClientError, "invalid value for #implicit_transaction: #{ implicit_transaction.inspect }"
|
74
98
|
end
|
75
99
|
end
|
76
100
|
|
@@ -135,11 +159,13 @@ module Pacer
|
|
135
159
|
end
|
136
160
|
puts "transaction committed" if Pacer.verbose == :very
|
137
161
|
blueprints_graph.stopTransaction TransactionalGraph::Conclusion::SUCCESS
|
162
|
+
reopen_read_transaction
|
138
163
|
on_commit_block.call if on_commit_block
|
139
164
|
end
|
140
165
|
rollback = ->(message = nil) do
|
141
166
|
puts ["transaction rolled back", message].compact.join(': ') if Pacer.verbose == :very
|
142
167
|
blueprints_graph.stopTransaction TransactionalGraph::Conclusion::FAILURE
|
168
|
+
reopen_read_transaction
|
143
169
|
end
|
144
170
|
[commit, rollback]
|
145
171
|
end
|
data/lib/pacer/loader.rb
CHANGED
@@ -53,7 +53,6 @@ require 'pacer/blueprints/group_vertex'
|
|
53
53
|
|
54
54
|
require 'pacer/blueprints/payload_elements'
|
55
55
|
|
56
|
-
require 'pacer/support/array'
|
57
56
|
require 'pacer/support/array_list'
|
58
57
|
require 'pacer/support/enumerable'
|
59
58
|
require 'pacer/support/proc'
|
@@ -79,7 +78,9 @@ require 'pacer/filter/block_filter'
|
|
79
78
|
require 'pacer/filter/object_filter'
|
80
79
|
require 'pacer/filter/random_filter'
|
81
80
|
require 'pacer/filter/limit_section_filter'
|
81
|
+
require 'pacer/filter/uniq_section'
|
82
82
|
|
83
|
+
require 'pacer/transform/identity'
|
83
84
|
require 'pacer/transform/branch'
|
84
85
|
require 'pacer/transform/cap'
|
85
86
|
require 'pacer/transform/stream_sort'
|
@@ -4,6 +4,8 @@ module Pacer
|
|
4
4
|
AbstractCollectionFilterPipe = com.tinkerpop.pipes.filter.CollectionFilterPipe
|
5
5
|
end
|
6
6
|
|
7
|
+
# This seemingly-useless class only exists because the class in Pipes
|
8
|
+
# is marked abstract despite being complete.
|
7
9
|
class CollectionFilterPipe < Renamed::AbstractCollectionFilterPipe
|
8
10
|
end
|
9
11
|
end
|
@@ -1,13 +1,23 @@
|
|
1
1
|
module Pacer::Pipes
|
2
2
|
class IdCollectionFilterPipe < RubyPipe
|
3
|
+
import com.tinkerpop.blueprints.Contains
|
4
|
+
attr_reader :contains_in
|
5
|
+
|
3
6
|
def initialize(ids, comparison)
|
4
7
|
super()
|
5
8
|
@ids = Set[*ids]
|
6
|
-
|
9
|
+
if comparison == Contains::IN
|
10
|
+
@contains_in = true
|
11
|
+
elsif
|
12
|
+
comparison == Contains::NOT_IN
|
13
|
+
@contains_in = false
|
14
|
+
else
|
15
|
+
fail InternalError, "Unknown comparison type for ID collection filter"
|
16
|
+
end
|
7
17
|
end
|
8
18
|
|
9
19
|
def processNextStart
|
10
|
-
if
|
20
|
+
if contains_in
|
11
21
|
while true
|
12
22
|
element = @starts.next
|
13
23
|
if element and @ids.include? element.getId
|
data/lib/pacer/pipe/loop_pipe.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Pacer::Pipes
|
2
2
|
class LoopPipe < RubyPipe
|
3
3
|
import java.util.ArrayList
|
4
|
+
BlueprintsGraph = com.tinkerpop.blueprints.Graph
|
4
5
|
|
5
6
|
def initialize(graph, looping_pipe, control_block)
|
6
7
|
super()
|
@@ -42,7 +43,6 @@ module Pacer::Pipes
|
|
42
43
|
|
43
44
|
def processNextStart
|
44
45
|
while true
|
45
|
-
# FIXME: hasNext shouldn't be raising an exception...
|
46
46
|
has_next = looping_pipe.hasNext
|
47
47
|
if has_next
|
48
48
|
element = looping_pipe.next
|
@@ -15,17 +15,17 @@ module Pacer::Pipes
|
|
15
15
|
l = obj.getProperty(@left)
|
16
16
|
r = obj.getProperty(@right)
|
17
17
|
case @filter
|
18
|
-
when
|
18
|
+
when Compare::EQUAL
|
19
19
|
return obj if l == r
|
20
|
-
when
|
20
|
+
when Compare::NOT_EQUAL
|
21
21
|
return obj if l != r
|
22
|
-
when
|
22
|
+
when Compare::GREATER_THAN
|
23
23
|
return obj if l and r and l > r
|
24
|
-
when
|
24
|
+
when Compare::LESS_THAN
|
25
25
|
return obj if l and r and l < r
|
26
|
-
when
|
26
|
+
when Compare::GREATER_THAN_EQUAL
|
27
27
|
return obj if l and r and l >= r
|
28
|
-
when
|
28
|
+
when Compare::LESS_THAN_EQUAL
|
29
29
|
return obj if l and r and l <= r
|
30
30
|
end
|
31
31
|
end
|
data/lib/pacer/pipes.rb
CHANGED
@@ -11,15 +11,16 @@ module Pacer
|
|
11
11
|
import com.tinkerpop.pipes.filter.RangeFilterPipe
|
12
12
|
import com.tinkerpop.pipes.filter.FilterPipe
|
13
13
|
|
14
|
-
import com.tinkerpop.
|
15
|
-
import com.tinkerpop.
|
14
|
+
import com.tinkerpop.pipes.transform.IdPipe
|
15
|
+
import com.tinkerpop.pipes.transform.PropertyPipe
|
16
16
|
|
17
17
|
IN = com.tinkerpop.blueprints.Direction::IN
|
18
18
|
OUT = com.tinkerpop.blueprints.Direction::OUT
|
19
19
|
BOTH = com.tinkerpop.blueprints.Direction::BOTH
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
import com.tinkerpop.blueprints.Compare
|
22
|
+
EQUAL = Compare::EQUAL
|
23
|
+
NOT_EQUAL = Compare::NOT_EQUAL
|
23
24
|
#GREATER_THAN, LESS_THAN, GREATER_THAN_EQUAL, LESS_THAN_EQUAL
|
24
25
|
end
|
25
26
|
|
@@ -19,33 +19,34 @@ module Pacer::Routes
|
|
19
19
|
# +size+ records.
|
20
20
|
def bulk_job(size = nil, target_graph = nil, pre_commit = nil)
|
21
21
|
target_graph ||= graph
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
graph.read_transaction do
|
23
|
+
if target_graph and not target_graph.in_bulk_job?
|
24
|
+
begin
|
25
|
+
target_graph.in_bulk_job = true
|
26
|
+
size ||= target_graph.bulk_job_size
|
27
|
+
counter = 0
|
28
28
|
print "Bulk job ->" if Pacer.verbose?
|
29
29
|
each_slice(size) do |slice|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
target_graph.transaction(nesting: true) do
|
31
|
+
print " #{counter}" if Pacer.verbose?
|
32
|
+
counter += size
|
33
|
+
slice.each do |element|
|
34
|
+
yield element
|
35
|
+
end
|
36
|
+
pre_commit.call if pre_commit
|
34
37
|
end
|
35
|
-
pre_commit.call if pre_commit
|
36
|
-
commit.call
|
37
38
|
end
|
39
|
+
ensure
|
40
|
+
puts '!' if Pacer.verbose?
|
41
|
+
target_graph.in_bulk_job = false
|
38
42
|
end
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
yield element
|
43
|
+
elsif target_graph
|
44
|
+
each do |element|
|
45
|
+
yield element
|
46
|
+
end
|
47
|
+
else
|
48
|
+
raise 'No graph in route for bulk job'
|
46
49
|
end
|
47
|
-
else
|
48
|
-
raise 'No graph in route for bulk job'
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -47,10 +47,6 @@ module Enumerable
|
|
47
47
|
Pacer::Pipes::EnumerablePipe.new self
|
48
48
|
end
|
49
49
|
|
50
|
-
def +(other)
|
51
|
-
Pacer::Pipes::MultiPipe.new [self, other]
|
52
|
-
end
|
53
|
-
|
54
50
|
# NOTE: if this is a collection of wrapped vertices or edges, Java pipes
|
55
51
|
# may crash with something like:
|
56
52
|
#
|
@@ -16,8 +16,8 @@ module Pacer
|
|
16
16
|
|
17
17
|
module Transform
|
18
18
|
module LookupIds
|
19
|
-
import com.tinkerpop.
|
20
|
-
import com.tinkerpop.
|
19
|
+
import com.tinkerpop.pipes.transform.IdVertexPipe
|
20
|
+
import com.tinkerpop.pipes.transform.IdEdgePipe
|
21
21
|
|
22
22
|
def attach_pipe(end_pipe)
|
23
23
|
fail ClientError, 'Can not look up elements without the graph' unless graph
|
data/lib/pacer/version.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
module Pacer
|
2
2
|
unless const_defined? :VERSION
|
3
|
-
VERSION = "1.
|
3
|
+
VERSION = "1.5.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.3.0"
|
10
|
+
BLUEPRINTS_VERSION = "2.6.0-SNAPSHOT"
|
11
|
+
PIPES_VERSION = "2.5.0"
|
13
12
|
end
|
14
13
|
end
|
@@ -87,7 +87,9 @@ module Pacer::Wrappers
|
|
87
87
|
# standard ruby console representation of an instantiated object.
|
88
88
|
# @return [String]
|
89
89
|
def inspect
|
90
|
-
|
90
|
+
graph.read_transaction do
|
91
|
+
"#<E[#{element_id}]:#{display_name}>"
|
92
|
+
end
|
91
93
|
end
|
92
94
|
|
93
95
|
# Returns the display name of the edge.
|
@@ -122,15 +122,17 @@ module Pacer::Wrappers
|
|
122
122
|
# @param [#to_s] key the property name
|
123
123
|
# @param [Object] value the value to set the property to
|
124
124
|
def []=(key, value)
|
125
|
-
|
125
|
+
begin
|
126
|
+
value = graph.encode_property(value)
|
127
|
+
rescue Exception => e
|
128
|
+
throw Pacer::ClientError.new "Unable to serialize #{ key }: #{ value.class }"
|
129
|
+
end
|
126
130
|
key = key.to_s
|
127
131
|
if value
|
128
132
|
element.setProperty(key, value)
|
129
133
|
else
|
130
134
|
element.removeProperty(key)
|
131
135
|
end
|
132
|
-
rescue Exception => e
|
133
|
-
throw Pacer::ClientError.new "Unable to serialize #{ key }: #{ value.class }"
|
134
136
|
end
|
135
137
|
|
136
138
|
# Specialize result to return self for elements.
|
@@ -75,7 +75,11 @@ module Pacer::Wrappers
|
|
75
75
|
# @yield [v] Optional block yields the vertex with the extensions added.
|
76
76
|
# @return nil or the result of the block or the extended vertex
|
77
77
|
def as(*exts)
|
78
|
-
if
|
78
|
+
if exts.length == 1 and not exts.first.is_a?(Module) and not exts.first.is_a?(Class) and exts.first
|
79
|
+
# NB: oops, I defined route#as to be the same as route#section. If the signature is
|
80
|
+
# matching the section method, then defer to it.
|
81
|
+
section *exts
|
82
|
+
elsif as?(*exts)
|
79
83
|
exts_to_add = extensions_missing(exts)
|
80
84
|
extended = exts_to_add.empty? ? self : add_extensions(exts_to_add)
|
81
85
|
if block_given?
|
@@ -113,7 +117,9 @@ module Pacer::Wrappers
|
|
113
117
|
# standard ruby console representation of an instantiated object.
|
114
118
|
# @return [String]
|
115
119
|
def inspect
|
116
|
-
|
120
|
+
graph.read_transaction do
|
121
|
+
"#<#{ ["V[#{element_id}]", display_name].compact.join(' ') }>"
|
122
|
+
end
|
117
123
|
end
|
118
124
|
|
119
125
|
# Returns the display name of the vertex.
|
data/pom.xml
CHANGED
@@ -7,10 +7,9 @@
|
|
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.3.0</gremlin.version>
|
10
|
+
<blueprints.version>2.6.0-SNAPSHOT</blueprints.version>
|
11
|
+
<gem.version>1.5.1</gem.version>
|
12
|
+
<pipes.version>2.5.0</pipes.version>
|
14
13
|
</properties>
|
15
14
|
<!-- NOTE: the following properties are automatically updated based on the values in lib/pacer-neo4j/version.rb -->
|
16
15
|
<version>${gem.version}</version>
|
@@ -41,34 +40,8 @@
|
|
41
40
|
<artifactId>pipes</artifactId>
|
42
41
|
<version>${pipes.version}</version>
|
43
42
|
</dependency>
|
44
|
-
<!-- MOAR GRAPH TRAVERSAL SUPPORT -->
|
45
|
-
<dependency>
|
46
|
-
<groupId>com.tinkerpop.gremlin</groupId>
|
47
|
-
<artifactId>gremlin-java</artifactId>
|
48
|
-
<version>${gremlin.version}</version>
|
49
|
-
</dependency>
|
50
43
|
</dependencies>
|
51
44
|
|
52
|
-
<repositories>
|
53
|
-
<repository>
|
54
|
-
<id>tinkerpop-repository</id>
|
55
|
-
<name>TinkerPop Maven2 Repository</name>
|
56
|
-
<url>http://tinkerpop.com/maven2</url>
|
57
|
-
<snapshots>
|
58
|
-
<enabled>true</enabled>
|
59
|
-
<updatePolicy>always</updatePolicy>
|
60
|
-
</snapshots>
|
61
|
-
</repository>
|
62
|
-
</repositories>
|
63
|
-
|
64
|
-
<distributionManagement>
|
65
|
-
<repository>
|
66
|
-
<id>tinkerpop-repository</id>
|
67
|
-
<name>TinkerPop Maven2 Repository</name>
|
68
|
-
<url>ftp://ftp.tinkerpop.com:21/public/maven2/</url>
|
69
|
-
</repository>
|
70
|
-
</distributionManagement>
|
71
|
-
|
72
45
|
<build>
|
73
46
|
<directory>${basedir}/target</directory>
|
74
47
|
<finalName>${project.artifactId}-${project.version}</finalName>
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Neo2Spec
|
4
|
+
class Person < Pacer::Wrappers::VertexWrapper
|
5
|
+
def self.route_conditions(graph)
|
6
|
+
{ type: 'person' }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Frog < Pacer::Wrappers::VertexWrapper
|
11
|
+
def self.route_conditions(graph)
|
12
|
+
{ frog: 'yes' }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Run.neo4j2 :read_only do
|
17
|
+
use_pacer_graphml_data :read_only
|
18
|
+
|
19
|
+
describe '#vertex' do
|
20
|
+
it 'should not raise an exception for invalid key type' do
|
21
|
+
graph.vertex('bad id').should be_nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#edge' do
|
26
|
+
it 'should not raise an exception for invalid key type' do
|
27
|
+
graph.edge('bad id').should be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'indexed' do
|
32
|
+
before do
|
33
|
+
# TODO FIXME: why do the presence of these key indices break lots of
|
34
|
+
# subsequent tests if they are on graph rather than graph2?
|
35
|
+
graph2.create_key_index :type, :vertex
|
36
|
+
graph2.create_key_index :name, :vertex
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Person do
|
40
|
+
subject { graph2.v(Person) }
|
41
|
+
|
42
|
+
# sanity checks
|
43
|
+
it { should be_a Pacer::Filter::LuceneFilter }
|
44
|
+
its(:query) { should == 'type:"person"' }
|
45
|
+
# This doesn't work because neo indices are out of sync before the transaction finalizes
|
46
|
+
#its(:count) { should == 2 }
|
47
|
+
|
48
|
+
its(:wrapper) { should == Person }
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Frog do
|
52
|
+
subject { graph2.v(Frog) }
|
53
|
+
|
54
|
+
# sanity checks
|
55
|
+
it { should_not be_a Pacer::Filter::LuceneFilter }
|
56
|
+
its(:count) { should == 0 }
|
57
|
+
|
58
|
+
its(:wrapper) { should == Frog }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|