neoon 0.0.4 → 0.0.5

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: b1ff7ac30436f19194698ede55cfe68529918122
4
- data.tar.gz: 3b62de2caf2e48745e2f67d9705490b5cfe43e48
3
+ metadata.gz: 28243d5e5b0830a48aa0df05d3b94dfc9b7bf3b7
4
+ data.tar.gz: 5d7b6ea2499ed9302ae792a566410a33a60047fe
5
5
  SHA512:
6
- metadata.gz: a5baa0e81c289446fee6744879834a45a878b976d265c10c871b0b666bdcc9c69f581108a665c1959533e0f73ae9241a2247da2d822043ac5ff8d084e708b0ed
7
- data.tar.gz: dcb1ea83f6b94370962a93f9a829833f2a1e1f6f882e1ea4458b530f56f8776b078644433bce4090b99b56b683743fae9e444ad645db6234a0be490497ee1026
6
+ metadata.gz: f5be28a492cfdfbfc9356c9e7eb69b5511df51d5cb90353b857dfc195a46a489d8e9f0e9d719d0e34a056d11ee77a13bd64e0394575c485ea29bb9f91711b6f7
7
+ data.tar.gz: 603ac48d81ef63a99a6004d64356a5cadfe9345a83e79568ffa262c3f4a20380990cbe64717a7ad8be80c24d753f5d8f7bde1223b3f4d61700cd0f4525e1bc54
data/README.md CHANGED
@@ -83,12 +83,12 @@ end
83
83
  This will be used internally to auto index models nodes.
84
84
 
85
85
  ```ruby
86
- Topic.neo_index_list #=> [:name, :slug]
86
+ Topic.neo_index_list #=> { :name => true, :slug => "UNIQUENESS" }
87
87
 
88
88
  #
89
89
  # Sync the indexed nodes as described in each model config. It returns the indexed fields.
90
90
  # Remember, this will be called on each model on the boot if preload_models set to true.
91
- Topic.neo_schema_update #=> [:name, :slug]
91
+ Topic.neo_schema_update #=> { :name => true, :slug => "UNIQUENESS" }
92
92
  ```
93
93
 
94
94
  ---
@@ -98,13 +98,13 @@ Topic.neo_schema_update #=> [:name, :slug]
98
98
  `Neoon::Cypher::InstanceQuery` should be initialized with an Class name or `label`. You can use `Neoon::Cypher::Query` to manually create indexes, constraints, etc.
99
99
 
100
100
  ```ruby
101
- l = Neoon::Cypher::Query.new('Person') #=> #<Neoon::Cypher::Query:0x007fe8926d2068 @label="Person">
101
+ l = Neoon::Cypher::Query.new('Person')
102
102
 
103
- l.create_index(:name).run
104
- # l.drop_index(:name).run
103
+ l.create_index(:name)
104
+ # l.drop_index(:name)
105
105
 
106
- l.create_constraint(:username).run
107
- # l.drop_constraint(:username).run
106
+ l.create_constraint(:username)
107
+ # l.drop_constraint(:username)
108
108
 
109
109
  l.list_indexes #=> { :name => true, :username => "UNIQUENESS" }
110
110
  ```
@@ -121,25 +121,25 @@ Use it with Struct:
121
121
 
122
122
  ```ruby
123
123
  Customer = Struct.new(:id, :neo_node_properties)
124
- cus = Customer.new(50, {:name => 'Julie', :address => 'PS'}) #=> #<Neoon::Cypher::InstanceQuery:0x007feb35953d00 @id=50, @label="Customer", @args={:name=>"Julie", :address=>"PS"}>
124
+ cus = Customer.new(50, {:name => 'Julie', :address => 'PS'})
125
125
 
126
126
  c = Neoon::Cypher::InstanceQuery.new(cus)
127
127
 
128
- c.find_node.run #=> Return node in Neo4j if already saved
129
- c.create_node.run #=> Create object node / or update it
130
- c.delete_node.run #=> Remove object node
128
+ c.find_node #=> Return node in Neo4j if already saved
129
+ c.create_node #=> Create object node / or update it
130
+ c.delete_node #=> Remove object node
131
131
  ```
132
132
 
133
- Note that the key of finding nodes in Neo4j is `id` as saved in Neo4j with key `db_id`.
133
+ Note that the key of finding nodes in Neo4j is `id` as saved in Neo4j with key `_id`.
134
134
 
135
135
  Another example on the model we defined above:
136
136
 
