Skip to content
This repository
  • 2 commits
  • 2 files changed
  • 0 comments
  • 1 contributor
Apr 30, 2012
Andreas Ronge added missing >> << operator right relation, e.g {(node > :r <:a) >> …
…:x}, closes #4
497001a
Andreas Ronge Make sure we insert clauses in the correct order and assign relations…
…hip names when needed, closes #3

Make things like "node(1) > (rel(:knows)[:since] == 1994) > :other; :other" possible
479a8e8

Showing 2 changed files with 79 additions and 18 deletions. Show diff stats Hide diff stats

  1. +53 17 lib/neo4j-core/cypher/cypher.rb
  2. +26 1 spec/neo4j/cypher_spec.rb
70 lib/neo4j-core/cypher/cypher.rb
@@ -222,7 +222,11 @@ def initialize(expressions, clause)
222 222 end
223 223
224 224 def insert_last(clause)
225   - i = @expressions.reverse.index { |e| e.clause == clause }
  225 + curr_clause = clause
  226 + while (i = @expressions.reverse.index { |e| e.clause == curr_clause }).nil? && curr_clause != :start
  227 + curr_clause = prev_clause(curr_clause)
  228 + end
  229 +
226 230 if i.nil?
227 231 @expressions << self
228 232 else
@@ -231,6 +235,10 @@ def insert_last(clause)
231 235 end
232 236 end
233 237
  238 + def prev_clause(clause)
  239 + {:limit => :skip, :skip => :order_by, :order_by => :return, :return => :where, :where => :match, :match => :start}[clause]
  240 + end
  241 +
234 242 def prefixes
235 243 {:start => "START", :where => " WHERE", :match => " MATCH", :return => " RETURN", :order_by => " ORDER BY", :skip => " SKIP", :limit => " LIMIT"}
236 244 end
@@ -255,14 +263,15 @@ def valid?
255 263 # # same as START n0=node(2,3,4) RETURN collect(n0.property)
256 264 class Property
257 265 # @private
258   - attr_reader :expressions, :var_name
  266 + attr_reader :expressions, :var_name, :var_expr
259 267 include Comparable
260 268 include MathOperator
261 269 include MathFunctions
262 270 include PredicateMethods
263 271
264   - def initialize(expressions, var, prop_name)
265   - @var = var.respond_to?(:var_name) ? var.var_name : var
  272 + def initialize(expressions, var_expr, prop_name)
  273 + @var_expr = var_expr
  274 + @var = var_expr.respond_to?(:var_name) ? var_expr.var_name : var_expr
266 275 @expressions = expressions
267 276 @prop_name = prop_name
268 277 @var_name = @prop_name ? "#{@var.to_s}.#{@prop_name}" : @var.to_s
@@ -576,7 +585,13 @@ def right_var_name
576 585
577 586 # @private
578 587 def right_expr
579   - @right.respond_to?(:expr) ? @right.expr : right_var_name
  588 + c = @right
  589 + r = while (c)
  590 + break c.var_expr if c.respond_to?(:var_expr)
  591 + c = c.respond_to?(:left_expr) && c.left_expr
  592 + end || @right
  593 +
  594 + r.respond_to?(:expr) ? r.expr : right_var_name
580 595 end
581 596
582 597 # @private
@@ -670,6 +685,16 @@ def -(other)
670 685 self.next = MatchRelLeft.new(self, other, expressions, :both)
671 686 end
672 687
  688 + def <<(other)
  689 + expressions.delete(self)
  690 + self.next = MatchNode.new(self, other, expressions, :incoming)
  691 + end
  692 +
  693 + def >>(other)
  694 + expressions.delete(self)
  695 + self.next = MatchNode.new(self, other, expressions, :outgoing)
  696 + end
  697 +
673 698 # @return [String] a cypher string for this match.
674 699 def expr
675 700 "#{dir_op}(#{right_var_name})"
@@ -787,14 +812,23 @@ def initialize(expressions, variables, expr)
787 812 variables << self
788 813 @expr = expr
789 814 @expressions = expressions
790   - guess = expr ? /([[:alpha:]]*)/.match(expr)[1] : ""
791   - @var_name = guess.empty? ? "v#{variables.size}" : guess
  815 + guess = expr ? /([[:alpha:]_]*)/.match(expr)[1] : ""
  816 + @auto_var_name = "v#{variables.size}"
  817 + @var_name = guess.empty? ? @auto_var_name : guess
