pacer 1.4.2-java → 1.5.1-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|