neography 0.0.31 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.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
|
+
[](http://travis-ci.org/maxdemarzi/neography)
|
|
2
|
+
[](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
|