137
137
  ```ruby
138
- t = Neoon::Cypher::InstanceQuery.new(Topic.first) #=> #<Neoon::Cypher::InstanceQuery:0x007fe894410b98 @id=1, @label="Topic", @args={...}>
138
+ t = Neoon::Cypher::InstanceQuery.new(Topic.first)
139
139
 
140
- t.find_node.run #=> Returns node in Neo4j if already saved
141
- t.create_node.run #=> Create object node / or update it
142
- t.delete_node.run #=> Remove object node
140
+ t.find_node #=> Returns node in Neo4j if already saved
141
+ t.create_node #=> Create object node / or update it
142
+ t.delete_node #=> Remove object node
143
143
  ```
144
144
 
145
145
  ---
@@ -6,15 +6,7 @@ module Faraday
6
6
  @app.call(env).on_complete do |env|
7
7
  case env[:status]
8
8
  when (400..499)
9
- body = JSON.parse(env[:body])
10
- raise "Neoon::Error::#{body["cause"]["exception"]}".constantize, "#{{
11
- :message => body["message"],
12
- :exception => body["exception"],
13
- :cause => {
14
- :message => body["cause"]["message"],
15
- :exception => body["cause"]["exception"]
16
- }
17
- } if env[:body]}"
9
+ raise "Neoon::Error::#{JSON.parse(env[:body])["cause"]["exception"]}".constantize.new(env[:response], env[:response].body)
18
10
  when (500..599)
19
11
  raise 'Something went error with Neo4j server.'
20
12
  end
@@ -5,10 +5,10 @@ module Neoon
5
5
  attr_reader :connection
6
6
 
7
7
  def initialize(url)
8
- @uri = URI.parse(url)
9
- end_point = "#{@uri.scheme}://#{@uri.host}:#{@uri.port}#{@uri.path}"
8
+ uri = URI.parse(url)
9
+ end_point = "#{uri.scheme}://#{uri.host}:#{uri.port}#{uri.path}"
10
10
  @connection ||= Faraday.new(end_point, connection_options.merge(:builder => middleware))
11
- @connection.basic_auth(@uri.user, @uri.password) if @uri.user && @uri.password
11
+ @connection.basic_auth(uri.user, uri.password) if uri.user && uri.password
12
12
  end
13
13
 
14
14
  include Request
@@ -26,7 +26,7 @@ module Neoon
26
26
  :request => {
27
27
  :open_timeout => 5,
28
28
  :timeout => 10,
29
- },
29
+ }
30
30
  }
31
31
  end
32
32
 
@@ -2,27 +2,21 @@ module Neoon
2
2
  module Cypher
3
3
  class Handler
4
4
 
5
- attr_reader :query, :args
5
+ attr_reader :query, :args, :result
6
6
 
7
7
  def initialize(hash)
8
- @query = hash[:query]
9
- @args = hash[:args]
10
- end
8
+ @query = hash[:query]
9
+ @args = hash[:args]
11
10
 
12
- def to_cypher
13
- if query.is_a?(Array)
14
- query.map { |q| q.gsub(/\s+/, ' ').strip }
15
- else
16
- query.gsub(/\s+/, ' ').strip
11
+ @result = begin
12
+ make_cypher_request(query, args)
13
+ rescue Exception => e
14
+ { :error => e }
17
15
  end
18
16
  end
19
17
 
20
- def run
21
- if query.is_a?(Array)
22
- query.each { |q| make_cypher_request(q, args) }
23
- else
24
- make_cypher_request(query, args)
25
- end
18
+ def to_cypher
19
+ [query.gsub(/\s+/, ' ').strip, args]
26
20
  end
27
21
 
28
22
  protected
@@ -7,37 +7,10 @@ module Neoon
7
7
  def initialize(object)
8
8
  @id = object.id
9
9
  @label = object.class.name
10
- @args = object.neo_node_properties
10
+ @args = object.neo_node_properties.merge(:_id => id)
11
11
  end
12
12
 
