neo4j-cypher 1.0.0.rc2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,9 +17,7 @@ module Neo4j
17
17
 
18
18
 
19
19
  class Create
20
- include ToPropString
21
20
  include Clause
22
- include Referenceable
23
21
 
24
22
  def initialize(clause_list, props)
25
23
  super(clause_list, :create, EvalContext)
@@ -59,7 +57,6 @@ module Neo4j
59
57
 
60
58
  class CreatePath
61
59
  include Clause
62
- include Referenceable
63
60
 
64
61
  attr_reader :arg_list
65
62
 
@@ -0,0 +1,16 @@
1
+ module Neo4j
2
+ module Cypher
3
+ class Foreach < AbstractFilter
4
+
5
+ def initialize(clause_list, input_context, &block)
6
+ super(clause_list, :foreach, input_context)
7
+ # Input can either be a property array or a node/relationship collection
8
+ input = input_context.clause
9
+ clause_list.delete(input)
10
+ filter_initialize(input_context, '', " : ", &block)
11
+ end
12
+
13
+ end
14
+ end
15
+
16
+ end
@@ -3,7 +3,6 @@ module Neo4j
3
3
 
4
4
  class MatchStart
5
5
  include Clause
6
- include Referenceable
7
6
 
8
7
  attr_reader :match_list
9
8
  attr_accessor :algorithm
@@ -196,7 +195,7 @@ module Neo4j
196
195
  set_rel(rels.first)
197
196
  else
198
197
  # wrap and maybe join several relationship strings
199
- @rel_var = RelVar.join(clause_list, rels)
198
+ @rel_var = RelVar.new(clause_list, rels)
200
199
  end
201
200
  self
202
201
  end
@@ -215,16 +214,11 @@ module Neo4j
215
214
  elsif rel.respond_to?(:clause) && rel.clause.match_value
216
215
  @rel_var = rel.clause
217
216
  else
218
- @rel_var = RelVar.new(clause_list, rel)
217
+ @rel_var = RelVar.new(clause_list, [rel])
219
218
  end
220
219
  self
221
220
  end
222
221
 
223
- def self.new_first(match_start, from, rel)
224
- from_var = NodeVar.as_var(match_start.clause_list, from)
225
- RelLeftMatchContext.new(match_start, from_var).set_rel(rel)
226
- end
227
-
228
222
  def -(to)
229
223
  @match_start.match_list.delete(self) # since it is complete now
230
224
  RelRightMatchContext.new(@match_start, self, @rel_var, to, :both)
@@ -308,32 +302,41 @@ module Neo4j
308
302
  end
309
303
 
310
304
  def to_cypher_no_join
311
- "(#{@from.var_name})#{DIR_OPERATORS[@dir]}(#{@to.var_name})"
305
+ x = @to.match_value
306
+ "(#{@from.match_value})#{DIR_OPERATORS[@dir]}(#{x})"
312
307
  end
313
308
 
314
309
  def to_cypher_join
315
- "#{DIR_OPERATORS[@dir]}(#{@to.var_name})"
310
+ "#{DIR_OPERATORS[@dir]}(#{@to.match_value})"
316
311
  end
317
312
  end
318
313
 
319
314
  class Entities
320
315
  include Clause
316
+ attr_reader :input
321
317
 
322
318
  def initialize(clause_list, iterable, input)
323
319
  super(clause_list, :entities, EvalContext)
324
- eval_context.iterable = iterable
325
- eval_context.input = input.clause
320
+ @iterable = iterable
321
+ @input = input.clause
322
+ end
323
+
324
+ def referenced!
325
+ @input.referenced!
326
+ end
327
+
328
+ def return_value
329
+ "#{@iterable}(#{@input.var_name})"
326
330
  end
327
331
 
328
332
  class EvalContext
329
333
  include Context
330
334
  include PredicateMethods
