neo4j-core 0.0.1-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 (71) hide show
  1. data/Gemfile +27 -0
  2. data/README.rdoc +27 -0
  3. data/config/neo4j/config.yml +102 -0
  4. data/lib/db/active_tx_log +1 -0
  5. data/lib/db/index/lucene-store.db +0 -0
  6. data/lib/db/index/lucene.log.1 +0 -0
  7. data/lib/db/index/lucene.log.active +0 -0
  8. data/lib/db/lock +0 -0
  9. data/lib/db/messages.log +530 -0
  10. data/lib/db/neostore +0 -0
  11. data/lib/db/neostore.id +0 -0
  12. data/lib/db/neostore.nodestore.db +0 -0
  13. data/lib/db/neostore.nodestore.db.id +0 -0
  14. data/lib/db/neostore.propertystore.db +0 -0
  15. data/lib/db/neostore.propertystore.db.arrays +0 -0
  16. data/lib/db/neostore.propertystore.db.arrays.id +0 -0
  17. data/lib/db/neostore.propertystore.db.id +0 -0
  18. data/lib/db/neostore.propertystore.db.index +0 -0
  19. data/lib/db/neostore.propertystore.db.index.id +0 -0
  20. data/lib/db/neostore.propertystore.db.index.keys +0 -0
  21. data/lib/db/neostore.propertystore.db.index.keys.id +0 -0
  22. data/lib/db/neostore.propertystore.db.strings +0 -0
  23. data/lib/db/neostore.propertystore.db.strings.id +0 -0
  24. data/lib/db/neostore.relationshipstore.db +0 -0
  25. data/lib/db/neostore.relationshipstore.db.id +0 -0
  26. data/lib/db/neostore.relationshiptypestore.db +0 -0
  27. data/lib/db/neostore.relationshiptypestore.db.id +0 -0
  28. data/lib/db/neostore.relationshiptypestore.db.names +0 -0
  29. data/lib/db/neostore.relationshiptypestore.db.names.id +0 -0
  30. data/lib/db/nioneo_logical.log.2 +0 -0
  31. data/lib/db/nioneo_logical.log.active +0 -0
  32. data/lib/db/tm_tx_log.1 +0 -0
  33. data/lib/neo4j/config.rb +139 -0
  34. data/lib/neo4j/cypher.rb +156 -0
  35. data/lib/neo4j/neo4j.rb +244 -0
  36. data/lib/neo4j/neo4j.rb~ +214 -0
  37. data/lib/neo4j/node.rb +39 -0
  38. data/lib/neo4j/relationship.rb +61 -0
  39. data/lib/neo4j/transaction.rb +86 -0
  40. data/lib/neo4j/type_converters/type_converters.rb +287 -0
  41. data/lib/neo4j-core/cypher/cypher.rb +867 -0
  42. data/lib/neo4j-core/cypher/result_wrapper.rb +39 -0
  43. data/lib/neo4j-core/database.rb +191 -0
  44. data/lib/neo4j-core/equal/equal.rb +23 -0
  45. data/lib/neo4j-core/event_handler.rb +265 -0
  46. data/lib/neo4j-core/index/class_methods.rb +117 -0
  47. data/lib/neo4j-core/index/index.rb +36 -0
  48. data/lib/neo4j-core/index/index_config.rb +112 -0
  49. data/lib/neo4j-core/index/indexer.rb +243 -0
  50. data/lib/neo4j-core/index/indexer_registry.rb +55 -0
  51. data/lib/neo4j-core/index/lucene_query.rb +264 -0
  52. data/lib/neo4j-core/lazy_map.rb +21 -0
  53. data/lib/neo4j-core/node/class_methods.rb +77 -0
  54. data/lib/neo4j-core/node/node.rb +47 -0
  55. data/lib/neo4j-core/property/property.rb +94 -0
  56. data/lib/neo4j-core/relationship/class_methods.rb +80 -0
  57. data/lib/neo4j-core/relationship/relationship.rb +97 -0
  58. data/lib/neo4j-core/relationship_set.rb +61 -0
  59. data/lib/neo4j-core/rels/rels.rb +147 -0
  60. data/lib/neo4j-core/rels/traverser.rb +99 -0
  61. data/lib/neo4j-core/to_java.rb +51 -0
  62. data/lib/neo4j-core/traversal/evaluator.rb +36 -0
  63. data/lib/neo4j-core/traversal/filter_predicate.rb +30 -0
  64. data/lib/neo4j-core/traversal/prune_evaluator.rb +20 -0
  65. data/lib/neo4j-core/traversal/rel_expander.rb +35 -0
  66. data/lib/neo4j-core/traversal/traversal.rb +130 -0
  67. data/lib/neo4j-core/traversal/traverser.rb +295 -0
  68. data/lib/neo4j-core/version.rb +5 -0
  69. data/lib/neo4j-core.rb +64 -0
  70. data/neo4j-core.gemspec +31 -0
  71. metadata +145 -0
@@ -0,0 +1,867 @@
1
+ module Neo4j
2
+ module Core
3
+ module Cypher
4
+
5
+ module MathFunctions
6
+ def abs(value=nil)
7
+ _add_math_func(:abs, value)
8
+ end
9
+
10
+ def sqrt(value=nil)
11
+ _add_math_func(:sqrt, value)
12
+ end
13
+
14
+ def round(value=nil)
15
+ _add_math_func(:round, value)
16
+ end
17
+
18
+ def sign(value=nil)
19
+ _add_math_func(:sign, value)
20
+ end
21
+
22
+ def _add_math_func(name, value=nil)
23
+ value ||= self.respond_to?(:var_name) ? self.var_name : to_s
24
+ expressions.delete(self)
25
+ Property.new(expressions, nil, name).to_function!(value)
26
+ end
27
+ end
28
+
29
+ module MathOperator
30
+ def -(other)
31
+ ExprOp.new(self, other, '-')
32
+ end
33
+
34
+ def +(other)
35
+ ExprOp.new(self, other, '+')
36
+ end
37
+ end
38
+
39
+ module Comparable
40
+ def <(other)
41
+ ExprOp.new(self, other, '<')
42
+ end
43
+
44
+ def <=(other)
45
+ ExprOp.new(self, other, '<=')
46
+ end
47
+
48
+ def =~(other)
49
+ ExprOp.new(self, other, '=~')
50
+ end
51
+
52
+ def >(other)
53
+ ExprOp.new(self, other, '>')
54
+ end
55
+
56
+ def >=(other)
57
+ ExprOp.new(self, other, '>=')
58
+ end
59
+
60
+ ## Only in 1.9
61
+ if RUBY_VERSION > "1.9.0"
62
+ eval %{
63
+ def !=(other)
64
+ other.is_a?(String) ? ExprOp.new(self, other, "!=") : super
65
+ end }
66
+ end
67
+
68
+ def ==(other)
69
+ if other.is_a?(Fixnum) || other.is_a?(String) || other.is_a?(Regexp)
70
+ ExprOp.new(self, other, "=")
71
+ else
72
+ super
73
+ end
74
+ end
75
+ end
76
+
77
+ module PredicateMethods
78
+ def all?(&block)
79
+ self.respond_to?(:iterable)
80
+ Predicate.new(expressions, :op => 'all', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
81
+ end
82
+
83
+ def extract(&block)
84
+ Predicate.new(expressions, :op => 'extract', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
85
+ end
86
+
87
+ def filter(&block)
88
+ Predicate.new(expressions, :op => 'filter', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
89
+ end
90
+
91
+ def any?(&block)
92
+ Predicate.new(@expressions, :op => 'any', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
93
+ end
94
+
95
+ def none?(&block)
96
+ Predicate.new(@expressions, :op => 'none', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
97
+ end
98
+
99
+ def single?(&block)
100
+ Predicate.new(@expressions, :op => 'single', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
101
+ end
102
+
103
+ end
104
+
105
+ module Variable
106
+ attr_accessor :return_method
107
+
108
+ def distinct
109
+ self.return_method = {:name => 'distinct', :bracket => false}
110
+ self
111
+ end
112
+
113
+ def [](prop_name)
114
+ Property.new(expressions, self, prop_name)
115
+ end
116
+
117
+ def as(v)
118
+ @var_name = v
119
+ self
120
+ end
121
+
122
+ def neo_id
123
+ Property.new(@expressions, self, 'ID').to_function!
124
+ end
125
+
126
+ def property?(p)
127
+ p = Property.new(expressions, self, p)
128
+ p.binary_operator("has")
129
+ end
130
+
131
+ def exist?
132
+ p = Property.new(expressions, self, p)
133
+ p.binary_operator("", " is null")
134
+ end
135
+ end
136
+
137
+ module Matchable
138
+ # This operator means related to, without regard to type or direction.
139
+ # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
140
+ # @return [MatchRelLeft, MatchNode]
141
+ def <=>(other)
142
+ MatchNode.new(self, other, expressions, :both)
143
+ end
144
+
145
+ # This operator means outgoing related to
146
+ # @param [Symbol, #var_name, String] other the relationship
147
+ # @return [MatchRelLeft, MatchNode]
148
+ def >(other)
149
+ MatchRelLeft.new(self, other, expressions, :outgoing)
150
+ end
151
+
152
+ # This operator means any direction related to
153
+ # @param (see #>)
154
+ # @return [MatchRelLeft, MatchNode]
155
+ def -(other)
156
+ MatchRelLeft.new(self, other, expressions, :both)
157
+ end
158
+
159
+ # This operator means incoming related to
160
+ # @param (see #>)
161
+ # @return [MatchRelLeft, MatchNode]
162
+ def <(other)
163
+ MatchRelLeft.new(self, other, expressions, :incoming)
164
+ end
165
+
166
+ # Outgoing relationship to other node
167
+ # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
168
+ # @return [MatchRelLeft, MatchNode]
169
+ def >>(other)
170
+ MatchNode.new(self, other, expressions, :outgoing)
171
+ end
172
+
173
+ # Incoming relationship to other node
174
+ # @param [Symbol, #var_name] other either a node (Symbol, #var_name)
175
+ # @return [MatchRelLeft, MatchNode]
176
+ def <<(other)
177
+ MatchNode.new(self, other, expressions, :incoming)
178
+ end
179
+ end
180
+
181
+ class Expression
182
+ attr_reader :expressions
183
+ attr_accessor :separator, :clause
184
+
185
+ def initialize(expressions, clause)
186
+ @clause = clause
187
+ @expressions = expressions
188
+ insert_last(clause)
189
+ @separator = ","
190
+ end
191
+
192
+ def insert_last(clause)
193
+ i = @expressions.reverse.index { |e| e.clause == clause }
194
+ if i.nil?
195
+ @expressions << self
196
+ else
197
+ pos = @expressions.size - i
198
+ @expressions.insert(pos, self)
199
+ end
200
+ end
201
+
202
+ def prefixes
203
+ {:start => "START", :where => " WHERE", :match => " MATCH", :return => " RETURN", :order_by => " ORDER BY", :skip => " SKIP", :limit => " LIMIT"}
204
+ end
205
+
206
+ def prefix
207
+ prefixes[clause]
208
+ end
209
+
210
+ def valid?
211
+ true
212
+ end
213
+
214
+ end
215
+
216
+ class Property
217
+ attr_reader :expressions, :var_name
218
+ include Comparable
219
+ include MathOperator
220
+ include MathFunctions
221
+ include PredicateMethods
222
+
223
+ def initialize(expressions, var, prop_name)
224
+ @var = var.respond_to?(:var_name) ? var.var_name : var
225
+ @expressions = expressions
226
+ @prop_name = prop_name
227
+ @var_name = @prop_name ? "#{@var.to_s}.#{@prop_name}" : @var.to_s
228
+ end
229
+
230
+ def to_function!(var = @var.to_s)
231
+ @var_name = "#{@prop_name}(#{var})"
232
+ self
233
+ end
234
+
235
+ def as(new_name)
236
+ @var_name = "#{@var_name} AS #{new_name}"
237
+ end
238
+
239
+ # required by the Predicate Methods Module
240
+ # @see PredicateMethods
241
+ def iterable
242
+ var_name
243
+ end
244
+
245
+ def input
246
+ self
247
+ end
248
+
249
+ def in?(values)
250
+ binary_operator("", " IN [#{values.map { |x| %Q["#{x}"] }.join(',')}]")
251
+ end
252
+
253
+ def distinct
254
+ @var_name = "distinct #{@var_name}"
255
+ self
256
+ end
257
+
258
+ def length
259
+ @prop_name = "length"
260
+ to_function!
261
+ self
262
+ end
263
+
264
+ %w[count sum avg min max collect head last tail].each do |meth_name|
265
+ define_method(meth_name) do
266
+ function(meth_name.to_s)
267
+ end
268
+ end
269
+
270
+ def function(func_name_pre, func_name_post = "")
271
+ ExprOp.new(self, nil, func_name_pre, func_name_post)
272
+ end
273
+
274
+ def binary_operator(op, post_fix = "")
275
+ ExprOp.new(self, nil, op, post_fix).binary!
276
+ end
277
+ end
278
+
279
+ class Start < Expression
280
+ attr_reader :var_name
281
+ include Variable
282
+ include Matchable
283
+
284
+ def initialize(var_name, expressions)
285
+ @var_name = "#{var_name}#{expressions.size}"
286
+ super(expressions, :start)
287
+ end
288
+
289
+ end
290
+
291
+ class StartNode < Start
292
+ attr_reader :nodes
293
+
294
+ def initialize(nodes, expressions)
295
+ super("n", expressions)
296
+ @nodes = nodes.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
297
+ end
298
+
299
+ def to_s
300
+ "#{var_name}=node(#{nodes.join(',')})"
301
+ end
302
+ end
303
+
304
+ class StartRel < Start
305
+ attr_reader :rels
306
+
307
+ def initialize(rels, expressions)
308
+ super("r", expressions)
309
+ @rels = rels.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
310
+ end
311
+
312
+ def to_s
313
+ "#{var_name}=relationship(#{rels.join(',')})"
314
+ end
315
+ end
316
+
317
+ class NodeQuery < Start
318
+ attr_reader :index_name, :query
319
+
320
+ def initialize(index_class, query, index_type, expressions)
321
+ super("n", expressions)
322
+ @index_name = index_class.index_name_for_type(index_type)
323
+ @query = query
324
+ end
325
+
326
+ def to_s
327
+ "#{var_name}=node:#{index_name}(#{query})"
328
+ end
329
+ end
330
+
331
+ class NodeLookup < Start
332
+ attr_reader :index_name, :query
333
+
334
+ def initialize(index_class, key, value, expressions)
335
+ super("n", expressions)
336
+ index_type = index_class.index_type(key.to_s)
337
+ raise "No index on #{index_class} property #{key}" unless index_type
338
+ @index_name = index_class.index_name_for_type(index_type)
339
+ @query = %Q[#{key}="#{value}"]
340
+ end
341
+
342
+ def to_s
343
+ %Q[#{var_name}=node:#{index_name}(#{query})]
344
+ end
345
+
346
+ end
347
+
348
+ # The return statement in the cypher query
349
+ class Return < Expression
350
+ attr_reader :var_name
351
+
352
+ def initialize(name_or_ref, expressions, opts = {})
353
+ super(expressions, :return)
354
+ @name_or_ref = name_or_ref
355
+ @name_or_ref.referenced! if @name_or_ref.respond_to?(:referenced!)
356
+ @var_name = @name_or_ref.respond_to?(:var_name) ? @name_or_ref.var_name : @name_or_ref.to_s
357
+ opts.each_pair { |k, v| self.send(k, v) }
358
+ end
359
+
360
+ def return_method
361
+ @name_or_ref.respond_to?(:return_method) && @name_or_ref.return_method
362
+ end
363
+
364
+ def as_return_method
365
+ if return_method[:bracket]
366
+ "#{return_method[:name]}(#@var_name)"
367
+ else
368
+ "#{return_method[:name]} #@var_name"
369
+ end
370
+ end
371
+
372
+ # Specifies an <tt>ORDER BY</tt> cypher query
373
+ # @param [Property] props the properties which should be sorted
374
+ # @return self
375
+ def asc(*props)
376
+ @order_by ||= OrderBy.new(expressions)
377
+ @order_by.asc(props)
378
+ self
379
+ end
380
+
381
+ # Specifies an <tt>ORDER BY</tt> cypher query
382
+ # @param [Property] props the properties which should be sorted
383
+ # @return self
384
+ def desc(*props)
385
+ @order_by ||= OrderBy.new(expressions)
386
+ @order_by.desc(props)
387
+ self
388
+ end
389
+
390
+ # Creates a <tt>SKIP</tt> cypher clause
391
+ # @param [Fixnum] val the number of entries to skip
392
+ # @return self
393
+ def skip(val)
394
+ Skip.new(expressions, val)
395
+ self
396
+ end
397
+
398
+ # Creates a <tt>LIMIT</tt> cypher clause
399
+ # @param [Fixnum] val the number of entries to limit
400
+ # @return self
401
+ def limit(val)
402
+ Limit.new(expressions, val)
403
+ self
404
+ end
405
+
406
+ def to_s
407
+ return_method ? as_return_method : var_name.to_s
408
+ end
409
+ end
410
+
411
+ class Skip < Expression
412
+ def initialize(expressions, value)
413
+ super(expressions, :skip)
414
+ @value = value
415
+ end
416
+
417
+ def to_s
418
+ @value
419
+ end
420
+ end
421
+
422
+ class Limit < Expression
423
+ def initialize(expressions, value)
424
+ super(expressions, :limit)
425
+ @value = value
426
+ end
427
+
428
+ def to_s
429
+ @value
430
+ end
431
+ end
432
+
433
+ class OrderBy < Expression
434
+ def initialize(expressions)
435
+ super(expressions, :order_by)
436
+ end
437
+
438
+ def asc(props)
439
+ @asc ||= []
440
+ @asc += props
441
+ end
442
+
443
+ def desc(props)
444
+ @desc ||= []
445
+ @desc += props
446
+ end
447
+
448
+ def to_s
449
+ s = []
450
+ s << @asc.map { |p| p.var_name }.join(",") if @asc
451
+ s << @desc.map { |p| p.var_name.to_s + " DESC" }.join(",") if @desc
452
+ s.join(',')
453
+ end
454
+ end
455
+
456
+ class Match < Expression
457
+ attr_reader :dir, :expressions, :left, :right, :var_name, :dir_op
458
+ attr_accessor :algorithm, :next, :prev
459
+ include Variable
460
+
461
+ def initialize(left, right, expressions, dir, dir_op)
462
+ super(expressions, :match)
463
+ @var_name = "m#{expressions.size}"
464
+ @dir = dir
465
+ @dir_op = dir_op
466
+ @prev = left if left.is_a?(Match)
467
+ @left = left
468
+ @right = right
469
+ end
470
+
471
+
472
+ def nodes
473
+ Entities.new(@expressions, "nodes", self)
474
+ end
475
+
476
+ def rels
477
+ Entities.new(@expressions, "relationships", self)
478
+ end
479
+
480
+ def length
481
+ self.return_method = {:name => 'length', :bracket => true}
482
+ self
483
+ end
484
+
485
+ def find_match_start
486
+ c = self
487
+ while (c.prev) do
488
+ c = c.prev
489
+ end
490
+ c
491
+ end
492
+
493
+ def left_var_name
494
+ @left.respond_to?(:var_name) ? @left.var_name : @left.to_s
495
+ end
496
+
497
+ def right_var_name
498
+ @right.respond_to?(:var_name) ? @right.var_name : @right.to_s
499
+ end
500
+
501
+ def right_expr
502
+ @right.respond_to?(:expr) ? @right.expr : right_var_name
503
+ end
504
+
505
+ def referenced!
506
+ @referenced = true
507
+ end
508
+
509
+ def referenced?
510
+ !!@referenced
511
+ end
512
+
513
+ def to_s
514
+ curr = find_match_start
515
+ result = (referenced? || curr.referenced?) ? "#{var_name} = " : ""
516
+ result << (algorithm ? "#{algorithm}(" : "")
517
+ begin
518
+ result << curr.expr
519
+ end while (curr = curr.next)
520
+ result << ")" if algorithm
521
+ result
522
+ end
523
+ end
524
+
525
+ class MatchRelLeft < Match
526
+ def initialize(left, right, expressions, dir)
527
+ super(left, right, expressions, dir, dir == :incoming ? '<-' : '-')
528
+ end
529
+
530
+ # @param [Symbol,NodeVar,String] other part of the match cypher statement.
531
+ # @return [MatchRelRight] the right part of an relationship cypher query.
532
+ def >(other)
533
+ expressions.delete(self)
534
+ self.next = MatchRelRight.new(self, other, expressions, :outgoing)
535
+ end
536
+
537
+ # @see #>
538
+ # @return (see #>)
539
+ def <(other)
540
+ expressions.delete(self)
541
+ self.next = MatchRelRight.new(self, other, expressions, :incoming)
542
+ end
543
+
544
+ # @see #>
545
+ # @return (see #>)
546
+ def -(other)
547
+ expressions.delete(self)
548
+ self.next = MatchRelRight.new(self, other, expressions, :both)
549
+ end
550
+
551
+ # @return [String] a cypher string for this match.
552
+ def expr
553
+ if prev
554
+ # we have chained more then one relationships in a match expression
555
+ "#{dir_op}[#{right_expr}]"
556
+ else
557
+ # the right is an relationship and could be an expressions, e.g "r?"
558
+ "(#{left_var_name})#{dir_op}[#{right_expr}]"
559
+ end
560
+ end
561
+ end
562
+
563
+ class MatchRelRight < Match
564
+ # @param left the left part of the query
565
+ # @param [Symbol,NodeVar,String] right part of the match cypher statement.
566
+ def initialize(left, right, expressions, dir)
567
+ super(left, right, expressions, dir, dir == :outgoing ? '->' : '-')
568
+ end
569
+
570
+ # @param [Symbol,NodeVar,String] other part of the match cypher statement.
571
+ # @return [MatchRelLeft] the right part of an relationship cypher query.
572
+ def >(other)
573
+ expressions.delete(self)
574
+ self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
575
+ end
576
+
577
+ # @see #>
578
+ # @return (see #>)
579
+ def <(other)
580
+ expressions.delete(self)
581
+ self.next = MatchRelLeft.new(self, other, expressions, :incoming)
582
+ end
583
+
584
+ # @see #>
585
+ # @return (see #>)
586
+ def -(other)
587
+ expressions.delete(self)
588
+ self.next = MatchRelLeft.new(self, other, expressions, :both)
589
+ end
590
+
591
+ # @return [String] a cypher string for this match.
592
+ def expr
593
+ "#{dir_op}(#{right_var_name})"
594
+ end
595
+ end
596
+
597
+ class MatchNode < Match
598
+ attr_reader :dir_op
599
+
600
+ def initialize(left, right, expressions, dir)
601
+ dir_op = case dir
602
+ when :outgoing then
603
+ "-->"
604
+ when :incoming then
605
+ "<--"
606
+ when :both then
607
+ "--"
608
+ end
609
+ super(left, right, expressions, dir, dir_op)
610
+ end
611
+
612
+ # @return [String] a cypher string for this match.
613
+ def expr
614
+ if prev
615
+ # we have chained more then one relationships in a match expression
616
+ "#{dir_op}(#{right_expr})"
617
+ else
618
+ # the right is an relationship and could be an expressions, e.g "r?"
619
+ "(#{left_var_name})#{dir_op}(#{right_expr})"
620
+ end
621
+ end
622
+
623
+ def <<(other)
624
+ expressions.delete(self)
625
+ self.next = MatchNode.new(self, other, expressions, :incoming)
626
+ end
627
+
628
+ def >>(other)
629
+ expressions.delete(self)
630
+ self.next = MatchNode.new(self, other, expressions, :outgoing)
631
+ end
632
+
633
+ # @param [Symbol,NodeVar,String] other part of the match cypher statement.
634
+ # @return [MatchRelRight] the right part of an relationship cypher query.
635
+ def >(other)
636
+ expressions.delete(self)
637
+ self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
638
+ end
639
+
640
+ # @see #>
641
+ # @return (see #>)
642
+ def <(other)
643
+ expressions.delete(self)
644
+ self.next = MatchRelLeft.new(self, other, expressions, :incoming)
645
+ end
646
+
647
+ # @see #>
648
+ # @return (see #>)
649
+ def -(other)
650
+ expressions.delete(self)
651
+ self.next = MatchRelLeft.new(self, other, expressions, :both)
652
+ end
653
+
654
+ end
655
+
656
+ # Represents an unbound node variable used in match statements
657
+ class NodeVar
658
+ include Variable
659
+ include Matchable
660
+
661
+ # @return the name of the variable
662
+ attr_reader :var_name
663
+ attr_reader :expressions
664
+
665
+ def initialize(expressions, variables)
666
+ @var_name = "v#{variables.size}"
667
+ variables << self
668
+ @expressions = expressions
669
+ end
670
+
671
+ # @return [String] a cypher string for this node variable
672
+ def to_s
673
+ var_name
674
+ end
675
+
676
+ end
677
+
678
+ # represent an unbound relationship variable used in match,where,return statement
679
+ class RelVar
680
+ include Variable
681
+
682
+ attr_reader :var_name, :expr, :expressions
683
+
684
+ def initialize(expressions, variables, expr)
685
+ variables << self
686
+ @expr = expr
687
+ @expressions = expressions
688
+ guess = expr ? /([[:alpha:]]*)/.match(expr)[1] : ""
689
+ @var_name = guess.empty? ? "v#{variables.size}" : guess
690
+ end
691
+
692
+ def rel_type
693
+ Property.new(@expressions, self, 'type').to_function!
694
+ end
695
+
696
+ # @return [String] a cypher string for this relationship variable
697
+ def to_s
698
+ var_name
699
+ end
700
+
701
+ end
702
+
703
+ class ExprOp < Expression
704
+ attr_reader :left, :right, :op, :neg, :post_fix
705
+ include MathFunctions
706
+
707
+ def initialize(left, right, op, post_fix = "")
708
+ super(left.expressions, :where)
709
+ @op = op
710
+ @post_fix = post_fix
711
+ self.expressions.delete(left)
712
+ self.expressions.delete(right)
713
+ @left = quote(left)
714
+ if regexp?(right)
715
+ @op = "=~"
716
+ @right = to_regexp(right)
717
+ else
718
+ @right = right && quote(right)
719
+ end
720
+ @neg = nil
721
+ end
722
+
723
+ def separator
724
+ " "
725
+ end
726
+
727
+ def quote(val)
728
+ if val.respond_to?(:var_name)
729
+ val.var_name
730
+ else
731
+ val.is_a?(String) ? %Q["#{val}"] : val
732
+ end
733
+ end
734
+
735
+ def regexp?(right)
736
+ @op == "=~" || right.is_a?(Regexp)
737
+ end
738
+
739
+ def to_regexp(val)
740
+ %Q[/#{val.respond_to?(:source) ? val.source : val.to_s}/]
741
+ end
742
+
743
+ def count
744
+ ExprOp.new(self, nil, 'count')
745
+ end
746
+
747
+ def &(other)
748
+ ExprOp.new(self, other, "and")
749
+ end
750
+
751
+ def |(other)
752
+ ExprOp.new(self, other, "or")
753
+ end
754
+
755
+ def -@
756
+ @neg = "not"
757
+ self
758
+ end
759
+
760
+ def not
761
+ @neg = "not"
762
+ self
763
+ end
764
+
765
+ # Only in 1.9
766
+ if RUBY_VERSION > "1.9.0"
767
+ eval %{
768
+ def !
769
+ @neg = "not"
770
+ self
771
+ end
772
+ }
773
+ end
774
+
775
+ def left_to_s
776
+ left.is_a?(ExprOp) ? "(#{left})" : left
777
+ end
778
+
779
+ def right_to_s
780
+ right.is_a?(ExprOp) ? "(#{right})" : right
781
+ end
782
+
783
+ def binary!
784
+ @binary = true
785
+ self
786
+ end
787
+
788
+ def valid?
789
+ # puts "valid? @binary=#{@binary} (#@left #@op #@right) in clause #{clause} ret #{@binary ? !!@left : !!@left && !!@right}"
790
+ # it is only valid in a where clause if it's either binary or it has right and left values
791
+ @binary ? @left : @left && @right
792
+ end
793
+
794
+ def to_s
795
+ if @right
796
+ neg ? "#{neg}(#{left_to_s} #{op} #{right_to_s})" : "#{left_to_s} #{op} #{right_to_s}"
797
+ else
798
+ # binary operator
799
+ neg ? "#{neg}#{op}(#{left_to_s}#{post_fix})" : "#{op}(#{left_to_s}#{post_fix})"
800
+ end
801
+ end
802
+ end
803
+
804
+ class Where < Expression
805
+ def initialize(expressions, where_statement = nil)
806
+ super(expressions, :where)
807
+ @where_statement = where_statement
808
+ end
809
+
810
+ def to_s
811
+ @where_statement.to_s
812
+ end
813
+ end
814
+
815
+ class Predicate < Expression
816
+ attr_accessor :params
817
+
818
+ def initialize(expressions, params)
819
+ @params = params
820
+ @identifier = :x
821
+ params[:input].referenced! if params[:input].respond_to?(:referenced!)
822
+ super(expressions, params[:clause])
823
+ end
824
+
825
+ def identifier(i)
826
+ @identifier = i
827
+ self
828
+ end
829
+
830
+ def to_s
831
+ input = params[:input]
832
+ if input.kind_of?(Property)
833
+ yield_param = Property.new([], @identifier, nil)
834
+ args = ""
835
+ else
836
+ yield_param = NodeVar.new([], []).as(@identifier.to_sym)
837
+ args = "(#{input.var_name})"
838
+ end
839
+ context = Neo4j::Cypher.new(yield_param, &params[:predicate_block])
840
+ context.expressions.each { |e| e.clause = nil }
841
+ if params[:clause] == :return
842
+ where_or_colon = ':'
843
+ else
844
+ where_or_colon = 'WHERE'
845
+ end
846
+ predicate_value = context.to_s[1..-1] # skip separator ,
847
+ "#{params[:op]}(#@identifier in #{params[:iterable]}#{args} #{where_or_colon} #{predicate_value})"
848
+ end
849
+ end
850
+
851
+ class Entities
852
+ include PredicateMethods
853
+ attr_reader :input, :expressions, :iterable
854
+
855
+ def initialize(expressions, iterable, input)
856
+ @iterable = iterable
857
+ @input = input
858
+ @expressions = expressions
859
+ end
860
+
861
+ end
862
+
863
+ end
864
+
865
+ end
866
+
867
+ end