pacer 0.9.1.1-java → 1.0.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/.autotest +4 -1
  2. data/.gitignore +4 -0
  3. data/.rspec +1 -1
  4. data/Gemfile-dev +33 -0
  5. data/Gemfile-release +4 -0
  6. data/README.md +27 -9
  7. data/Rakefile +26 -8
  8. data/bin/autotest +1 -1
  9. data/lib/pacer/blueprints/multi_graph.rb +7 -19
  10. data/lib/pacer/blueprints/ruby_graph.rb +77 -52
  11. data/lib/pacer/blueprints/tg.rb +6 -93
  12. data/lib/pacer/blueprints.rb +0 -1
  13. data/lib/pacer/core/graph/edges_route.rb +10 -12
  14. data/lib/pacer/core/graph/element_route.rb +14 -21
  15. data/lib/pacer/core/graph/graph_index_route.rb +12 -8
  16. data/lib/pacer/core/graph/graph_route.rb +2 -5
  17. data/lib/pacer/core/graph/mixed_route.rb +3 -5
  18. data/lib/pacer/core/graph/vertices_route.rb +26 -27
  19. data/lib/pacer/core/route.rb +35 -66
  20. data/lib/pacer/exceptions.rb +13 -6
  21. data/lib/pacer/extensions/block_filter_element.rb +0 -5
  22. data/lib/pacer/filter/collection_filter.rb +9 -2
  23. data/lib/pacer/filter/empty_filter.rb +12 -3
  24. data/lib/pacer/filter/future_filter.rb +5 -5
  25. data/lib/pacer/filter/loop_filter.rb +7 -13
  26. data/lib/pacer/filter/object_filter.rb +10 -16
  27. data/lib/pacer/filter/property_filter/filters.rb +134 -93
  28. data/lib/pacer/filter/property_filter.rb +22 -19
  29. data/lib/pacer/filter/where_filter/node_visitor.rb +47 -26
  30. data/lib/pacer/filter/where_filter.rb +24 -3
  31. data/lib/pacer/function_resolver.rb +7 -2
  32. data/lib/pacer/graph/graph_ml.rb +39 -0
  33. data/lib/pacer/graph/graph_transactions_mixin.rb +107 -175
  34. data/lib/pacer/graph/pacer_graph.rb +438 -0
  35. data/lib/pacer/graph/simple_encoder.rb +20 -0
  36. data/lib/pacer/graph/yaml_encoder.rb +81 -0
  37. data/lib/pacer/graph.rb +8 -10
  38. data/lib/pacer/pipe/blackbox_pipeline.rb +11 -4
  39. data/lib/pacer/pipe/block_filter_pipe.rb +5 -22
  40. data/lib/pacer/pipe/cross_product_transform_pipe.rb +5 -7
  41. data/lib/pacer/pipe/edges_pipe.rb +22 -0
  42. data/lib/pacer/pipe/enumerable_pipe.rb +3 -9
  43. data/lib/pacer/pipe/expandable_pipe.rb +2 -14
  44. data/lib/pacer/pipe/id_collection_filter_pipe.rb +2 -8
  45. data/lib/pacer/pipe/is_empty_pipe.rb +5 -12
  46. data/lib/pacer/pipe/is_unique_pipe.rb +3 -13
  47. data/lib/pacer/pipe/label_collection_filter_pipe.rb +1 -7
  48. data/lib/pacer/pipe/label_prefix_pipe.rb +0 -6
  49. data/lib/pacer/pipe/loop_pipe.rb +27 -25
  50. data/lib/pacer/pipe/never_pipe.rb +1 -1
  51. data/lib/pacer/pipe/path_wrapping_pipe.rb +40 -0
  52. data/lib/pacer/pipe/process_pipe.rb +2 -20
  53. data/lib/pacer/pipe/property_comparison_pipe.rb +0 -6
  54. data/lib/pacer/pipe/ruby_pipe.rb +10 -3
  55. data/lib/pacer/pipe/simple_visitor_pipe.rb +12 -11
  56. data/lib/pacer/pipe/stream_sort_pipe.rb +1 -7
  57. data/lib/pacer/pipe/stream_uniq_pipe.rb +0 -6
  58. data/lib/pacer/pipe/type_filter_pipe.rb +1 -7
  59. data/lib/pacer/pipe/unary_transform_pipe.rb +6 -8
  60. data/lib/pacer/pipe/unwrapping_pipe.rb +13 -0
  61. data/lib/pacer/pipe/vertices_pipe.rb +22 -0
  62. data/lib/pacer/pipe/visitor_pipe.rb +3 -7
  63. data/lib/pacer/pipe/wrapping_pipe.rb +37 -0
  64. data/lib/pacer/pipes.rb +17 -12
  65. data/lib/pacer/route/mixin/bulk_operations.rb +8 -9
  66. data/lib/pacer/route/mixin/route_operations.rb +17 -11
  67. data/lib/pacer/route/mixins.rb +0 -1
  68. data/lib/pacer/route.rb +198 -121
  69. data/lib/pacer/side_effect/aggregate.rb +22 -2
  70. data/lib/pacer/side_effect/as.rb +73 -0
  71. data/lib/pacer/side_effect/group_count.rb +0 -3
  72. data/lib/pacer/side_effect/is_unique.rb +7 -6
  73. data/lib/pacer/side_effect.rb +1 -1
  74. data/lib/pacer/support/enumerable.rb +14 -12
  75. data/lib/pacer/support/nil_class.rb +5 -0
  76. data/lib/pacer/support/proc.rb +2 -2
  77. data/lib/pacer/support.rb +1 -1
  78. data/lib/pacer/transform/cap.rb +1 -1
  79. data/lib/pacer/transform/has_count_cap.rb +1 -1
  80. data/lib/pacer/transform/join.rb +20 -16
  81. data/lib/pacer/transform/map.rb +6 -2
  82. data/lib/pacer/transform/path.rb +44 -20
  83. data/lib/pacer/transform/sort_section.rb +58 -51
  84. data/lib/pacer/utils/tsort.rb +7 -2
  85. data/lib/pacer/utils.rb +0 -1
  86. data/lib/pacer/version.rb +4 -3
  87. data/lib/pacer/visitors/section.rb +42 -0
  88. data/lib/pacer/visitors/visits_section.rb +32 -0
  89. data/lib/pacer/visitors.rb +7 -0
  90. data/lib/pacer/wrappers/edge_wrapper.rb +164 -11
  91. data/lib/pacer/wrappers/element_wrapper.rb +133 -8
  92. data/lib/pacer/wrappers/index_wrapper.rb +47 -0
  93. data/lib/pacer/wrappers/vertex_wrapper.rb +175 -12
  94. data/lib/pacer/wrappers/wrapper_selector.rb +40 -0
  95. data/lib/pacer/wrappers/wrapping_pipe_function.rb +90 -0
  96. data/lib/pacer/wrappers.rb +3 -1
  97. data/lib/pacer-1.0.0-standalone.jar +0 -0
  98. data/lib/pacer.rb +13 -47
  99. data/pacer.gemspec +0 -8
  100. data/pom.xml +10 -3
  101. data/spec/pacer/blueprints/dex_spec.rb +12 -26
  102. data/spec/pacer/blueprints/neo4j_spec.rb +14 -28
  103. data/spec/pacer/blueprints/tg_spec.rb +6 -54
  104. data/spec/pacer/core/graph/edges_route_spec.rb +1 -1
  105. data/spec/pacer/core/graph/element_route_spec.rb +2 -2
  106. data/spec/pacer/core/graph/graph_route_spec.rb +2 -2
  107. data/spec/pacer/core/graph/vertices_route_spec.rb +10 -3
  108. data/spec/pacer/core/route_spec.rb +35 -58
  109. data/spec/pacer/filter/empty_filter_spec.rb +5 -6
  110. data/spec/pacer/filter/future_filter_spec.rb +8 -8
  111. data/spec/pacer/filter/loop_filter_spec.rb +120 -6
  112. data/spec/pacer/filter/object_filter_spec.rb +15 -0
  113. data/spec/pacer/filter/property_filter/filters_spec.rb +169 -0
  114. data/spec/pacer/filter/property_filter_spec.rb +15 -12
  115. data/spec/pacer/filter/uniq_filter_spec.rb +1 -1
  116. data/spec/pacer/filter/where_filter_spec.rb +55 -7
  117. data/spec/pacer/graph/{graph_mixin_spec.rb → pacer_graph_spec.rb} +114 -185
  118. data/spec/pacer/route/mixin/base_spec.rb +36 -35
  119. data/spec/pacer/route/mixin/route_operations_spec.rb +4 -46
  120. data/spec/pacer/side_effect/as_spec.rb +34 -0
  121. data/spec/pacer/support/enumerable_spec.rb +6 -6
  122. data/spec/pacer/transform/join_spec.rb +7 -5
  123. data/spec/pacer/transform/map_spec.rb +55 -0
  124. data/spec/pacer/transform/path_spec.rb +30 -15
  125. data/spec/pacer/transform/process_spec.rb +42 -0
  126. data/spec/pacer/transform/sort_section_spec.rb +82 -0
  127. data/spec/pacer/wrapper/edge_wrapper_spec.rb +122 -2
  128. data/spec/pacer/wrapper/element_wrapper_spec.rb +289 -3
  129. data/spec/pacer/wrapper/vertex_wrapper_spec.rb +289 -2
  130. data/spec/spec_helper.rb +16 -7
  131. data/spec/support/graph_runner.rb +80 -29
  132. data/tags +1165 -0
  133. metadata +46 -107
  134. data/.rvmrc +0 -0
  135. data/lib/pacer/blueprints/extensions.rb +0 -77
  136. data/lib/pacer/graph/edge_mixin.rb +0 -127
  137. data/lib/pacer/graph/element_mixin.rb +0 -202
  138. data/lib/pacer/graph/graph_indices_mixin.rb +0 -93
  139. data/lib/pacer/graph/graph_mixin.rb +0 -361
  140. data/lib/pacer/graph/index_mixin.rb +0 -30
  141. data/lib/pacer/graph/vertex_mixin.rb +0 -119
  142. data/lib/pacer/pipe/map_pipe.rb +0 -36
  143. data/lib/pacer/pipe/variable_store_iterator_wrapper.rb +0 -26
  144. data/lib/pacer/route/mixin/variable_route_module.rb +0 -26
  145. data/lib/pacer/side_effect/section.rb +0 -25
  146. data/lib/pacer/support/iterator_mixins.rb +0 -110
  147. data/lib/pacer/wrappers/new_element.rb +0 -106
  148. data/lib/pacer-0.9.1.1-standalone.jar +0 -0
  149. data/spec/pacer/graph/edge_mixin_spec.rb +0 -116
  150. data/spec/pacer/graph/element_mixin_spec.rb +0 -297
  151. data/spec/pacer/graph/index_mixin_spec.rb +0 -0
  152. data/spec/pacer/graph/vertex_mixin_spec.rb +0 -192
