neo4j-core 3.0.0.alpha.19 → 3.0.0.rc.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 99c353a80ee0078fb684f74860c6b9adab86f81a
4
- data.tar.gz: 5164eb9d290c70506f2e38c8e70952b59e058b0b
3
+ metadata.gz: d20898c080d0bca882d65f41646ef7e4067a5b9b
4
+ data.tar.gz: adc55730515f69c5b8df000ffdd661964520a1eb
5
5
  SHA512:
6
- metadata.gz: ff3c176237a7fe786532cee32b922fcf6e239c9493bf3a64b0da3adf38d4e73941948cad014bcb486aab6ddfb6ece763b11cc14e65e89b354504d520d9d513bf
7
- data.tar.gz: c4a5a1e0b1597f5a0f12ad4a88d8b13f730429101552a778f99583efbe3eddabec83f6964fea15193084e1da7bbc5e7839a2e9e09df2539843bc3b9d017efcac
6
+ metadata.gz: 45044b6d438c430d95ca67c70a2572479c2fcaaa5f4001b117f0096d2a497f119b1f9ea5212966ba4fff83266d7308d8c93aefc043a6a5eae2827e7a040fc0d1
7
+ data.tar.gz: c3812fad93af67cdde06336b870aa67a7de44e7052c2c24ad6e0d038ce23d788573b2791ef4cf00baf05758860bdd63811a3c3bb135e59309dde36cc2b7b0a47
data/README.md CHANGED
@@ -1,458 +1,29 @@
1
1
  # Neo4j-core v3.0 [![Code Climate](https://codeclimate.com/github/andreasronge/neo4j-core.png)](https://codeclimate.com/github/andreasronge/neo4j-core) [![Build Status](https://travis-ci.org/andreasronge/neo4j-core.png)](https://travis-ci.org/andreasronge/neo4j-core)
2
2
 
3
- A simple Ruby wrapper around the Neo4j graph database that works with the server and embedded Neo4j API.
4
- This gem can be used both from JRuby and normal MRI. You may get better performance using it from JRuby and the embedded
5
- Neo4j, but it will probably be easier to develop (e.g. faster to run tests) on MRI and neo4j server.
6
- This gem is designed to work well together with the neo4j active model compliant gem (see the 3.0 branch).
3
+ A simple Ruby wrapper around the Neo4j graph database that works with the server and embedded Neo4j API. This gem can be used both from JRuby and normal MRI.
4
+ It can be used standalone without the neo4j gem.
7
5
 
8
- For the stable v2.0 version, see the v2.0 branch https://github.com/andreasronge/neo4j-core/tree/v2.x
9
- Do not use this gem in production.
6
+ ## Documentation
10
7
 
