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
@@ -2,19 +2,20 @@ module Pacer::Wrappers
2
2
  class EdgeWrapper < ElementWrapper
3
3
  include Pacer::Edge
4
4
  include Pacer::Core::Graph::EdgesRoute
5
- include Pacer::ElementMixin
6
- include Pacer::EdgeMixin
7
5
 
8
6
  def_delegators :@element,
9
7
  :getId, :getLabel, :getPropertyKeys, :getProperty, :setProperty, :removeProperty,
10
- :getInVertex, :getOutVertex,
11
- :getRawEdge,
12
- :graph, :graph=, :<=>, :==
8
+ :getVertex,
9
+ :getRawEdge
13
10
 
14
11
  class << self
15
12
  def wrapper_for(exts)
16
13
  @wrappers = {} unless defined? @wrappers
17
- @wrappers[exts.to_set] ||= build_edge_wrapper(exts)
14
+ if exts
15
+ @wrappers[exts.to_set] ||= build_edge_wrapper(exts)
16
+ else
17
+ fail Pacer::LogicError, "Extensions should not be nil"
18
+ end
18
19
  end
19
20
 
20
21
  def clear_cache
@@ -30,22 +31,174 @@ module Pacer::Wrappers
30
31
 
31
32
  # This method must be defined here rather than in the superclass in order
32
33
  # to correctly override the method in an included module
33
- def extensions
34
- self.class.extensions
34
+ attr_reader :element
35
+
36
+ def label
37
+ getLabel
38
+ end
39
+
40
+ # The incoming vertex for this edge.
41
+ # @return [Pacer::Wrappers::VertexWrapper]
42
+ def in_vertex(extensions = nil)
43
+ v = element.getVertex Pacer::Pipes::IN
44
+ if extensions.is_a? Enumerable
45
+ v = VertexWrapper.wrapper_for(extensions).new v
46
+ elsif extensions
47
+ v = VertexWrapper.wrapper_for([extensions]).new v
48
+ else
49
+ v = VertexWrapper.new v
50
+ end
51
+ v.graph = graph
52
+ v
53
+ end
54
+
55
+ # The outgoing vertex for this edge.
56
+ # @return [Pacer::Wrappers::VertexWrapper]
57
+ def out_vertex(extensions = nil)
58
+ v = element.getVertex Pacer::Pipes::OUT
59
+ if extensions.is_a? Enumerable
60
+ v = VertexWrapper.wrapper_for(extensions).new v
61
+ elsif extensions
62
+ v = VertexWrapper.wrapper_for([extensions]).new v
63
+ else
64
+ v = VertexWrapper.new v
65
+ end
66
+ v.graph = graph
67
+ v
35
68
  end
36
69
 
37
70
  # This method must be defined here rather than in the superclass in order
38
71
  # to correctly override the method in an included module
39
- def element
40
- @element
72
+ def extensions
73
+ self.class.extensions
41
74
  end
42
75
 
76
+ # Add extensions to this edge.
77
+ #
78
+ # If any extension has a Edge module within it, this edge will
79
+ # be extended with the extension's Edge module.
80
+ #
81
+ # @param [[extensions]] exts the extensions to add
82
+ # @return [Pacer::Wrappers::EdgeWrapper] this edge wrapped up and including
83
+ # the extensions
43
84
  def add_extensions(exts)
44
85
  if exts.any?
45
- self.class.wrap(element, extensions + exts.to_a)
86
+ e = self.class.wrap(element, extensions + exts.to_a)
87
+ e.graph = graph
88
+ e
46
89
  else
47
90
  self
48
91
  end
49
92
  end