@@ -1,6 +1,6 @@
1
1
  module Pacer
2
- module Core
3
- module Route
2
+ module Routes
3
+ module RouteOperations
4
4
  def loop(&block)
5
5
  chain_route :filter => :loop, :looping_route => block
6
6
  end
@@ -16,7 +16,7 @@ module Pacer
16
16
  arg.to_enum(:times).inject(self) do |route_end, count|
17
17
  yield route_end
18
18
  end
19
- when Range
19
+ when Range
20
20
  if arg.exclude_end?
21
21
  range = arg.begin..(arg.end - 1)
22
22
  else
@@ -36,18 +36,12 @@ module Pacer
36
36
  r.while_description = "repeat #{ arg.inspect }"
37
37
  r
38
38
  else
39
- raise "Invalid repeat range"
39
+ fail ArgumentError, "Invalid repeat range"
40
40
  end
41
41
  end
42
42
  end
43
43
  end
44
44
 
45
- module ElementMixin
46
- def loop(&block)
47
- chain_route :filter => :loop, :looping_route => block
48
- end
49
- end
50
-
51
45
  module Filter
52
46
  module LoopFilter
53
47
  attr_reader :looping_route
@@ -61,8 +55,7 @@ module Pacer
61
55
  end
62
56
  end
63
57
 