331
- attr_accessor :input, :iterable
332
- #
333
- #def each(&cypher_dsl)
334
- # Predicate.new(clause_list, :clause => clause, :input => input, :predicate_block => cypher_dsl)
335
- # #RootClause::EvalContext.new(self).instance_exec(*arg_exec, &cypher_dsl)
336
- #end
335
+ include Returnable
336
+
337
+ include Variable
338
+ include Matchable
339
+ include Aggregate
337
340
  end
338
341
  end
339
342
 
@@ -0,0 +1,22 @@
1
+ module Neography
2
+
3
+ # Monkey patch so it works better with neo4-cypher gem and becomes more similar to neo4j-core
4
+ class Relationship
5
+ def _java_rel
6
+ self
7
+ end
8
+ end
9
+
10
+ class Node
11
+ def _java_node
12
+ self
13
+ end
14
+ end
15
+
16
+ class Rest
17
+ def execute_cypher(params, &dsl)
18
+ q = Neo4j::Cypher.query(params, &dsl).to_s
19
+ execute_query(q)
20
+ end
21
+ end
22
+ end
@@ -4,7 +4,6 @@ module Neo4j
4
4
  # Represents an unbound node variable used in match statements
5
5
  class NodeVar
6
6
  include Clause
7
- include Referenceable
8
7
 
9
8
  def initialize(clause_list, var_name = nil)
10
9
  super(clause_list, :node_var, EvalContext)
@@ -35,7 +35,6 @@ module Neo4j
35
35
  class Operator
36
36
  attr_reader :left_operand, :right_operand, :op, :neg, :eval_context
37
37
  include Clause
38
- include Referenceable
39
38
 
40
39
  def initialize(clause_list, left_operand, right_operand, op, clause_type = :where, post_fix = nil, &dsl)
41
40
  super(clause_list, clause_type, EvalContext)
@@ -48,19 +47,14 @@ module Neo4j
48
47
  @valid = true
49
48
 
50
49
  # since we handle it ourself in to_cypher method unless it needs to be declared (as a cypher start node/relationship)
51
- clause_list.delete(left_operand) unless declare_operand?(left_operand)
52
- clause_list.delete(right_operand) unless declare_operand?(right_operand)
53
-
50
+ clause_list.delete(left_operand) if remove_operand?(left_operand)
51
+ clause_list.delete(right_operand) if remove_operand?(right_operand)
54
52
  @neg = nil
55
53
  end
56
54
 
57
- def declare_operand?(operand)
55
+ def remove_operand?(operand)
58
56
  clause = operand.respond_to?(:clause) ? operand.clause : operand
59
- clause.kind_of?(Clause) && clause.clause_type == :start
60
- end
61
-
62
- def separator
63
- " and "
57
+ clause.kind_of?(Clause) && clause.clause_type == :where
64
58
  end
65
59
 
66
60
  def match_value
@@ -1,62 +1,11 @@
1
1
  module Neo4j
2
2
  module Cypher
3
- class Predicate
4
- include Clause
5
- include Referenceable
6
- attr_accessor :params
3
+ class Predicate < AbstractFilter
7
4
 