792 818 end
793 819
794 820 def rel_type
795 821 Property.new(@expressions, self, 'type').to_function!
796 822 end
797 823
  824 + def [](p)
  825 + if @expr.to_s[0..0] == ':'
  826 + @var_name = @auto_var_name
  827 + @expr = "#{@var_name}#{@expr}"
  828 + end
  829 + super
  830 + end
  831 +
798 832 # @return [String] a cypher string for this relationship variable
799 833 def to_s
800 834 var_name
@@ -803,21 +837,24 @@ def to_s
803 837 end
804 838
805 839 class ExprOp < Expression
806   - attr_reader :left, :right, :op, :neg, :post_fix
  840 + attr_reader :left, :right, :op, :neg, :post_fix, :left_expr, :right_expr
807 841 include MathFunctions
808 842
809   - def initialize(left, right, op, post_fix = "")
810   - super(left.expressions, :where)
  843 +
  844 + def initialize(left_expr, right_expr, op, post_fix = "")
  845 + super(left_expr.expressions, :where)
  846 + @left_expr = left_expr
  847 + @right_expr = right_expr
811 848 @op = op
812 849 @post_fix = post_fix
813   - self.expressions.delete(left)
814   - self.expressions.delete(right)
815   - @left = quote(left)
816   - if regexp?(right)
  850 + self.expressions.delete(left_expr)
  851 + self.expressions.delete(right_expr)
  852 + @left = quote(left_expr)
  853 + if regexp?(right_expr)
817 854 @op = "=~"
818   - @right = to_regexp(right)
  855 + @right = to_regexp(right_expr)
819 856 else
820   - @right = right && quote(right)
  857 + @right = right_expr && quote(right_expr)
821 858 end
822 859 @neg = nil
823 860 end
@@ -888,7 +925,6 @@ def binary!
888 925 end
889 926
890 927 def valid?
891   - # puts "valid? @binary=#{@binary} (#@left #@op #@right) in clause #{clause} ret #{@binary ? !!@left : !!@left && !!@right}"
892 928 # it is only valid in a where clause if it's either binary or it has right and left values
893 929 @binary ? @left : @left && @right
894 930 end
27 spec/neo4j/cypher_spec.rb
@@ -541,7 +541,6 @@ def self._load_wrapper; end
541 541 end
542 542 end
543 543
544   - # start a=node(5), b=node(7) match a-[:friends]->x where not(x-[:friends]->b) return x
545 544 describe "a=node(5);b=node(7);x=node; a > ':friends' > x; (x > ':friends' > node > ':work' > b).not; x" do
546 545 it do
547 546 Proc.new do
@@ -550,6 +549,32 @@ def self._load_wrapper; end
550 549 end
551 550 end
552 551
  552 +
  553 + describe "(node(5) > :r > :middle) >> node(7)" do
  554 + it do
  555 + Proc.new do
  556 + (node(5) > :r > :middle) >> node(7)
  557 + end.should be_cypher("START n0=node(5),n2=node(7) MATCH m3 = (n0)-[r]->(middle)-->(n2) RETURN m3")
  558 + end
  559 + end
  560 +
  561 +
  562 + describe "node(1) > (r=rel(:friends)) > :other; r[:since] == 1994; :other" do
  563 + it do
  564 + Proc.new do
  565 + node(1) > (r=rel(:friends)) > :other; r[:since] == 1994; :other
  566 + end.should be_cypher("START n0=node(1) MATCH (n0)-[v1:`friends`]->(other) WHERE v1.since = 1994 RETURN other")
  567 + end
  568 + end
  569 +
  570 + describe "node(1) > (rel(:knows)[:since] == 1994) > :other; :other" do
  571 + it do
  572 + Proc.new do
  573 + node(1) > (rel(:knows)[:since] == 1994) > :other; :other
  574 + end.should be_cypher("START n0=node(1) MATCH (n0)-[v1:`knows`]->(other) WHERE v1.since = 1994 RETURN other")
  575 + end
  576 + end
  577 +
553 578 # Cypher > 1.7.0 (snapshot)
554 579 # start begin = node(2), end = node(1) match p = begin -[*]-> end with p foreach(r in relationships(p) : delete r) with p foreach(n in nodes(p) : delete n)
555 580 # start a=node(0), b=node(5) with a,b create rel a-[:friends]->b

No commit comments for this range

Something went wrong with that request. Please try again.