64
- def while(yield_paths = false, &block)
65
- @yield_paths = yield_paths
58
+ def while(&block)
66
59
  @control_block = block
67
60
  self
68
61
  end
@@ -71,8 +64,9 @@ module Pacer
71
64
 
72
65
  def attach_pipe(end_pipe)
73
66
  unless @control_block
74
- raise 'No loop control block specified. Use either #while or #until after #loop.'
67
+ fail ClientError, 'No loop control block specified. Use either #while or #until after #loop.'
75
68
  end
69
+
76
70
  pipe = Pacer::Pipes::LoopPipe.new(graph, looping_pipe, @control_block)
77
71
  pipe.setStarts(end_pipe) if end_pipe
78
72
  pipe
@@ -2,30 +2,24 @@ module Pacer
2
2
  module Routes
3
3
  module RouteOperations
4
4
  def is(value)
5
- if value.nil? and graph and defined? Pacer::DexGraph and graph.is_a? Pacer::DexGraph
6
- # NOTE: This is a workaround for https://github.com/tinkerpop/blueprints/issues/178
7
- only(value)
5
+ if value.is_a? Symbol
6
+ chain_route :filter => :property, :block => proc { |v| v.vars[value] == v }
8
7
  else
9
- if value.is_a? Symbol
10
- chain_route :filter => :property, :block => proc { |v| v.vars[value] == v }
11
- else
12
- chain_route({ :filter => :object, :value => value })
13
- end
8
+ chain_route({ :filter => :object, :value => value })
14
9
  end
