neo4j-core 0.0.15-java → 2.0.0.alpha.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.
- data/Gemfile +2 -2
- data/README.rdoc +12 -192
- data/lib/neo4j-core.rb +3 -19
- data/lib/neo4j-core/database.rb +5 -4
- data/lib/neo4j-core/event_handler.rb +1 -1
- data/lib/neo4j-core/index/class_methods.rb +41 -27
- data/lib/neo4j-core/index/index.rb +4 -3
- data/lib/neo4j-core/index/index_config.rb +23 -30
- data/lib/neo4j-core/index/indexer.rb +53 -65
- data/lib/neo4j-core/index/indexer_registry.rb +2 -2
- data/lib/neo4j-core/index/lucene_query.rb +42 -53
- data/lib/neo4j-core/node/class_methods.rb +4 -4
- data/lib/neo4j-core/node/node.rb +8 -1
- data/lib/neo4j-core/property/property.rb +3 -1
- data/lib/neo4j-core/relationship/relationship.rb +10 -8
- data/lib/neo4j-core/rels/rels.rb +4 -9
- data/lib/neo4j-core/rels/traverser.rb +27 -13
- data/lib/neo4j-core/traversal/prune_evaluator.rb +2 -2
- data/lib/neo4j-core/traversal/traverser.rb +27 -122
- data/lib/neo4j-core/type_converters/type_converters.rb +287 -0
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core/version.rb~ +3 -0
- data/lib/neo4j/config.rb +6 -3
- data/lib/neo4j/neo4j.rb +22 -51
- data/lib/neo4j/node.rb +0 -27
- data/lib/neo4j/relationship.rb +0 -25
- data/lib/test.rb +27 -0
- data/neo4j-core.gemspec +2 -2
- metadata +11 -17
- data/lib/neo4j-core/cypher/cypher.rb +0 -969
- data/lib/neo4j-core/cypher/result_wrapper.rb +0 -48
- data/lib/neo4j-core/hash_with_indifferent_access.rb +0 -165
- data/lib/neo4j-core/index/unique_factory.rb +0 -54
- data/lib/neo4j-core/property/java.rb +0 -59
- data/lib/neo4j-core/wrapper/class_methods.rb +0 -22
- data/lib/neo4j-core/wrapper/wrapper.rb +0 -20
- data/lib/neo4j/algo.rb +0 -300
- data/lib/neo4j/cypher.rb +0 -180
data/lib/neo4j-core/version.rb
CHANGED
data/lib/neo4j/config.rb
CHANGED
@@ -37,7 +37,7 @@ module Neo4j
|
|
37
37
|
# @return [Hash] the default file loaded by yaml
|
38
38
|
def defaults
|
39
39
|
require 'yaml'
|
40
|
-
@defaults ||=
|
40
|
+
@defaults ||= YAML.load_file(default_file)
|
41
41
|
end
|
42
42
|
|
43
43
|
# @return [String] the expanded path of the Config[:storage_path] property
|
@@ -56,7 +56,7 @@ module Neo4j
|
|
56
56
|
# @yield config
|
57
57
|
# @yieldparam [Neo4j::Config] config - this configuration class
|
58
58
|
def use
|
59
|
-
@configuration ||=
|
59
|
+
@configuration ||= {}
|
60
60
|
yield @configuration
|
61
61
|
nil
|
62
62
|
end
|
@@ -123,13 +123,16 @@ module Neo4j
|
|
123
123
|
map
|
124
124
|
end
|
125
125
|
|
126
|
+
private
|
127
|
+
|
126
128
|
# @return The a new configuration using default values as a hash.
|
127
129
|
def setup()
|
128
|
-
@configuration =
|
130
|
+
@configuration = {}
|
129
131
|
@configuration.merge!(defaults)
|
130
132
|
@configuration
|
131
133
|
end
|
132
134
|
|
135
|
+
|
133
136
|
end
|
134
137
|
end
|
135
138
|
|
data/lib/neo4j/neo4j.rb
CHANGED
@@ -5,17 +5,10 @@
|
|
5
5
|
# The Neo4j modules is used to interact with an Neo4j Database instance.
|
6
6
|
# You can for example start and stop an instance and list all the nodes that exist in the database.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
# require 'neo4j'
|
10
|
-
# Neo4j::Transaction.run { Neo4j.ref_node.outgoing(:friends) << Neo4j::Node.new(:name => 'andreas')}
|
11
|
-
# Neo4j.ref_node.node(:outgoing, :friends)[:name] #=> 'andreas'
|
12
|
-
# Neo4j.query(Neo4j.ref_node){|ref| ref > ':friends' > :x; :x}
|
13
|
-
#
|
14
|
-
# ==== Notice - Starting and Stopping Neo4j
|
8
|
+
# === Starting and Stopping Neo4j
|
15
9
|
# You don't normally need to start the Neo4j database since it will be automatically started when needed.
|
16
10
|
# Before the database is started you should configure where the database is stored, see {Neo4j::Config]}.
|
17
11
|
#
|
18
|
-
#
|
19
12
|
module Neo4j
|
20
13
|
|
21
14
|
# @return [String] The version of the Neo4j jar files
|
@@ -58,10 +51,9 @@ module Neo4j
|
|
58
51
|
end
|
59
52
|
|
60
53
|
# Checks read only mode of the database. Only one process can have write access to the database.
|
61
|
-
# It will always return false if the database is not started yet.
|
62
54
|
# @return [true, false] if the database has started up in read only mode
|
63
55
|
def read_only?
|
64
|
-
|
56
|
+
(@db && @db.graph && @db.read_only?)
|
65
57
|
end
|
66
58
|
|
67
59
|
# Returns a started db instance. Starts it's not running.
|
@@ -72,10 +64,14 @@ module Neo4j
|
|
72
64
|
db
|
73
65
|
end
|
74
66
|
|
75
|
-
#
|
76
|
-
|
67
|
+
# Runs all user defined migrations.
|
68
|
+
def migrate!
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [String, nil] the current storage path of a running neo4j database. If the database is not running it returns nil.
|
77
73
|
def storage_path
|
78
|
-
return
|
74
|
+
return nil unless db.running?
|
79
75
|
db.storage_path
|
80
76
|
end
|
81
77
|
|
@@ -89,42 +85,18 @@ module Neo4j
|
|
89
85
|
# Check the neo4j
|
90
86
|
# Returns an enumerable of hash values.
|
91
87
|
#
|
92
|
-
# @example
|
93
|
-
# q = Neo4j.query{ match node(3) <=> node(:x); ret :x}
|
94
|
-
# q.first[:n] #=> the @node
|
95
|
-
# q.columns.first => :n
|
96
|
-
#
|
97
|
-
# @example Using the Cypher DSL and one parameter (n=Neo4j.ref_node)
|
98
|
-
# q = Neo4j.query(Neo4j.ref_node){|n| n <=> node(:x); :x}
|
99
|
-
# q.first[:n] #=> the @node
|
100
|
-
# q.columns.first => :n
|
101
|
-
#
|
102
|
-
# @example Using an array of nodes
|
103
|
-
# # same as - two_nodes=node(Neo4j.ref_node.neo_id, node_b.neo_id), b = node(b.neo_id)
|
104
|
-
# q = Neo4j.query([Neo4j.ref_node, node_b], node_c){|two_nodes, b| two_nodes <=> b; b}
|
88
|
+
# @example
|
105
89
|
#
|
106
|
-
#
|
107
|
-
# q
|
108
|
-
# q.first
|
109
|
-
# q.columns.first => :n
|
90
|
+
# q = Neo4j.query("START n=node({node}) RETURN n", 'node' => @node.neo_id)
|
91
|
+
# q.first['n'] #=> the @node
|
92
|
+
# q.columns.first => 'n'
|
110
93
|
#
|
111
|
-
# @see Cypher
|
112
|
-
# @see http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation
|
94
|
+
# @see {http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation}
|
113
95
|
# @note Returns a read-once only forward iterable.
|
114
|
-
# @
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
_query(q)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Performs a cypher query with given string
|
122
|
-
# @param [String] q the cypher query as a String
|
123
|
-
# @return (see #query)
|
124
|
-
def _query(q)
|
125
|
-
engine = Java::OrgNeo4jCypherJavacompat::ExecutionEngine.new(db)
|
126
|
-
result = engine.execute(q)
|
127
|
-
Neo4j::Core::Cypher::ResultWrapper.new(result)
|
96
|
+
# @return [Enumerable] a forward read once only Enumerable, containing hash values.
|
97
|
+
def query(query, params = {})
|
98
|
+
engine = org.neo4j.cypher.javacompat.ExecutionEngine.new(db)
|
99
|
+
engine.execute(query, params)
|
128
100
|
end
|
129
101
|
|
130
102
|
|
@@ -193,7 +165,7 @@ module Neo4j
|
|
193
165
|
|
194
166
|
# Usually, a client attaches relationships to this node that leads into various parts of the node space.
|
195
167
|
# ®return the reference node, which is a "starting point" in the node space.
|
196
|
-
# @note In case the ref_node has been assigned via the threadlocal_ref_node method,
|
168
|
+
# @note In case the ref_node has been assigned via the threadlocal_ref_node method,
|
197
169
|
# then that node will be returned instead.
|
198
170
|
# @see the design guide at http://wiki.neo4j.org/content/Design_Guide
|
199
171
|
def ref_node(this_db = self.started_db)
|
@@ -227,16 +199,15 @@ module Neo4j
|
|
227
199
|
# Neo4j.management(org.neo4j.management.HighAvailability).isMaster
|
228
200
|
#
|
229
201
|
# @param jmx_clazz the JMX class http://api.neo4j.org/current/org/neo4j/management/package-summary.html
|
230
|
-
# @param this_db default currently
|
202
|
+
# @param this_db default currently runnig instance or a newly started neo4j db instance
|
231
203
|
# @see for the jmx_clazz p
|
232
|
-
|
233
|
-
def management(jmx_clazz = Java::OrgNeo4jJmx::Primitives, this_db = self.started_db)
|
204
|
+
def management(jmx_clazz = org.neo4j.jmx.Primitives, this_db = self.started_db)
|
234
205
|
this_db.management(jmx_clazz)
|
235
206
|
end
|
236
207
|
|
237
208
|
# @return [Enumerable] all nodes in the database
|
238
209
|
def all_nodes(this_db = self.started_db)
|
239
|
-
Enumerator.new(this_db, :each_node)
|
210
|
+
Enumerable::Enumerator.new(this_db, :each_node)
|
240
211
|
end
|
241
212
|
|
242
213
|
# @return [Enumerable] all nodes in the database but not wrapped in ruby classes.
|
data/lib/neo4j/node.rb
CHANGED
@@ -9,39 +9,14 @@ module Neo4j
|
|
9
9
|
# *org.neo4j.kernel.impl.core.NodeProxy* object. This java object includes the same mixin as this class. The #class method on the java object
|
10
10
|
# returns Neo4j::Node in order to make it feel like an ordinary Ruby object.
|
11
11
|
#
|
12
|
-
# @example Create a node with one property (see {Neo4j::Core::Node::ClassMethods})
|
13
|
-
# Neo4j::Node.new(:name => 'andreas')
|
14
|
-
#
|
15
|
-
# @example Create a relationship (see {Neo4j::Core::Traversal})
|
16
|
-
# Neo4j::Node.new.outgoing(:friends) << Neo4j::Node.new
|
17
|
-
#
|
18
|
-
# @example Finding relationships (see {Neo4j::Core::Rels})
|
19
|
-
# node.rels(:outgoing, :friends)
|
20
|
-
#
|
21
|
-
# @example Lucene index (see {Neo4j::Core::Index})
|
22
|
-
# Neo4j::Node.trigger_on(:typex => 'MyTypeX')
|
23
|
-
# Neo4j::Node.index(:name)
|
24
|
-
# a = Neo4j::Node.new(:name => 'andreas', :typex => 'MyTypeX')
|
25
|
-
# # finish_tx
|
26
|
-
# Neo4j::Node.find(:name => 'andreas').first.should == a
|
27
|
-
#
|
28
12
|
class Node
|
29
13
|
extend Neo4j::Core::Node::ClassMethods
|
30
|
-
extend Neo4j::Core::Wrapper::ClassMethods
|
31
|
-
extend Neo4j::Core::Index::ClassMethods
|
32
14
|
|
33
15
|
include Neo4j::Core::Property
|
34
16
|
include Neo4j::Core::Rels
|
35
17
|
include Neo4j::Core::Traversal
|
36
18
|
include Neo4j::Core::Equal
|
37
19
|
include Neo4j::Core::Node
|
38
|
-
include Neo4j::Core::Wrapper
|
39
|
-
include Neo4j::Core::Property::Java # for documentation purpose only
|
40
|
-
include Neo4j::Core::Index
|
41
|
-
|
42
|
-
node_indexer do
|
43
|
-
index_names :exact => 'default_node_index_exact', :fulltext => 'default_node_index_fulltext'
|
44
|
-
end
|
45
20
|
|
46
21
|
class << self
|
47
22
|
|
@@ -54,8 +29,6 @@ module Neo4j
|
|
54
29
|
include Neo4j::Core::Traversal
|
55
30
|
include Neo4j::Core::Equal
|
56
31
|
include Neo4j::Core::Node
|
57
|
-
include Neo4j::Core::Wrapper
|
58
|
-
include Neo4j::Core::Index
|
59
32
|
end
|
60
33
|
end
|
61
34
|
end
|
data/lib/neo4j/relationship.rb
CHANGED
@@ -29,36 +29,13 @@ module Neo4j
|
|
29
29
|
#
|
30
30
|
# node.outgoing(:friends) << other_node << yet_another_node
|
31
31
|
#
|
32
|
-
# @example lucene index
|
33
|
-
# Neo4j::Relationship.trigger_on(:typey => 123)
|
34
|
-
# Neo4j::Relationship.index(:name)
|
35
|
-
# a = Neo4j::Relationship.new(:friends, Neo4j::Node.new, Neo4j::Node.new, :typey => 123, :name => 'kalle')
|
36
|
-
# # Finish tx
|
37
|
-
# Neo4j::Relationship.find(:name => 'kalle').first.should be_nil
|
38
|
-
#
|
39
32
|
# @see http://api.neo4j.org/current/org/neo4j/graphdb/Relationship.html
|
40
33
|
#
|
41
34
|
class Relationship
|
42
35
|
extend Neo4j::Core::Relationship::ClassMethods
|
43
|
-
extend Neo4j::Core::Wrapper::ClassMethods
|
44
|
-
extend Neo4j::Core::Index::ClassMethods
|
45
|
-
|
46
36
|
include Neo4j::Core::Property
|
47
37
|
include Neo4j::Core::Equal
|
48
38
|
include Neo4j::Core::Relationship
|
49
|
-
include Neo4j::Core::Wrapper
|
50
|
-
include Neo4j::Core::Property::Java # for documentation purpose only
|
51
|
-
include Neo4j::Core::Index
|
52
|
-
|
53
|
-
|
54
|
-
# (see Neo4j::Core::Relationship::ClassMethods#new)
|
55
|
-
def initialize(rel_type, start_node, end_node, props={})
|
56
|
-
end
|
57
|
-
|
58
|
-
|
59
|
-
rel_indexer do
|
60
|
-
index_names :exact => 'default_rel_index_exact', :fulltext => 'default_rel_index_fulltext'
|
61
|
-
end
|
62
39
|
|
63
40
|
class << self
|
64
41
|
def extend_java_class(java_clazz) #:nodoc:
|
@@ -66,8 +43,6 @@ module Neo4j
|
|
66
43
|
include Neo4j::Core::Property
|
67
44
|
include Neo4j::Core::Equal
|
68
45
|
include Neo4j::Core::Relationship
|
69
|
-
include Neo4j::Core::Wrapper
|
70
|
-
include Neo4j::Core::Index
|
71
46
|
end
|
72
47
|
end
|
73
48
|
|
data/lib/test.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
puts "TEST"
|
2
|
+
|
3
|
+
class LazyMap
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def initialize(stuff, &map_block)
|
7
|
+
@stuff = stuff
|
8
|
+
@map_block = map_block
|
9
|
+
end
|
10
|
+
|
11
|
+
def each
|
12
|
+
@stuff.each{|x| yield @map_block.call(x)}
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
class Foo
|
18
|
+
include Enumerable
|
19
|
+
|
20
|
+
def each
|
21
|
+
(1..5).to_a.each do |x|
|
22
|
+
yield x
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
e = LazyMap.new(Foo.new, &:to_s)
|
27
|
+
puts "Max #{e.find{|x| x == "2"}}"
|
data/neo4j-core.gemspec
CHANGED
@@ -25,7 +25,7 @@ It comes included with the Apache Lucene document database.
|
|
25
25
|
s.files = Dir.glob("{bin,lib,config}/**/*") + %w(README.rdoc Gemfile neo4j-core.gemspec)
|
26
26
|
s.has_rdoc = true
|
27
27
|
s.extra_rdoc_files = %w( README.rdoc )
|
28
|
-
s.rdoc_options = ["--quiet", "--title", "Neo4j
|
28
|
+
s.rdoc_options = ["--quiet", "--title", "Neo4j.rb", "--line-numbers", "--main", "README.rdoc", "--inline-source"]
|
29
29
|
|
30
|
-
s.add_dependency("neo4j-community", "
|
30
|
+
s.add_dependency("neo4j-community", "1.6.1.alpha.1")
|
31
31
|
end
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.0.
|
4
|
+
prerelease: 6
|
5
|
+
version: 2.0.0.alpha.1
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- Andreas Ronge
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-03-11 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: neo4j-community
|
@@ -18,9 +18,9 @@ dependencies:
|
|
18
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
|
-
- - "
|
21
|
+
- - "="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 1.
|
23
|
+
version: 1.6.1.alpha.1
|
24
24
|
type: :runtime
|
25
25
|
version_requirements: *id001
|
26
26
|
description: |
|
@@ -37,10 +37,9 @@ extensions: []
|
|
37
37
|
extra_rdoc_files:
|
38
38
|
- README.rdoc
|
39
39
|
files:
|
40
|
+
- lib/test.rb
|
40
41
|
- lib/neo4j-core.rb
|
41
42
|
- lib/neo4j/config.rb
|
42
|
-
- lib/neo4j/algo.rb
|
43
|
-
- lib/neo4j/cypher.rb
|
44
43
|
- lib/neo4j/transaction.rb
|
45
44
|
- lib/neo4j/neo4j.rb
|
46
45
|
- lib/neo4j/neo4j.rb~
|
@@ -48,14 +47,13 @@ files:
|
|
48
47
|
- lib/neo4j/relationship.rb
|
49
48
|
- lib/neo4j-core/event_handler.rb
|
50
49
|
- lib/neo4j-core/lazy_map.rb
|
51
|
-
- lib/neo4j-core/
|
50
|
+
- lib/neo4j-core/version.rb~
|
52
51
|
- lib/neo4j-core/database.rb
|
53
52
|
- lib/neo4j-core/relationship_set.rb
|
54
53
|
- lib/neo4j-core/version.rb
|
55
54
|
- lib/neo4j-core/to_java.rb
|
56
55
|
- lib/neo4j-core/node/node.rb
|
57
56
|
- lib/neo4j-core/node/class_methods.rb
|
58
|
-
- lib/neo4j-core/property/java.rb
|
59
57
|
- lib/neo4j-core/property/property.rb
|
60
58
|
- lib/neo4j-core/equal/equal.rb
|
61
59
|
- lib/neo4j-core/traversal/rel_expander.rb
|
@@ -64,21 +62,17 @@ files:
|
|
64
62
|
- lib/neo4j-core/traversal/traversal.rb
|
65
63
|
- lib/neo4j-core/traversal/traverser.rb
|
66
64
|
- lib/neo4j-core/traversal/evaluator.rb
|
65
|
+
- lib/neo4j-core/type_converters/type_converters.rb
|
67
66
|
- lib/neo4j-core/rels/traverser.rb
|
68
67
|
- lib/neo4j-core/rels/rels.rb
|
69
|
-
- lib/neo4j-core/wrapper/wrapper.rb
|
70
|
-
- lib/neo4j-core/wrapper/class_methods.rb
|
71
68
|
- lib/neo4j-core/index/index_config.rb
|
72
69
|
- lib/neo4j-core/index/indexer.rb
|
73
70
|
- lib/neo4j-core/index/lucene_query.rb
|
74
71
|
- lib/neo4j-core/index/indexer_registry.rb
|
75
|
-
- lib/neo4j-core/index/unique_factory.rb
|
76
72
|
- lib/neo4j-core/index/class_methods.rb
|
77
73
|
- lib/neo4j-core/index/index.rb
|
78
74
|
- lib/neo4j-core/relationship/class_methods.rb
|
79
75
|
- lib/neo4j-core/relationship/relationship.rb
|
80
|
-
- lib/neo4j-core/cypher/cypher.rb
|
81
|
-
- lib/neo4j-core/cypher/result_wrapper.rb
|
82
76
|
- config/neo4j/config.yml
|
83
77
|
- README.rdoc
|
84
78
|
- Gemfile
|
@@ -90,7 +84,7 @@ post_install_message:
|
|
90
84
|
rdoc_options:
|
91
85
|
- --quiet
|
92
86
|
- --title
|
93
|
-
- Neo4j
|
87
|
+
- Neo4j.rb
|
94
88
|
- --line-numbers
|
95
89
|
- --main
|
96
90
|
- README.rdoc
|
@@ -106,9 +100,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
106
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
101
|
none: false
|
108
102
|
requirements:
|
109
|
-
- - "
|
103
|
+
- - ">"
|
110
104
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
105
|
+
version: 1.3.1
|
112
106
|
requirements: []
|
113
107
|
|
114
108
|
rubyforge_project: neo4j-core
|
@@ -1,969 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
module Core
|
3
|
-
|
4
|
-
# This module contains a number of mixins and classes used by the neo4j.rb cypher DSL.
|
5
|
-
# The Cypher DSL is evaluated in the context of {Neo4j::Cypher} which contains a number of methods (e.g. {Neo4j::Cypher#node})
|
6
|
-
# which returns classes from this module.
|
7
|
-
module Cypher
|
8
|
-
|
9
|
-
module MathFunctions
|
10
|
-
def abs(value=nil)
|
11
|
-
_add_math_func(:abs, value)
|
12
|
-
end
|
13
|
-
|
14
|
-
def sqrt(value=nil)
|
15
|
-
_add_math_func(:sqrt, value)
|
16
|
-
end
|
17
|
-
|
18
|
-
def round(value=nil)
|
19
|
-
_add_math_func(:round, value)
|
20
|
-
end
|
21
|
-
|
22
|
-
def sign(value=nil)
|
23
|
-
_add_math_func(:sign, value)
|
24
|
-
end
|
25
|
-
|
26
|
-
# @private
|
27
|
-
def _add_math_func(name, value=nil)
|
28
|
-
value ||= self.respond_to?(:var_name) ? self.var_name : to_s
|
29
|
-
expressions.delete(self)
|
30
|
-
Property.new(expressions, nil, name).to_function!(value)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module MathOperator
|
35
|
-
def -(other)
|
36
|
-
ExprOp.new(self, other, '-')
|
37
|
-
end
|
38
|
-
|
39
|
-
def +(other)
|
40
|
-
ExprOp.new(self, other, '+')
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module Comparable
|
45
|
-
def <(other)
|
46
|
-
ExprOp.new(self, other, '<')
|
47
|
-
end
|
48
|
-
|
49
|
-
def <=(other)
|
50
|
-
ExprOp.new(self, other, '<=')
|
51
|
-
end
|
52
|
-
|
53
|
-
def =~(other)
|
54
|
-
ExprOp.new(self, other, '=~')
|
55
|
-
end
|
56
|
-
|
57
|
-
def >(other)
|
58
|
-
ExprOp.new(self, other, '>')
|
59
|
-
end
|
60
|
-
|
61
|
-
def >=(other)
|
62
|
-
ExprOp.new(self, other, '>=')
|
63
|
-
end
|
64
|
-
|
65
|
-
## Only in 1.9
|
66
|
-
if RUBY_VERSION > "1.9.0"
|
67
|
-
eval %{
|
68
|
-
def !=(other)
|
69
|
-
other.is_a?(String) ? ExprOp.new(self, other, "!=") : super
|
70
|
-
end }
|
71
|
-
end
|
72
|
-
|
73
|
-
def ==(other)
|
74
|
-
if other.is_a?(Fixnum) || other.is_a?(String) || other.is_a?(Regexp)
|
75
|
-
ExprOp.new(self, other, "=")
|
76
|
-
else
|
77
|
-
super
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
module PredicateMethods
|
83
|
-
def all?(&block)
|
84
|
-
self.respond_to?(:iterable)
|
85
|
-
Predicate.new(expressions, :op => 'all', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
|
86
|
-
end
|
87
|
-
|
88
|
-
def extract(&block)
|
89
|
-
Predicate.new(expressions, :op => 'extract', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
|
90
|
-
end
|
91
|
-
|
92
|
-
def filter(&block)
|
93
|
-
Predicate.new(expressions, :op => 'filter', :clause => :return, :input => input, :iterable => iterable, :predicate_block => block)
|
94
|
-
end
|
95
|
-
|
96
|
-
def any?(&block)
|
97
|
-
Predicate.new(@expressions, :op => 'any', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
|
98
|
-
end
|
99
|
-
|
100
|
-
def none?(&block)
|
101
|
-
Predicate.new(@expressions, :op => 'none', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
|
102
|
-
end
|
103
|
-
|
104
|
-
def single?(&block)
|
105
|
-
Predicate.new(@expressions, :op => 'single', :clause => :where, :input => input, :iterable => iterable, :predicate_block => block)
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
module Variable
|
111
|
-
attr_accessor :return_method
|
112
|
-
|
113
|
-
def distinct
|
114
|
-
self.return_method = {:name => 'distinct', :bracket => false}
|
115
|
-
self
|
116
|
-
end
|
117
|
-
|
118
|
-
def [](prop_name)
|
119
|
-
Property.new(expressions, self, prop_name)
|
120
|
-
end
|
121
|
-
|
122
|
-
def as(v)
|
123
|
-
@var_name = v
|
124
|
-
self
|
125
|
-
end
|
126
|
-
|
127
|
-
# generates a <tt>ID</tt> cypher fragment.
|
128
|
-
def neo_id
|
129
|
-
Property.new(@expressions, self, 'ID').to_function!
|
130
|
-
end
|
131
|
-
|
132
|
-
# generates a <tt>has</tt> cypher fragment.
|
133
|
-
def property?(p)
|
134
|
-
p = Property.new(expressions, self, p)
|
135
|
-
p.binary_operator("has")
|
136
|
-
end
|
137
|
-
|
138
|
-
# generates a <tt>is null</tt> cypher fragment.
|
139
|
-
def exist?
|
140
|
-
p = Property.new(expressions, self, p)
|
141
|
-
p.binary_operator("", " is null")
|
142
|
-
end
|
143
|
-
|
144
|
-
# Can be used instead of [_classname] == klass
|
145
|
-
def is_a?(klass)
|
146
|
-
return super if klass.class != Class || !klass.respond_to?(:_load_wrapper)
|
147
|
-
self[:_classname] == klass.to_s
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
module Matchable
|
152
|
-
# This operator means related to, without regard to type or direction.
|
153
|
-
# @param [Symbol, #var_name] other either a node (Symbol, #var_name)
|
154
|
-
# @return [MatchRelLeft, MatchNode]
|
155
|
-
def <=>(other)
|
156
|
-
MatchNode.new(self, other, expressions, :both)
|
157
|
-
end
|
158
|
-
|
159
|
-
# This operator means outgoing related to
|
160
|
-
# @param [Symbol, #var_name, String] other the relationship
|
161
|
-
# @return [MatchRelLeft, MatchNode]
|
162
|
-
def >(other)
|
163
|
-
MatchRelLeft.new(self, other, expressions, :outgoing)
|
164
|
-
end
|
165
|
-
|
166
|
-
# This operator means any direction related to
|
167
|
-
# @param (see #>)
|
168
|
-
# @return [MatchRelLeft, MatchNode]
|
169
|
-
def -(other)
|
170
|
-
MatchRelLeft.new(self, other, expressions, :both)
|
171
|
-
end
|
172
|
-
|
173
|
-
# This operator means incoming related to
|
174
|
-
# @param (see #>)
|
175
|
-
# @return [MatchRelLeft, MatchNode]
|
176
|
-
def <(other)
|
177
|
-
MatchRelLeft.new(self, other, expressions, :incoming)
|
178
|
-
end
|
179
|
-
|
180
|
-
# Outgoing relationship to other node
|
181
|
-
# @param [Symbol, #var_name] other either a node (Symbol, #var_name)
|
182
|
-
# @return [MatchRelLeft, MatchNode]
|
183
|
-
def >>(other)
|
184
|
-
MatchNode.new(self, other, expressions, :outgoing)
|
185
|
-
end
|
186
|
-
|
187
|
-
def outgoing(rel_type)
|
188
|
-
node = NodeVar.new(@expressions, @variables)
|
189
|
-
MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :outgoing) > node
|
190
|
-
node
|
191
|
-
end
|
192
|
-
|
193
|
-
def incoming(rel_type)
|
194
|
-
node = NodeVar.new(@expressions, @variables)
|
195
|
-
MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :incoming) < node
|
196
|
-
node
|
197
|
-
end
|
198
|
-
|
199
|
-
def both(rel_type)
|
200
|
-
node = NodeVar.new(@expressions, @variables)
|
201
|
-
MatchRelLeft.new(self, ":`#{rel_type}`", expressions, :both) < node
|
202
|
-
node
|
203
|
-
end
|
204
|
-
|
205
|
-
# Incoming relationship to other node
|
206
|
-
# @param [Symbol, #var_name] other either a node (Symbol, #var_name)
|
207
|
-
# @return [MatchRelLeft, MatchNode]
|
208
|
-
def <<(other)
|
209
|
-
MatchNode.new(self, other, expressions, :incoming)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
class Expression
|
214
|
-
attr_reader :expressions
|
215
|
-
attr_accessor :separator, :clause
|
216
|
-
|
217
|
-
def initialize(expressions, clause)
|
218
|
-
@clause = clause
|
219
|
-
@expressions = expressions
|
220
|
-
insert_last(clause)
|
221
|
-
@separator = ","
|
222
|
-
end
|
223
|
-
|
224
|
-
def insert_last(clause)
|
225
|
-
i = @expressions.reverse.index { |e| e.clause == clause }
|
226
|
-
if i.nil?
|
227
|
-
@expressions << self
|
228
|
-
else
|
229
|
-
pos = @expressions.size - i
|
230
|
-
@expressions.insert(pos, self)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def prefixes
|
235
|
-
{:start => "START", :where => " WHERE", :match => " MATCH", :return => " RETURN", :order_by => " ORDER BY", :skip => " SKIP", :limit => " LIMIT"}
|
236
|
-
end
|
237
|
-
|
238
|
-
def prefix
|
239
|
-
prefixes[clause]
|
240
|
-
end
|
241
|
-
|
242
|
-
def valid?
|
243
|
-
true
|
244
|
-
end
|
245
|
-
|
246
|
-
end
|
247
|
-
|
248
|
-
# A property is returned from a Variable by using the [] operator.
|
249
|
-
#
|
250
|
-
# It has a number of useful method like
|
251
|
-
# <tt>count</tt>, <tt>sum</tt>, <tt>avg</tt>, <tt>min</tt>, <tt>max</tt>, <tt>collect</tt>, <tt>head</tt>, <tt>last</tt>, <tt>tail</tt>,
|
252
|
-
#
|
253
|
-
# @example
|
254
|
-
# n=node(2, 3, 4); n[:name].collect
|
255
|
-
# # same as START n0=node(2,3,4) RETURN collect(n0.property)
|
256
|
-
class Property
|
257
|
-
# @private
|
258
|
-
attr_reader :expressions, :var_name
|
259
|
-
include Comparable
|
260
|
-
include MathOperator
|
261
|
-
include MathFunctions
|
262
|
-
include PredicateMethods
|
263
|
-
|
264
|
-
def initialize(expressions, var, prop_name)
|
265
|
-
@var = var.respond_to?(:var_name) ? var.var_name : var
|
266
|
-
@expressions = expressions
|
267
|
-
@prop_name = prop_name
|
268
|
-
@var_name = @prop_name ? "#{@var.to_s}.#{@prop_name}" : @var.to_s
|
269
|
-
end
|
270
|
-
|
271
|
-
# @private
|
272
|
-
def to_function!(var = @var.to_s)
|
273
|
-
@var_name = "#{@prop_name}(#{var})"
|
274
|
-
self
|
275
|
-
end
|
276
|
-
|
277
|
-
# Make it possible to rename a property with a different name (AS)
|
278
|
-
def as(new_name)
|
279
|
-
@var_name = "#{@var_name} AS #{new_name}"
|
280
|
-
end
|
281
|
-
|
282
|
-
# required by the Predicate Methods Module
|
283
|
-
# @see PredicateMethods
|
284
|
-
# @private
|
285
|
-
def iterable
|
286
|
-
var_name
|
287
|
-
end
|
288
|
-
|
289
|
-
def input
|
290
|
-
self
|
291
|
-
end
|
292
|
-
|
293
|
-
# @private
|
294
|
-
def in?(values)
|
295
|
-
binary_operator("", " IN [#{values.map { |x| %Q["#{x}"] }.join(',')}]")
|
296
|
-
end
|
297
|
-
|
298
|
-
# Only return distinct values/nodes/rels/paths
|
299
|
-
def distinct
|
300
|
-
@var_name = "distinct #{@var_name}"
|
301
|
-
self
|
302
|
-
end
|
303
|
-
|
304
|
-
def length
|
305
|
-
@prop_name = "length"
|
306
|
-
to_function!
|
307
|
-
self
|
308
|
-
end
|
309
|
-
|
310
|
-
%w[count sum avg min max collect head last tail].each do |meth_name|
|
311
|
-
define_method(meth_name) do
|
312
|
-
function(meth_name.to_s)
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
|
-
# @private
|
317
|
-
def function(func_name_pre, func_name_post = "")
|
318
|
-
ExprOp.new(self, nil, func_name_pre, func_name_post)
|
319
|
-
end
|
320
|
-
|
321
|
-
# @private
|
322
|
-
def binary_operator(op, post_fix = "")
|
323
|
-
ExprOp.new(self, nil, op, post_fix).binary!
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
class Start < Expression
|
328
|
-
# @private
|
329
|
-
attr_reader :var_name
|
330
|
-
include Variable
|
331
|
-
include Matchable
|
332
|
-
|
333
|
-
def initialize(var_name, expressions)
|
334
|
-
@var_name = "#{var_name}#{expressions.size}"
|
335
|
-
super(expressions, :start)
|
336
|
-
end
|
337
|
-
|
338
|
-
end
|
339
|
-
|
340
|
-
# Can be created from a <tt>node</tt> dsl method.
|
341
|
-
class StartNode < Start
|
342
|
-
# @private
|
343
|
-
attr_reader :nodes
|
344
|
-
|
345
|
-
def initialize(nodes, expressions)
|
346
|
-
super("n", expressions)
|
347
|
-
|
348
|
-
@nodes = nodes.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
|
349
|
-
end
|
350
|
-
|
351
|
-
def to_s
|
352
|
-
"#{var_name}=node(#{nodes.join(',')})"
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
|
357
|
-
# Can be created from a <tt>rel</tt> dsl method.
|
358
|
-
class StartRel < Start
|
359
|
-
# @private
|
360
|
-
attr_reader :rels
|
361
|
-
|
362
|
-
def initialize(rels, expressions)
|
363
|
-
super("r", expressions)
|
364
|
-
@rels = rels.map { |n| n.respond_to?(:neo_id) ? n.neo_id : n }
|
365
|
-
end
|
366
|
-
|
367
|
-
def to_s
|
368
|
-
"#{var_name}=relationship(#{rels.join(',')})"
|
369
|
-
end
|
370
|
-
end
|
371
|
-
|
372
|
-
class NodeQuery < Start
|
373
|
-
attr_reader :index_name, :query
|
374
|
-
|
375
|
-
def initialize(index_class, query, index_type, expressions)
|
376
|
-
super("n", expressions)
|
377
|
-
@index_name = index_class.index_name_for_type(index_type)
|
378
|
-
@query = query
|
379
|
-
end
|
380
|
-
|
381
|
-
def to_s
|
382
|
-
"#{var_name}=node:#{index_name}(#{query})"
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
class NodeLookup < Start
|
387
|
-
attr_reader :index_name, :query
|
388
|
-
|
389
|
-
def initialize(index_class, key, value, expressions)
|
390
|
-
super("n", expressions)
|
391
|
-
index_type = index_class.index_type(key.to_s)
|
392
|
-
raise "No index on #{index_class} property #{key}" unless index_type
|
393
|
-
@index_name = index_class.index_name_for_type(index_type)
|
394
|
-
@query = %Q[#{key}="#{value}"]
|
395
|
-
end
|
396
|
-
|
397
|
-
def to_s
|
398
|
-
%Q[#{var_name}=node:#{index_name}(#{query})]
|
399
|
-
end
|
400
|
-
|
401
|
-
end
|
402
|
-
|
403
|
-
# The return statement in the cypher query
|
404
|
-
class Return < Expression
|
405
|
-
attr_reader :var_name
|
406
|
-
|
407
|
-
def initialize(name_or_ref, expressions, opts = {})
|
408
|
-
super(expressions, :return)
|
409
|
-
@name_or_ref = name_or_ref
|
410
|
-
@name_or_ref.referenced! if @name_or_ref.respond_to?(:referenced!)
|
411
|
-
@var_name = @name_or_ref.respond_to?(:var_name) ? @name_or_ref.var_name : @name_or_ref.to_s
|
412
|
-
opts.each_pair { |k, v| self.send(k, v) }
|
413
|
-
end
|
414
|
-
|
415
|
-
# @private
|
416
|
-
def return_method
|
417
|
-
@name_or_ref.respond_to?(:return_method) && @name_or_ref.return_method
|
418
|
-
end
|
419
|
-
|
420
|
-
# @private
|
421
|
-
def as_return_method
|
422
|
-
if return_method[:bracket]
|
423
|
-
"#{return_method[:name]}(#@var_name)"
|
424
|
-
else
|
425
|
-
"#{return_method[:name]} #@var_name"
|
426
|
-
end
|
427
|
-
end
|
428
|
-
|
429
|
-
# Specifies an <tt>ORDER BY</tt> cypher query
|
430
|
-
# @param [Property] props the properties which should be sorted
|
431
|
-
# @return self
|
432
|
-
def asc(*props)
|
433
|
-
@order_by ||= OrderBy.new(expressions)
|
434
|
-
@order_by.asc(props)
|
435
|
-
self
|
436
|
-
end
|
437
|
-
|
438
|
-
# Specifies an <tt>ORDER BY</tt> cypher query
|
439
|
-
# @param [Property] props the properties which should be sorted
|
440
|
-
# @return self
|
441
|
-
def desc(*props)
|
442
|
-
@order_by ||= OrderBy.new(expressions)
|
443
|
-
@order_by.desc(props)
|
444
|
-
self
|
445
|
-
end
|
446
|
-
|
447
|
-
# Creates a <tt>SKIP</tt> cypher clause
|
448
|
-
# @param [Fixnum] val the number of entries to skip
|
449
|
-
# @return self
|
450
|
-
def skip(val)
|
451
|
-
Skip.new(expressions, val)
|
452
|
-
self
|
453
|
-
end
|
454
|
-
|
455
|
-
# Creates a <tt>LIMIT</tt> cypher clause
|
456
|
-
# @param [Fixnum] val the number of entries to limit
|
457
|
-
# @return self
|
458
|
-
def limit(val)
|
459
|
-
Limit.new(expressions, val)
|
460
|
-
self
|
461
|
-
end
|
462
|
-
|
463
|
-
def to_s
|
464
|
-
return_method ? as_return_method : var_name.to_s
|
465
|
-
end
|
466
|
-
end
|
467
|
-
|
468
|
-
# Can be used to skip result from a return clause
|
469
|
-
class Skip < Expression
|
470
|
-
def initialize(expressions, value)
|
471
|
-
super(expressions, :skip)
|
472
|
-
@value = value
|
473
|
-
end
|
474
|
-
|
475
|
-
def to_s
|
476
|
-
@value
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
# Can be used to limit result from a return clause
|
481
|
-
class Limit < Expression
|
482
|
-
def initialize(expressions, value)
|
483
|
-
super(expressions, :limit)
|
484
|
-
@value = value
|
485
|
-
end
|
486
|
-
|
487
|
-
def to_s
|
488
|
-
@value
|
489
|
-
end
|
490
|
-
end
|
491
|
-
|
492
|
-
class OrderBy < Expression
|
493
|
-
def initialize(expressions)
|
494
|
-
super(expressions, :order_by)
|
495
|
-
@orders = []
|
496
|
-
end
|
497
|
-
|
498
|
-
def asc(props)
|
499
|
-
@orders << [:asc, props]
|
500
|
-
end
|
501
|
-
|
502
|
-
def desc(props)
|
503
|
-
@orders << [:desc, props]
|
504
|
-
end
|
505
|
-
|
506
|
-
def to_s
|
507
|
-
@orders.map do |pair|
|
508
|
-
if pair[0] == :asc
|
509
|
-
pair[1].map(&:var_name).join(', ')
|
510
|
-
else
|
511
|
-
pair[1].map(&:var_name).join(', ') + " DESC"
|
512
|
-
end
|
513
|
-
end.join(', ')
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
# Created from a node's match operator like >> or <.
|
518
|
-
class Match < Expression
|
519
|
-
# @private
|
520
|
-
attr_reader :dir, :expressions, :left, :right, :var_name, :dir_op
|
521
|
-
# @private
|
522
|
-
attr_accessor :algorithm, :next, :prev
|
523
|
-
include Variable
|
524
|
-
|
525
|
-
def initialize(left, right, expressions, dir, dir_op)
|
526
|
-
super(expressions, :match)
|
527
|
-
@var_name = "m#{expressions.size}"
|
528
|
-
@dir = dir
|
529
|
-
@dir_op = dir_op
|
530
|
-
@prev = left if left.is_a?(Match)
|
531
|
-
@left = left
|
532
|
-
@right = right
|
533
|
-
end
|
534
|
-
|
535
|
-
|
536
|
-
# Generates a <tt>x in nodes(m3)</tt> cypher expression.
|
537
|
-
#
|
538
|
-
# @example
|
539
|
-
# p.nodes.all? { |x| x[:age] > 30 }
|
540
|
-
def nodes
|
541
|
-
Entities.new(@expressions, "nodes", self)
|
542
|
-
end
|
543
|
-
|
544
|
-
# Generates a <tt>x in relationships(m3)</tt> cypher expression.
|
545
|
-
#
|
546
|
-
# @example
|
547
|
-
# p.relationships.all? { |x| x[:age] > 30 }
|
548
|
-
def rels
|
549
|
-
Entities.new(@expressions, "relationships", self)
|
550
|
-
end
|
551
|
-
|
552
|
-
# returns the length of the path
|
553
|
-
def length
|
554
|
-
self.return_method = {:name => 'length', :bracket => true}
|
555
|
-
self
|
556
|
-
end
|
557
|
-
|
558
|
-
# @private
|
559
|
-
def find_match_start
|
560
|
-
c = self
|
561
|
-
while (c.prev) do
|
562
|
-
c = c.prev
|
563
|
-
end
|
564
|
-
c
|
565
|
-
end
|
566
|
-
|
567
|
-
# @private
|
568
|
-
def left_var_name
|
569
|
-
@left.respond_to?(:var_name) ? @left.var_name : @left.to_s
|
570
|
-
end
|
571
|
-
|
572
|
-
# @private
|
573
|
-
def right_var_name
|
574
|
-
@right.respond_to?(:var_name) ? @right.var_name : @right.to_s
|
575
|
-
end
|
576
|
-
|
577
|
-
# @private
|
578
|
-
def right_expr
|
579
|
-
@right.respond_to?(:expr) ? @right.expr : right_var_name
|
580
|
-
end
|
581
|
-
|
582
|
-
# @private
|
583
|
-
def referenced!
|
584
|
-
@referenced = true
|
585
|
-
end
|
586
|
-
|
587
|
-
# @private
|
588
|
-
def referenced?
|
589
|
-
!!@referenced
|
590
|
-
end
|
591
|
-
|
592
|
-
# @private
|
593
|
-
def to_s
|
594
|
-
curr = find_match_start
|
595
|
-
result = (referenced? || curr.referenced?) ? "#{var_name} = " : ""
|
596
|
-
result << (algorithm ? "#{algorithm}(" : "")
|
597
|
-
begin
|
598
|
-
result << curr.expr
|
599
|
-
end while (curr = curr.next)
|
600
|
-
result << ")" if algorithm
|
601
|
-
result
|
602
|
-
end
|
603
|
-
end
|
604
|
-
|
605
|
-
# The left part of a match clause, e.g. node < rel(':friends')
|
606
|
-
# Can return {MatchRelRight} using a match operator method.
|
607
|
-
class MatchRelLeft < Match
|
608
|
-
def initialize(left, right, expressions, dir)
|
609
|
-
super(left, right, expressions, dir, dir == :incoming ? '<-' : '-')
|
610
|
-
end
|
611
|
-
|
612
|
-
# @param [Symbol,NodeVar,String] other part of the match cypher statement.
|
613
|
-
# @return [MatchRelRight] the right part of an relationship cypher query.
|
614
|
-
def >(other)
|
615
|
-
expressions.delete(self)
|
616
|
-
self.next = MatchRelRight.new(self, other, expressions, :outgoing)
|
617
|
-
end
|
618
|
-
|
619
|
-
# @see #>
|
620
|
-
# @return (see #>)
|
621
|
-
def <(other)
|
622
|
-
expressions.delete(self)
|
623
|
-
self.next = MatchRelRight.new(self, other, expressions, :incoming)
|
624
|
-
end
|
625
|
-
|
626
|
-
# @see #>
|
627
|
-
# @return (see #>)
|
628
|
-
def -(other)
|
629
|
-
expressions.delete(self)
|
630
|
-
self.next = MatchRelRight.new(self, other, expressions, :both)
|
631
|
-
end
|
632
|
-
|
633
|
-
# @return [String] a cypher string for this match.
|
634
|
-
def expr
|
635
|
-
if prev
|
636
|
-
# we have chained more then one relationships in a match expression
|
637
|
-
"#{dir_op}[#{right_expr}]"
|
638
|
-
else
|
639
|
-
# the right is an relationship and could be an expressions, e.g "r?"
|
640
|
-
"(#{left_var_name})#{dir_op}[#{right_expr}]"
|
641
|
-
end
|
642
|
-
end
|
643
|
-
end
|
644
|
-
|
645
|
-
class MatchRelRight < Match
|
646
|
-
# @param left the left part of the query
|
647
|
-
# @param [Symbol,NodeVar,String] right part of the match cypher statement.
|
648
|
-
def initialize(left, right, expressions, dir)
|
649
|
-
super(left, right, expressions, dir, dir == :outgoing ? '->' : '-')
|
650
|
-
end
|
651
|
-
|
652
|
-
# @param [Symbol,NodeVar,String] other part of the match cypher statement.
|
653
|
-
# @return [MatchRelLeft] the right part of an relationship cypher query.
|
654
|
-
def >(other)
|
655
|
-
expressions.delete(self)
|
656
|
-
self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
|
657
|
-
end
|
658
|
-
|
659
|
-
# @see #>
|
660
|
-
# @return (see #>)
|
661
|
-
def <(other)
|
662
|
-
expressions.delete(self)
|
663
|
-
self.next = MatchRelLeft.new(self, other, expressions, :incoming)
|
664
|
-
end
|
665
|
-
|
666
|
-
# @see #>
|
667
|
-
# @return (see #>)
|
668
|
-
def -(other)
|
669
|
-
expressions.delete(self)
|
670
|
-
self.next = MatchRelLeft.new(self, other, expressions, :both)
|
671
|
-
end
|
672
|
-
|
673
|
-
# @return [String] a cypher string for this match.
|
674
|
-
def expr
|
675
|
-
"#{dir_op}(#{right_var_name})"
|
676
|
-
end
|
677
|
-
|
678
|
-
# negate this match
|
679
|
-
def not
|
680
|
-
expressions.delete(self)
|
681
|
-
ExprOp.new(left, nil, "not").binary!
|
682
|
-
end
|
683
|
-
|
684
|
-
if RUBY_VERSION > "1.9.0"
|
685
|
-
eval %{
|
686
|
-
def !
|
687
|
-
expressions.delete(self)
|
688
|
-
ExprOp.new(left, nil, "not").binary!
|
689
|
-
end
|
690
|
-
}
|
691
|
-
end
|
692
|
-
|
693
|
-
end
|
694
|
-
|
695
|
-
# The right part of a match clause (node_b), e.g. node_a > rel(':friends') > node_b
|
696
|
-
#
|
697
|
-
class MatchNode < Match
|
698
|
-
attr_reader :dir_op
|
699
|
-
|
700
|
-
def initialize(left, right, expressions, dir)
|
701
|
-
dir_op = case dir
|
702
|
-
when :outgoing then
|
703
|
-
"-->"
|
704
|
-
when :incoming then
|
705
|
-
"<--"
|
706
|
-
when :both then
|
707
|
-
"--"
|
708
|
-
end
|
709
|
-
super(left, right, expressions, dir, dir_op)
|
710
|
-
end
|
711
|
-
|
712
|
-
# @return [String] a cypher string for this match.
|
713
|
-
def expr
|
714
|
-
if prev
|
715
|
-
# we have chained more then one relationships in a match expression
|
716
|
-
"#{dir_op}(#{right_expr})"
|
717
|
-
else
|
718
|
-
# the right is an relationship and could be an expressions, e.g "r?"
|
719
|
-
"(#{left_var_name})#{dir_op}(#{right_expr})"
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
def <<(other)
|
724
|
-
expressions.delete(self)
|
725
|
-
self.next = MatchNode.new(self, other, expressions, :incoming)
|
726
|
-
end
|
727
|
-
|
728
|
-
def >>(other)
|
729
|
-
expressions.delete(self)
|
730
|
-
self.next = MatchNode.new(self, other, expressions, :outgoing)
|
731
|
-
end
|
732
|
-
|
733
|
-
# @param [Symbol,NodeVar,String] other part of the match cypher statement.
|
734
|
-
# @return [MatchRelRight] the right part of an relationship cypher query.
|
735
|
-
def >(other)
|
736
|
-
expressions.delete(self)
|
737
|
-
self.next = MatchRelLeft.new(self, other, expressions, :outgoing)
|
738
|
-
end
|
739
|
-
|
740
|
-
# @see #>
|
741
|
-
# @return (see #>)
|
742
|
-
def <(other)
|
743
|
-
expressions.delete(self)
|
744
|
-
self.next = MatchRelLeft.new(self, other, expressions, :incoming)
|
745
|
-
end
|
746
|
-
|
747
|
-
# @see #>
|
748
|
-
# @return (see #>)
|
749
|
-
def -(other)
|
750
|
-
expressions.delete(self)
|
751
|
-
self.next = MatchRelLeft.new(self, other, expressions, :both)
|
752
|
-
end
|
753
|
-
|
754
|
-
end
|
755
|
-
|
756
|
-
# Represents an unbound node variable used in match statements
|
757
|
-
class NodeVar
|
758
|
-
include Variable
|
759
|
-
include Matchable
|
760
|
-
|
761
|
-
# @return the name of the variable
|
762
|
-
attr_reader :var_name
|
763
|
-
attr_reader :expressions
|
764
|
-
|
765
|
-
def initialize(expressions, variables)
|
766
|
-
variables ||= []
|
767
|
-
@var_name = "v#{variables.size}"
|
768
|
-
variables << self
|
769
|
-
@variables = variables
|
770
|
-
@expressions = expressions
|
771
|
-
end
|
772
|
-
|
773
|
-
# @return [String] a cypher string for this node variable
|
774
|
-
def to_s
|
775
|
-
var_name
|
776
|
-
end
|
777
|
-
|
778
|
-
end
|
779
|
-
|
780
|
-
# represent an unbound relationship variable used in match,where,return statement
|
781
|
-
class RelVar
|
782
|
-
include Variable
|
783
|
-
|
784
|
-
attr_reader :var_name, :expr, :expressions
|
785
|
-
|
786
|
-
def initialize(expressions, variables, expr)
|
787
|
-
variables << self
|
788
|
-
@expr = expr
|
789
|
-
@expressions = expressions
|
790
|
-
guess = expr ? /([[:alpha:]]*)/.match(expr)[1] : ""
|
791
|
-
@var_name = guess.empty? ? "v#{variables.size}" : guess
|
792
|
-
end
|
793
|
-
|
794
|
-
def rel_type
|
795
|
-
Property.new(@expressions, self, 'type').to_function!
|
796
|
-
end
|
797
|
-
|
798
|
-
# @return [String] a cypher string for this relationship variable
|
799
|
-
def to_s
|
800
|
-
var_name
|
801
|
-
end
|
802
|
-
|
803
|
-
end
|
804
|
-
|
805
|
-
class ExprOp < Expression
|
806
|
-
attr_reader :left, :right, :op, :neg, :post_fix
|
807
|
-
include MathFunctions
|
808
|
-
|
809
|
-
def initialize(left, right, op, post_fix = "")
|
810
|
-
super(left.expressions, :where)
|
811
|
-
@op = op
|
812
|
-
@post_fix = post_fix
|
813
|
-
self.expressions.delete(left)
|
814
|
-
self.expressions.delete(right)
|
815
|
-
@left = quote(left)
|
816
|
-
if regexp?(right)
|
817
|
-
@op = "=~"
|
818
|
-
@right = to_regexp(right)
|
819
|
-
else
|
820
|
-
@right = right && quote(right)
|
821
|
-
end
|
822
|
-
@neg = nil
|
823
|
-
end
|
824
|
-
|
825
|
-
def separator
|
826
|
-
" "
|
827
|
-
end
|
828
|
-
|
829
|
-
def quote(val)
|
830
|
-
if val.respond_to?(:var_name) && !val.kind_of?(Match)
|
831
|
-
val.var_name
|
832
|
-
else
|
833
|
-
val.is_a?(String) ? %Q["#{val}"] : val
|
834
|
-
end
|
835
|
-
end
|
836
|
-
|
837
|
-
def regexp?(right)
|
838
|
-
@op == "=~" || right.is_a?(Regexp)
|
839
|
-
end
|
840
|
-
|
841
|
-
def to_regexp(val)
|
842
|
-
%Q[/#{val.respond_to?(:source) ? val.source : val.to_s}/]
|
843
|
-
end
|
844
|
-
|
845
|
-
def count
|
846
|
-
ExprOp.new(self, nil, 'count')
|
847
|
-
end
|
848
|
-
|
849
|
-
def &(other)
|
850
|
-
ExprOp.new(self, other, "and")
|
851
|
-
end
|
852
|
-
|
853
|
-
def |(other)
|
854
|
-
ExprOp.new(self, other, "or")
|
855
|
-
end
|
856
|
-
|
857
|
-
def -@
|
858
|
-
@neg = "not"
|
859
|
-
self
|
860
|
-
end
|
861
|
-
|
862
|
-
def not
|
863
|
-
@neg = "not"
|
864
|
-
self
|
865
|
-
end
|
866
|
-
|
867
|
-
# Only in 1.9
|
868
|
-
if RUBY_VERSION > "1.9.0"
|
869
|
-
eval %{
|
870
|
-
def !
|
871
|
-
@neg = "not"
|
872
|
-
self
|
873
|
-
end
|
874
|
-
}
|
875
|
-
end
|
876
|
-
|
877
|
-
def left_to_s
|
878
|
-
left.is_a?(ExprOp) ? "(#{left})" : left
|
879
|
-
end
|
880
|
-
|
881
|
-
def right_to_s
|
882
|
-
right.is_a?(ExprOp) ? "(#{right})" : right
|
883
|
-
end
|
884
|
-
|
885
|
-
def binary!
|
886
|
-
@binary = true
|
887
|
-
self
|
888
|
-
end
|
889
|
-
|
890
|
-
def valid?
|
891
|
-
# puts "valid? @binary=#{@binary} (#@left #@op #@right) in clause #{clause} ret #{@binary ? !!@left : !!@left && !!@right}"
|
892
|
-
# it is only valid in a where clause if it's either binary or it has right and left values
|
893
|
-
@binary ? @left : @left && @right
|
894
|
-
end
|
895
|
-
|
896
|
-
def to_s
|
897
|
-
if @right
|
898
|
-
neg ? "#{neg}(#{left_to_s} #{op} #{right_to_s})" : "#{left_to_s} #{op} #{right_to_s}"
|
899
|
-
else
|
900
|
-
# binary operator
|
901
|
-
neg ? "#{neg}#{op}(#{left_to_s}#{post_fix})" : "#{op}(#{left_to_s}#{post_fix})"
|
902
|
-
end
|
903
|
-
end
|
904
|
-
end
|
905
|
-
|
906
|
-
class Where < Expression
|
907
|
-
def initialize(expressions, where_statement = nil)
|
908
|
-
super(expressions, :where)
|
909
|
-
@where_statement = where_statement
|
910
|
-
end
|
911
|
-
|
912
|
-
def to_s
|
913
|
-
@where_statement.to_s
|
914
|
-
end
|
915
|
-
end
|
916
|
-
|
917
|
-
class Predicate < Expression
|
918
|
-
attr_accessor :params
|
919
|
-
|
920
|
-
def initialize(expressions, params)
|
921
|
-
@params = params
|
922
|
-
@identifier = :x
|
923
|
-
params[:input].referenced! if params[:input].respond_to?(:referenced!)
|
924
|
-
super(expressions, params[:clause])
|
925
|
-
end
|
926
|
-
|
927
|
-
def identifier(i)
|
928
|
-
@identifier = i
|
929
|
-
self
|
930
|
-
end
|
931
|
-
|
932
|
-
def to_s
|
933
|
-
input = params[:input]
|
934
|
-
if input.kind_of?(Property)
|
935
|
-
yield_param = Property.new([], @identifier, nil)
|
936
|
-
args = ""
|
937
|
-
else
|
938
|
-
yield_param = NodeVar.new([], []).as(@identifier.to_sym)
|
939
|
-
args = "(#{input.var_name})"
|
940
|
-
end
|
941
|
-
context = Neo4j::Cypher.new(yield_param, ¶ms[:predicate_block])
|
942
|
-
context.expressions.each { |e| e.clause = nil }
|
943
|
-
if params[:clause] == :return
|
944
|
-
where_or_colon = ':'
|
945
|
-
else
|
946
|
-
where_or_colon = 'WHERE'
|
947
|
-
end
|
948
|
-
predicate_value = context.to_s[1..-1] # skip separator ,
|
949
|
-
"#{params[:op]}(#@identifier in #{params[:iterable]}#{args} #{where_or_colon} #{predicate_value})"
|
950
|
-
end
|
951
|
-
end
|
952
|
-
|
953
|
-
class Entities
|
954
|
-
include PredicateMethods
|
955
|
-
attr_reader :input, :expressions, :iterable
|
956
|
-
|
957
|
-
def initialize(expressions, iterable, input)
|
958
|
-
@iterable = iterable
|
959
|
-
@input = input
|
960
|
-
@expressions = expressions
|
961
|
-
end
|
962
|
-
|
963
|
-
end
|
964
|
-
|
965
|
-
end
|
966
|
-
|
967
|
-
end
|
968
|
-
|
969
|
-
end
|