93
+
94
+ # Returns the element with a new simple wrapper.
95
+ # @return [EdgeWrapper]
96
+ def no_extensions
97
+ EdgeWrapper.new element
98
+ end
99
+
100
+ # Returns a human-readable representation of the edge using the
101
+ # standard ruby console representation of an instantiated object.
102
+ # @return [String]
103
+ def inspect
104
+ "#<E[#{element_id}]:#{display_name}>"
105
+ end
106
+
107
+ # Returns the display name of the edge.
108
+ # @return [String]
109
+ def display_name
110
+ if graph and graph.edge_name
111
+ graph.edge_name.call self
112
+ else
113
+ "#{ out_vertex.element_id }-#{ getLabel }-#{ in_vertex.element_id }"
114
+ end
115
+ end
116
+
117
+ # Deletes the edge from its graph.
118
+ def delete!
119
+ graph.remove_edge element
120
+ end
121
+
122
+ # Clones this edge into the target graph.
123
+ #
124
+ # This differs from the {#copy_into} in that it tries to set
125
+ # the new element_id the same as the original element_id.
126
+ #
127
+ # @param [PacerGraph] target_graph
128
+ # @param [Hash] opts
129
+ # @option opts :create_vertices [true] Create the vertices
130
+ # associated to this edge if they don't already exist.
131
+ # @yield [e] Optional block yields the edge after it has been created.
132
+ # @return [Pacer::Wrappers::EdgeWrapper] the new edge
133
+ #
134
+ # @raise [StandardError] If this the associated vertices don't exist and :create_vertices is not set
135
+ def clone_into(target_graph, opts = {})
136
+ e_idx = target_graph.index("tmp-e-#{graph.graph_id}", :edge, :create => true)
137
+ e = target_graph.edge(element_id)
138
+ unless e
139
+ e = e_idx.first('id', element_id)
140
+ if e
141
+ e = EdgeWrapper.new(e)
142
+ e.graph = target_graph
143
+ end
144
+ end
145
+ unless e
146
+ v_idx = target_graph.index("tmp-v-#{graph.graph_id}", :vertex, :create => true)
147
+ iv = target_graph.vertex(in_vertex.element_id) || v_idx.first('id', in_vertex.element_id)
148
+ ov = target_graph.vertex(out_vertex.element_id) || v_idx.first('id', out_vertex.element_id)
149
+ if opts[:create_vertices]
150
+ iv ||= in_vertex.clone_into target_graph
151
+ ov ||= out_vertex.clone_into target_graph
152
+ end
153
+ if not iv or not ov
154
+ message = "Vertex not found for #{ self.inspect }: #{ iv.inspect } -> #{ ov.inspect }"
155
+ puts message if opts[:show_missing_vertices]
156
+ raise message unless opts[:ignore_missing_vertices]
157
+ return nil
158
+ end
159
+ e = target_graph.create_edge(element_id, iv, ov, label, properties)
160
+ e_idx.put('id', element_id, e)
161
+ yield e if block_given?
162
+ end
163
+ e
164
+ end
165
+
166
+ # Copies this edge into the target graph with the next available
167
+ # edge id.
168
+ #
169
+ # @param [PacerGraph] target_graph
170
+ # @yield [e] Optional block yields the edge after it has been created.
171
+ # @return [Pacer::Wrappers::EdgeWrapper] the new edge
172
+ #
173
+ # @raise [StandardError] If this the associated vertices don't exist
174
+ def copy_into(target_graph)
175
+ v_idx = target_graph.index("tmp-v-#{graph.graph_id}", :vertex, :create => true)
176
+ iv = v_idx.first('id', in_vertex.element_id) || target_graph.vertex(in_vertex.element_id)
177
+ ov = v_idx.first('id', out_vertex.element_id) || target_graph.vertex(out_vertex.element_id)
178
+
179
+ raise 'vertices not found' if not iv or not ov
180
+ e = target_graph.create_edge nil, iv, ov, label, properties
181
+ yield e if block_given?
182
+ e
183
+ end
184
+
185
+ # Test equality to another object.
186
+ #
187
+ # Elements are equal if they are the same element type and have the same id
188
+ # and the same graph, regardless of extensions/wrappers.
189
+ #
190
+ # If the graphdb instantiates multiple copies of the same element
191
+ # this method will return true when comparing them.
192
+ #
193
+ # If the other instance is an unwrapped edge, this will always return
194
+ # false because otherwise the == method would not be symetrical.
195
+ #
196
+ # @see #eql?
197
+ # @param other
198
+ def ==(other)
199
+ other.is_a? EdgeWrapper and
200
+ element_id == other.element_id and
201
+ graph == other.graph
202
+ end
50
203
  end
51
204
  end