15
10
  end
16
11
 
17
12
  def is_not(value)
18
- if value.nil? and graph and defined? Pacer::DexGraph and graph.is_a? Pacer::DexGraph
19
- # NOTE: This is a workaround for https://github.com/tinkerpop/blueprints/issues/178
20
- except(value)
13
+ if value.is_a? Symbol
14
+ chain_route :filter => :property, :block => proc { |v| v.vars[value] != v }
21
15
  else
22
- if value.is_a? Symbol
23
- chain_route :filter => :property, :block => proc { |v| v.vars[value] != v }
24
- else
25
- chain_route({ :filter => :object, :value => value, :negate => true })
26
- end
16
+ chain_route({ :filter => :object, :value => value, :negate => true })
27
17
  end
28
18
  end
19
+
20
+ def compact
21
+ is_not nil
22
+ end
29
23
  end
30
24
  end
31
25
 
@@ -1,8 +1,40 @@
1
1
  module Pacer
2
2
  module Filter
3
+ class KeyIndex
4
+ attr_reader :graph, :element_type
5
+
6
+ def initialize(graph, element_type)
7
+ @graph = graph
8
+ @element_type = element_type
9
+ end
10
+
11
+ # FIXME: there is no count for key indices anymore. I'm counting
12
+ # up to 10 elements to try to find good indices, otherwise using
13
+ # anything...
14
+ def count(key, value)
15
+ iter = get(key, value).iterator
16
+ 10.times do |n|
17
+ if iter.hasNext
18
+ iter.next
19
+ else
20
+ return n
21
+ end
22
+ end
23
+ 1_000_000 # Random high number.
24
+ end
25
+
26
+ def get(key, value)
27
+ if element_type == :vertex
28
+ graph.blueprints_graph.getVertices(key, value)
29
+ else
30
+ graph.blueprints_graph.getEdges(key, value)
31
+ end
32
+ end
33
+ end
34
+
3
35
  module PropertyFilter
4
36
  class Filters
5
- attr_reader :properties, :extensions, :route_modules
37
+ attr_reader :properties, :extensions, :route_modules, :best_index_value
6
38
  attr_accessor :wrapper, :blocks
7
39
 
8
40
  # Allow Pacer to use index counts to determine which index has
@@ -25,11 +57,11 @@ module Pacer
25
57
  # @attr [Boolean] search_manual_indices
26
58
  attr_accessor :search_manual_indices
27
59
 
28
- protected
60
+ protected
29
61
 
30
62
  attr_accessor :non_ext_props
31
63
 
32
- public
64
+ public
33
65
 
34
66
  def initialize(filters)
35
67
  @properties = []
@@ -47,7 +79,7 @@ module Pacer
47
79
  # @note this is not threadsafe if you are reusing predefined
48
80
  # routes on multiple graphs.
49
81
  #
50
- # @attr [GraphMixin] g a graph
82
+ # @attr [PacerGraph] g a graph
51
83
  attr_reader :graph
52
84
 
53
85
  def graph=(g)
@@ -70,55 +102,6 @@ module Pacer
70
102
  end
71
103
  end
72
104
 
73
- def add_filter(filter, extension)
74
- case filter
75
- when Hash
76
- reset_properties
77
- filter.each do |k, v|
78
- self.non_ext_props << [k.to_s, v] unless extension
79
- self.properties << [k.to_s, v]
80
- end
81
- when Module, Class
82
- if filter.is_a? Class and filter.ancestors.include? Pacer::Wrappers::ElementWrapper
83
- self.wrapper = filter
84
- else
85
- self.extensions << filter
86
- end
87
- if filter.respond_to? :route_conditions
88
- add_filters filter.route_conditions, filter
89
- end
90
- if filter.respond_to? :route
91
- self.route_modules << filter
92
- end
93
- when Array
94
- add_filters(filter, extension)
95
- when nil
96
- else
97
- raise "Unknown filter: #{ filter.class }: #{ filter.inspect }"
98
- end
99
- end
100
-
101
- def add_filters(filters, extension)
102
- if filters.is_a? Array
103
- filters.each do |filter|
104
- add_filter filter, extension
105
- end
106
- else
107
- add_filter filters, extension
108
- end
109
- end
110
-
111
- def encode_value(value)
112
- value = graph.encode_property(value)
113
- if value.respond_to? :to_java
114
- jvalue = value.to_java
115
- elsif value.respond_to? :to_java_string
116
- jvalue = value.to_java_string
117
- else
118
- jvalue = value
119
- end
120
- end
121
-
122
105
  def build_pipeline(route, start_pipe, pipe = nil)
123
106
  self.graph = route.graph
124
107
  pipe ||= start_pipe
@@ -173,39 +156,77 @@ module Pacer
173
156
  result
174
157
  end
175
158
 
176
- protected
159
+ protected
160
+
161
+ def add_filter(filter, extension)
162
+ case filter
163
+ when Hash
164
+ reset_properties
165
+ filter.each do |k, v|
166
+ self.non_ext_props << [k.to_s, v] unless extension
167
+ self.properties << [k.to_s, v]
168
+ end
169
+ when Module, Class
170
+ if filter.is_a? Class and filter.ancestors.include? Pacer::Wrappers::ElementWrapper
171
+ self.wrapper = filter
172
+ else
173
+ self.extensions << filter
174
+ end
175
+ if filter.respond_to? :route_conditions
176
+ add_filters filter.route_conditions, filter
177
+ end
178
+ if filter.respond_to? :route
179
+ self.route_modules << filter
180
+ end
181
+ when Array
182
+ add_filters(filter, extension)
183
+ when nil
184
+ else
185
+ if filter.respond_to? :wrapper
186
+ self.wrapper = filter.wrapper
187
+ if filter.respond_to? :route_conditions
188
+ add_filters filter.route_conditions, filter
189
+ end
190
+ elsif filter.respond_to? :parts
191
+ self.extensions.concat filter.parts.to_a
192
+ if filter.respond_to? :route_conditions
193
+ add_filters filter.route_conditions, filter
194
+ end
195
+ else
196
+ raise "Unknown filter: #{ filter.class }: #{ filter.inspect }"
197
+ end
198
+ end
199
+ end
200
+
201
+ def add_filters(filters, extension)
202
+ if filters.is_a? Array
203
+ filters.each do |filter|
204
+ add_filter filter, extension
205
+ end
206
+ else
207
+ add_filter filters, extension
208
+ end
209
+ end
210
+
211
+ def encode_value(value)
212
+ value = graph.encode_property(value)
213
+ if value.respond_to? :to_java
214
+ jvalue = value.to_java
215
+ elsif value.respond_to? :to_java_string
216
+ jvalue = value.to_java_string
217
+ else
218
+ jvalue = value
219
+ end
220
+ end
177
221
 
178
222
  def find_best_index(element_type)
179
223
  return @best_index if @best_index
180
224
  avail = available_indices(element_type)
181
225
  return nil if avail.empty?
182
226
  index_options = []
183
- yield avail, index_options if block_given?
184
227
  properties.each do |k, v|
185
- if v.is_a? Hash
186
- v.each do |k2, v2|
187
- if (idxs = avail["name:#{k}"]).any?
188
- if choose_best_index
189
- idxs.each do |idx|
190
- index_options << [idx.count(k2, encode_value(v2)), [idx, k2, v2], [k, v]]
191
- end
192
- else
193
- @best_index_value = [k, v]
194
- return @best_index = [idxs.first, k2, v2]
195
- end
196
- end
197
- end
198
- elsif (idxs = (avail["key:#{k}"] + avail[:all])).any?
199
- if choose_best_index
200
- idxs.each do |idx|
201
- index_options << [idx.count(k, encode_value(v)), [idx, k, v], [k, v]]
202
- end
203
- else
204
- @best_index_value = [k, v]
205
- return @best_index = [idxs.first, k, v]
206
- end
207
- else
208
- nil
228
+ if index_for_property(avail, index_options, k, v)
229
+ return @best_index
209
230
  end
210
231
  end
211
232
  index_options = index_options.sort_by do |a|
@@ -223,6 +244,32 @@ module Pacer
223
244
  @best_index
224
245
  end
225
246
 
247
+ def index_for_property(avail, index_options, k, v)
248
+ if v.is_a? Hash
249
+ if (idxs = avail["name:#{k}"]).any?
250
+ v.each do |k2, v2|
251
+ return true if check_index(index_options, idxs, k2.to_s, v2, [k, v])
252
+ end
253
+ end
254
+ false
255
+ elsif (idxs = (avail["key:#{k}"] + avail[:all])).any?
256
+ true if check_index(index_options, idxs, k, v, [k, v])
257
+ end
258
+ end
259
+
260
+ def check_index(index_options, idxs, k, v, index_value)
261
+ if choose_best_index
262
+ idxs.each do |idx|
263
+ index_options << [idx.count(k, encode_value(v)), [idx, k, v], index_value]
264
+ end
265
+ false
266
+ else
267
+ @best_index_value = index_value
268
+ @best_index = [idxs.first, k, v]
269
+ true
270
+ end
271
+ end
272
+
226
273
  def reset_properties
