neo4j-cypher 1.0.0.rc2 → 1.0.0
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.
- data/Gemfile +4 -0
- data/README.rdoc +28 -77
- data/lib/neo4j-cypher.rb +3 -1
- data/lib/neo4j-cypher/abstract_filter.rb +78 -0
- data/lib/neo4j-cypher/argument.rb +0 -1
- data/lib/neo4j-cypher/clause.rb +39 -1
- data/lib/neo4j-cypher/clause_list.rb +30 -15
- data/lib/neo4j-cypher/collection.rb +14 -0
- data/lib/neo4j-cypher/context.rb +27 -27
- data/lib/neo4j-cypher/create.rb +0 -3
- data/lib/neo4j-cypher/foreach.rb +16 -0
- data/lib/neo4j-cypher/match.rb +21 -18
- data/lib/neo4j-cypher/neography.rb +22 -0
- data/lib/neo4j-cypher/node_var.rb +0 -1
- data/lib/neo4j-cypher/operator.rb +4 -10
- data/lib/neo4j-cypher/predicate.rb +5 -56
- data/lib/neo4j-cypher/property.rb +4 -12
- data/lib/neo4j-cypher/rel_var.rb +25 -31
- data/lib/neo4j-cypher/return.rb +0 -1
- data/lib/neo4j-cypher/root.rb +44 -22
- data/lib/neo4j-cypher/start.rb +36 -40
- data/lib/neo4j-cypher/version.rb +2 -2
- data/lib/neo4j-cypher/where.rb +16 -3
- data/lib/neo4j-cypher/with.rb +1 -3
- data/lib/tasks/analyzer.rake +54 -0
- metadata +13 -6
- data/lib/neo4j-cypher/mixins.rb +0 -47
data/lib/neo4j-cypher/create.rb
CHANGED
@@ -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
|
data/lib/neo4j-cypher/match.rb
CHANGED
@@ -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.
|
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
|
-
|
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.
|
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
|
-
|
325
|
-
|
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
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
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
|
@@ -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)
|
52
|
-
clause_list.delete(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
|
55
|
+
def remove_operand?(operand)
|
58
56
|
clause = operand.respond_to?(:clause) ? operand.clause : operand
|
59
|
-
clause.kind_of?(Clause) && clause.clause_type == :
|
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,
|
9
|
-
super(clause_list,
|
10
|
-
|
11
|
-
|
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, ¶ms[: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(',')}]")
|
data/lib/neo4j-cypher/rel_var.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
27
|
-
|
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
|
31
|
-
|
32
|
+
def guess_var_name_from_string(expr)
|
33
|
+
guess = /([[:alpha:]_]*)/.match(expr)[1]
|
34
|
+
guess && !guess.empty? && guess
|
35
|
+
end
|
32
36
|
|
33
|
-
|
34
|
-
|
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
|
41
|
-
|
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!
|
data/lib/neo4j-cypher/return.rb
CHANGED
data/lib/neo4j-cypher/root.rb
CHANGED
@@ -33,7 +33,7 @@ module Neo4j
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def return_names
|
36
|
-
ret = clause_list.
|
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
|
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 [
|
75
|
+
# @return [LuceneQuery]
|
73
76
|
def query(index_class, q, index_type = :exact)
|
74
|
-
|
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 [
|
94
|
+
# @return [LuceneQuery]
|
82
95
|
def lookup(index_class, key, value)
|
83
|
-
|
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
|
-
|
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
|
-
|
149
|
-
ReturnItem.new(clause_list, "nodes(#{s})").eval_context
|
167
|
+
_entities(args, 'nodes')
|
150
168
|
end
|
151
169
|
|
152
170
|
def rels(*args)
|
153
|
-
|
154
|
-
|
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)
|