orientdb_client 0.0.1 → 0.0.2

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: aeff7a5103216c207de656f5dd0addb641d2265a
4
- data.tar.gz: 54538b3766d81b1f42d244909b302a9789d71a67
3
+ metadata.gz: 3b21ad9036b5e5873f1f51dc9508dd386bddd7b0
4
+ data.tar.gz: 503d006feb63fd5d7ff3ab7994af1e5d86839fed
5
5
  SHA512:
6
- metadata.gz: b7338004884c5dac72cbee3816ab4e1865c1a30f4389270f081e62a055f0d951b35845e8cdebfabfa6d18fcbf9ebd13b543e2c158043ac2335854db142eb63b7
7
- data.tar.gz: bd0fd3eebb9028e72e9de1857eeff9e4c73b826153f291b39746f97acd73bd9dff60838910def0381478549480b77eec31da3817b2b01a5b43bf9c2f68e8b919
6
+ metadata.gz: 9eb18afed7dd6191124107a6919df244536c4468e11a599690134f43f150470c20a8d078f3aea3db7131b8c165608cda500fd1a8104182d5385ba6b962480e98
7
+ data.tar.gz: 252f573b2958cb4ffcbae1b7a71f0cb115d8e5f78e5748c563f5b9d1a41700c30f2629a7f1da8d51e7849b99c0df4bffd397cd37c453b53c15a9d2ab7737e509
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ script: bundle exec rspec --tag ~'type:integration'
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # OrientdbClient
2
2
 
