pacer 0.9.1.1-java → 1.0.0-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 (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!