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

Sign up to get free protection for your applications and to get access to all the features.
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: []