227
274
  @encoded_properties = nil
228
275
  if @best_index_value
@@ -243,21 +290,15 @@ module Pacer
243
290
  def available_indices(element_type)
244
291
  return @available_indices if @available_indices
245
292
  @available_indices = Hash.new { |h, k| h[k] = [] }
246
- return @available_indices unless indices
247
- index_class = graph.index_class(element_type)
248
- indices.each do |index|
249
- next unless index.index_class == index_class
250
- if index.index_type == Pacer.automatic_index
251
- if keys = index.getAutoIndexKeys
252
- keys.each do |key|
253
- @available_indices["key:#{key}"] << index
254
- end
255
- else
256
- @available_indices[:all] << index
257
- end
258
- else
293
+ key_index = KeyIndex.new(graph, element_type)
294
+ graph.key_indices(element_type).each do |key|
295
+ @available_indices["key:#{key}"] = [key_index]
296
+ end
297
+ if search_manual_indices
298
+ indices.each do |index|
299
+ next unless graph.index_class? element_type, index.index_class
259
300
  @available_indices["name:#{index.index_name}"] = [index]
260
- @available_indices[:all] << index if search_manual_indices
301
+ @available_indices[:all] << index
261
302
  end
262
303
  end
263
304
  @available_indices
@@ -28,43 +28,48 @@ module Pacer
28
28
  filters.is_a? Pacer::Filter::PropertyFilter::Filters
29
29
  end
30
30
 
31
- def property_filter_before(base, filters, block)
32
- filters = Pacer::Route.edge_filters(filters)
31
+ def property_filter_before(base, args, block)
32
+ filters = Pacer::Route.edge_filters(args)
33
33
  filters.blocks = [block] if block
34
+ args = chain_args(filters)
34
35
  if filters.extensions_only? and base.is_a? Route
35
- base.wrapper ||= filters.wrapper if filters.wrapper
36
- base.add_extensions(filters.extensions)
37
- yield base
36
+ yield base.chain_route(args)
38
37
  elsif filters and filters.any?
39
- yield new(:back => base, :filter => :property, :filters => filters)
38
+ yield base.chain_route(args.merge!(filter: :property, filters: filters))
40
39
  else
41
40
  yield base
42
41
  end
43
42
  end
44
43
 
45
- def property_filter(base, filters, block)
46
- filters = Pacer::Route.edge_filters(filters)
44
+ def property_filter(base, args, block)
45
+ filters = Pacer::Route.edge_filters(args)
47
46
  filters.blocks = [block] if block
47
+ args = chain_args(filters)
48
48
  if filters.extensions_only? and base.is_a? Route
49
- base.wrapper ||= filters.wrapper if filters.wrapper
50
- base.add_extensions(filters.extensions)
51
- elsif filters and filters.any?
52
- new(:back => base, :filter => :property, :filters => filters)
53
- elsif Pacer.vertex? base
54
- new(:back => base, :pipe_class => Pacer::Pipes::IdentityPipe)
55
- elsif Pacer.edge? base
56
- new(:back => base, :pipe_class => Pacer::Pipes::IdentityPipe)
49
+ base.chain_route(args)
50
+ elsif filters.any?
51
+ base.chain_route(args.merge!(filter: :property, filters: filters))
52
+ elsif base.is_a? Pacer::Wrappers::ElementWrapper
53
+ base.chain_route({})
57
54
  else
58
55
  base
59
56
  end
60
57
  end
58
+
59
+ def chain_args(filters)
60
+ if filters.wrapper or (filters.extensions and not filters.extensions.empty?)
61
+ { extensions: filters.extensions, wrapper: filters.wrapper }
62
+ else
63
+ {}
64
+ end
65
+ end
61
66
  end
62
67
  end
63
68
 
64
69
  module Filter
65
70
  module PropertyFilter
66
71
  #import com.tinkerpop.pipes.filter.LabelCollectionFilterPipe
67
- import com.tinkerpop.pipes.filter.PropertyFilterPipe
72
+ import com.tinkerpop.gremlin.pipes.filter.PropertyFilterPipe
68
73
 
69
74
  def filters=(f)
70
75
  if f.is_a? Filters