3
+ [![Build Status](https://travis-ci.org/lukeasrodgers/orientdb_client.svg)](https://travis-ci.org/lukeasrodgers/orientdb_client)
4
+
3
5
  Ruby client for Orientdb. Probably not quite ready for production yet.
4
6
  Inspired by https://github.com/veny/orientdb4r
5
7
 
@@ -14,6 +16,8 @@ Tested on:
14
16
  * 2.0.4
15
17
  * 2.0.2
16
18
 
19
+ CI tests with Travis currently only run non-integration tests (i.e. they don't actually hit an Orientdb server).
20
+
17
21
  ## Installation
18
22
 
19
23
  Add this line to your application's Gemfile:
@@ -51,7 +55,7 @@ Orientdb::logger = MyLogger.new
51
55
  # use a different HttpAdapter
52
56
  require 'orientdb_client'
53
57
  require 'orientdb_client/http_adapters/curb_adapter'
54
- client = OrientdbClient.cient(adapter: 'CurbAdapter')
58
+ client = OrientdbClient.client(adapter: 'CurbAdapter')
55
59
  ```
56
60
 
57
61
  ## HTTP Adapters
@@ -313,21 +313,27 @@ module OrientdbClient
313
313
  raise ClientError.new("#{odb_error_class}: #{odb_error_message}", code, body)
314
314
  when /OCommandExecutionException/
315
315
  raise CommandExecutionException.new("#{odb_error_class}: #{odb_error_message}", code, body)
316
- when /OSchemaException/
316
+ when /OSchemaException|OIndexException/
317
317
  raise ClientError.new("#{odb_error_class}: #{odb_error_message}", code, body)
318
318
  when /OConcurrentModification/
319
- raise MVCCError.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
319
+ raise MVCCError.new("#{odb_error_class}: #{odb_error_message}", code, body)
320
320
  when /IllegalStateException/
321
- raise ServerError.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
321
+ raise ServerError.new("#{odb_error_class}: #{odb_error_message}", code, body)
322
322
  when /ORecordDuplicate/
323
- raise DuplicateRecordError.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
323
+ raise DuplicateRecordError.new("#{odb_error_class}: #{odb_error_message}", code, body)
324
+ when /ODistributedException/
325
+ if odb_error_message.match(/ORecordDuplicate/)
326
+ raise DistributedDuplicateRecordError.new("#{odb_error_class}: #{odb_error_message}", code, body)
327
+ else
328
+ raise DistributedException.new("#{odb_error_class}: #{odb_error_message}", code, body)
329
+ end
324
330
  when /OTransactionException/
325
331
  if odb_error_message.match(/ORecordDuplicate/)
326
- raise DistributedDuplicateRecordError.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
332
+ raise DistributedDuplicateRecordError.new("#{odb_error_class}: #{odb_error_message}", code, body)
327
333
  elsif odb_error_message.match(/distributed/)
328
- raise DistributedTransactionException.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
334
+ raise DistributedTransactionException.new("#{odb_error_class}: #{odb_error_message}", code, body)
329
335
  else
330
- raise TransactionException.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
336
+ raise TransactionException.new("#{odb_error_class}: #{odb_error_message}", code, body)
331
337
  end
332
338
  when /ODatabaseException/
333
339
  if odb_error_message.match(/already exists/)
@@ -335,7 +341,11 @@ module OrientdbClient
335
341
  else
336
342
  klass = ServerError
337
343
  end
338
- raise klass.new("#{odb_error_class}: #{odb_error_message}", response.response_code, response.body)
344
+ raise klass.new("#{odb_error_class}: #{odb_error_message}", code, body)
345
+ when /ODistributedRecordLockedException/
346
+ raise DistributedRecordLockedException.new("#{odb_error_class}: #{odb_error_message}", code, body)
347
+ when /OSerializationException/
348
+ raise SerializationException.new("#{odb_error_class}: #{odb_error_message}", code, body)
339
349
  end
340
350
  end
341
351
 
@@ -343,15 +353,17 @@ module OrientdbClient
343
353
  body = response.body
344
354
  json = Oj.load(body)
345
355
  # odb > 2.1 (?) errors are in JSON format
346
- matches = json['errors'].first['content'].match(/\A([^:]+):\s?(.+)/m)
356
+ matches = json['errors'].first['content'].match(/\A([^:]+):?\s?(.*)/m)
347
357
  [matches[1], matches[2]]
348
358
  rescue => e
349
- if (response.body.match(/Database.*already exists/))
350
- raise ConflictError.new(e.message, response.response_code, response.body)
351
- elsif (response.body.match(/NegativeArraySizeException/))
352
- raise NegativeArraySizeException.new(e.message, response.response_code, response.body)
359
+ code = response.response_code
360
+ body = response.body
361
+ if (body.match(/Database.*already exists/))
362
+ raise ConflictError.new(e.message, code, body)
363
+ elsif (body.match(/NegativeArraySizeException/))
364
+ raise NegativeArraySizeException.new(e.message, code, body)
353
365
  else
354
- raise OrientdbError.new("Could not parse Orientdb server error", response.response_code, response.body)
366
+ raise OrientdbError.new("Could not parse Orientdb server error: #{code}, #{body}")
355
367
  end
356
368
  end
357
369
 
@@ -17,12 +17,16 @@ module OrientdbClient
17
17
  class TransactionException < ServerError; end
18
18
  class DistributedTransactionException < TransactionException; end
19
19
  class MVCCError < ServerError; end
20
+ class DistributedRecordLockedException < TransactionException; end
21
+ # Generic DistributedException, generally a more specific error is preferable.
22
+ class DistributedException < ServerError; end
20
23
 
21
24
  # ClientError: you did something wrong
22
25
  class ClientError < OrientdbError; end
23
26
  class UnauthorizedError < ClientError; end
24
27
  class IllegalArgumentException < ClientError; end
25
28
  class CommandExecutionException < ClientError; end
29
+ class SerializationException < ClientError; end
26
30
 
27
31
  # ConflictError: you tried to create something that already exists
28
32
  class ConflictError < ClientError; end
@@ -1,3 +1,3 @@
1
1
  module OrientdbClient
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -13,16 +13,16 @@ RSpec.describe OrientdbClient do
13
13
  let(:db) { OrientdbClient::Test::DatabaseName }
14
14
  let(:temp_db_name) { "#{OrientdbClient::Test::DatabaseName}_temp" }
15
15
 
16
- after(:each) do
17
- if client.connected?
18
- client.disconnect
19
- end
20
- if client.database_exists?(temp_db_name)
21
- client.delete_database(temp_db_name, username: valid_username, password: valid_password)
16
+ describe 'integration specs', type: :integration do
17
+ after(:each) do
18
+ if client.connected?
19
+ client.disconnect
20
+ end
21
+ if client.database_exists?(temp_db_name)
22
+ client.delete_database(temp_db_name, username: valid_username, password: valid_password)
23
+ end
22
24
  end
23
- end
24
25
 
25
- describe 'integration specs', type: :integration do
26
26
  describe '#connect' do
27
27
  subject { client.connect(username: username, password: password, db: db) }
28
28
 
@@ -91,7 +91,7 @@ RSpec.describe OrientdbClient do
91
91
  before do
92
92
  client.connect(username: username, password: password, db: db)
93
93
  end
94
-
94
+
95
95
  context 'with valid database parameters' do
96
96
  it 'creates a database' do
97
97
  client.create_database(temp_db_name, 'plocal', 'document')
@@ -128,55 +128,57 @@ RSpec.describe OrientdbClient do
128
128
  end
129
129
 
130
130
  describe '#delete_database' do
131
- before(:each) do
132
- if !client.database_exists?(temp_db_name)
133
- client.create_database(temp_db_name, 'plocal', 'document', username: valid_username, password: valid_password)
134
- end
135
- end
136
-
137
- context 'without existing connection' do
138
- context 'with valid authentication options' do
139
- it 'deletes the database' do
140
- client.delete_database(temp_db_name, username: username, password: password)
141
- expect(client.database_exists?(temp_db_name)).to be false
131
+ if !$distributed_mode
132
+ before(:each) do
133
+ if !client.database_exists?(temp_db_name)
134
+ client.create_database(temp_db_name, 'plocal', 'document', username: valid_username, password: valid_password)
142
135
  end
143
136
  end
144
137
 
145
- context 'with invalid authentication options' do
146
- it 'raises UnauthorizedError' do
147
- expect do
148
- client.delete_database(temp_db_name, username: 'foo', password: 'bar')
149
- end.to raise_exception(OrientdbClient::UnauthorizedError)
138
+ context 'without existing connection' do
139
+ context 'with valid authentication options' do
140
+ it 'deletes the database' do
141
+ client.delete_database(temp_db_name, username: username, password: password)
142
+ expect(client.database_exists?(temp_db_name)).to be false
143
+ end
150
144
  end
151
145
 
152
- it 'does not delete the database' do
153
- begin
154
- client.delete_database(temp_db_name, username: 'foo', password: 'bar')
155
- rescue
156
- ensure
157
- expect(client.database_exists?(temp_db_name)).to be true
146
+ context 'with invalid authentication options' do
147
+ it 'raises UnauthorizedError' do
148
+ expect do
149
+ client.delete_database(temp_db_name, username: 'foo', password: 'bar')
150
+ end.to raise_exception(OrientdbClient::UnauthorizedError)
151
+ end
152
+
153
+ it 'does not delete the database' do
154
+ begin
155
+ client.delete_database(temp_db_name, username: 'foo', password: 'bar')
156
+ rescue
157
+ ensure
158
+ expect(client.database_exists?(temp_db_name)).to be true
159
+ end
158
160
  end
159
161
  end
160
162
  end
161
- end
162
163
 
163
- context 'with existing connection' do
164
- before do
165
- client.connect(username: username, password: password, db: db)
166
- end
167
-
168
- context 'with valid database parameters' do
169
- it 'deletes the database' do
170
- client.delete_database(temp_db_name)
171
- expect(client.database_exists?(temp_db_name)).to be false
164
+ context 'with existing connection' do
165
+ before do
166
+ client.connect(username: username, password: password, db: db)
172
167
  end
173
- end
174
168
 
175
- context 'with no matching database' do
176
- it 'raises a ClientError' do
177
- expect do
178
- client.delete_database(temp_db_name + 'baz')
179
- end.to raise_exception(OrientdbClient::ClientError, /OConfigurationException/)
169
+ context 'with valid database parameters' do
170
+ it 'deletes the database' do
171
+ client.delete_database(temp_db_name)
172
+ expect(client.database_exists?(temp_db_name)).to be false
173
+ end
174
+ end
175
+
176
+ context 'with no matching database' do
177
+ it 'raises a ClientError' do
178
+ expect do
179
+ client.delete_database(temp_db_name + 'baz')
180
+ end.to raise_exception(OrientdbClient::ClientError, /OConfigurationException/)
181
+ end
180
182
  end
181
183
  end
182
184
  end
@@ -228,9 +230,25 @@ RSpec.describe OrientdbClient do
228
230
  end
229
231
  end
230
232
 
233
+ context 'with invalid JSON' do
234
+ it 'raises SerializationException' do
235
+ expect do
236
+ client.command('insert into OUser CONTENT ' + Oj.dump({a:1}))
237
+ end.to raise_exception(OrientdbClient::SerializationException)
238
+ end
239
+ end
240
+
241
+ context 'creating index for property that does not exist' do
242
+ it 'raises a ClientError' do
243
+ expect do
244
+ client.command('create index UserIdx on OUser (user_id) unique')
245
+ end.to raise_exception(OrientdbClient::ClientError)
246
+ end
247
+ end
248
+
231
249
  context 'with invalid query' do
232
250
  it 'returns result' do
233
- expect { client.query('select * crumb') }.to raise_exception(OrientdbClient::ClientError, /OCommandSQLParsingException/)
251
+ expect { client.command('select * crumb') }.to raise_exception(OrientdbClient::ClientError, /OCommandSQLParsingException/)
234
252
  end
235
253
  end
236
254
  end
@@ -358,6 +376,7 @@ RSpec.describe OrientdbClient do
358
376
  end
359
377
  end
360
378
 
379
+ # This spec sometimes fails on Orientdb 2.1.X
361
380
  context 'when class does not exist' do
362
381
  it 'raises exception' do
363
382
  expect do
@@ -635,6 +654,32 @@ RSpec.describe OrientdbClient do
635
654
  end
636
655
  end
637
656
 
657
+ describe 'duplicate record creation violating index constraint' do
658
+ before do
659
+ client.connect(username: username, password: password, db: db)
660
+ if client.has_class?('Person')
661
+ client.command('delete vertex Person')
662
+ client.drop_class('Person')
663
+ end
664
+ end
665
+ after do
666
+ client.command('delete vertex Person')
667
+ client.drop_class('Person')
668
+ end
669
+
670
+ it 'raises DuplicateRecordError' do
671
+ error_klass = $distributed_mode ? OrientdbClient::DistributedDuplicateRecordError : OrientdbClient:: DuplicateRecordError
672
+ client.create_class('Person', extends: 'V') do |c|
673
+ c.property('user_id', 'integer')
674
+ end
675
+ client.command('create index PersonIdx on Person (user_id) unique')
676
+ client.command('insert into Person CONTENT ' + Oj.dump({'user_id' => 1}))
677
+ expect do
678
+ client.command('insert into Person CONTENT ' + Oj.dump({'user_id' => 1}))
679
+ end.to raise_exception(error_klass)
680
+ end
681
+ end
682
+
638
683
  end
639
684
 
640
685
  # These specs will sometimes fail, not too much we can do about that, depends
@@ -674,7 +719,8 @@ RSpec.describe OrientdbClient do
674
719
  jim_rid = jim['result'][0]['@rid']
675
720
  bob_rid = bob['result'][0]['@rid']
676
721
  thrs = []
677
- expect do
722
+ err = nil
723
+ begin
678
724
  thrs << Thread.new do
679
725
  100.times do
680
726
  client.command("create edge Friend from #{jim_rid} to #{bob_rid}")
@@ -688,7 +734,16 @@ RSpec.describe OrientdbClient do
688
734
  end
689
735
  end
690
736
  thrs.each { |t| t.join }
691
- end.to raise_exception(OrientdbClient::MVCCError, /OConcurrentModificationException/)
737
+ rescue => e
738
+ err = e
739
+ ensure
740
+ if $distributed_mode
741
+ correct_error_raised = err.is_a?(OrientdbClient::MVCCError) || err.is_a?(OrientdbClient::DistributedRecordLockedException)
742
+ else
743
+ correct_error_raised = err.is_a?(OrientdbClient::MVCCError)
744
+ end
745
+ expect(correct_error_raised).to be true
746
+ end
692
747
  end
693
748
  end
694
749
 
data/spec/spec_helper.rb CHANGED
@@ -25,6 +25,19 @@ require 'webmock/rspec'
25
25
  WebMock.disable_net_connect!(:allow_localhost => true)
26
26
 
27
27
  $db = ENV['ORIENTDB_TEST_DATABASENAME'] || OrientdbClient::Test::DatabaseName
28
+ begin
29
+ r = `ps aux | grep -E "server.*orient.*distributed=true" | grep -v grep | wc -l`;
30
+ $distributed_mode = r.strip.chomp.to_i == 1
31
+ rescue
32
+ puts "Could not determine Orientdb distributed/standalone mode, assuming standalone"
33
+ $distributed_mode = false
34
+ ensure
35
+ if $distributed_mode
36
+ # Orientdb distributed mode does not support db deletion.
37
+ # https://github.com/orientechnologies/orientdb/issues/3746
38
+ puts "Orientdb is running in distributed mode; skipping some tests."
39
+ end
40
+ end
28
41
 
29
42
  RSpec.configure do |config|
30
43
  # rspec-expectations config goes here. You can use an alternate
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: orientdb_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luke Rodgers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-04 00:00:00.000000000 Z
11
+ date: 2015-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -146,6 +146,7 @@ extra_rdoc_files: []
146
146
  files:
147
147
  - ".gitignore"
148
148
  - ".rspec"
149
+ - ".travis.yml"
149
150
  - Gemfile
150
151
  - LICENSE.txt
151
152
  - README.md
@@ -194,3 +195,4 @@ test_files:
194
195
  - spec/spec_helper.rb
195
196
  - spec/support/shared_examples_for_http_adapter.rb
196
197
  - spec/typhoeus_adapter_spec.rb
198
+ has_rdoc: