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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +20 -1
  3. data/README.md +29 -15
  4. data/Rakefile +0 -1
  5. data/lib/pacer/core/graph/edges_route.rb +5 -5
  6. data/lib/pacer/core/graph/vertices_route.rb +7 -7
  7. data/lib/pacer/core/route.rb +39 -23
  8. data/lib/pacer/filter/collection_filter.rb +6 -5
  9. data/lib/pacer/filter/empty_filter.rb +1 -0
  10. data/lib/pacer/filter/loop_filter.rb +13 -2
  11. data/lib/pacer/filter/property_filter.rb +1 -1
  12. data/lib/pacer/filter/property_filter/filters.rb +1 -1
  13. data/lib/pacer/filter/uniq_section.rb +56 -0
  14. data/lib/pacer/filter/where_filter/node_visitor.rb +13 -12
  15. data/lib/pacer/graph/graph_ml.rb +4 -2
  16. data/lib/pacer/graph/graph_transactions_mixin.rb +26 -0
  17. data/lib/pacer/graph/pacer_graph.rb +1 -1
  18. data/lib/pacer/loader.rb +2 -1
  19. data/lib/pacer/pipe/collection_filter_pipe.rb +2 -0
  20. data/lib/pacer/pipe/id_collection_filter_pipe.rb +12 -2
  21. data/lib/pacer/pipe/loop_pipe.rb +1 -1
  22. data/lib/pacer/pipe/property_comparison_pipe.rb +6 -6
  23. data/lib/pacer/pipes.rb +5 -4
  24. data/lib/pacer/route/mixin/bulk_operations.rb +22 -21
  25. data/lib/pacer/support/enumerable.rb +0 -4
  26. data/lib/pacer/transform/identity.rb +10 -0
  27. data/lib/pacer/transform/lookup_ids.rb +2 -2
  28. data/lib/pacer/version.rb +3 -4
  29. data/lib/pacer/wrappers/edge_wrapper.rb +3 -1
  30. data/lib/pacer/wrappers/element_wrapper.rb +5 -3
  31. data/lib/pacer/wrappers/vertex_wrapper.rb +8 -2
  32. data/pom.xml +3 -30
  33. data/spec/pacer/blueprints/neo4j2_spec.rb +62 -0
  34. data/spec/pacer/blueprints/neo4j_spec.rb +6 -4
  35. data/spec/pacer/core/graph/graph_route_spec.rb +11 -3
  36. data/spec/pacer/core/route_spec.rb +1 -1
  37. data/spec/pacer/filter/empty_filter_spec.rb +1 -1
  38. data/spec/pacer/route/mixin/bulk_operations_spec.rb +11 -3
  39. data/spec/pacer/wrapper/element_wrapper_spec.rb +15 -15
  40. data/spec/pacer/wrapper/vertex_wrapper_spec.rb +4 -4
  41. data/spec/spec_helper.rb +5 -4
  42. data/spec/support/graph_runner.rb +11 -0
  43. data/spec/support/use_transactions.rb +4 -0
  44. metadata +7 -4
  45. data/lib/pacer/support/array.rb +0 -18
@@ -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.send :creating_elements do
21
- com.tinkerpop.blueprints.util.io.graphml.GraphMLReader.input_graph graph.blueprints_graph, stream
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
@@ -204,7 +204,7 @@ module Pacer
204
204
  end
205
205
 
206
206
  def features
207
- blueprints_graph.features
207
+ blueprints_graph.getFeatures
208
208
  end
209
209
 
210
210
  def inspect
@@ -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
- @comparison = comparison
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 @comparison == Pacer::Pipes::EQUAL
20
+ if contains_in
11
21
  while true
12
22
  element = @starts.next
13
23
  if element and @ids.include? element.getId
@@ -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 FilterPipe::Filter::EQUAL
18
+ when Compare::EQUAL
19
19
  return obj if l == r
20
- when FilterPipe::Filter::NOT_EQUAL
20
+ when Compare::NOT_EQUAL
21
21
  return obj if l != r
22
- when FilterPipe::Filter::GREATER_THAN
22
+ when Compare::GREATER_THAN
23
23
  return obj if l and r and l > r
24
- when FilterPipe::Filter::LESS_THAN
24
+ when Compare::LESS_THAN
25
25
  return obj if l and r and l < r
26
- when FilterPipe::Filter::GREATER_THAN_EQUAL
26
+ when Compare::GREATER_THAN_EQUAL
27
27
  return obj if l and r and l >= r
28
- when FilterPipe::Filter::LESS_THAN_EQUAL
28
+ when Compare::LESS_THAN_EQUAL
29
29
  return obj if l and r and l <= r
30
30
  end
31
31
  end
@@ -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.gremlin.pipes.transform.IdPipe
15
- import com.tinkerpop.gremlin.pipes.transform.PropertyPipe
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
- EQUAL = FilterPipe::Filter::EQUAL
22
- NOT_EQUAL = FilterPipe::Filter::NOT_EQUAL
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
- if target_graph and not target_graph.in_bulk_job?
23
- begin
24
- target_graph.in_bulk_job = true
25
- size ||= target_graph.bulk_job_size
26
- counter = 0
27
- target_graph.transaction(nesting: true) do |commit, rollback|
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
- print " #{counter}" if Pacer.verbose?
31
- counter += size
32
- slice.each do |element|
33
- yield element
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
- ensure
40
- puts '!' if Pacer.verbose?
41
- target_graph.in_bulk_job = false
42
- end
43
- elsif target_graph
44
- each do |element|
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
  #
@@ -0,0 +1,10 @@
1
+ module Pacer
2
+ module Routes
3
+ module RouteOperations
4
+ def identity
5
+ chain_route route_name: 'identity', pipe_class: com.tinkerpop.pipes.IdentityPipe
6
+ end
7
+ end
8
+ end
9
+ end
10
+
@@ -16,8 +16,8 @@ module Pacer
16
16
 
17
17
  module Transform
18
18
  module LookupIds
19
- import com.tinkerpop.gremlin.pipes.transform.IdVertexPipe
20
- import com.tinkerpop.gremlin.pipes.transform.IdEdgePipe
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
@@ -1,14 +1,13 @@
1
1
  module Pacer
2
2
  unless const_defined? :VERSION
3
- VERSION = "1.4.2"
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.3.0"
11
- PIPES_VERSION = "2.3.0"
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
- "#<E[#{element_id}]:#{display_name}>"
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
- value = graph.encode_property(value)
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 as?(*exts)
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
- "#<#{ ["V[#{element_id}]", display_name].compact.join(' ') }>"
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.3.0</blueprints.version>
11
- <gem.version>1.4.2</gem.version>
12
- <pipes.version>2.3.0</pipes.version>
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