@@ -3,16 +3,26 @@ module Pacer::Wrappers
3
3
  include Pacer::Element
4
4
  extend Forwardable
5
5
  include Comparable
6
+ include Pacer::Routes::RouteOperations
7
+ include Pacer::Core::Graph::ElementRoute
6
8
 
7
9
  class << self
8
10
  def wrap(element, exts)
9
- wrapper_for(exts).new(element.element)
11
+ if element.respond_to? :element
12
+ wrapper_for(exts).new(element.element)
13
+ else
14
+ wrapper_for(exts).new(element)
15
+ end
10
16
  end
11
17
 
12
18
  def extensions
13
19
  @extensions ||= []
14
20
  end
15
21
 
22
+ def add_extensions(exts)
23
+ wrapper_for(extensions + exts.to_a)
24
+ end
25
+
16
26
  def clear_cache
17
27
  Pacer.send :remove_const, :Wrap if Pacer.const_defined? :Wrap
18
28
  VertexWrapper.clear_cache
@@ -37,8 +47,19 @@ module Pacer::Wrappers
37
47
  sc_name = superclass.to_s.split(/::/).last
38
48
  exts = exts.uniq unless exts.is_a? Set
39
49
  classname = "#{sc_name}#{exts.map { |m| m.to_s }.join('')}".gsub(/::/, '_').gsub(/\W/, '')
40
- eval "module ::Pacer; module Wrap; class #{classname.to_s} < #{sc_name}; end; end; end"
41
- wrapper = Pacer::Wrap.const_get classname
50
+ begin
51
+ wrapper = Pacer::Wrap.const_get classname
52
+ rescue NameError
53
+ eval %{
54
+ module ::Pacer
55
+ module Wrap
56
+ class #{classname.to_s} < #{sc_name}
57
+ end
58
+ end
59
+ end
60
+ }
61
+ wrapper = Pacer::Wrap.const_get classname
62
+ end
42
63
  exts.each do |obj|
43
64
  if obj.is_a? Module or obj.is_a? Class
44
65
  mod_names.each do |mod_name|
@@ -53,21 +74,125 @@ module Pacer::Wrappers
53
74
  end
54
75
  end
55
76
 
77
+ # For internal use only.
78
+ #
79
+ # The graph the element belongs to.
80
+ #
81
+ # Used to help prevent objects from different graphs from being
82
+ # accidentally associated, as well as to get graph-specific data for
83
+ # the element.
84
+ #
85
+ # @return [PacerGraph]
86
+ attr_accessor :graph
87
+ attr_reader :element
88
+
56
89
  def initialize(element)
57
- @element = element
90
+ if element.is_a? ElementWrapper
91
+ @element = element.element
92
+ else
93
+ @element = element
94
+ end
58
95
  after_initialize
59
96
  end
60
97
 
98
+ def hash
99
+ element.hash
100
+ end
101
+
102
+ # Convenience method to retrieve a property by name.
103
+ #
104
+ # @param [#to_s] key the property name
105
+ # @return [Object]
106
+ def [](key)
107
+ if key.is_a? Array
108
+ key.map { |k| self[k] }
109
+ else
110
+ value = element.getProperty(key.to_s)
111
+ graph.decode_property(value)
112
+ end
113
+ end
114
+
115
+ # Convenience method to set a property by name to the given value.
116
+ # @param [#to_s] key the property name
117
+ # @param [Object] value the value to set the property to
118
+ def []=(key, value)
119
+ value = graph.encode_property(value)
120
+ key = key.to_s
121
+ if value
122
+ if value != element.getProperty(key)
123
+ element.setProperty(key, value)
124
+ end
125
+ else
126
+ element.removeProperty(key) if element.getPropertyKeys.include? key
127
+ end
128
+ end
129
+
130
+ # Specialize result to return self for elements.
131
+ # @return [ElementWrapper] self
132
+ def result(name = nil)
133
+ self
134
+ end
135
+
136
+ # Query whether the current node belongs to the given graph.
137
+ #
138
+ # @param [Object] g the object to compare to {#graph}
139
+ def from_graph?(g)
140
+ g.blueprints_graph.equal? graph.blueprints_graph
141
+ end
142
+
143
+ # Returns a hash of property values by name.
144
+ #
145
+ # @return [Hash]
146
+ def properties
147
+ element.getPropertyKeys.inject({}) { |h, name| h[name] = element.getProperty(name); h }
148
+ end
149
+
150
+ # Replace the element's properties with the given hash
151
+ #
152
+ # @param [Hash] props the element's new properties
153
+ def properties=(props)
154
+ (element.getPropertyKeys - props.keys.collect { |k| k.to_s }).each do |key|
155
+ element.removeProperty key
156
+ end
157
+ props.each do |key, value|
158
+ self[key] = value
159
+ end
160
+ end
161
+
162
+ def property_keys
163
+ getPropertyKeys
164
+ end
165
+
166
+ # The id of the current element
167
+ # @return [Object] element id (type varies by graph implementation.
61
168
  def element_id
