neography 0.0.31 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.travis.yml +1 -1
- data/CONTRIBUTORS +2 -1
- data/README.md +247 -0
- data/Rakefile +1 -2
- data/lib/neography/config.rb +48 -16
- data/lib/neography/connection.rb +151 -0
- data/lib/neography/errors.rb +42 -0
- data/lib/neography/node.rb +17 -14
- data/lib/neography/node_relationship.rb +3 -1
- data/lib/neography/node_traverser.rb +24 -20
- data/lib/neography/property.rb +31 -28
- data/lib/neography/property_container.rb +1 -1
- data/lib/neography/relationship.rb +16 -19
- data/lib/neography/rest/auto_indexes.rb +64 -0
- data/lib/neography/rest/batch.rb +262 -0
- data/lib/neography/rest/clean.rb +19 -0
- data/lib/neography/rest/cypher.rb +24 -0
- data/lib/neography/rest/gremlin.rb +24 -0
- data/lib/neography/rest/helpers.rb +26 -0
- data/lib/neography/rest/indexes.rb +97 -0
- data/lib/neography/rest/node_auto_indexes.rb +14 -0
- data/lib/neography/rest/node_indexes.rb +35 -0
- data/lib/neography/rest/node_paths.rb +57 -0
- data/lib/neography/rest/node_properties.rb +11 -0
- data/lib/neography/rest/node_relationships.rb +53 -0
- data/lib/neography/rest/node_traversal.rb +81 -0
- data/lib/neography/rest/nodes.rb +102 -0
- data/lib/neography/rest/paths.rb +36 -0
- data/lib/neography/rest/properties.rb +56 -0
- data/lib/neography/rest/relationship_auto_indexes.rb +14 -0
- data/lib/neography/rest/relationship_indexes.rb +35 -0
- data/lib/neography/rest/relationship_properties.rb +11 -0
- data/lib/neography/rest/relationships.rb +23 -0
- data/lib/neography/rest.rb +285 -615
- data/lib/neography/tasks.rb +1 -1
- data/lib/neography/version.rb +1 -1
- data/lib/neography.rb +13 -2
- data/neography.gemspec +8 -8
- data/spec/integration/authorization_spec.rb +2 -2
- data/spec/integration/index_spec.rb +4 -4
- data/spec/integration/neography_spec.rb +2 -2
- data/spec/integration/node_path_spec.rb +2 -2
- data/spec/integration/node_relationship_spec.rb +5 -3
- data/spec/integration/node_spec.rb +20 -19
- data/spec/integration/parsing_spec.rb +2 -2
- data/spec/integration/relationship_spec.rb +2 -2
- data/spec/integration/rest_batch_spec.rb +28 -28
- data/spec/integration/rest_bulk_spec.rb +2 -2
- data/spec/integration/rest_experimental_spec.rb +2 -2
- data/spec/integration/rest_gremlin_fail_spec.rb +2 -2
- data/spec/integration/rest_header_spec.rb +4 -9
- data/spec/integration/rest_index_spec.rb +21 -1
- data/spec/integration/rest_node_spec.rb +58 -44
- data/spec/integration/rest_path_spec.rb +5 -5
- data/spec/integration/rest_plugin_spec.rb +8 -2
- data/spec/integration/rest_relationship_spec.rb +35 -30
- data/spec/integration/rest_traverse_spec.rb +2 -2
- data/spec/matchers.rb +33 -0
- data/spec/neography_spec.rb +23 -0
- data/spec/spec_helper.rb +19 -1
- data/spec/unit/config_spec.rb +46 -0
- data/spec/unit/connection_spec.rb +205 -0
- data/spec/unit/node_spec.rb +100 -0
- data/spec/unit/properties_spec.rb +136 -0
- data/spec/unit/relationship_spec.rb +118 -0
- data/spec/unit/rest/batch_spec.rb +243 -0
- data/spec/unit/rest/clean_spec.rb +17 -0
- data/spec/unit/rest/cypher_spec.rb +21 -0
- data/spec/unit/rest/gremlin_spec.rb +26 -0
- data/spec/unit/rest/node_auto_indexes_spec.rb +67 -0
- data/spec/unit/rest/node_indexes_spec.rb +126 -0
- data/spec/unit/rest/node_paths_spec.rb +80 -0
- data/spec/unit/rest/node_properties_spec.rb +80 -0
- data/spec/unit/rest/node_relationships_spec.rb +78 -0
- data/spec/unit/rest/node_traversal_spec.rb +128 -0
- data/spec/unit/rest/nodes_spec.rb +188 -0
- data/spec/unit/rest/paths_spec.rb +69 -0
- data/spec/unit/rest/relationship_auto_indexes_spec.rb +67 -0
- data/spec/unit/rest/relationship_indexes_spec.rb +128 -0
- data/spec/unit/rest/relationship_properties_spec.rb +80 -0
- data/spec/unit/rest/relationships_spec.rb +22 -0
- metadata +86 -19
- data/Gemfile.lock +0 -44
- data/README.rdoc +0 -420
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CONTRIBUTORS
CHANGED
data/README.md
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
[![Build Status](https://secure.travis-ci.org/maxdemarzi/neography.png?branch=master)](http://travis-ci.org/maxdemarzi/neography)
|
2
|
+
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/maxdemarzi/neography)
|
3
|
+
|
4
|
+
## Welcome to Neography
|
5
|
+
|
6
|
+
Neography is a thin Ruby wrapper to the Neo4j Rest API, for more information:
|
7
|
+
|
8
|
+
* [Getting Started with Neo4j Server](http://neo4j.org/community/)
|
9
|
+
* [Neo4j Rest API Reference](http://docs.neo4j.org/chunked/milestone/rest-api.html)
|
10
|
+
|
11
|
+
If you want to the full power of Neo4j, you will want to use JRuby and the excellent Neo4j.rb gem at https://github.com/andreasronge/neo4j by Andreas Ronge
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
### Gemfile
|
17
|
+
|
18
|
+
Add `neography` to your Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'neography'
|
22
|
+
```
|
23
|
+
|
24
|
+
And run Bundler:
|
25
|
+
|
26
|
+
```sh
|
27
|
+
$ bundle
|
28
|
+
```
|
29
|
+
|
30
|
+
### Manually:
|
31
|
+
|
32
|
+
Or install `neography` manually:
|
33
|
+
|
34
|
+
```sh
|
35
|
+
$ gem install 'neography'
|
36
|
+
```
|
37
|
+
|
38
|
+
And require the gem in your Ruby code:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
require 'rubygems'
|
42
|
+
require 'neography'
|
43
|
+
```
|
44
|
+
|
45
|
+
Read the wiki for information about [dependencies](https://github.com/maxdemarzi/neography/wiki/Dependencies).
|
46
|
+
|
47
|
+
[Rake tasks](https://github.com/maxdemarzi/neography/wiki/Rake-tasks) are available for downloading, installing and running Neo4j.
|
48
|
+
|
49
|
+
|
50
|
+
## Usage
|
51
|
+
|
52
|
+
### Configuration and initialization
|
53
|
+
|
54
|
+
Configure Neography as follows:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
# these are the default values:
|
58
|
+
Neography.configure do |config|
|
59
|
+
config.protocol = "http://"
|
60
|
+
config.server = "localhost"
|
61
|
+
config.port = 7474
|
62
|
+
config.directory = "" # prefix this path with '/'
|
63
|
+
config.cypher_path = "/cypher"
|
64
|
+
config.gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
|
65
|
+
config.log_file = "neography.log"
|
66
|
+
config.log_enabled = false
|
67
|
+
config.max_threads = 20
|
68
|
+
config.authentication = nil # 'basic' or 'digest'
|
69
|
+
config.username = nil
|
70
|
+
config.password = nil
|
71
|
+
config.parser = {:parser => MultiJsonParser}
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
Then initialize a `Rest` instance:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
@neo = Neography::Rest.new
|
79
|
+
```
|
80
|
+
|
81
|
+
For overriding these default and other initialization methods, see the
|
82
|
+
[configuration and initialization](https://github.com/maxdemarzi/neography/wiki/Configuration-and-initialization) page in the Wiki.
|
83
|
+
|
84
|
+
|
85
|
+
### REST API
|
86
|
+
|
87
|
+
Neography supports the creation and retrieval of nodes and relationships through the Neo4j REST interface.
|
88
|
+
It supports indexes, Gremlin scripts, Cypher queries and batch operations.
|
89
|
+
|
90
|
+
Some of this functionality is shown here, but all of it is explained in the following Wiki pages:
|
91
|
+
|
92
|
+
* [Nodes](https://github.com/maxdemarzi/neography/wiki/Nodes) - Create, get and delete nodes.
|
93
|
+
* [Node properties](https://github.com/maxdemarzi/neography/wiki/Node-properties) - Set, get and remove node properties.
|
94
|
+
* [Node relationships](https://github.com/maxdemarzi/neography/wiki/Node-relationships) - Create and get relationships between nodes.
|
95
|
+
* [Relationship](https://github.com/maxdemarzi/neography/wiki/Relationships) - Get and delete relationships.
|
96
|
+
* [Relationship properties](https://github.com/maxdemarzi/neography/wiki/Relationship-properties) - Create, get and delete relationship properties.
|
97
|
+
* [Node indexes](https://github.com/maxdemarzi/neography/wiki/Node-indexes) - List and create node indexes. Add, remove, get and search nodes in indexes.
|
98
|
+
* [Relationship indexes](https://github.com/maxdemarzi/neography/wiki/Relationship-indexes) - List and create relationships indexes. Add, remove, get and search relationships in indexes.
|
99
|
+
* [Auto indexes](https://github.com/maxdemarzi/neography/wiki/Auto-indexes) - Get, set and remove auto indexes.
|
100
|
+
* [Scripts and queries](https://github.com/maxdemarzi/neography/wiki/Scripts-and-queries) - Run Gremlin scripts and Cypher queries.
|
101
|
+
* [Paths and traversal](https://github.com/maxdemarzi/neography/wiki/Paths-and-traversal) - Paths between nodes and path traversal.
|
102
|
+
* [Batch](https://github.com/maxdemarzi/neography/wiki/Batch) - Execute multiple calls at once.
|
103
|
+
* [Errors](https://github.com/maxdemarzi/neography/wiki/Errors) - Errors raised if REST API calls fail.
|
104
|
+
|
105
|
+
|
106
|
+
Some example usage:
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
# Node creation:
|
110
|
+
node1 = @neo.create_node("age" => 31, "name" => "Max")
|
111
|
+
node2 = @neo.create_node("age" => 33, "name" => "Roel")
|
112
|
+
|
113
|
+
# Node properties:
|
114
|
+
@neo.set_node_properties(node1, {"weight" => 200})
|
115
|
+
|
116
|
+
# Relationships between nodes:
|
117
|
+
@neo.create_relationship("coding_buddies", node1, node2)
|
118
|
+
|
119
|
+
# Get node relationships:
|
120
|
+
@neo.get_node_relationships(node2, "in", "coding_buddies")
|
121
|
+
|
122
|
+
# Use indexes:
|
123
|
+
@neo.add_node_to_index("people", "name", "max", node1)
|
124
|
+
@neo.get_node_index("people", "name", "max")
|
125
|
+
|
126
|
+
# Cypher queries:
|
127
|
+
@neo.execute_query("start n=node(0) return n")
|
128
|
+
|
129
|
+
# Batches:
|
130
|
+
@neo.batch [:create_node, {"name" => "Max"}],
|
131
|
+
[:create_node, {"name" => "Marc"}]
|
132
|
+
```
|
133
|
+
|
134
|
+
This is just a small sample of the full API, see the [Wiki documentation](https://github.com/maxdemarzi/neography/wiki) for the full API.
|
135
|
+
|
136
|
+
Neography raises REST API errors as Ruby errors, see the wiki page about [errors](https://github.com/maxdemarzi/neography/wiki/Errors).
|
137
|
+
(**Note**: older versions of Neography did not raise any errors!)
|
138
|
+
|
139
|
+
|
140
|
+
## *Phase 2*
|
141
|
+
|
142
|
+
Trying to mimic the [Neo4j.rb API](https://github.com/andreasronge/neo4j/wiki/Neo4j%3A%3ACore-Nodes-Properties-Relationships).
|
143
|
+
|
144
|
+
Now we are returning full objects. The properties of the node or relationship can be accessed directly (`node.name`).
|
145
|
+
The Neo4j ID is available by using `node.neo_id`.
|
146
|
+
|
147
|
+
Some of this functionality is shown here, but all of it is explained in the following Wiki pages:
|
148
|
+
|
149
|
+
* [Nodes](https://github.com/maxdemarzi/neography/wiki/Phase-2-Nodes) - Create, load and delete nodes.
|
150
|
+
* [Node properties](https://github.com/maxdemarzi/neography/wiki/Phase-2-Node-properties) - Add, get and remove node properties.
|
151
|
+
* [Node relationships](https://github.com/maxdemarzi/neography/wiki/Phase-2-Node-relationships) - Create and retrieve node relationships.
|
152
|
+
* [Node paths](https://github.com/maxdemarzi/neography/wiki/Phase-2-Node-paths) - Gets paths between nodes.
|
153
|
+
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
# create two nodes:
|
157
|
+
n1 = Neography::Node.create("age" => 31, "name" => "Max")
|
158
|
+
n2 = Neography::Node.create("age" => 33, "name" => "Roel")
|
159
|
+
|
160
|
+
n1.exist? # => true
|
161
|
+
|
162
|
+
# get and change some properties:
|
163
|
+
n1[:age] # => 31
|
164
|
+
n1.name # => "Max"
|
165
|
+
n1[:age] = 32 # change property
|
166
|
+
n1.weight = 190 # new property
|
167
|
+
n1.age = nil # remove property
|
168
|
+
|
169
|
+
# add a relationship between nodes:
|
170
|
+
new_rel = Neography::Relationship.create(:coding_buddies, n1, n2)
|
171
|
+
|
172
|
+
# remove a relationship:
|
173
|
+
new_rel.del
|
174
|
+
|
175
|
+
# add a relationship on nodes:
|
176
|
+
n1.outgoing(:coding_buddies) << n2
|
177
|
+
|
178
|
+
# more advanced relationship traversal:
|
179
|
+
n1.outgoing(:friends) # Get nodes related by outgoing friends relationship
|
180
|
+
n1.outgoing(:friends).depth(2).include_start_node # Get n1 and nodes related by friends and friends of friends
|
181
|
+
|
182
|
+
n1.rel?(:outgoing, :friends) # Has outgoing friends relationship
|
183
|
+
n1.rels(:friends,:work).outgoing # Get outgoing friends and work relationships
|
184
|
+
|
185
|
+
n1.all_paths_to(n2).incoming(:friends).depth(4) # Gets all paths of a specified type
|
186
|
+
n1.shortest_path_to(n2).incoming(:friends).depth(4).nodes # Gets just nodes in path
|
187
|
+
```
|
188
|
+
|
189
|
+
This is just a small sample of the full API, see the [Wiki documentation](https://github.com/maxdemarzi/neography/wiki) for the full API.
|
190
|
+
|
191
|
+
## More
|
192
|
+
|
193
|
+
### Examples
|
194
|
+
|
195
|
+
Some [example code](https://github.com/maxdemarzi/neography/wiki/Examples).
|
196
|
+
|
197
|
+
|
198
|
+
### Testing
|
199
|
+
|
200
|
+
Some [tips about testing](https://github.com/maxdemarzi/neography/wiki/Testing).
|
201
|
+
|
202
|
+
|
203
|
+
### Related Neo4j projects
|
204
|
+
|
205
|
+
Complement to Neography are the:
|
206
|
+
|
207
|
+
* [Neo4j Active Record Adapter](https://github.com/yournextleap/activerecord-neo4j-adapter) by Nikhil Lanjewar
|
208
|
+
* [Neology](https://github.com/lordkada/neology) by Carlo Alberto Degli Atti
|
209
|
+
* [Neoid](https://github.com/elado/neoid) by Elad Ossadon
|
210
|
+
|
211
|
+
An alternative to Neography is [Architect4r](https://github.com/namxam/architect4r) by Maximilian Schulz
|
212
|
+
|
213
|
+
|
214
|
+
### Neography in the Wild
|
215
|
+
|
216
|
+
* [Vouched](http://getvouched.com)
|
217
|
+
* [Neovigator](http://neovigator.herokuapp.com) fork it at https://github.com/maxdemarzi/neovigator
|
218
|
+
* [Neoflix](http://neoflix.herokuapp.com) fork it at https://github.com/maxdemarzi/neoflix
|
219
|
+
|
220
|
+
|
221
|
+
### Getting started with Neography
|
222
|
+
|
223
|
+
* [Getting Started with Ruby and Neo4j](http://maxdemarzi.com/2012/01/04/getting-started-with-ruby-and-neo4j/)
|
224
|
+
* [Graph visualization with Neo4j](http://maxdemarzi.com/2012/01/11/graph-visualization-and-neo4j/)
|
225
|
+
* [Neo4j on Heroku](http://maxdemarzi.com/2012/01/13/neo4j-on-heroku-part-one/)
|
226
|
+
|
227
|
+
|
228
|
+
## Contributing
|
229
|
+
|
230
|
+
Please create a [new issue](https://github.com/maxdemarzi/neography/issues) if you run into any bugs.
|
231
|
+
|
232
|
+
Contribute patches via [pull requests](https://github.com/maxdemarzi/neography/pulls).
|
233
|
+
|
234
|
+
|
235
|
+
## Help
|
236
|
+
|
237
|
+
If you are just starting out, or need help send me an e-mail at maxdemarzi@gmail.com.
|
238
|
+
|
239
|
+
Check you my blog at http://maxdemarzi.com where I have more Neography examples.
|
240
|
+
|
241
|
+
|
242
|
+
## Licenses
|
243
|
+
|
244
|
+
* Neography - MIT, see the LICENSE file http://github.com/maxdemarzi/neography/tree/master/LICENSE.
|
245
|
+
* Lucene - Apache, see http://lucene.apache.org/java/docs/features.html
|
246
|
+
* Neo4j - Dual free software/commercial license, see http://neo4j.org
|
247
|
+
|
data/Rakefile
CHANGED
data/lib/neography/config.rb
CHANGED
@@ -1,20 +1,52 @@
|
|
1
1
|
module Neography
|
2
|
-
class Config
|
3
|
-
|
2
|
+
class Config
|
3
|
+
|
4
|
+
attr_accessor :protocol, :server, :port, :directory,
|
5
|
+
:cypher_path, :gremlin_path,
|
6
|
+
:log_file, :log_enabled,
|
7
|
+
:max_threads,
|
8
|
+
:authentication, :username, :password,
|
9
|
+
:parser
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
set_defaults
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
{
|
17
|
+
:protocol => @protocol,
|
18
|
+
:server => @server,
|
19
|
+
:port => @port,
|
20
|
+
:directory => @directory,
|
21
|
+
:cypher_path => @cypher_path,
|
22
|
+
:gremlin_path => @gremlin_path,
|
23
|
+
:log_file => @log_file,
|
24
|
+
:log_enabled => @log_enabled,
|
25
|
+
:max_threads => @max_threads,
|
26
|
+
:authentication => @authentication,
|
27
|
+
:username => @username,
|
28
|
+
:password => @password,
|
29
|
+
:parser => @parser
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def set_defaults
|
36
|
+
@protocol = "http://"
|
37
|
+
@server = "localhost"
|
38
|
+
@port = 7474
|
39
|
+
@directory = ""
|
40
|
+
@cypher_path = "/cypher"
|
41
|
+
@gremlin_path = "/ext/GremlinPlugin/graphdb/execute_script"
|
42
|
+
@log_file = "neography.log"
|
43
|
+
@log_enabled = false
|
44
|
+
@max_threads = 20
|
45
|
+
@authentication = nil
|
46
|
+
@username = nil
|
47
|
+
@password = nil
|
48
|
+
@parser = {:parser => MultiJsonParser}
|
49
|
+
end
|
4
50
|
|
5
|
-
@protocol = 'http://'
|
6
|
-
@server = 'localhost'
|
7
|
-
@port = 7474
|
8
|
-
@directory = ''
|
9
|
-
@cypher_path = '/cypher'
|
10
|
-
@gremlin_path = '/ext/GremlinPlugin/graphdb/execute_script'
|
11
|
-
@log_file = 'neography.log'
|
12
|
-
@log_enabled = false
|
13
|
-
@logger = Logger.new(@log_file) if @log_enabled
|
14
|
-
@max_threads = 20
|
15
|
-
@authentication = {}
|
16
|
-
@username = nil
|
17
|
-
@password = nil
|
18
|
-
@parser = {:parser => MultiJsonParser}
|
19
51
|
end
|
20
52
|
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Neography
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
USER_AGENT = "Neography/#{Neography::VERSION}"
|
5
|
+
|
6
|
+
attr_accessor :protocol, :server, :port, :directory,
|
7
|
+
:cypher_path, :gremlin_path,
|
8
|
+
:log_file, :log_enabled, :logger,
|
9
|
+
:max_threads,
|
10
|
+
:authentication, :username, :password,
|
11
|
+
:parser
|
12
|
+
|
13
|
+
def initialize(options = ENV['NEO4J_URL'] || {})
|
14
|
+
config = merge_configuration(options)
|
15
|
+
save_local_configuration(config)
|
16
|
+
end
|
17
|
+
|
18
|
+
def configure(protocol, server, port, directory)
|
19
|
+
@protocol = protocol
|
20
|
+
@server = server
|
21
|
+
@port = port
|
22
|
+
@directory = directory
|
23
|
+
end
|
24
|
+
|
25
|
+
def configuration
|
26
|
+
"#{@protocol}#{@server}:#{@port}#{@directory}/db/data"
|
27
|
+
end
|
28
|
+
|
29
|
+
def merge_options(options)
|
30
|
+
merged_options = options.merge!(@authentication).merge!(@parser)
|
31
|
+
merged_options[:headers].merge!(@user_agent) if merged_options[:headers]
|
32
|
+
merged_options
|
33
|
+
end
|
34
|
+
|
35
|
+
def get(path, options={})
|
36
|
+
evaluate_response(HTTParty.get(configuration + path, merge_options(options)))
|
37
|
+
end
|
38
|
+
|
39
|
+
def post(path, options={})
|
40
|
+
evaluate_response(HTTParty.post(configuration + path, merge_options(options)))
|
41
|
+
end
|
42
|
+
|
43
|
+
def put(path, options={})
|
44
|
+
evaluate_response(HTTParty.put(configuration + path, merge_options(options)))
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete(path, options={})
|
48
|
+
evaluate_response(HTTParty.delete(configuration + path, merge_options(options)))
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def merge_configuration(options)
|
54
|
+
options = parse_string_options(options) unless options.is_a? Hash
|
55
|
+
config = Neography.configuration.to_hash
|
56
|
+
config.merge(options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def save_local_configuration(config)
|
60
|
+
@protocol = config[:protocol]
|
61
|
+
@server = config[:server]
|
62
|
+
@port = config[:port]
|
63
|
+
@directory = config[:directory]
|
64
|
+
@cypher_path = config[:cypher_path]
|
65
|
+
@gremlin_path = config[:gremlin_path]
|
66
|
+
@log_file = config[:log_file]
|
67
|
+
@log_enabled = config[:log_enabled]
|
68
|
+
@max_threads = config[:max_threads]
|
69
|
+
@parser = config[:parser]
|
70
|
+
|
71
|
+
@user_agent = { "User-Agent" => USER_AGENT }
|
72
|
+
|
73
|
+
@authentication = {}
|
74
|
+
if config[:authentication]
|
75
|
+
@authentication = {
|
76
|
+
"#{config[:authentication]}_auth".to_sym => {
|
77
|
+
:username => config[:username],
|
78
|
+
:password => config[:password]
|
79
|
+
}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
if @log_enabled
|
84
|
+
@logger = Logger.new(@log_file)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def evaluate_response(response)
|
89
|
+
code = response.code
|
90
|
+
body = response.body
|
91
|
+
case code
|
92
|
+
when 200
|
93
|
+
@logger.debug "OK" if @log_enabled
|
94
|
+
response.parsed_response
|
95
|
+
when 201
|
96
|
+
@logger.debug "OK, created #{body}" if @log_enabled
|
97
|
+
response.parsed_response
|
98
|
+
when 204
|
99
|
+
@logger.debug "OK, no content returned" if @log_enabled
|
100
|
+
nil
|
101
|
+
when 400...500
|
102
|
+
handle_4xx_response(code, body)
|
103
|
+
nil
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def handle_4xx_response(code, body)
|
108
|
+
parsed_body = JSON.parse(body)
|
109
|
+
message = parsed_body["message"]
|
110
|
+
stacktrace = parsed_body["stacktrace"]
|
111
|
+
|
112
|
+
@logger.error "#{code} error: #{body}" if @log_enabled
|
113
|
+
|
114
|
+
case code
|
115
|
+
when 400, 404
|
116
|
+
case parsed_body["exception"]
|
117
|
+
when "SyntaxException" ; raise SyntaxException.new(message, code, stacktrace)
|
118
|
+
when "PropertyValueException" ; raise PropertyValueException.new(message, code, stacktrace)
|
119
|
+
when "BadInputException" ; raise BadInputException.new(message, code, stacktrace)
|
120
|
+
when "NodeNotFoundException" ; raise NodeNotFoundException.new(message, code, stacktrace)
|
121
|
+
when "NoSuchPropertyException" ; raise NoSuchPropertyException.new(message, code, stacktrace)
|
122
|
+
when "RelationshipNotFoundException" ; raise RelationshipNotFoundException.new(message, code, stacktrace)
|
123
|
+
when "NotFoundException" ; raise NotFoundException.new(message, code, stacktrace)
|
124
|
+
else
|
125
|
+
raise NeographyError.new(message, code, stacktrace)
|
126
|
+
end
|
127
|
+
when 401
|
128
|
+
raise UnauthorizedError.new(message, code, stacktrace)
|
129
|
+
when 409
|
130
|
+
raise OperationFailureException.new(message, code, stacktrace)
|
131
|
+
else
|
132
|
+
raise NeographyError.new(message, code, stacktrace)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def parse_string_options(options)
|
137
|
+
url = URI.parse(options)
|
138
|
+
options = {
|
139
|
+
:protocol => url.scheme + "://",
|
140
|
+
:server => url.host,
|
141
|
+
:port => url.port,
|
142
|
+
:directory => url.path,
|
143
|
+
:username => url.user,
|
144
|
+
:password => url.password
|
145
|
+
}
|
146
|
+
options[:authentication] = 'basic' unless url.user.nil?
|
147
|
+
options
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Neography
|
2
|
+
|
3
|
+
class NeographyError < StandardError
|
4
|
+
attr_reader :message, :code, :stacktrace
|
5
|
+
|
6
|
+
def initialize(message = nil, code = nil, stacktrace = nil)
|
7
|
+
@message = message
|
8
|
+
@code = code
|
9
|
+
@stacktrace = stacktrace
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# HTTP Authentication error
|
14
|
+
class UnauthorizedError < NeographyError; end
|
15
|
+
|
16
|
+
# the Neo4j server Exceptions returned by the REST API:
|
17
|
+
|
18
|
+
# A node could not be found
|
19
|
+
class NodeNotFoundException < NeographyError; end
|
20
|
+
|
21
|
+
# A node cannot be deleted because it has relationships
|
22
|
+
class OperationFailureException < NeographyError; end
|
23
|
+
|
24
|
+
# Properties can not be null
|
25
|
+
class PropertyValueException < NeographyError; end
|
26
|
+
|
27
|
+
# Trying to a delete a property that does not exist
|
28
|
+
class NoSuchPropertyException < NeographyError; end
|
29
|
+
|
30
|
+
# A relationship could not be found
|
31
|
+
class RelationshipNotFoundException < NeographyError; end
|
32
|
+
|
33
|
+
# Error during valid Cypher query
|
34
|
+
class BadInputException < NeographyError; end
|
35
|
+
|
36
|
+
# Invalid Cypher query syntax
|
37
|
+
class SyntaxException < NeographyError; end
|
38
|
+
|
39
|
+
# A path could not be found by node traversal
|
40
|
+
class NotFoundException < NeographyError; end
|
41
|
+
|
42
|
+
end
|
data/lib/neography/node.rb
CHANGED
@@ -9,24 +9,22 @@ module Neography
|
|
9
9
|
attr_accessor :neo_server
|
10
10
|
|
11
11
|
class << self
|
12
|
-
def create(
|
13
|
-
|
14
|
-
|
15
|
-
db = (args[0].is_a?(Neography::Rest) && args[0]) || args[1] || Neography::Rest.new
|
12
|
+
def create(props = nil, db = Neography::Rest.new)
|
13
|
+
raise ArgumentError.new("syntax deprecated") if props.is_a?(Neography::Rest)
|
14
|
+
|
16
15
|
node = self.new(db.create_node(props))
|
17
16
|
node.neo_server = db
|
18
17
|
node
|
19
18
|
end
|
20
19
|
|
21
|
-
def load(
|
22
|
-
|
23
|
-
node = !args[0].is_a?(Neography::Rest) && args[0] || args[1]
|
20
|
+
def load(node, db = Neography::Rest.new)
|
21
|
+
raise ArgumentError.new("syntax deprecated") if node.is_a?(Neography::Rest)
|
24
22
|
|
25
|
-
# a db instance can be given, it is the first argument or the second
|
26
|
-
db = (args[0].is_a?(Neography::Rest) && args[0]) || args[1] || Neography::Rest.new
|
27
23
|
node = db.get_node(node)
|
28
|
-
|
29
|
-
|
24
|
+
if node
|
25
|
+
node = self.new(node)
|
26
|
+
node.neo_server = db
|
27
|
+
end
|
30
28
|
node
|
31
29
|
end
|
32
30
|
|
@@ -34,12 +32,17 @@ module Neography
|
|
34
32
|
end
|
35
33
|
|
36
34
|
def del
|
37
|
-
|
35
|
+
neo_server.delete_node!(self.neo_id)
|
38
36
|
end
|
39
37
|
|
40
38
|
def exist?
|
41
|
-
|
39
|
+
begin
|
40
|
+
neo_server.get_node(self.neo_id)
|
41
|
+
true
|
42
|
+
rescue NodeNotFoundException
|
43
|
+
false
|
44
|
+
end
|
42
45
|
end
|
43
46
|
|
44
47
|
end
|
45
|
-
end
|
48
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Neography
|
2
2
|
module NodeRelationship
|
3
3
|
|
4
|
+
DIRECTIONS = ["incoming", "in", "outgoing", "out", "all", "both"]
|
5
|
+
|
4
6
|
def outgoing(types=nil)
|
5
7
|
NodeTraverser.new(self).outgoing(types)
|
6
8
|
end
|
@@ -32,4 +34,4 @@ module Neography
|
|
32
34
|
end
|
33
35
|
|
34
36
|
end
|
35
|
-
end
|
37
|
+
end
|