8
- def initialize(clause_list, params)
9
- super(clause_list, params[:clause])
10
- @identifier = :x
11
- @separator = params[:separator] || ','
12
- params[:input].referenced! if params[:input].respond_to?(:referenced!)
13
-
14
- clause_list.push
15
-
16
- var = NodeVar.as_var(clause_list, @identifier)
17
-
18
- input = params[:input]
19
-
20
- # TODO refactor please
21
- if input.kind_of?(Property)
22
- eval_prop = Property.new(var)
23
- eval_prop.expr = @identifier
24
- yield_param = eval_prop.eval_context
25
- args = ""
26
- else
27
- yield_param = var.eval_context
28
- args = "(#{input.var_name})"
29
- end
30
-
31
- result = RootClause::EvalContext.new(self).instance_exec(yield_param, &params[:predicate_block])
32
-
33
- result = case params[:clause]
34
- when :return_item
35
- block_result = result.clause.to_cypher
36
- "#{params[:op]}(#@identifier in #{params[:iterable]}#{args} : #{block_result})"
37
- when :foreach
38
- block_result = clause_list.to_cypher
39
- "#{params[:op]}(#@identifier in #{params[:iterable]}#{args} : #{block_result})"
40
- else
41
- block_result = clause_list.to_cypher
42
- "#{params[:op]}(#@identifier in #{params[:iterable]}#{args} WHERE #{block_result})"
43
- end
44
-
45
- clause_list.pop
46
- @result = result
47
- end
48
-
49
- def return_value
50
- to_cypher
51
- end
52
-
53
-
54
- def separator
55
- @separator
56
- end
57
-
58
- def to_cypher
59
- @result
5
+ def initialize(clause_list, method_name, input_context, &block)
6
+ super(clause_list, :where, input_context)
7
+ # Input can either be a property array or a node/relationship collection
8
+ filter_initialize(input_context, method_name, " WHERE ", &block)
60
9
  end
61
10
  end
62
11
 
@@ -10,15 +10,17 @@ module Neo4j
10
10
  # n=node(2, 3, 4); n[:name].collect
11
11
  # # same as START n0=node(2,3,4) RETURN collect(n0.property)
12
12
  class Property
13
- include Referenceable
14
13
  include Clause
15
14
 
15
+ attr_accessor :prop_name
16
+
16
17
  def initialize(var, prop_name = nil)
17
18
  super(var.clause_list, :property, EvalContext)
18
19
  @var = var
19
20
  @prop_name = prop_name
20
21
  end
21
22
 
23
+ # TODO check why needed
22
24
  def var_name
23
25
  @var.var_name
24
26
  end
@@ -65,6 +67,7 @@ module Neo4j
65
67
  include MathFunctions
66
68
  include PredicateMethods
67
69
  include Aggregate
70
+ include Returnable
68
71
 
69
72
  def asc
70
73
  ReturnItem.new(clause_list, self).eval_context.asc
@@ -88,17 +91,6 @@ module Neo4j
88
91
  self
89
92
  end
90
93
 
91
- # required by the Predicate Methods Module
92
- # @see PredicateMethods
93
- # @private
94
- def iterable
95
- clause.return_value
96
- end
97
-
98
- def input
99
- clause
100
- end
101
-
102
94
  # @private
103
95
  def in?(values)