62
- @element.get_id
169
+ element.getId
63
170
  end
64
171
 
65
- def hash
66
- @element.hash
172
+ # Sort objects semi arbitrarily based on {#display_name}.
173
+ # @param other
174
+ #
175
+ # @return [Fixnum]
176
+ def <=>(other)
177
+ display_name.to_s <=> other.display_name.to_s
67
178
  end
68
179
 
180
+ # Test object equality of the element instance.
181
+ #
182
+ # Wrappers/extensions (if any) are ignored, the underlying element
183
+ # only is compared
184
+ #
185
+ # If the graphdb instantiates multiple copies of the same element
186
+ # this method will return false when comparing them.
187
+ #
188
+ # @see #==
189
+ # @param other
69
190
  def eql?(other)
70
- @element.eql?(other)
191
+ if other.respond_to? :element_id
192
+ other.graph == graph and other.element_id == element_id
193
+ else
194
+ element.equals other
195
+ end
71
196
  end
72
197
 
73
198
  protected
@@ -0,0 +1,47 @@
1
+ module Pacer::Wrappers
2
+ class IndexWrapper
3
+ attr_reader :index, :graph, :element_type
4
+
5
+ def initialize(graph, index, element_type)
6
+ @index = index
7
+ @graph = graph
8
+ @element_type = element_type
9
+ end
10
+
11
+ def name
12
+ index.index_name
13
+ end
14
+
15
+ def wrapper
16
+ WrapperSelector.build element_type
17
+ end
18
+
19
+ def first(key, value, extensions = nil)
20
+ e = index.get(key, value).first
21
+ if e
22
+ e = wrapper.new e
23
+ e = e.add_extensions extensions if extensions
24
+ e.graph = graph
25
+ end
26
+ e
27
+ end
28
+
29
+ def all(key, value, extensions = nil)
30
+ iter = index.get(key, value)
31
+ if graph or extensions
32
+ pipe = Pacer::Pipes::WrappingPipe.new graph, element_type, extensions
33
+ pipe.setStarts iter.iterator
34
+ pipe
35
+ else
36
+ iter
37
+ end
38
+ end
39
+
40
+ def put(key, value, element)
41
+ if element.is_a? ElementWrapper
42
+ element = element.element
43
+ end
44
+ index.put key, value, element
45
+ end
46
+ end
47
+ end
@@ -2,19 +2,20 @@ module Pacer::Wrappers
2
2
  class VertexWrapper < ElementWrapper
3
3
  include Pacer::Vertex
4
4
  include Pacer::Core::Graph::VerticesRoute
5
- include Pacer::ElementMixin
6
- include Pacer::VertexMixin
7
5
 
8
6
  def_delegators :@element,
9
7
  :getId, :getPropertyKeys, :getProperty, :setProperty, :removeProperty,
10
- :getOutEdges, :getInEdges,
11
- :getRawVertex,
12
- :graph, :graph=, :<=>, :==
8
+ :getEdges,
9
+ :getRawVertex
13
10
 
14
11
  class << self
15
12
  def wrapper_for(exts)
16
13
  @wrappers = {} unless defined? @wrappers
17
- @wrappers[exts.to_set] ||= build_vertex_wrapper(exts)
14
+ if exts
15
+ @wrappers[exts.to_set] ||= build_vertex_wrapper(exts)
16
+ else
17
+ fail Pacer::LogicError, "Extensions should not be nil"
18
+ end
18
19
  end