@@ -72,8 +77,6 @@ module Pacer
72
77
  else
73
78
  @filters = EdgeFilters.new(f)
74
79
  end
75
- self.wrapper ||= f.wrapper if f.wrapper
76
- add_extensions f.extensions
77
80
  end
78
81
 
79
82
  # Return an array of filter options for the current route.
@@ -7,7 +7,7 @@ module Pacer
7
7
  import com.tinkerpop.pipes.filter.AndFilterPipe
8
8
  import com.tinkerpop.pipes.filter.OrFilterPipe
9
9
  import com.tinkerpop.pipes.filter.ObjectFilterPipe
10
- import com.tinkerpop.pipes.transform.PropertyPipe
10
+ import com.tinkerpop.gremlin.pipes.transform.PropertyPipe
11
11
  import com.tinkerpop.pipes.transform.HasCountPipe
12
12
  NeverPipe = Pacer::Pipes::NeverPipe
13
13
  IdentityPipe = Pacer::Pipes::IdentityPipe
@@ -34,11 +34,11 @@ module Pacer
34
34
  '>=' => FilterPipe::Filter::LESS_THAN_EQUAL
35
35
  )
36
36
 
37
- COMPARITORS = %w[ == != > < >= <= ]
37
+ COMPARATORS = %w[ == != > < >= <= ]
38
38
  METHODS = %w[ + - * / % ]
39
- REGEX_COMPARITORS = %w[ =~ !~ ]
39
+ REGEX_COMPARATORS = %w[ =~ !~ ]
40
40
 
41
- VALID_OPERATIONS = COMPARITORS + METHODS # + REGEX_COMPARITORS
41
+ VALID_OPERATIONS = COMPARATORS + METHODS # + REGEX_COMPARATORS
42
42
 
43
43
  class Pipe
44
44
  def initialize(pipe, *args)
@@ -118,7 +118,7 @@ module Pacer
118
118
  # TODO: support regex matches
119
119
 
120
120
  raise "Operation not supported: #{ name }" unless VALID_OPERATIONS.include? name
121
- if COMPARITORS.include? name
121
+ if COMPARATORS.include? name
122
122
  if a.is_a? Value and b.is_a? Value
123
123
  if a.value.send name, b.value
124
124
  Pipe.new IdentityPipe
@@ -139,11 +139,23 @@ module Pacer
139
139
  Pipe.new CrossProductTransformPipe, name, a, b
140
140
  end
141
141
  end
142
- end
142
+ end
143
+
144
+ def negate(pipe)
145
+ Pipe.new(Pipeline, pipe, Pipe.new(HasCountPipe, -1, 0), Pipe.new(ObjectFilterPipe, true, Filters['==']))
146
+ end
147
+
148
+ def comparable_pipe(pipe)
149
+ if pipe.pipe == PropertyPipe
150
+ build_comparison(pipe, Value.new(nil), '!=')
151
+ else
152
+ pipe
153
+ end
154
+ end
143
155
 
144
156
  def visitAndNode(node)
145
- a = node.first_node.accept(self)
146
- b = node.second_node.accept(self)
157
+ a = comparable_pipe node.first_node.accept(self)
158
+ b = comparable_pipe node.second_node.accept(self)
147
159
 
148
160
  if a.pipe == AndFilterPipe and b.pipe == AndFilterPipe
149
161
  Pipe.new AndFilterPipe, *a.args, *b.args
@@ -154,11 +166,11 @@ module Pacer
154
166
  else
155
167
  Pipe.new AndFilterPipe, a, b
156
168
  end
157
- end
169
+ end
158
170
 
159
171
  def visitArrayNode(node)
160
172
  Value.new Value.new(node.child_nodes.map { |n| n.accept self }).values!
161
- end
173
+ end
162
174
 
163
175
  def visitBignumNode(node)
164
176
  Value.new node.value.to_s
@@ -174,12 +186,16 @@ module Pacer
174
186
  if a.is_a? Value
175
187
  Value.new a.value.send(a.name)
176
188
  elsif a.pipe == PropertyPipe
177
- Pipe.new(UnaryTransformPipe, node.name, a)
189
+ if node.name == '!'
190
+ negate(comparable_pipe(a))
191
+ else
192
+ Pipe.new(UnaryTransformPipe, node.name, a)
193
+ end
178
194
  else
179
195
  case node.name
180
196
  when '!'
181
197
  # Special case for "a == 1 and not (b == 1)", etc.
182
- Pipe.new(Pipeline, a, Pipe.new(HasCountPipe, -1, 0), Pipe.new(ObjectFilterPipe, true, Filters['==']))
198
+ negate a
183
199
  else