8
+ * [3.0 Documentation](https://github.com/andreasronge/neo4j-core/wiki)
9
+ * [2.x Documentation](https://github.com/andreasronge/neo4j-core/tree/v2.x)
11
10
 
12
- ## Installation
13
11
 
14
- You can use this gem in two different ways:
12
+ ## Support
15
13
 
16
- * embedded - talking directly to the database using the Neo4j Java API (only JRuby)
17
- * server - talking to the Neo4j Server via HTTP (Both JRuby and MRI)
14
+ * [Neo4j.rb mailing list](https://groups.google.com/forum/#!forum/neo4jrb)
15
+ * Consulting support ? ask any of the developers
18
16
 
19
- ### Embedded or Server Neo4j ?
17
+ ## Developers
20
18
 
21
- I suggest you start using the Neo4j server instead of Neo4j embedded because it is easier to use for development.
22
- If you later get performance problem (e.g. too many HTTP requests hitting the Neo4j Server)
23
- you can try the embedded neo4j with almost no changes in your code base.
24
- The embedded neo4j via JRuby also gives you direct access to the Neo4j Java API (e.g. the Neo4j Traversal API)
25
- which can be used to do more powerful and efficient traversals.
19
+ * [Andreas Ronge](https://github.com/andreasronge)
20
+ * [Brian Underwood](https://github.com/cheerfulstoic)
21
+ * [Chris Grigg](https://github.com/subvertallchris)
26
22
 
27
- ### Usage from Neo4j Server
28
23
 
29
- You need to install the Neo4j server. This can be done by using a Rake task.
30
-
31
-
32
- Install the gem:
33
- ```
34
- gem install neo4j-core --pre
35
- ```
36
-
37
- Create a Rakefile with the following content:
38
-
39
- ```
40
- require 'neo4j/tasks/neo4j_server'
41
- ```
42
-
43
- Install and start neo4j by typing:
44
- ```
45
- rake neo4j:install[community-2.1.3]
46
- rake neo4j:start
47
- ```
48
-
49
-
50
- ### Usage from Neo4j Embedded
51
-
52
- The Gemfile contains references to Neo4j Java libraries. Nothing is needed to be installed.
53
- The embedded database is only accessible from JRuby (unlike the Neo4j Server).
54
- No need to start the server since it is embedded.
55
-
56
- ## Neo4j-core API, v3.0
57
-
58
- ### API Documentation
59
-
60
- * [Neo4j::Node](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Node)
61
- * [Neo4j::Relationship](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Relationship)
62
- * [Neo4j::Session](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Session)
63
- * [Neo4j::Label](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Label)
64
- * [Neo4j::Transaction](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Transaction)
65
- * [Neo4j::Query](Neo4j/Query.html)
66
-
67
- See also [Neo4j Docs](http://docs.neo4j.org/)
68
-
69
-
70
- ### Database Session
71
-
72
- There are currently two available types of session, one for connecting to a neo4j server
73
- and one for connecting to the embedded Neo4j database (which requires JRuby).
74
-
75
- Using the Neo4j Server: `:server_db`
76
- Open a IRB/Pry session:
77
-
78
- ```ruby
79
- require 'neo4j-core'
80
- # Using Neo4j Server Cypher Database
81
- session = Neo4j::Session.open(:server_db)
82
- ```
83
-
84
- ### Session Configuration
85
-
86
- Example, Basic Authentication:
87
-
88
- ```ruby
89
- Neo4j::Session.open(:server_db, 'http://my.server', basic_auth: { username: 'username', password: 'password'})
90
- ```
91
-
92
- The last option hash is passed on to HTTParty. See here for more available options:
93
- http://rdoc.info/github/jnunemaker/httparty/HTTParty/ClassMethods
94
-
95
- ### Embedded Session
96
-
97
- Using the Neo4j Embedded Database, `:embedded_db`
98
-
99
- ```ruby
100
- # Using Neo4j Embedded Database
101
- session = Neo4j::Session.open(:embedded_db, '/folder/db', auto_commit: true)
102
- session.start
103
- ```
104
-
105
- To stop the database (only supported via the embedded database) use
106
- ```
107
- session.shutdown
108
- session.running? #=> false
109
- session.close # make the session not current/default
110
- ```
111
-
112
- ### Session.current
113
-
114
- When a session has been created it will be stored in the `Neo4j::Session` object.
115
- Example, get the default session
116
-
117
- ```ruby
118
- session = Neo4j::Session.current
119
- ```
120
-
121
- ### Multiple Sessions
122
-
123
- The default session is used by all operation unless specified as the last argument.
124
- For example create a node with a different session:
125
-
126
- ```ruby
127
- my_session = Neo4j::Session.create_session(:server_db, "http://localhost:7474")
128
- Neo4j::Node.create(name: 'kalle', my_session)
129
- ```
130
-
131
- When using the Neo4j Server: `:server_db`, multiple sessions are supported. They
132
- can be created using the open_named method. This method takes two extra parameters,
133
- the second parameter is the session name, and the third parameter is whether the new session should over-ride
134
- the default session (becoming the session returned by calling `Neo4j::Session.current`).
135
- Valid options are true (always become current), false (never become current) and nil (become current if no
136
- existing current session).
137
-
138
- ```ruby
139
- Neo4j::Session.open_named(:server_db, :test, true, "https://localhost:7474")
140
- session = Neo4j::Session.named :test # Returns the session named :test.
141
- session = Neo4j::Session.current # Returns the session named :test, because the 'default' flag was set to true.
142
- ```
143
-
144
-
145
- ### Label and Index Support
146
-
147
- Create a node with an label `person` and one property
148
- ```ruby
149
- Neo4j::Node.create({name: 'kalle'}, :person)
150
- ```
151
-
152
- Add index on a label
153
-
154
- ```ruby
155
- person = Label.create(:person)
156
- person.create_index(:name) # compound keys will be supported in Neo4j 2.1
157
-
158
- # drop index
159
- person.drop_index(:name)
160
- ```
161
-
162
- ```ruby
163
- # which indexes do we have and on which properties,
164
- red.indexes.each {|i| puts "Index #{i.label} properties: #{i.properties}"}
165
-
166
- # drop index, we assume it's the first one we want
167
- red.indexes.first.drop(:name)
168
-
169
- # which indices exist ?
170
- # (compound keys will be supported in Neo4j 2.1 (?))
171
- red.indexes # => {:property_keys => [[:age]]}
172
- ```
173
-
174
- Constraints
175
-
176
- Only unique constraint and single property is supported (yet).
177
-
178
- ```ruby
179
- label = Neo4j::Label.create(:person)
180
- label.create_constraint(:name, type: :unique)
181
- label.drop_constraint(:name, type: :unique)
182
- ```
183
-
184
- ### Creating Nodes
185
-
186
- ```ruby
187
- # notice, label argument can be both Label objects or string/symbols.
188
- node = Node.create({name: 'andreas'}, red, :green)
189
- puts "Created node #{node[:name]} with labels #{node.labels.map(&:name).join(', ')}"
190
- ```
191
-
192
- Notice, nodes will be indexed based on which labels they have.
193
-
194
- Setting properties
195
-
196
- ```ruby
197
- node = Node.create({name: 'andreas'}, red, :green)
198
- node[:name] = 'changed name' # changes immediately one property
199
- node[:name] # => 'changed name'
200
- node.props # => {name: 'changed name'}
201
- node.props={ foo: 42} # replace all properties
202
- node.update_props( bar: 42) # keeps old properties (unlike #props=) update with given hash
203
- ```
204
-
205
- Notice properties are never stored in ruby objects, instead they are always fetched from the database.
206
-
207
- ### Finding Nodes by Label
208
-
209
- Each node and relationship has a id, `neo_id`
210
-
211
- ```ruby
212
- node = Neo4j::Node.create
213
- # load the node again from the database
214
- node2 = Neo4j::Node.load(node.neo_id)
215
- ```
216
-
217
- Finding nodes by label:
218
-
219
- ```ruby
220
- # Find nodes using an index, returns an Enumerable
221
- Neo4j::Label.find_nodes(:red, :name, "andreas")
222
-
223
- # Find all nodes for this label, returns an Enumerable
224
- Neo4j::Label.find_all_nodes(:red)
225
-
226
- # which labels does a node have ?
227
- node.labels # [:red]
228
- ```
229
-
230
- ### Cypher Queries
231
-
232
- Full documentation, see [Neo4j::Session#query](http://www.rubydoc.info/github/andreasronge/neo4j-core/Neo4j/Session#query-instance_method) or RSpecs.
233
-
234
- Examples using queries as strings:
235
-
236
- ```ruby
237
- # same as Neo4j::Session.current.query
238
- Neo4j::Session.query.create(n: Label: {mydata: 'Hello'}).exec
239
-
240
- # With cypher parameters
241
- Neo4j::Session.query.start(n: "node({a_parameter})").params(a_parameter: 0).pluck("ID(n)").first
242
- ```
243
-
244
- Example of chained queries:
245
-
246
- ```ruby
247
- query = Neo4j::Session.query.match(n: :person) # Returns a Query object
248
-
249
-
250
- query.return(:n) # Also returns a Query object
251
-
252
- query.return(:n).to_a # Returns an array of result rows as Structs (i.e. [<struct n=Node>, etc...])
253
-
254
- query.pluck(:n) # Returns an array of nodes
255
-
256
- query.return(n: [:name, :age]) # => [<struct name='Brian', age=33>, etc...]
257
-
258
- query.where(name: /kalle.*/)
259
-
260
- query.order(n: {name: :desc, age: :asc}).skip(5).limit(4) # sorting and skip and limit the result
261
-
262
- query.match('n-[:friends]->o').where(o: {age: 42}, n: {age: 1})
263
-
264
- query.match('n-[f:friends]->o').pluck(:f) # [<Relationship>, etc..]
265
-
266
- ```
267
-
268
-
269
-
270
- ### Transactions
271
-
272
- By default each Neo4j operation is wrapped in an transaction.
273
- If you want to execute several operation in one operation you can use the `Neo4j::Transaction` class, example:
274
-
275
- ```ruby
276
- Neo4j::Transaction.run do
277
- n = Neo4j::Node.create(name: 'kalle')
278
- n[:age] = 42
279
- end
280
- ```
281
-
282
- Rollback occurs if an exception is thrown, or the failure method is called on the transaction.
283
-
284
- E.g.
285
-
286
- ```ruby
287
- Neo4j::Transaction.run do |tx|
288
- n = Neo4j::Node.create(name: 'kalle')
289
- tx.failure # all operations inside this tx will be rollbacked
290
- n[:age] = 42
291
- end
292
-
293
- ```
294
-
295
- This feature is experimental, since it has not been tested enough.
296
-
297
- ### Relationship
298
-
299
- How to create a relationship between node n1 and node n2 with one property
300
-
301
- ```ruby
302
- n1 = Neo4j::Node.create
303
- n2 = Neo4j::Node.create
304
- rel = n1.create_rel(:knows, n2, since: 1994)
305
-
306
- # Alternative
307
- Neo4j::Relationship.create(:knows, n1, n2, since: 1994)
308
- ```
309
-
310
- Setting properties on relationships works like setting properties on nodes.
311
-
312
- Finding relationships
313
-
314
- ```ruby
315
- # any type any direction any label
316
- n1.rels
317
-
318
- # Outgoing of one type:
319
- n1.rels(dir: :outgoing, type: :know).to_a
320
-
321
- # same but expects only one relationship
322
- n1.rel(dir: :outgoing, type: :best_friend)
323
-
324
- # several types
325
- n1.rels(types: [:knows, :friend])
326
-
327
- # label
328
- n1.rels(label: :rich)
329
-
330
- # matching several labels
331
- n1.rels(labels: [:rich, :poor])
332
-
333
- # outgoing between two nodes
334
- n1.rels(dir: :outgoing, between: n2)
335
- ```
336
-
337
- Returns nodes instead of relationships
338
-
339
- ```ruby
340
- # same parameters as rels method
341
- n1.nodes(dir: outgoing)
342
- n1.node(dir: outgoing)
343
- ```
344
-
345
-
346
- Delete relationship
347
-
348
- ```ruby
349
- rel = n1.rel(:outgoing, :know) # expects only one relationship
350
- rel.del
351
- ```
352
-
353
-
354
-
355
- ## Implementation:
356
-
357
- All method prefixed with `_` gives direct access to the java layer/rest layer.
358
- Notice, the database starts with auto commit by default.
359
-
360
- No state is cached in the neo4j-core (e.g. neo4j properties).
361
-
362
- The public `Neo4j::Node` classes is abstract and provides a common API/docs for both the embedded and
363
- neo4j server.
364
-
365
- The Neo4j::Embedded and Neo4j::Server modules contains drivers for classes like the `Neo4j::Node`.
366
- This is implemented something like this:
367
-
368
- ```ruby
369
- class Neo4j::Node
370
- # YARD docs
371
- def [](key)
372
- # abstract method - impl using either HTTP or Java API
373
- get_property(key,session=Neo4j::Session.current)
374
- end
375
-
376
-
377
- def self.create(props, session=Neo4j::Session.current)
378
- session.create_node(props)
379
- end
380
- end
381
- ```
382
-
383
- Both implementation use the same E2E specs.
384
-
385
-
386
- ## Testing
387
-
388
- The testing will be using much more mocking.
389
-
390
- * The `unit` rspec folder only contains testing for one Ruby module. All other modules should be mocked.
391
- * The `integration` rspec folder contains testing for two or more modules but mocks the neo4j database access.
392
- * The `e2e` rspec folder for use the real database (or Neo4j's ImpermanentDatabase)
393
- * The `shared_examples` common specs for different types of databases
394
-
395
-
396
- ## The public API
397
-
398
- * {Neo4j::Node} The Neo4j Node
399
-
400
- * {Neo4j::Relationship} The Relationship
401
-
402
- * {Neo4j::Session} The session to the embedded or server database.
403
-
404
-
405
- See also the cypher DSL gem, [Neo4j Wiki](https://github.com/andreasronge/neo4j/wiki/Neo4j%3A%3ACore-Cypher)
406
-
407
- ## Version 3.0
408
-
409
- The neo4j-core version 3.0 uses the java Jar and/or the Neo4j Server version 2.0.0-M6+ . This mean that it should work on
410
- Ruby implementation and not just JRuby !
411
-
412
- It uses the new label feature in order to do mappings between `Neo4j::Node` (java objects) and your own ruby classes.
413
-
414
- The code base for the 3.0 should be smaller and simpler to maintain because there is less work to be done in the
415
- Ruby layer but also by removing features that are too complex or not that useful.
416
-
417
- The neo4j-wrapper source code is included in this git repo until the refactoring has stabilized.
418
- The old source code for neo4j-core is also included (lib.old). The old source code might later on be copied into the
419
- 3.0 source code (the lib folder).
420
-
421
- The neo4j-core gem will work for both the embedded Neo4j API and the server api.
422
- That means that neo4j.rb will work on any Ruby implementation and not just JRuby. This is under investigation !
423
- It's possible that some features for the Neo4j.rb 2.0 will not be available in the 3.0 version since it has to work
424
- with both the Neo4j server and Neo4j embedded APIs.
425
-
426
- Since neo4j-core provides one unified API to both the server end embedded neo4j database the neo4j-wrapper and neo4j
427
- gems will also work with server and embedded neo4j databases.
428
-
429
- New features:
430
-
431
- * neo4j-core provides the same API to both the Embedded database and the Neo4j Server
432
- * auto commit is each operation is now default (neo4j-core)
433
-
434
- Removed features:
435
-
436
- * auto start of the database (neo4j-core)
437
- * wrapping of Neo4j::Relationship java objects but there will be a work around (neo4j-wrapper)
438
- * traversals (the outgoing/incoming/both methods) moves to a new gem, neo4j-traversal.
439
- * rules will not be supported
440
- * versioning will not be supported, will Neo4j support it ?
441
- * multitenancy will not be supported, will Neo4j support it ?
442
-
443
- Changes:
444
-
445
- * `Neo4j::Node.create` now creates a node instead of `Neo4j::Node.new`
446
- * `Neo4j::Node#rels` different arguments, see below
447
- * Many Neo4j Java methods requires you to close an ResourceIterable as well as be in an transaction (even for read operations)
448
- In neo4j-core there are two version of these methods, one that create transaction and close the iterable for you and one raw
449
- where you have to do it yourself (which may give you be better performance).
450
- * The neo4j-core includes the neo4j-wrapper implementation.
451
-
452
- Future (when Neo4j 2.1 is released)
453
- * Support for fulltext search
454
- * Compound keys in index
24
+ ## Contributing
455
25
 
26
+ Pull request with high test coverage and good [code climate](https://codeclimate.com/github/andreasronge/neo4j-core) values will be accepted faster.
456
27
 
457
28
  ## License
458
29
  * Neo4j.rb - MIT, see the LICENSE file http://github.com/andreasronge/neo4j-core/tree/master/LICENSE.
data/lib/neo4j-core.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'forwardable'
2
2
  require 'fileutils'
3
3
 
4
+ require 'neo4j-core/version'
4
5
  require 'neo4j/property_validator'
5
6
  require 'neo4j/property_container'
7
+ require 'neo4j-core/active_entity'
6
8
  require 'neo4j-core/helpers'
7
9
  require 'neo4j-core/cypher_translator'
8
10
  require 'neo4j-core/query'
@@ -23,4 +25,7 @@ else
23
25
  # just for the tests
24
26
  module Neo4j::Embedded
25
27
  end
28
+
29
+ require 'oj'
30
+ require 'oj_mimic_json'
26
31
  end
@@ -0,0 +1,26 @@
1
+ require 'forwardable'
2
+ require 'fileutils'
3
+
4
+ require 'neo4j/property_validator'
5
+ require 'neo4j/property_container'
6
+ require 'neo4j-core/helpers'
7
+ require 'neo4j-core/cypher_translator'
8
+ require 'neo4j-core/query'
9
+
10
+ require 'neo4j/entity_equality'
11
+ require 'neo4j/node'
12
+ require 'neo4j/label'
13
+ require 'neo4j/session'
14
+
15
+ require 'neo4j/relationship'
16
+ require 'neo4j/transaction'
17
+
18
+ require 'neo4j-server'
19
+
20
+ if RUBY_PLATFORM == 'java'
21
+ require 'neo4j-embedded'
22
+ else
23
+ # just for the tests
24
+ module Neo4j::Embedded
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Neo4j::Core
2
+
3
+ # A module to make Neo4j::Node and Neo4j::Relationship work better together with neo4j.rb's Neo4j::ActiveNode and Neo4j::ActiveRel
4
+ module ActiveEntity
5
+ # @return true
6
+ def persisted?
7
+ true
8
+ end
9
+
10
+ end
11
+ end
12
+
13
+
@@ -1,4 +1,5 @@
1
1
  require 'neo4j-core/query_clauses'
2
+ require 'active_support/notifications'
2
3
 
3
4
  module Neo4j::Core
4
5
  # Allows for generation of cypher queries via ruby method calls (inspired by ActiveRecord / arel syntax)
@@ -142,7 +143,11 @@ module Neo4j::Core
142
143
  end
143
144
 
144
145
  def response
145
- response = @session._query(self.to_cypher, @_params)
146
+ return @response if @response
147
+ cypher = self.to_cypher
148
+ @response = ActiveSupport::Notifications.instrument('neo4j.cypher_query', context: @options[:context] || 'CYPHER', cypher: cypher, params: @_params) do
149
+ @session._query(cypher, merge_params)
150
+ end
146
151
  if !response.respond_to?(:error?) || !response.error?
147
152
  response
148
153
  else
@@ -183,7 +188,7 @@ module Neo4j::Core
183
188
  # @example
184
189
  # Query.new.match(n: :Person).return(p: :name}.pluck(p: :name) # => Array of names
185
190
  # @example
186
- # Query.new.match(n: :Person).return(p: :name}.pluck('p, p.name') # => Array of [node, name] pairs
191
+ # Query.new.match(n: :Person).return(p: :name}.pluck('p, DISTINCT p.name') # => Array of [node, name] pairs
187
192
  #
188
193
  def pluck(*columns)
189
194
  query = self.dup
@@ -199,6 +204,8 @@ module Neo4j::Core
199
204
 
200
205
  query = query.return(columns)
201
206
 
207
+ columns = query.response.columns
208
+
202
209
  case columns.size
203
210
  when 0
204
211
  raise ArgumentError, 'No columns specified for Query#pluck'
@@ -301,6 +308,11 @@ module Neo4j::Core
301
308
 
302
309
  partitioning
303
310
  end
311
+
312
+ def merge_params
313
+ @clauses.compact.inject(@_params) {|params, clause| params.merge(clause.params) }
314
+ end
315
+
304
316
  end
305
317
  end
306
318
 
@@ -13,9 +13,12 @@ module Neo4j::Core
13
13
  class Clause
14
14
  include CypherTranslator
15
15
 
16
+ attr_reader :params
17
+
16
18
  def initialize(arg, options = {})
17
19
  @arg = arg
18
20
  @options = options
21
+ @params = {}
19
22
  end
20
23
 
21
24
  def value
@@ -154,27 +157,25 @@ module Neo4j::Core
154
157
  class WhereClause < Clause
155
158
  @keyword = 'WHERE'
156
159
 
157
- def from_key_and_value(key, value)
160
+ def from_key_and_value(key, value, previous_keys = [])
158
161
  case value
159
162
  when Hash
160
163
  value.map do |k, v|
161
164
  if k.to_sym == :neo_id
162
- "ID(#{key}) = #{v}"
165
+ "ID(#{key}) = #{v.to_i}"
163
166
  else
164
- key.to_s + '.' + from_key_and_value(k, v)
167
+ key.to_s + '.' + from_key_and_value(k, v, previous_keys + [key])
165
168
  end
166
169
  end.join(' AND ')
167
- when Array
168
- "#{key} IN [#{value.join(', ')}]"
169
170
  when NilClass
170
171
  "#{key} IS NULL"
171
172
  when Regexp
172
173
  pattern = (value.casefold? ? "(?i)" : "") + value.source
173
174
  "#{key} =~ #{escape_value(pattern.gsub(/\\/, '\\\\\\'))}"
174
- when /^\{[^\{\}]+\}$/
175
- "#{key} = #{value}"
175
+ when Array
176
+ key_value_string(key, value, previous_keys)
176
177
  else
177
- "#{key} = #{value.inspect}"
178
+ key_value_string(key, value, previous_keys)
178
179
  end
179
180
  end
180
181
 
@@ -183,6 +184,19 @@ module Neo4j::Core
183
184
  clauses.map(&:value).join(' AND ')
184
185
  end
185
186
  end
187
+
188
+ private
189
+
190
+ def key_value_string(key, value, previous_keys = [])
191
+ param = (previous_keys + [key]).join('_').gsub(/[\(\)\._]+/, '_')
192
+ @params = @params.merge(param.to_sym => value)
193
+
194
+ if value.is_a?(Array)
195
+ "#{key} IN {#{param}}"
196
+ else
197
+ "#{key} = {#{param}}"
198
+ end
199
+ end
186
200
  end
187
201
 
188
202
 
@@ -368,12 +382,12 @@ module Neo4j::Core
368
382
  "#{key} = #{value}"
369
383
  when Hash
370
384
  if @options[:set_props]
385
+ attribute_string = value.map {|k, v| "#{k}: #{v.inspect}" }.join(', ')
386
+ "#{key} = {#{attribute_string}}"
387
+ else
371
388
  value.map do |k, v|
372
389
  "#{key}.#{k} = #{v.inspect}"
373
390
  end
374
- else
375
- attribute_string = value.map {|k, v| "#{k}: #{v.inspect}" }.join(', ')
376
- "#{key} = {#{attribute_string}}"
377
391
  end
378
392
  else
379
393
  raise ArgError.new(value)
@@ -392,7 +406,7 @@ module Neo4j::Core
392
406
 
393
407
  def initialize(*args)
394
408
  super
395
- @options[:set_props] = true
409
+ @options[:set_props] = false
396
410
  end
397
411
  end
398
412
 
@@ -1,5 +1,5 @@
1
1
  module Neo4j
2
2
  module Core
3
- VERSION = "3.0.0.alpha.19"
3
+ VERSION = "3.0.0.rc.1"
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Neo4j
2
2
  module Core
3
- VERSION = "3.0.0.alpha.16"
3
+ VERSION = "3.0.0.rc1"
4
4
  end
5
5
  end
@@ -54,6 +54,7 @@ module Neo4j::Embedded
54
54
  java_clazz.class_eval do
55
55
  include Neo4j::Embedded::Property
56
56
  include Neo4j::EntityEquality
57
+ include Neo4j::Core::ActiveEntity
57
58
  extend Neo4j::Core::TxMethods
58
59
 
59
60
  def inspect
@@ -78,7 +79,6 @@ module Neo4j::Embedded
78
79
  Java::OrgNeo4jGraphdb.DynamicLabel.label(label_name)
79
80
  end
80
81
 
81
-
82
82
  def _add_label(*label_name)
83
83
  label_name.each do |name|
84
84
  addLabel(_java_label(name))
@@ -7,6 +7,7 @@ module Neo4j::Embedded
7
7
  include Neo4j::Embedded::Property
8
8
  include Neo4j::EntityEquality
9
9
  include Neo4j::Relationship::Wrapper
10
+ include Neo4j::Core::ActiveEntity
10
11
  extend Neo4j::Core::TxMethods
11
12
 
12
13
  alias_method :_other_node, :getOtherNode
@@ -2,6 +2,7 @@ module Neo4j::Server
2
2
  class CypherNode < Neo4j::Node
3
3
  include Neo4j::Server::Resource
4
4
  include Neo4j::Core::CypherTranslator
5
+ include Neo4j::Core::ActiveEntity
5
6
 
6
7
  def initialize(session, value)
7
8
  @session = session
@@ -3,6 +3,7 @@ module Neo4j::Server
3
3
  class CypherRelationship < Neo4j::Relationship
4
4
  include Neo4j::Server::Resource
5
5
  include Neo4j::Core::CypherTranslator
6
+ include Neo4j::Core::ActiveEntity
6
7
 
7
8
  attr_reader :start_node_neo_id, :end_node_neo_id
8
9
 
@@ -59,14 +59,18 @@ module Neo4j::Server
59
59
  end
60
60
 
61
61
  def map_row_value(value, session)
62
- return value unless value.is_a?(Hash)
63
-
64
- if value['labels']
65
- add_entity_id(value)
66
- CypherNode.new(session, value).wrapper
67
- elsif value['type']
68
- add_entity_id(value)
69
- CypherRelationship.new(session, value).wrapper
62
+ if value.is_a?(Hash)
63
+ if value['labels']
64
+ add_entity_id(value)
65
+ CypherNode.new(session, value).wrapper
66
+ elsif value['type']
67
+ add_entity_id(value)
68
+ CypherRelationship.new(session, value).wrapper
69
+ else
70
+ value
71
+ end
72
+ elsif value.is_a?(Array)
73
+ value.map {|v| map_row_value(v, session) }
70
74
  else
71
75
  value
72
76
  end
@@ -101,7 +105,7 @@ module Neo4j::Server
101
105
  end
102
106
 
103
107
  def add_entity_id(data)
104
- data.merge!({'id' => data['self'].match(/\d+$/)[0].to_i})
108
+ data.merge!({'id' => data['self'].split('/')[-1].to_i})
105
109
  end
106
110
 
107
111
  def error?
data/lib/neo4j/session.rb CHANGED
@@ -51,11 +51,19 @@ module Neo4j
51
51
  end
52
52
  end
53
53
 
54
- # Returns a Query object. See Neo4j::Core::Query for more details, but basic usage looks like:
54
+
55
+ # Performs a cypher query. See {Neo4j::Core::Query} for more details, but basic usage looks like:
56
+ #
57
+ # @example Using cypher DSL
58
+ # Neo4j::Session.query.match("(c:person)-[:friends]->(p:person)").where(c: {name: 'andreas'}).pluck(:p).first[:name]
59
+ #
60
+ # @example Show the generated Cypher
61
+ # Neo4j::Session.query..match("(c:person)-[:friends]->(p:person)").where(c: {name: 'andreas'}).return(:p).to_cypher
55
62
  #
56
- # @example
57
- # session.query.match("(c:Car)<-[:OWNS]-(p:Person)").where(c: {vin: '234UAEB3425B'}).return(:p).first[:p]
63
+ # @example Use Cypher string instead of the cypher DSL
64
+ # Neo4j::Session.query("MATCH (c:person)-[:friends]->(p:person) WHERE c.name = \"andreas\" RETURN p").first[:p][:name]
58
65
  #
66
+ # @return [Neo4j::Core::Query, Enumerable] return a Query object for DSL or a Enumerable if using raw cypher strings
59
67
  # @see http://docs.neo4j.org/chunked/milestone/cypher-query-lang.html The Cypher Query Language Documentation
60
68
  #
61
69
  def query(options = {})
@@ -0,0 +1,18 @@
1
+ module Neo4j
2
+ module Tasks
3
+
4
+ module ConfigServer
5
+
6
+ def config(data, port)
7
+ s = set_property(data, 'org.neo4j.server.webserver.https.enabled', 'false')
8
+ set_property(s, 'org.neo4j.server.webserver.port', port)
9
+ end
10
+
11
+ def set_property(data, property, value)
12
+ data.gsub(/#{property}\s*=\s*(\w+)/, "#{property}=#{value}")
13
+ end
14
+
15
+ extend self
16
+ end
17
+ end
18
+ end
@@ -2,6 +2,7 @@
2
2
  require 'os'
3
3
  require 'httparty'
4
4
  require 'zip'
5
+ require File.expand_path("../config_server", __FILE__)
5
6
 
6
7
  namespace :neo4j do
7
8
 
@@ -56,18 +57,26 @@ namespace :neo4j do
56
57
  file_name
57
58
  end
58
59
 
59
- desc "Install Neo4j, example neo4j:install[community,2.0.3]"
60
- task :install, :edition, :version do |t, args|
61
- args.with_defaults(:edition => "community")
60
+ def get_environment(args)
61
+ args[:environment] || 'development'
62
+ end
63
+
64
+ def install_location(args)
65
+ FileUtils.mkdir_p("db/neo4j")
66
+ "db/neo4j/#{get_environment(args)}"
67
+ end
62
68
 
63
- file = args[:version] ? "#{args[:edition]}-#{args[:version]}" : "#{args[:edition]}"
64
- puts "Installing Neo4j-#{file}"
69
+ desc "Install Neo4j, example neo4j:install[community-2.1.3,development]"
70
+ task :install, :edition, :environment do |_, args|
71
+ file = args[:edition]
72
+ environment = get_environment(args)
73
+ puts "Installing Neo4j-#{file} environment: #{environment}"
65
74
 
66
75
  downloaded_file = download_neo4j file
67
76
 
68
77
  if OS::Underlying.windows?
69
78
  # Extract and move to neo4j directory
70
- unless File.exist?('neo4j')
79
+ unless File.exist?(install_location(args))
71
80
  Zip::ZipFile.open(downloaded_file) do |zip_file|
72
81
  zip_file.each do |f|
73
82
  f_path=File.join(".", f.name)
@@ -79,100 +88,126 @@ namespace :neo4j do
79
88
  end
80
89
  end
81
90
  end
82
- FileUtils.mv "neo4j-#{file}", "neo4j"
91
+ FileUtils.mv "neo4j-#{file}", install_location(args)
83
92
  FileUtils.rm downloaded_file
84
93
  end
85
94
 
86
95
  # Install if running with Admin Privileges
87
- if %x[reg query "HKU\\S-1-5-19"].size > 0
88
- %x[neo4j/bin/neo4j install]
96
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
97
+ %x["#{install_location(args)}/bin/neo4j install"]
89
98
  puts "Neo4j Installed as a service."
90
99
  end
91
100
 
92
101
  else
93
102
  %x[tar -xvf #{downloaded_file}]
94
- %x[mv neo4j-#{file} neo4j]
103
+ %x[mv neo4j-#{file} #{install_location(args)}]
95
104
  %x[rm #{downloaded_file}]
96
105
  puts "Neo4j Installed in to neo4j directory."
97
106
  end
98
- puts "Type 'rake neo4j:start' to start it"
107
+ puts "Type 'rake neo4j:start' or 'rake neo4j:start[ENVIRONMENT]' to start it\nType 'neo4j:config[ENVIRONMENT,PORT]' for changing server port, (default 7474)"
99
108
  end
100
109
 
101
110
  desc "Start the Neo4j Server"
102
- task :start do
103
- puts "Starting Neo4j..."
111
+ task :start, :environment do |_, args|
112
+ puts "Starting Neo4j #{get_environment(args)}..."
104
113
  if OS::Underlying.windows?
105
114
  if %x[reg query "HKU\\S-1-5-19"].size > 0
106
- %x[neo4j/bin/Neo4j.bat start] #start service
115
+ %x[#{install_location(args)}/bin/Neo4j.bat start] #start service
107
116
  else
108
117
  puts "Starting Neo4j directly, not as a service."
109
- %x[neo4j/bin/Neo4j.bat]
118
+ %x[#{install_location(args)}/bin/Neo4j.bat]
110
119
  end
111
120
  else
112
- %x[neo4j/bin/neo4j start]
121
+ %x[#{install_location(args)}/bin/neo4j start]
113
122
  end
114
123
  end
115
-
124
+
125
+ desc "Configure Server, e.g. rake neo4j:config[development,8888]"
126
+ task :config, :environment, :port do |_, args|
127
+
128
+ port = args[:port]
129
+ raise "no port given" unless port
130
+ puts "Config Neo4j #{get_environment(args)} for port #{port}"
131
+ location = "#{install_location(args)}/conf/neo4j-server.properties"
132
+ text = File.read(location)
133
+ replace = Neo4j::Tasks::ConfigServer.config(text, port)
134
+ File.open(location, "w") {|file| file.puts replace}
135
+ end
136
+
116
137
  desc "Stop the Neo4j Server"
117
- task :stop do
118
- puts "Stopping Neo4j..."
138
+ task :stop, :environment do |_, args|
139
+ puts "Stopping Neo4j #{get_environment(args)}..."
119
140
  if OS::Underlying.windows?
120
141
  if %x[reg query "HKU\\S-1-5-19"].size > 0
121
- %x[neo4j/bin/Neo4j.bat stop] #stop service
142
+ %x[#{install_location(args)}/bin/Neo4j.bat stop] #stop service
122
143
  else
123
144
  puts "You do not have administrative rights to stop the Neo4j Service"
124
145
  end
125
146
  else
126
- %x[neo4j/bin/neo4j stop]
147
+ %x[#{install_location(args)}/bin/neo4j stop]
148
+ end
149
+ end
150
+
151
+ desc "Get info the Neo4j Server"
152
+ task :info, :environment do |_, args|
153
+ puts "Info from Neo4j #{get_environment(args)}..."
154
+ if OS::Underlying.windows?
155
+ if %x[reg query "HKU\\S-1-5-19"].size > 0
156
+ %x[#{install_location(args)}/bin/Neo4j.bat info] #stop service
157
+ else
158
+ puts "You do not have administrative rights to get info from the Neo4j Service"
159
+ end
160
+ else
161
+ puts %x[#{install_location(args)}/bin/neo4j info]
127
162
  end
128
163
  end
129
164
 
130
165
  desc "Restart the Neo4j Server"
131
- task :restart do
132
- puts "Restarting Neo4j..."
166
+ task :restart, :environment do |_, args|
167
+ puts "Restarting Neo4j #{get_environment(args)}..."
133
168
  if OS::Underlying.windows?
134
169
  if %x[reg query "HKU\\S-1-5-19"].size > 0
135
- %x[neo4j/bin/Neo4j.bat restart]
170
+ %x[#{install_location(args)}/bin/Neo4j.bat restart]
136
171
  else
137
172
  puts "You do not have administrative rights to restart the Neo4j Service"
138
173
  end
139
174
  else
140
- %x[neo4j/bin/neo4j restart]
175
+ %x[#{install_location(args)}/bin/neo4j restart]
141
176
  end
142
177
  end
143
178
 
144
179
  desc "Reset the Neo4j Server"
145
- task :reset_yes_i_am_sure do
180
+ task :reset_yes_i_am_sure, :environment do |_, args|
146
181
  # Stop the server
147
182
  if OS::Underlying.windows?
148
183
  if %x[reg query "HKU\\S-1-5-19"].size > 0
149
- %x[neo4j/bin/Neo4j.bat stop]
184
+ %x[#{install_location(args)}/bin/Neo4j.bat stop]
150
185
 
151
186
  # Reset the database
152
- FileUtils.rm_rf("neo4j/data/graph.db")
153
- FileUtils.mkdir("neo4j/data/graph.db")
187
+ FileUtils.rm_rf("#{install_location(args)}/data/graph.db")
188
+ FileUtils.mkdir("#{install_location(args)}/data/graph.db")
154
189
 
155
190
  # Remove log files
156
- FileUtils.rm_rf("neo4j/data/log")
157
- FileUtils.mkdir("neo4j/data/log")
191
+ FileUtils.rm_rf("#{install_location(args)}/data/log")
192
+ FileUtils.mkdir("#{install_location(args)}/data/log")
158
193
 
159
- %x[neo4j/bin/Neo4j.bat start]
194
+ %x[#{install_location(args)}/bin/Neo4j.bat start]
160
195
  else
161
196
  puts "You do not have administrative rights to reset the Neo4j Service"
162
197
  end
163
198
  else
164
- %x[neo4j/bin/neo4j stop]
199
+ %x[#{install_location(args)}/bin/neo4j stop]
165
200
 
166
201
  # Reset the database
167
- FileUtils.rm_rf("neo4j/data/graph.db")
168
- FileUtils.mkdir("neo4j/data/graph.db")
202
+ FileUtils.rm_rf("#{install_location(args)}/data/graph.db")
203
+ FileUtils.mkdir("#{install_location(args)}/data/graph.db")
169
204
 
170
205
  # Remove log files
171
- FileUtils.rm_rf("neo4j/data/log")
172
- FileUtils.mkdir("neo4j/data/log")
206
+ FileUtils.rm_rf("#{install_location(args)}/data/log")
207
+ FileUtils.mkdir("#{install_location(args)}/data/log")
173
208
 
174
209
  # Start the server
175
- %x[neo4j/bin/neo4j start]
210
+ %x[#{install_location(args)}/bin/neo4j start]
176
211
  end
177
212
  end
178
213
 
data/neo4j-core.gemspec CHANGED
@@ -30,11 +30,15 @@ It comes included with the Apache Lucene document database.
30
30
 
31
31
  # Not released yet
32
32
  s.add_dependency("httparty")
33
- s.add_dependency("json")
34
33
  s.add_dependency("os") # for Rake task
35
34
  s.add_dependency("zip") # for Rake task
35
+ s.add_dependency("activesupport") # For ActiveSupport::Notifications
36
36
 
37
37
  if RUBY_PLATFORM =~ /java/
38
+ s.add_dependency("json")
38
39
  s.add_dependency("neo4j-community", '~> 2.1.1')
40
+ else
41
+ s.add_dependency("oj")
42
+ s.add_dependency("oj_mimic_json")
39
43
  end
40
44
  end
metadata CHANGED
@@ -1,85 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.alpha.19
4
+ version: 3.0.0.rc.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Ronge
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-14 00:00:00.000000000 Z
11
+ date: 2014-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
15
22
  version_requirements: !ruby/object:Gem::Requirement
16
23
  requirements:
17
- - - '>='
24
+ - - ">="
18
25
  - !ruby/object:Gem::Version
19
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: os
20
29
  requirement: !ruby/object:Gem::Requirement
21
30
  requirements:
22
- - - '>='
31
+ - - ">="
23
32
  - !ruby/object:Gem::Version
24
33
  version: '0'
25
- prerelease: false
26
34
  type: :runtime
27
- - !ruby/object:Gem::Dependency
28
- name: json
35
+ prerelease: false
29
36
  version_requirements: !ruby/object:Gem::Requirement
30
37
  requirements:
31
- - - '>='
38
+ - - ">="
32
39
  - !ruby/object:Gem::Version
33
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: zip
34
43
  requirement: !ruby/object:Gem::Requirement
35
44
  requirements:
36
- - - '>='
45
+ - - ">="
37
46
  - !ruby/object:Gem::Version
38
47
  version: '0'
39
- prerelease: false
40
48
  type: :runtime
41
- - !ruby/object:Gem::Dependency
42
- name: os
49
+ prerelease: false
43
50
  version_requirements: !ruby/object:Gem::Requirement
44
51
  requirements:
45
- - - '>='
52
+ - - ">="
46
53
  - !ruby/object:Gem::Version
47
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
48
57
  requirement: !ruby/object:Gem::Requirement
49
58
  requirements:
50
- - - '>='
59
+ - - ">="
51
60
  - !ruby/object:Gem::Version
52
61
  version: '0'
53
- prerelease: false
54
62
  type: :runtime
55
- - !ruby/object:Gem::Dependency
56
- name: zip
63
+ prerelease: false
57
64
  version_requirements: !ruby/object:Gem::Requirement
58
65
  requirements:
59
- - - '>='
66
+ - - ">="
60
67
  - !ruby/object:Gem::Version
61
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: oj
62
71
  requirement: !ruby/object:Gem::Requirement
63
72
  requirements:
64
- - - '>='
73
+ - - ">="
65
74
  - !ruby/object:Gem::Version
66
75
  version: '0'
67
- prerelease: false
68
76
  type: :runtime
69
- - !ruby/object:Gem::Dependency
70
- name: neo4j-community
77
+ prerelease: false
71
78
  version_requirements: !ruby/object:Gem::Requirement
72
79
  requirements:
73
- - - ~>
80
+ - - ">="
74
81
  - !ruby/object:Gem::Version
75
- version: 2.1.1
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: oj_mimic_json
76
85
  requirement: !ruby/object:Gem::Requirement
77
86
  requirements:
78
- - - ~>
87
+ - - ">="
79
88
  - !ruby/object:Gem::Version
80
- version: 2.1.1
81
- prerelease: false
89
+ version: '0'
82
90
  type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: |
84
98
  You can think of Neo4j as a high-performance graph engine with all the features of a mature and robust database.
85
99
  The programmer works with an object-oriented, flexible network structure rather than with strict and static tables
@@ -94,6 +108,8 @@ files:
94
108
  - Gemfile
95
109
  - README.md
96
110
  - lib/neo4j-core.rb
111
+ - lib/neo4j-core.rb~
112
+ - lib/neo4j-core/active_entity.rb
97
113
  - lib/neo4j-core/cypher_translator.rb
98
114
  - lib/neo4j-core/hash_with_indifferent_access.rb
99
115
  - lib/neo4j-core/helpers.rb
@@ -136,6 +152,7 @@ files:
136
152
  - lib/neo4j/relationship.rb
137
153
  - lib/neo4j/session.rb
138
154
  - lib/neo4j/session.rb~
155
+ - lib/neo4j/tasks/config_server.rb
139
156
  - lib/neo4j/tasks/neo4j_server.rb
140
157
  - lib/neo4j/transaction.rb
141
158
  - neo4j-core.gemspec
@@ -143,31 +160,31 @@ homepage: http://github.com/andreasronge/neo4j-core/tree
143
160
  licenses:
144
161
  - MIT
145
162
  metadata: {}
146
- post_install_message:
163
+ post_install_message:
147
164
  rdoc_options:
148
- - --quiet
149
- - --title
165
+ - "--quiet"
166
+ - "--title"
150
167
  - Neo4j::Core
151
- - --line-numbers
152
- - --main
168
+ - "--line-numbers"
169
+ - "--main"
153
170
  - README.rdoc
154
- - --inline-source
171
+ - "--inline-source"
155
172
  require_paths:
156
173
  - lib
157
174
  required_ruby_version: !ruby/object:Gem::Requirement
158
175
  requirements:
159
- - - '>='
176
+ - - ">="
160
177
  - !ruby/object:Gem::Version
161
178
  version: 1.8.7
162
179
  required_rubygems_version: !ruby/object:Gem::Requirement
163
180
  requirements:
164
- - - '>'
181
+ - - ">"
165
182
  - !ruby/object:Gem::Version
166
183
  version: 1.3.1
167
184
  requirements: []
168
185
  rubyforge_project: neo4j-core
169
186
  rubygems_version: 2.2.2
170
- signing_key:
187
+ signing_key:
171
188
  specification_version: 4
172
189
  summary: A graph database for Ruby
173
190
  test_files: []