104
96
  clause.unary_operator("", :where, " IN [#{values.map { |x| %Q["#{x}"] }.join(',')}]")
@@ -3,49 +3,43 @@ module Neo4j
3
3
 
4
4
  class RelVar
5
5
  include Clause
6
- include ToPropString
7
- include Referenceable
8
6
 
9
7
  def initialize(clause_list, expr, props = nil)
10
8
  super(clause_list, :rel_var, EvalContext)
11
9
 
12
- case expr
13
- when String
14
- @match_value = expr.empty? ? '?' : expr.to_s
15
- guess = expr.is_a?(String) && /([[:alpha:]_]*)/.match(expr)[1]
16
- self.var_name = guess.to_sym if guess && !guess.empty?
17
- when Symbol
18
- @match_value = ":`#{expr}`"
19
- else
20
- raise "Illegal arg for rel #{expr.class}"
21
- end
10
+ self.var_name = guess_var_name_from_string(expr.first) if expr.first.is_a?(String)
22
11
 
23
- @match_value = "#@match_value #{to_prop_string(props)}" if props
12
+ if props
13
+ @match_value = "#{match_value_from_args(expr)} #{to_prop_string(props)}"
14
+ else
15
+ @match_value = match_value_from_args(expr)
16
+ end
24
17
  end
25
18
 
26
- def rel_type
27
- @match_value.include?(':') ? @match_value.split(':').last : @match_value.sub('?', '')
19
+ def match_value_from_args(expr)
20
+ if expr.first.is_a?(String)
21
+ expr.first
22
+ elsif expr.first.is_a?(Symbol)
23
+ ":#{expr.map { |e| match_value_from_symbol(e) }.join('|')}"
24
+ elsif expr.empty?
25
+ '?'
26
+ else
27
+ # try to join several RelVars to one rel var
28
+ ":#{expr.map { |e| e.clause.rel_type }.join('|')}"
29
+ end
28
30
  end
29
31
 
30
- def self.join(clause_list, rel_types)
31
- rel_string = rel_types.map { |r| _rel_to_string(clause_list, r) }.join('|')
32
+ def guess_var_name_from_string(expr)
33
+ guess = /([[:alpha:]_]*)/.match(expr)[1]
34
+ guess && !guess.empty? && guess
35
+ end
32
36
 
33
- if rel_string.empty?
34
- RelVar.new(clause_list, "")
35
- else
36
- RelVar.new(clause_list, ":#{rel_string}")
37
- end
37
+ def match_value_from_symbol(expr)
38
+ "`#{expr}`"
38
39
  end
39
40
 
40
- def self._rel_to_string(clause_list, rel_or_symbol)
41
- case rel_or_symbol
42
- when String, Symbol
43
- RelVar.new(clause_list, rel_or_symbol).rel_type
44
- when Neo4j::Cypher::RelVar::EvalContext
45
- rel_or_symbol.clause.rel_type
46
- else
47
- raise "Unknown type of relationship, got #{rel_or_symbol.class}"
48
- end
41
+ def rel_type
42
+ @match_value.include?(':') ? @match_value.split(':').last : @match_value.sub('?', '')
49
43
  end
50
44
 
51
45
  def referenced!
@@ -84,7 +84,6 @@ module Neo4j
84
84
  # The return statement in the cypher query
85
85
  class ReturnItem
86
86
  include Clause
87
- include Referenceable
88
87
  attr_accessor :order_by
89
88
 
90
89
  def initialize(clause_list, name_or_ref)
@@ -33,7 +33,7 @@ module Neo4j
33
33
  end
34
34
 
35
35
  def return_names
36
- ret = clause_list.clause_list.find{|r| r.respond_to?(:return_items)}
36
+ ret = clause_list.return_clause
37
37
  ret ? ret.return_items.map { |ri| (ri.alias_name || ri.return_value).to_sym } : []
38
38
  end
39
39
 
@@ -46,12 +46,10 @@ module Neo4j
46
46
  # @return self
47
47
  def match(*, &match_dsl)
48
48
  instance_eval(&match_dsl) if match_dsl
49
- self
50
49
  end
51
50
 
52
51
  def match_not(&match_dsl)
53
52
  instance_eval(&match_dsl).not
54
- self
55
53
  end
56
54
 
57
55
  # Does nothing, just for making the DSL easier to read (maybe)
@@ -60,29 +58,55 @@ module Neo4j
60
58
  self
61
59
  end
62
60
 
63
- def where(w=nil)
64
- Where.new(clause_list, w) if w.is_a?(String)
61
+ def where(w=nil, &block)
62
+ Where.new(clause_list, self, w, &block)
63
+ self
64
+ end
65
+
66
+ def where_not(w=nil, &block)
67
+ Where.new(clause_list, self, w, &block).neg!
65
68
  self
66
69
  end
67
70
 
68
71
  # Specifies a start node by performing a lucene query.
69
- # @param [Class] index_class a class responsible for an index
72
+ # @param [Class, String] index_class a class responsible for an index or the string value of the index
70
73
  # @param [String] q the lucene query
71
74
  # @param [Symbol] index_type the type of index
72
- # @return [NodeQuery]
75
+ # @return [LuceneQuery]
73
76
  def query(index_class, q, index_type = :exact)
74
- NodeQuery.new(clause_list, index_class, q, index_type).eval_context
77
+ LuceneQuery.query_node_by_class(clause_list, index_class, q, index_type).eval_context
78
+ end
79
+
80
+ # Specifies a start relationship by performing a lucene query.
81
+ # @param [Class, String] index_class a class responsible for an index or the string value of the index
82
+ # @param [String] q the lucene query
83
+ # @param [Symbol] index_type the type of index
84
+ # @return [LuceneQuery]
85
+ def query_rel(index_class, q, index_type = :exact)
86
+ LuceneQuery.query_rel_by_class(clause_list, index_class, q, index_type).eval_context
75
87
  end
76
88
 
89
+
77
90
  # Specifies a start node by performing a lucene query.
78
- # @param [Class] index_class a class responsible for an index
91
+ # @param [Class, String] index_class a class responsible for an index or the string value of the index
79
92
  # @param [String, Symbol] key the key we ask for
80
93
  # @param [String, Symbol] value the value of the key we ask for
81
- # @return [NodeLookup]
94
+ # @return [LuceneQuery]
82
95
  def lookup(index_class, key, value)
83
- NodeLookup.new(clause_list, index_class, key, value).eval_context
96
+ LuceneQuery.lookup_node_by_class(clause_list, index_class, key, value).eval_context
84
97
  end
85
98
 
99
+
100
+ # Specifies a start relationship by performing a lucene query.
101
+ # @param [Class, String] index_class a class responsible for an index or the string value of the index
102
+ # @param [String, Symbol] key the key we ask for
103
+ # @param [String, Symbol] value the value of the key we ask for
104
+ # @return [LuceneQuery]
105
+ def lookup_rel(index_class, key, value)
106
+ LuceneQuery.lookup_rel_by_class(clause_list, index_class, key, value).eval_context
107
+ end
108
+
109
+
86
110
  # Creates a node variable.
87
111
  # It will create different variables depending on the type of the first element in the nodes argument.
88
112
  # * Fixnum - it will be be used as neo_id for start node(s) (StartNode)
@@ -106,14 +130,9 @@ module Neo4j
106
130
  def rel(*rels)
107
131
  if rels.first.is_a?(Fixnum) || rels.first.respond_to?(:neo_id)
108
132
  StartRel.new(clause_list, rels).eval_context
109
- elsif rels.first.is_a?(Symbol)
110
- RelVar.new(clause_list, ":`#{rels.first}`", rels[1]).eval_context
111
- elsif rels.first.is_a?(String)
112
- RelVar.new(clause_list, rels.first, rels[1]).eval_context
113
- elsif rels.empty?
114
- RelVar.new(clause_list, '?').eval_context
115
133
  else
116
- raise "Unknown arg #{rels.inspect}"
134
+ props = rels.pop if rels.last.is_a?(Hash)
135
+ RelVar.new(clause_list, rels, props).eval_context
117
136
  end
118
137
  end
119
138
 
@@ -145,13 +164,16 @@ module Neo4j
145
164
  end
146
165
 
147
166
  def nodes(*args)
148
- s = args.map { |x| x.clause.referenced!; x.clause.var_name }.join(", ")
149
- ReturnItem.new(clause_list, "nodes(#{s})").eval_context
167
+ _entities(args, 'nodes')
150
168
  end
151
169
 
152
170
  def rels(*args)
153
- s = args.map { |x| x.clause.referenced!; x.clause.var_name }.join(", ")
154
- ReturnItem.new(clause_list, "relationships(#{s})").eval_context
171
+ _entities(args, 'relationships')
172
+ end
173
+
174
+ def _entities(arg_list, entity_type)
175
+ s = arg_list.map { |x| x.clause.referenced!; x.clause.var_name }.join(", ")
176
+ ReturnItem.new(clause_list, "#{entity_type}(#{s})").eval_context
155
177
  end
156
178
 
157
179
  def create_path(*args, &block)