13
- def find_node
14
- cypher_query = <<-CYPHER
15
- MATCH node:#{label} WHERE node._id = #{id}
16
- RETURN node
17
- CYPHER
18
- cypherable(:query => cypher_query)
19
- end
20
-
21
- def create_node
22
- cypher_query = <<-CYPHER
23
- MERGE (node:#{label} { _id: #{id} })
24
- ON CREATE node SET node = {props}
25
- ON MATCH node SET node = {props}
26
- RETURN node
27
- CYPHER
28
- cypherable(:query => cypher_query, :args => {:props => args})
29
- end
30
- alias_method :update_node, :create_node
31
- alias_method :save_node, :create_node
32
-
33
- def delete_node
34
- cypher_query = <<-CYPHER
35
- MATCH node:#{label}
36
- WHERE node._id = #{id}
37
- DELETE node
38
- CYPHER
39
- cypherable(:query => cypher_query)
40
- end
13
+ include Neoon::Cypher::Node::Operations
41
14
 
42
15
  protected
43
16
 
@@ -0,0 +1,43 @@
1
+ module Neoon
2
+ module Cypher
3
+ module Node
4
+ module Operations
5
+
6
+ def find_node
7
+ cypher_query = <<-CYPHER
8
+ MATCH node:#{label} WHERE node._id = #{id}
9
+ RETURN node
10
+ CYPHER
11
+ cypherable(:query => cypher_query)
12
+ end
13
+
14
+ def save_node
15
+ # since you can't update a constrain with same value
16
+ # we have to remove the node and re-create it
17
+ # other way ???
18
+ delete_node unless (label.constantize.respond_to?(:neo_schema_index_keys) ? label.constantize.neo_schema_index_keys : Neoon::Cypher::Query.new(label).list_indexes).select{|k,v| v=='UNIQUENESS'}.empty?
19
+
20
+ cypher_query = <<-CYPHER
21
+ MERGE (node:#{label} { _id: #{id} })
22
+ ON CREATE node SET node = {props}
23
+ ON MATCH node SET node = {props}
24
+ RETURN node
25
+ CYPHER
26
+ cypherable(:query => cypher_query, :args => {:props => args})
27
+ end
28
+ alias_method :update_node, :save_node
29
+ alias_method :create_node, :save_node
30
+
31
+ def delete_node
32
+ cypher_query = <<-CYPHER
33
+ MATCH node:#{label}
34
+ WHERE node._id = #{id}
35
+ DELETE node
36
+ CYPHER
37
+ cypherable(:query => cypher_query)
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/neoon/error.rb CHANGED
@@ -1,11 +1,27 @@
1
1
  module Neoon
2
2
  module Error
3
3
 
4
- class Exception < StandardError; end
4
+ class Exception < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response, message)
8
+ @response = response
9
+ super(message)
10
+ end
11
+ end
12
+
5
13
  class IndexException < Exception; end
6
14
  class SchemaException < Exception; end
7
15
  class CypherException < Exception; end
8
16
 
17
+ # custom
18
+ class NodeNotFoundException < Exception; end
19
+
20
+ # org.neo4j.kernel.impl.api.constraints
21
+ class ConstraintValidationKernelException < Exception; end
22
+ class UnableToValidateConstraintKernelException < Exception; end
23
+ class UniqueConstraintViolationKernelException < Exception; end
24
+
9
25
  # org.neo4j.kernel.api.exceptions
10
26
  class BeginTransactionFailureException < Exception; end
11
27
  class ConstraintCreationException < Exception; end
@@ -3,21 +3,26 @@ module Neoon
3
3
  module Node
4
4
 
5
5
  def neo_node
6
- _cypher_query.find_node.run.data.first.first.data
6
+ _node = _cypher_query.find_node.result.data
7
+ if _node.empty?
8
+ excep = { :message => "Cannot find node with id [#{_cypher_query.id}] in database.", :exception => "NodeNotFoundException" }
9
+ raise Neoon::Error::NodeNotFoundException.new excep, excep
10
+ end
11
+ _node.first.first.data
7
12
  end
8
13
 
9
14
  def neo_create
10
- _cypher_query.create_node.run.data
15
+ _cypher_query.create_node.result.data
11
16
  end
12
17
  alias_method :neo_save, :neo_create
13
18
  alias_method :neo_update, :neo_create
14
19
 
15
20
  def neo_destroy
16
- _cypher_query.delete_node.run.data
21
+ _cypher_query.delete_node.result.data
17
22
  end
18
23
 
19
24
  def neo_node_properties
20
- _neo_node.merge({ :_id => self.id })
25
+ _neo_node.merge(:_id => self.id)
21
26
  end
22
27
 
23
28
  protected
@@ -8,20 +8,18 @@ module Neoon
8
8
 
9
9
  def neo_index_create key
10
10
  if neo_schema_index_keys.select { |k,v| v == 'UNIQUENESS' }.include? key
11
- _cypher_query.create_constraint(key).run
11
+ _cypher_query.create_constraint(key)
12
12
  else
13
- _cypher_query.create_index(key).run
13
+ _cypher_query.create_index(key)
14
14
  end
15
- true
16
15
  end
17
16
 
18
17
  def neo_index_drop key
19
18
  if neo_index_list[key] == 'UNIQUENESS'
20
- _cypher_query.drop_constraint(key).run
19
+ _cypher_query.drop_constraint(key)
21
20
  else
22
- _cypher_query.drop_index(key).run
21
+ _cypher_query.drop_index(key)
23
22
  end
24
- true
25
23
  end
26
24
 
27
25
  def neo_index_drop_all
data/lib/neoon/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neoon
2
- VERSION = '0.0.4'
2
+ VERSION = '0.0.5'
3
3
  end
data/lib/neoon.rb CHANGED
@@ -14,6 +14,7 @@ require 'neoon/cypher/handler'
14
14
  require 'neoon/cypher/schema/indexes'
15
15
  require 'neoon/cypher/schema/constraints'
16
16
  require 'neoon/cypher/query'
17
+ require 'neoon/cypher/node/operations'
17
18
  require 'neoon/cypher/instance_query'
18
19
 
19
20
  require 'neoon/model/config'
@@ -6,6 +6,14 @@ describe Neoon::Model::Config do
6
6
  require 'app/models/topic'
7
7
  end
8
8
 
9
+ it 'responds to .neoon' do
10
+ expect(Topic).to respond_to(:neoon)
11
+ end
12
+
13
+ it 'responds to .neo_model_config' do
14
+ expect(Topic).to respond_to(:neo_model_config)
15
+ end
16
+
9
17
  it 'returns the model config singleton' do
10
18
  expect(Topic.neo_model_config.class).to eq Neoon::Model::Config
11
19
  end
@@ -2,80 +2,54 @@ require 'spec_helper'
2
2
 
3
3
  describe Neoon::Model::Node do
4
4
 
5
- before :each do
5
+ before :all do
6
6
  require 'app/models/topic'
7
+ Topic.neo_schema_update
7
8
  Topic.destroy_all
8
9
  end
9
10
 
10
- context '' do
11
- it 'responds to neoon' do
12
- expect(Topic).to respond_to(:neoon)
13
- end
14
-
15
- it 'responds to neo_model_config' do
16
- expect(Topic).to respond_to(:neo_model_config)
17
- end
11
+ after :all do
12
+ Topic.destroy_all
18
13
  end
19
14
 
20
- context 'save' do
21
- before do
22
- @t = Topic.where(:name => 'Apple').first_or_create
23
- end
24
-
25
- after :all do
26
- Topic.destroy_all
27
- end
15
+ let(:topic) { Topic.where(:name => 'Apple').first_or_create }
28
16
 
29
- it 'responds to neo_save' do
30
- @t.respond_to?(:neo_save).should be_true
17
+ context 'save' do
18
+ it 'responds to .neo_save' do
19
+ expect(topic).to respond_to(:neo_save)
31
20
  end
32
21
 
33
22
  it 'sets neo_node_properties' do
34
- @t.neo_node_properties[:_id].should == @t.id
35
- @t.neo_node_properties[:name].should == @t.name
36
- @t.neo_node_properties[:slug].should == "#{@t.id}-#{@t.name.underscore}"
37
- end
38
-
39
- it 'saves to neo' do
40
- @t.neo_node._id.should == @t.id
23
+ expect(topic.neo_node_properties[:_id]).to eql topic.id
24
+ expect(topic.neo_node_properties[:name]).to eql topic.name
25
+ expect(topic.neo_node_properties[:slug]).to eql "#{topic.id}-#{topic.name.underscore}"
41
26
  end
42
27
 
43
- it 'updates to neo after assigning attr and save OR update_attribute()' do
44
- @t.name = 'MacBook'
45
- @t.save
46
- @t.neo_node.name.should == 'MacBook'
47
- @t.neo_node._id.should == @t.id
48
-
49
- @t.update_attribute(:name, 'Technology')
50
- @t.neo_node.name.should == 'Technology'
51
- @t.neo_node._id.should == @t.id
28
+ it 'has same values' do
29
+ expect(topic.neo_node._id).to eql topic.id
30
+ expect(topic.neo_node.name).to eql topic.name
31
+ expect(topic.neo_node.slug).to eql "#{topic.id}-#{topic.name.underscore}"
52
32
  end
53
33
 
54
34
  it 'has 1 record' do
55
- Topic.count.should == Neoon.db.q('MATCH n:Topic return n').data.count
56
- Topic.count.should == 1
35
+ expect(Topic.count).to eql Neoon.db.q('MATCH n:Topic return n').data.count
36
+ expect(Topic.count).to eql 1
57
37
  end
58
38
  end
59
39
 
60
40
  context 'destroy' do
61
- before do
62
- @t1 = Topic.where(:name => 'Amr').first_or_create
41
+ it 'responds to .neo_destroy' do
42
+ expect(topic).to respond_to(:neo_destroy)
63
43
  end
64
44
 
65
- after :all do
66
- Topic.destroy_all
45
+ it 'doesn\'t exist in neo4j' do
46
+ topic.destroy
47
+ expect { topic.neo_node }.to raise_error Neoon::Error::NodeNotFoundException
67
48
  end
68
49
 
69
- it 'responds to neo_destroy' do
70
- @t1.respond_to?(:neo_destroy).should be_true
71
- end
72
-
73
- it 'has 2 records' do
74
- topic = Topic.new name: 'Jo'
75
- topic.save
76
-
77
- Topic.count.should == Neoon.db.q('MATCH n:Topic return n').data.count
78
- Topic.count.should == 2
50
+ it 'has 0 record' do
51
+ expect(Topic.count).to eql Neoon.db.q('MATCH n:Topic return n').data.count
52
+ expect(Topic.count).to eql 0
79
53
  end
80
54
  end
81
55
 
@@ -9,7 +9,7 @@ describe Neoon::Model::Schema do
9
9
 
10
10
  context 'list index' do
11
11
  context 'from model config' do
12
- it 'responds to neo_schema_index_keys' do
12
+ it 'responds to .neo_schema_index_keys' do
13
13
  expect(Topic).to respond_to(:neo_schema_index_keys)
14
14
  end
15
15
  it 'returns all indexed properties' do
@@ -52,7 +52,7 @@ describe Neoon::Model::Schema do
52
52
  end
53
53
 
54
54
  context 'create index' do
55
- it 'responds to neo_index_create' do
55
+ it 'responds to .neo_index_create' do
56
56
  expect(Topic).to respond_to(:neo_index_create)
57
57
  end
58
58
 
@@ -63,8 +63,8 @@ describe Neoon::Model::Schema do
63
63
  expect(Topic.neo_index_create(:slug)).to be_true
64
64
  expect(Topic.neo_index_list.keys).to eql [:name, :slug]
65
65
 
66
- expect { Topic.neo_index_create(:name) }.to raise_error Neoon::Error::AlreadyIndexedException
67
- expect { Topic.neo_index_create(:slug) }.to raise_error Neoon::Error::AlreadyConstrainedException
66
+ expect(Topic.neo_index_create(:name).result[:error].class).to eq Neoon::Error::AlreadyIndexedException
67
+ expect(Topic.neo_index_create(:slug).result[:error].class).to eq Neoon::Error::AlreadyConstrainedException
68
68
  end
69
69
 
70
70
  end
@@ -75,7 +75,7 @@ describe Neoon::Model::Schema do
75
75
  Topic.neo_index_create(:slug)
76
76
  end
77
77
 
78
- it 'responds to neo_index_drop' do
78
+ it 'responds to .neo_index_drop' do
79
79
  expect(Topic).to respond_to(:neo_index_drop)
80
80
  end
81
81
 
@@ -86,8 +86,8 @@ describe Neoon::Model::Schema do
86
86
  expect(Topic.neo_index_drop(:slug)).to be_true
87
87
  expect(Topic.neo_index_list.keys).to eql []
88
88
 
89
- expect { Topic.neo_index_drop(:name) }.to raise_error Neoon::Error::DropIndexFailureException
90
- expect { Topic.neo_index_drop(:slug) }.to raise_error Neoon::Error::DropIndexFailureException
89
+ expect(Topic.neo_index_drop(:name).result[:error].class).to eq Neoon::Error::DropIndexFailureException
90
+ expect(Topic.neo_index_drop(:slug).result[:error].class).to eq Neoon::Error::DropIndexFailureException
91
91
  end
92
92
  end
93
93
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neoon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amr Tamimi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-09-28 00:00:00.000000000 Z
11
+ date: 2013-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -157,6 +157,7 @@ files:
157
157
  - lib/neoon/config.rb
158
158
  - lib/neoon/cypher/handler.rb
159
159
  - lib/neoon/cypher/instance_query.rb
160
+ - lib/neoon/cypher/node/operations.rb
160
161
  - lib/neoon/cypher/query.rb
161
162
  - lib/neoon/cypher/schema/constraints.rb
162
163
  - lib/neoon/cypher/schema/indexes.rb