184
200
  raise 'not sure'
185
201
  end
@@ -189,11 +205,11 @@ module Pacer
189
205
 
190
206
  def visitFalseNode(node)
191
207
  Pipe.new NeverPipe
192
- end
208
+ end
193
209
 
194
210
  def visitFixnumNode(node)
195
211
  Value.new node.value
196
- end
212
+ end
197
213
 
198
214
  def visitFloatNode(node)
199
215
  Value.new node.value
@@ -207,7 +223,7 @@ module Pacer
207
223
  a = Pipe.new PropertyPipe, node.name
208
224
  b = node.value_node.accept(self)
209
225
  build_comparison(a, b, '==')
210
- end
226
+ end
211
227
 
212
228
  def visitLocalVarNode(node)
213
229
  Pipe.new PropertyPipe, node.name
@@ -215,15 +231,16 @@ module Pacer
215
231
 
216
232
  def visitNewlineNode(node)
217
233
  node.next_node.accept(self)
218
- end
234
+ end
219
235
 
220
236
  def visitNilNode(node)
221
237
  Value.new nil
222
- end
238
+ end
223
239
 
224
240
  def visitOrNode(node)
225
- a = node.first_node.accept(self)
226
- b = node.second_node.accept(self)
241
+ a = comparable_pipe node.first_node.accept(self)
242
+ b = comparable_pipe node.second_node.accept(self)
243
+
227
244
  if a.pipe == OrFilterPipe and b.pipe == OrFilterPipe
228
245
  Pipe.new OrFilterPipe, *a.args, *b.args
229
246
  elsif a.pipe == OrFilterPipe
@@ -233,7 +250,7 @@ module Pacer
233
250
  else
234
251
  Pipe.new OrFilterPipe, a, b
235
252
  end
236
- end
253
+ end
237
254
 
238
255
  def visitRootNode(node)
239
256
  pipe = node.body_node.accept self
@@ -246,25 +263,29 @@ module Pacer
246
263
  Pipe.new NeverPipe
247
264
  end
248
265
  else
249
- Pipe.new AndFilterPipe, pipe
266
+ Pipe.new AndFilterPipe, comparable_pipe(pipe)
250
267
  end
251
- end
268
+ end
252
269
 
253
270
  def visitStrNode(node)
254
271
  Value.new node.value
255
- end
272
+ end
256
273
 
257
274
  def visitSymbolNode(node)
258
275
  Value.new values.fetch(node.name.to_sym, node.name.to_sym)
259
- end
276
+ end
260
277
 
261
278
  def visitTrueNode(node)
262
279
  Pipe.new IdentityPipe
263
- end
280
+ end
264
281
 
265
282
  def visitVCallNode(node)
266
283
  Pipe.new PropertyPipe, node.name
267
- end
284
+ end
285
+
286
+ def visitXStrNode(node)
287
+ Pipe.new PropertyPipe, node.value
288
+ end
268
289
 
269
290
  def visitYieldNode(node)
270
291
  block = node.args_node.child_nodes.first.accept(self)
@@ -1,10 +1,27 @@
1
1
  require 'pacer/filter/where_filter/node_visitor'
2
+ require 'jruby' # for JRuby.parse
2
3
 
3
4
  module Pacer
4
5
  module Routes
5
6
  module RouteOperations
6
- def where(str, values = {})
7
- chain_route :filter => :where, :where_statement => str, :values => values
7
+ def where(str, values = {}, *more, &block)
8
+ if str.is_a? String or str.is_a? Symbol
9
+ if str !~ /\A\s*\Z/
10
+ chain_route :filter => :where, :where_statement => str.to_s, :values => values
11
+ else
12
+ self
13
+ end
14
+ else
15
+ filter(str, values, *more, &block)
16
+ end
17
+ end
18
+
19
+ def unless(str, values = {})
20
+ if str and str !~ /\A\s*\Z/
21
+ where "not (#{str})", values
22
+ else
23
+ self
24
+ end
8
25
  end
9
26
  end
10
27
  end
@@ -24,7 +41,11 @@ module Pacer
24
41
  end
25
42
 
26
43
  def intermediate
27
- @intermediate ||= parsed.accept(NodeVisitor.new(self, values || {}))
44
+ encoded_values = {}
45
+ if values
46
+ values.each { |k, v| encoded_values[k.to_sym] = graph.encode_property(v) }
47
+ end
48
+ @intermediate ||= parsed.accept(NodeVisitor.new(self, encoded_values))
28
49
  end
29
50
 
30
51
  def build!