19
20
 
20
21
  def clear_cache
@@ -30,22 +31,184 @@ module Pacer::Wrappers
30
31
 
31
32
  # This method must be defined here rather than in the superclass in order
32
33
  # to correctly override the method in an included module
33
- def extensions
34
- self.class.extensions
35
- end
34
+ attr_reader :element
36
35
 
37
36
  # This method must be defined here rather than in the superclass in order
38
37
  # to correctly override the method in an included module
39
- def element
40
- @element
38
+ def extensions
39
+ self.class.extensions
41
40
  end
42
41
 
42
+ # Add extensions to this vertex.
43
+ #
44
+ # If any extension has a Vertex module within it, this vertex will
45
+ # be extended with the extension's Vertex module.
46
+ #
47
+ # @param [[extensions]] exts the extensions to add
48
+ # @return [Pacer::EdgeWrapper] this vertex wrapped up and including
49
+ # the extensions
43
50
  def add_extensions(exts)
44
51
  if exts.any?
45
- self.class.wrap(element, extensions + exts.to_a)
52
+ e = self.class.wrap(element, extensions + exts.to_a)
53
+ e.graph = graph
54
+ e
46
55
  else
47
56
  self
48
57
  end
49
58
  end
59
+
60
+ # Returns the element with a new simple wrapper.
61
+ # @return [VertexWrapper]
62
+ def no_extensions
63
+ e = VertexWrapper.new element
64
+ e.graph = graph
65
+ e
66
+ end
67
+
68
+ # Checks that the given extensions can be applied to the vertex. If
69
+ # they can then yield the vertex correctly extended or return the extended
70
+ # vertex. If not then do not yield and return nil.
71
+ #
72
+ # @param [extensions] exts extensions to add if possible
73
+ # @yield [v] Optional block yields the vertex with the extensions added.
74
+ # @return nil or the result of the block or the extended vertex
75
+ def as(*exts)
76
+ if as?(*exts)
77
+ exts_to_add = extensions_missing(exts)
78
+ extended = exts_to_add.empty? ? self : add_extensions(exts_to_add)
79
+ if block_given?
80
+ yield extended
81
+ else
82
+ extended
83
+ end
84
+ end
85
+ end
86
+
87
+ def only_as(*exts)
88
+ if as?(*exts)
89
+ extended = exts.empty? ? no_extensions : no_extensions.add_extensions(exts)
90
+ if block_given?
91
+ yield extended
92
+ else
93
+ extended
94
+ end
95
+ end
96
+ end
97
+
98
+ def as?(*exts)
99
+ has_exts = extensions_missing(exts).all? do |ext|
100
+ if ext.respond_to? :route_conditions
101
+ ext.route_conditions.all? do |k, v|
102
+ self[k] == v
103
+ end
104
+ else
105
+ true
106
+ end
107
+ end
108
+ end
109
+
110
+ # Returns a human-readable representation of the vertex using the
111
+ # standard ruby console representation of an instantiated object.
112
+ # @return [String]
113
+ def inspect
114
+ "#<#{ ["V[#{element_id}]", display_name].compact.join(' ') }>"
115
+ end
116
+
117
+ # Returns the display name of the vertex.
118
+ # @return [String]
119
+ def display_name
120
+ graph.vertex_name.call self if graph and graph.vertex_name
121
+ end
122
+
123
+ # Deletes the vertex from its graph along with all related edges.
124
+ def delete!
125
+ graph.remove_vertex element
126
+ end
127
+
128
+ # Copies including the vertex id unless a vertex with that id
129
+ # already exists.
130
+ # @param [PacerGraph] target_graph
131
+ # @param opts for compatibility with {Pacer::Wrappers::EdgeWrapper#clone_into}
132
+ # @yield [v] Optional block yields the vertex after it has been created.
133
+ # @return [Pacer::Wrappers::VertexWrapper] the new vertex
134
+ def clone_into(target_graph, opts = nil)
135
+ v_idx = target_graph.index("tmp-v-#{graph.graph_id}", :vertex, :create => true)
136
+ v = target_graph.vertex(element_id) || v_idx.first('id', element_id)
137
+ unless v
138
+ v = target_graph.create_vertex element_id, properties
139
+ v_idx.put('id', element_id, v.element)
140
+ yield v if block_given?
141
+ end
142
+ v
143
+ end
144
+
145
+ # Make a new copy of the element with the next available vertex id.
146
+ #
147
+ # @param [PacerGraph] target_graph
148
+ # @yield [v] Optional block yields the vertex after it has been created.
149
+ # @return [Pacer::Wrappers::VertexWrapper] the new vertex
150
+ def copy_into(target_graph)
151
+ v = target_graph.create_vertex properties
152
+ yield v if block_given?
153
+ v
154
+ end
155
+
156
+ def out_edges(*labels_and_extensions)
157
+ get_edges_helper Pacer::Pipes::OUT, *labels_and_extensions
158
+ end
159
+
160
+ def in_edges(*labels_and_extensions)
161
+ get_edges_helper Pacer::Pipes::IN, *labels_and_extensions
162
+ end
163
+
164
+ def both_edges(*labels_and_extensions)
165
+ get_edges_helper Pacer::Pipes::BOTH, *labels_and_extensions
166
+ end
167
+
168
+ # Test equality to another object.
169
+ #
170
+ # Elements are equal if they are the same type and have the same id
171
+ # and the same graph, regardless of extensions.
172
+ #
173
+ # If the graphdb instantiates multiple copies of the same element
174
+ # this method will return true when comparing them.
175
+ #
176
+ # If the other instance is an unwrapped vertex, this will always return
177
+ # false because otherwise the == method would not be symetrical.
178
+ #
179
+ # @see #eql?
180
+ # @param other
181
+ def ==(other)
182
+ other.is_a? VertexWrapper and
183
+ element_id == other.element_id and
184
+ graph == other.graph
185
+ end
186
+
187
+ protected
188
+
189
+ def get_edges_helper(direction, *labels_and_extensions)
190
+ labels, exts = split_labels_and_extensions(labels_and_extensions)
191
+ pipe = Pacer::Pipes::WrappingPipe.new graph, :edge, exts
192
+ pipe.setStarts element.getEdges(direction, *labels).iterator
193
+ pipe
194
+ end
195
+
196
+ def split_labels_and_extensions(mixed)
197
+ labels = Set[]
198
+ exts = []
199
+ mixed.each do |obj|
200
+ if obj.is_a? Symbol or obj.is_a? String
201
+ labels << obj
202
+ else
203
+ exts << obj
204
+ end
205
+ end
206
+ [labels, exts.uniq]
207
+ end
208
+
209
+ # Return the extensions this vertex is missing from the given array
210
+ def extensions_missing(exts)
211
+ Set.new(exts.flatten).difference extensions.to_set
212
+ end
50
213
  end
51
214
  end
@@ -0,0 +1,40 @@
1
+ module Pacer::Wrappers
2
+ class WrapperSelector
3
+ import com.tinkerpop.blueprints.Vertex
4
+ import com.tinkerpop.blueprints.Edge
5
+
6
+ def self.build(element_type = nil, extensions = [])
7
+ if element_type == :vertex
8
+ Pacer::Wrappers::VertexWrapper.wrapper_for extensions
9
+ elsif element_type == :edge
10
+ Pacer::Wrappers::EdgeWrapper.wrapper_for extensions
11
+ else
12
+ new extensions
13
+ end
14
+ end
15
+
16
+ attr_reader :extensions
17
+ attr_accessor :vertex_wrapper, :edge_wrapper
18
+
19
+ def initialize(extensions = [])
20
+ @extensions = extensions
21
+ end
22
+
23
+ def wrapper(element)
24
+ if element.is_a? Vertex
25
+ self.vertex_wrapper ||= Pacer::Wrappers::VertexWrapper.wrapper_for extensions
26
+ elsif element.is_a? Edge
27
+ self.edge_wrapper ||= Pacer::Wrappers::EdgeWrapper.wrapper_for extensions
28
+ end
29
+ end
30
+
31
+ def new(element)
32
+ w = wrapper(element)
33
+ if w
34
+ w.new element
35
+ else
36
+ element
37
+ end
38
+ end
39
+ end
40
+ end