orientdb4r 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/orientdb4r/chained_error.rb +37 -0
- data/lib/orientdb4r/client.rb +71 -5
- data/lib/orientdb4r/rest/client.rb +125 -24
- data/lib/orientdb4r/rest/model.rb +140 -0
- data/lib/orientdb4r/utils.rb +9 -0
- data/lib/orientdb4r/version.rb +1 -0
- data/lib/orientdb4r.rb +34 -6
- data/test/test_database.rb +25 -3
- data/test/test_ddo.rb +24 -6
- data/test/test_document_crud.rb +135 -0
- data/test/test_utils.rb +30 -0
- metadata +8 -4
- data/lib/orientdb4r/document.rb +0 -6
- data/lib/orientdb4r/rest/oclass.rb +0 -58
@@ -0,0 +1,37 @@
|
|
1
|
+
module Orientdb4r
|
2
|
+
|
3
|
+
###
|
4
|
+
# This mixin extends an error to be able to track a chain of exceptions.
|
5
|
+
module ChainedError
|
6
|
+
|
7
|
+
attr_reader :cause
|
8
|
+
|
9
|
+
###
|
10
|
+
# Constructor.
|
11
|
+
def initialize message = nil, cause = $!
|
12
|
+
super message unless message.nil?
|
13
|
+
super $! if message.nil? and !cause.nil?
|
14
|
+
@cause = cause
|
15
|
+
end
|
16
|
+
|
17
|
+
###
|
18
|
+
# Modification of original method Error#set_backtrace
|
19
|
+
# to descend the full depth of the exception chain.
|
20
|
+
def set_backtrace bt
|
21
|
+
unless cause.nil?
|
22
|
+
cause.backtrace.reverse.each do |line|
|
23
|
+
if bt.last == line
|
24
|
+
bt.pop
|
25
|
+
next
|
26
|
+
end
|
27
|
+
break
|
28
|
+
end
|
29
|
+
bt.push "<<<CAUSED BY>>>: #{cause.class}: #{cause.message}"
|
30
|
+
bt.concat cause.backtrace
|
31
|
+
end
|
32
|
+
super bt
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/lib/orientdb4r/client.rb
CHANGED
@@ -9,24 +9,39 @@ module Orientdb4r
|
|
9
9
|
@connected = false
|
10
10
|
end
|
11
11
|
|
12
|
+
# --------------------------------------------------------------- CONNECTION
|
13
|
+
|
12
14
|
###
|
13
15
|
# Connects client to the server.
|
14
16
|
def connect options
|
15
17
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
16
18
|
end
|
17
19
|
|
20
|
+
|
18
21
|
###
|
19
22
|
# Disconnects client from the server.
|
20
23
|
def disconnect
|
21
24
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
22
25
|
end
|
23
26
|
|
27
|
+
|
24
28
|
###
|
25
29
|
# Gets flag whenever the client is connected or not.
|
26
30
|
def connected?
|
27
31
|
@connected
|
28
32
|
end
|
29
33
|
|
34
|
+
|
35
|
+
###
|
36
|
+
# Retrieve information about the connected OrientDB Server.
|
37
|
+
# Enables additional authentication to the server with an account
|
38
|
+
# that can access the 'server.info' resource.
|
39
|
+
def server(options={})
|
40
|
+
raise NotImplementedError, 'this should be overridden by concrete client'
|
41
|
+
end
|
42
|
+
|
43
|
+
# ----------------------------------------------------------------- DATABASE
|
44
|
+
|
30
45
|
###
|
31
46
|
# Creates a new database.
|
32
47
|
# You can provide an additional authentication to the server with 'database.create' resource
|
@@ -35,24 +50,30 @@ module Orientdb4r
|
|
35
50
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
36
51
|
end
|
37
52
|
|
53
|
+
|
38
54
|
###
|
39
55
|
# Gets informations about requested class.
|
40
56
|
def get_class(name)
|
41
57
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
42
58
|
end
|
43
59
|
|
60
|
+
# ---------------------------------------------------------------------- SQL
|
61
|
+
|
44
62
|
###
|
45
63
|
# Executes a query against the database.
|
46
64
|
def query(sql)
|
47
65
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
48
66
|
end
|
49
67
|
|
68
|
+
|
50
69
|
###
|
51
70
|
# Executes a command against the database.
|
52
|
-
def command(sql
|
71
|
+
def command(sql)
|
53
72
|
raise NotImplementedError, 'this should be overridden by concrete client'
|
54
73
|
end
|
55
74
|
|
75
|
+
# -------------------------------------------------------------------- CLASS
|
76
|
+
|
56
77
|
###
|
57
78
|
# Creates a new class in the schema.
|
58
79
|
def create_class(name, options={})
|
@@ -66,7 +87,7 @@ module Orientdb4r
|
|
66
87
|
|
67
88
|
drop_class name if options[:force]
|
68
89
|
|
69
|
-
command sql
|
90
|
+
command sql
|
70
91
|
|
71
92
|
if block_given?
|
72
93
|
proxy = Orientdb4r::Utils::Proxy.new(self, name)
|
@@ -77,14 +98,28 @@ module Orientdb4r
|
|
77
98
|
end
|
78
99
|
end
|
79
100
|
|
101
|
+
|
80
102
|
###
|
81
103
|
# Removes a class from the schema.
|
82
|
-
def drop_class(name)
|
83
|
-
# TODO in :mode=>:strict verify if the class is no a super class
|
104
|
+
def drop_class(name, options={})
|
84
105
|
raise ArgumentError, "class name is blank" if blank?(name)
|
106
|
+
|
107
|
+
# :mode=>:strict forbids to drop a class that is a super class for other one
|
108
|
+
opt_pattern = { :mode => :nil }
|
109
|
+
verify_options(options, opt_pattern)
|
110
|
+
if :strict == options[:mode]
|
111
|
+
response = @resource["connect/#{@database}"].get
|
112
|
+
connect_info = process_response(response, :mode => :strict)
|
113
|
+
children = connect_info['classes'].select { |i| i['superClass'] == name }
|
114
|
+
unless children.empty?
|
115
|
+
raise OrientdbError, "class is super-class, cannot be deleted, name=#{name}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
85
119
|
command "DROP CLASS #{name}"
|
86
120
|
end
|
87
121
|
|
122
|
+
|
88
123
|
###
|
89
124
|
# Creates a new property in the schema.
|
90
125
|
# You need to create the class before.
|
@@ -98,7 +133,7 @@ module Orientdb4r
|
|
98
133
|
verify_options(options, opt_pattern)
|
99
134
|
|
100
135
|
cmd = "CREATE PROPERTY #{clazz}.#{property} #{type.to_s}"
|
101
|
-
command cmd
|
136
|
+
command cmd
|
102
137
|
|
103
138
|
unless options.empty?
|
104
139
|
options.each do |k,v|
|
@@ -107,6 +142,37 @@ module Orientdb4r
|
|
107
142
|
end
|
108
143
|
end
|
109
144
|
|
145
|
+
# ----------------------------------------------------------------- DOCUMENT
|
146
|
+
|
147
|
+
###
|
148
|
+
# Create a new document.
|
149
|
+
# Returns the Record-id assigned.
|
150
|
+
def create_document(doc)
|
151
|
+
raise NotImplementedError, 'this should be overridden by concrete client'
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
###
|
156
|
+
# Retrieves a document by given ID.
|
157
|
+
def get_document(rid)
|
158
|
+
raise NotImplementedError, 'this should be overridden by concrete client'
|
159
|
+
end
|
160
|
+
|
161
|
+
|
162
|
+
###
|
163
|
+
# Updates an existing document.
|
164
|
+
def update_document(doc)
|
165
|
+
raise NotImplementedError, 'this should be overridden by concrete client'
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
###
|
170
|
+
# Deletes an existing document.
|
171
|
+
def delete_document(rid)
|
172
|
+
raise NotImplementedError, 'this should be overridden by concrete client'
|
173
|
+
end
|
174
|
+
|
175
|
+
|
110
176
|
protected
|
111
177
|
|
112
178
|
###
|
@@ -31,15 +31,13 @@ module Orientdb4r
|
|
31
31
|
begin
|
32
32
|
response = @resource["connect/#{@database}"].get
|
33
33
|
rslt = process_response(response, :mode => :strict)
|
34
|
+
|
35
|
+
decorate_classes_with_model(rslt['classes'])
|
36
|
+
|
34
37
|
@connected = true
|
35
|
-
rescue
|
38
|
+
rescue
|
36
39
|
@connected = false
|
37
|
-
raise
|
38
|
-
rescue Exception => e
|
39
|
-
Orientdb4r::logger.error e.message
|
40
|
-
Orientdb4r::logger.error e.backtrace.inspect
|
41
|
-
@connected = false
|
42
|
-
raise e
|
40
|
+
raise ConnectionError
|
43
41
|
end
|
44
42
|
rslt
|
45
43
|
end
|
@@ -54,6 +52,8 @@ module Orientdb4r
|
|
54
52
|
Orientdb4r::logger.warn '401 Unauthorized - bug in disconnect?'
|
55
53
|
ensure
|
56
54
|
@connected = false
|
55
|
+
@user = nil
|
56
|
+
@password = nil
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -70,11 +70,8 @@ module Orientdb4r
|
|
70
70
|
resource = ::RestClient::Resource.new(url, :user => u, :password => p)
|
71
71
|
begin
|
72
72
|
response = resource["database/#{options[:database]}/#{options[:type]}"].post ''
|
73
|
-
rescue
|
74
|
-
raise
|
75
|
-
:http_code_403 => 'forbidden operation (insufficient rights?)', \
|
76
|
-
:http_code_500 => 'failed to create database (exists already?)'
|
77
|
-
|
73
|
+
rescue
|
74
|
+
raise OrientdbError
|
78
75
|
end
|
79
76
|
process_response(response)
|
80
77
|
end
|
@@ -90,31 +87,128 @@ module Orientdb4r
|
|
90
87
|
# workaround - use metadate delivered by 'connect'
|
91
88
|
response = @resource["connect/#{@database}"].get
|
92
89
|
connect_info = process_response(response, :mode => :strict)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
90
|
+
|
91
|
+
classes = connect_info['classes'].select { |i| i['name'] == name }
|
92
|
+
raise ArgumentError, "class not found, name=#{name}" unless 1 == classes.size
|
93
|
+
decorate_classes_with_model(classes)
|
94
|
+
clazz = classes[0]
|
95
|
+
clazz.extend Orientdb4r::HashExtension
|
96
|
+
clazz.extend Orientdb4r::OClass
|
97
|
+
unless clazz['properties'].nil? # there can be a class without properties
|
98
|
+
clazz.properties.each do |prop|
|
99
|
+
prop.extend Orientdb4r::HashExtension
|
100
|
+
prop.extend Orientdb4r::Property
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
clazz
|
98
106
|
end
|
99
107
|
|
108
|
+
|
100
109
|
def query(sql) #:nodoc:
|
110
|
+
raise ArgumentError, 'query is blank' if blank? sql
|
111
|
+
|
101
112
|
response = @resource["query/#{@database}/sql/#{URI.escape(sql)}"].get
|
102
113
|
rslt = process_response(response)
|
103
114
|
rslt['result']
|
104
115
|
end
|
105
116
|
|
106
|
-
|
117
|
+
|
118
|
+
def command(sql) #:nodoc:
|
119
|
+
raise ArgumentError, 'command is blank' if blank? sql
|
107
120
|
begin
|
108
121
|
#puts "REQ #{sql}"
|
109
122
|
response = @resource["command/#{@database}/sql/#{URI.escape(sql)}"].post ''
|
110
123
|
rslt = process_response(response)
|
111
124
|
rslt
|
112
125
|
#puts "RESP #{response.code}"
|
113
|
-
rescue
|
114
|
-
raise
|
126
|
+
rescue
|
127
|
+
raise OrientdbError
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
def server(options={}) #:nodoc:
|
133
|
+
options_pattern = { :user => :optional, :password => :optional }
|
134
|
+
verify_options(options, options_pattern)
|
135
|
+
|
136
|
+
|
137
|
+
u = options.include?(:user) ? options[:user] : user
|
138
|
+
p = options.include?(:password) ? options[:password] : password
|
139
|
+
resource = ::RestClient::Resource.new(url, :user => u, :password => p)
|
140
|
+
begin
|
141
|
+
response = resource['server'].get
|
142
|
+
rescue
|
143
|
+
raise OrientdbError
|
144
|
+
end
|
145
|
+
process_response(response)
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# ----------------------------------------------------------------- DOCUMENT
|
150
|
+
|
151
|
+
def create_document(doc)
|
152
|
+
begin
|
153
|
+
response = @resource["document/#{@database}"].post doc.to_json, :content_type => 'application/json'
|
154
|
+
rescue
|
155
|
+
raise DataError
|
156
|
+
end
|
157
|
+
rid = process_response(response)
|
158
|
+
raise ArgumentError, "invalid RID format, RID=#{rid}" unless rid =~ /^#[0-9]+:[0-9]+/
|
159
|
+
rid
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def get_document(rid) #:nodoc:
|
164
|
+
raise ArgumentError, 'blank RID' if blank? rid
|
165
|
+
# remove the '#' prefix
|
166
|
+
rid = rid[1..-1] if rid.start_with? '#'
|
167
|
+
|
168
|
+
begin
|
169
|
+
response = @resource["document/#{@database}/#{rid}"].get
|
170
|
+
rescue
|
171
|
+
raise NotFoundError
|
115
172
|
end
|
173
|
+
rslt = process_response(response)
|
174
|
+
rslt.extend Orientdb4r::DocumentMetadata
|
175
|
+
rslt
|
116
176
|
end
|
117
177
|
|
178
|
+
|
179
|
+
def update_document(doc) #:nodoc:
|
180
|
+
raise ArgumentError, 'document is nil' if doc.nil?
|
181
|
+
raise ArgumentError, 'document has no RID' if doc.doc_rid.nil?
|
182
|
+
raise ArgumentError, 'document has no version' if doc.doc_version.nil?
|
183
|
+
|
184
|
+
rid = doc.delete '@rid'
|
185
|
+
rid = rid[1..-1] if rid.start_with? '#'
|
186
|
+
|
187
|
+
begin
|
188
|
+
@resource["document/#{@database}/#{rid}"].put doc.to_json, :content_type => 'application/json'
|
189
|
+
rescue
|
190
|
+
raise DataError
|
191
|
+
end
|
192
|
+
# empty http response
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
def delete_document(rid) #:nodoc:
|
197
|
+
raise ArgumentError, 'blank RID' if blank? rid
|
198
|
+
# remove the '#' prefix
|
199
|
+
rid = rid[1..-1] if rid.start_with? '#'
|
200
|
+
|
201
|
+
begin
|
202
|
+
response = @resource["document/#{@database}/#{rid}"].delete
|
203
|
+
puts "DELETE '#{response}'"
|
204
|
+
rescue
|
205
|
+
raise DataError
|
206
|
+
end
|
207
|
+
# empty http response
|
208
|
+
end
|
209
|
+
|
210
|
+
# ------------------------------------------------------------------ Helpers
|
211
|
+
|
118
212
|
private
|
119
213
|
|
120
214
|
###
|
@@ -156,10 +250,17 @@ module Orientdb4r
|
|
156
250
|
rslt
|
157
251
|
end
|
158
252
|
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
|
253
|
+
def decorate_classes_with_model(classes)
|
254
|
+
classes.each do |clazz|
|
255
|
+
clazz.extend Orientdb4r::HashExtension
|
256
|
+
clazz.extend Orientdb4r::OClass
|
257
|
+
unless clazz['properties'].nil? # there can be a class without properties
|
258
|
+
clazz.properties.each do |prop|
|
259
|
+
prop.extend Orientdb4r::HashExtension
|
260
|
+
prop.extend Orientdb4r::Property
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
163
264
|
end
|
164
265
|
|
165
266
|
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
module Orientdb4r
|
2
|
+
|
3
|
+
|
4
|
+
###
|
5
|
+
# Extends a Hash produced by JSON.parse.
|
6
|
+
module HashExtension
|
7
|
+
|
8
|
+
###
|
9
|
+
# Gets an attribute value that has to be presented.
|
10
|
+
def get_mandatory_attribute(name)
|
11
|
+
key = name.to_s
|
12
|
+
raise ::ArgumentError, "unknown attribute, name=#{key}" unless self.include? key
|
13
|
+
self[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
###
|
20
|
+
# This module represents API to OrientDB's class.
|
21
|
+
module OClass
|
22
|
+
|
23
|
+
###
|
24
|
+
# Gets name of the class.
|
25
|
+
def name
|
26
|
+
get_mandatory_attribute :name
|
27
|
+
end
|
28
|
+
|
29
|
+
###
|
30
|
+
# Gets properties of the class.
|
31
|
+
# Returns nil for a class without properties.
|
32
|
+
def properties
|
33
|
+
self['properties']
|
34
|
+
end
|
35
|
+
|
36
|
+
###
|
37
|
+
# Gets a property with the given name.
|
38
|
+
def property(name)
|
39
|
+
raise ArgumentError, 'no properties defined on class' if properties.nil?
|
40
|
+
props = properties.select { |i| i['name'] == name.to_s }
|
41
|
+
raise ::ArgumentError, "unknown property, name=#{name}" if props.empty?
|
42
|
+
raise ::ArgumentError, "too many properties found, name=#{name}" if props.size > 1 # just to be sure
|
43
|
+
props[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
###
|
47
|
+
# Gets the super-class.
|
48
|
+
def super_class
|
49
|
+
get_mandatory_attribute :superClass
|
50
|
+
end
|
51
|
+
|
52
|
+
###
|
53
|
+
# Gets clusters of the class.
|
54
|
+
def clusters
|
55
|
+
get_mandatory_attribute :clusters
|
56
|
+
end
|
57
|
+
|
58
|
+
###
|
59
|
+
# Gets the default cluster.
|
60
|
+
def default_cluster
|
61
|
+
get_mandatory_attribute :defaultCluster
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
###
|
68
|
+
# This module represents API to OrientDB's property.
|
69
|
+
module Property
|
70
|
+
|
71
|
+
###
|
72
|
+
# Gets name of the property.
|
73
|
+
def name
|
74
|
+
get_mandatory_attribute :name
|
75
|
+
end
|
76
|
+
|
77
|
+
###
|
78
|
+
# Gets type of the property.
|
79
|
+
def type
|
80
|
+
get_mandatory_attribute :type
|
81
|
+
end
|
82
|
+
|
83
|
+
###
|
84
|
+
# Gets the 'mandatory' flag.
|
85
|
+
def mandatory
|
86
|
+
get_mandatory_attribute :mandatory
|
87
|
+
end
|
88
|
+
|
89
|
+
###
|
90
|
+
# Gets the 'notNull' flag.
|
91
|
+
def not_null
|
92
|
+
get_mandatory_attribute :notNull
|
93
|
+
end
|
94
|
+
|
95
|
+
###
|
96
|
+
# Gets the minimal allowed value.
|
97
|
+
def min
|
98
|
+
self['min']
|
99
|
+
end
|
100
|
+
|
101
|
+
###
|
102
|
+
# Gets the maximal allowed value.
|
103
|
+
def max
|
104
|
+
self['max']
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
###
|
111
|
+
# This module represents API to document metadata.
|
112
|
+
module DocumentMetadata
|
113
|
+
|
114
|
+
###
|
115
|
+
# Gets the document class.
|
116
|
+
def doc_class
|
117
|
+
self['@class']
|
118
|
+
end
|
119
|
+
|
120
|
+
###
|
121
|
+
# Gets the document ID.
|
122
|
+
def doc_rid
|
123
|
+
self['@rid']
|
124
|
+
end
|
125
|
+
|
126
|
+
###
|
127
|
+
# Gets the document version.
|
128
|
+
def doc_version
|
129
|
+
self['@version']
|
130
|
+
end
|
131
|
+
|
132
|
+
###
|
133
|
+
# Gets the document type.
|
134
|
+
def doc_type
|
135
|
+
self['@type']
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
data/lib/orientdb4r/utils.rb
CHANGED
@@ -3,6 +3,8 @@ module Orientdb4r
|
|
3
3
|
module Utils
|
4
4
|
|
5
5
|
def verify_options(options, pattern)
|
6
|
+
raise ArgumentError, 'options cannot be nil' if options.nil?
|
7
|
+
|
6
8
|
# unknown key?
|
7
9
|
options.keys.each do |k|
|
8
10
|
raise ArgumentError, "unknow option: #{k}" unless pattern.keys.include? k
|
@@ -11,6 +13,13 @@ module Orientdb4r
|
|
11
13
|
pattern.each do |k,v|
|
12
14
|
raise ArgumentError, "missing mandatory option: #{k}" if v == :mandatory and !options.keys.include? k
|
13
15
|
end
|
16
|
+
# option in a set of allowed values
|
17
|
+
pattern.each do |k,v|
|
18
|
+
if v.instance_of? Array
|
19
|
+
raise ArgumentError, "value '#{options[k]}' not in #{v.inspect}, key=#{k}" unless v.include?(options[k])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
14
23
|
options
|
15
24
|
end
|
16
25
|
|
data/lib/orientdb4r/version.rb
CHANGED
@@ -2,6 +2,7 @@ module Orientdb4r
|
|
2
2
|
|
3
3
|
# Version history.
|
4
4
|
VERSION_HISTORY = [
|
5
|
+
['0.2.0', '2012-06-12', "Introduces document's CRUD operations"],
|
5
6
|
['0.1.2', '2012-06-10', 'Introduces new OClass module'],
|
6
7
|
['0.1.1', '2012-06-08', 'First working version (including unit tests) released at github.com'],
|
7
8
|
['0.1.0', '2012-06-02', 'Initial version on Ruby-1.9.3p194 and OrientDB-1.0.0']
|
data/lib/orientdb4r.rb
CHANGED
@@ -8,17 +8,26 @@ require 'orientdb4r/version'
|
|
8
8
|
# This module represents the entry point for using the Ruby OrientDB client.
|
9
9
|
module Orientdb4r
|
10
10
|
|
11
|
-
autoload :Utils,
|
12
|
-
autoload :Client,
|
13
|
-
autoload :RestClient,
|
14
|
-
autoload :
|
11
|
+
autoload :Utils, 'orientdb4r/utils'
|
12
|
+
autoload :Client, 'orientdb4r/client'
|
13
|
+
autoload :RestClient, 'orientdb4r/rest/client'
|
14
|
+
autoload :HashExtension, 'orientdb4r/rest/model'
|
15
|
+
autoload :OClass, 'orientdb4r/rest/model'
|
16
|
+
autoload :ChainedError, 'orientdb4r/chained_error'
|
15
17
|
|
16
18
|
|
17
19
|
class << self
|
18
20
|
|
19
21
|
###
|
20
22
|
# Gets a new database client or an existing for the current thread.
|
23
|
+
# === options
|
24
|
+
# * :force => true
|
21
25
|
def client options={}
|
26
|
+
if :new == options[:instance]
|
27
|
+
options.delete :instance
|
28
|
+
return RestClient.new options
|
29
|
+
end
|
30
|
+
|
22
31
|
Thread.current[:orientdb_client] ||= RestClient.new options
|
23
32
|
end
|
24
33
|
|
@@ -34,8 +43,23 @@ module Orientdb4r
|
|
34
43
|
|
35
44
|
|
36
45
|
###
|
37
|
-
# Basic error
|
38
|
-
class OrientdbError < StandardError
|
46
|
+
# Basic error that indicates an unexpected situation during the client call.
|
47
|
+
class OrientdbError < StandardError
|
48
|
+
include ChainedError
|
49
|
+
end
|
50
|
+
|
51
|
+
###
|
52
|
+
# Error indicating problems with communicating with the database.
|
53
|
+
class ConnectionError < OrientdbError; end
|
54
|
+
|
55
|
+
###
|
56
|
+
# Error raised to inform that an object identified by RID cannot be get.
|
57
|
+
class NotFoundError < OrientdbError; end
|
58
|
+
|
59
|
+
###
|
60
|
+
# Error indicating that manipulation against the given data resulted in some illegal operation,
|
61
|
+
# mismatched types or incorrect cardinality.
|
62
|
+
class DataError < OrientdbError; end
|
39
63
|
|
40
64
|
end
|
41
65
|
|
@@ -46,3 +70,7 @@ Orientdb4r::logger.level = Logger::INFO
|
|
46
70
|
|
47
71
|
Orientdb4r::logger.info \
|
48
72
|
"Orientdb4r #{Orientdb4r::VERSION}, running on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
|
73
|
+
|
74
|
+
|
75
|
+
#client = Orientdb4r.client
|
76
|
+
#client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
data/test/test_database.rb
CHANGED
@@ -17,17 +17,24 @@ class TestDatabase < Test::Unit::TestCase
|
|
17
17
|
###
|
18
18
|
# CONNECT
|
19
19
|
def test_connect
|
20
|
+
assert_nothing_thrown do @client.connect :database => 'temp', :user => 'admin', :password => 'admin'; end
|
20
21
|
rslt = @client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
21
22
|
assert_instance_of Hash, rslt
|
22
23
|
assert rslt.size > 0
|
23
24
|
assert rslt.include? 'classes'
|
24
25
|
|
26
|
+
# connection refused
|
27
|
+
client = Orientdb4r.client :port => 2840, :instance => :new
|
28
|
+
assert_raise Orientdb4r::ConnectionError do
|
29
|
+
client.connect :database => 'temp', :user => 'admin', :password => 'admin'
|
30
|
+
end
|
31
|
+
|
25
32
|
# bad DB name
|
26
|
-
assert_raise Orientdb4r::
|
33
|
+
assert_raise Orientdb4r::ConnectionError do
|
27
34
|
@client.connect :database => 'unknown_db', :user => 'admin', :password => 'admin'
|
28
35
|
end
|
29
36
|
# bad credentials
|
30
|
-
assert_raise Orientdb4r::
|
37
|
+
assert_raise Orientdb4r::ConnectionError do
|
31
38
|
@client.connect :database => 'temp', :user => 'admin1', :password => 'admin'
|
32
39
|
end
|
33
40
|
end
|
@@ -45,7 +52,7 @@ class TestDatabase < Test::Unit::TestCase
|
|
45
52
|
|
46
53
|
###
|
47
54
|
# CREATE DATABASE
|
48
|
-
# Temporary disabled
|
55
|
+
# Temporary disabled because of unknown way how to drop a new created datatabse.
|
49
56
|
def xtest_create_database
|
50
57
|
@client.create_database :database => 'UniT', :user => 'root', :password => 'root'
|
51
58
|
# creating an existing DB
|
@@ -63,4 +70,19 @@ class TestDatabase < Test::Unit::TestCase
|
|
63
70
|
#@client.command "DROP DATABASE UniT" : NOT WORKING now
|
64
71
|
end
|
65
72
|
|
73
|
+
|
74
|
+
###
|
75
|
+
# SERVER info
|
76
|
+
# Temporary disabled because of dependency to password of 'root' account
|
77
|
+
def xtest_server
|
78
|
+
# admin/admin has not 'server.info' resource access in standard installation
|
79
|
+
assert_raise Orientdb4r::OrientdbError do @client.server :user => 'admin', :password => 'admin'; end
|
80
|
+
|
81
|
+
assert_nothing_thrown do @client.server :user => 'root', :password => 'root'; end
|
82
|
+
rslt = @client.server :user => 'root', :password => 'root'
|
83
|
+
assert_instance_of Hash, rslt
|
84
|
+
assert rslt.include? 'connections'
|
85
|
+
assert_not_nil rslt['connections']
|
86
|
+
end
|
87
|
+
|
66
88
|
end
|
data/test/test_ddo.rb
CHANGED
@@ -11,7 +11,6 @@ class TestDdo < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
def initialize(params)
|
13
13
|
super params
|
14
|
-
|
15
14
|
@client = Orientdb4r.client
|
16
15
|
end
|
17
16
|
|
@@ -21,7 +20,7 @@ class TestDdo < Test::Unit::TestCase
|
|
21
20
|
|
22
21
|
def teardown
|
23
22
|
# remove the testing class after each test
|
24
|
-
@client.drop_class(CLASS)
|
23
|
+
@client.drop_class(CLASS, :mode => :strict)
|
25
24
|
@client.disconnect
|
26
25
|
end
|
27
26
|
|
@@ -45,6 +44,14 @@ class TestDdo < Test::Unit::TestCase
|
|
45
44
|
assert_instance_of Array, clazz.clusters
|
46
45
|
assert !clazz.clusters.empty?
|
47
46
|
assert_not_nil clazz.default_cluster
|
47
|
+
# test Property
|
48
|
+
prop = clazz.property :password
|
49
|
+
assert_equal 'password', prop.name
|
50
|
+
assert_equal 'STRING', prop.type
|
51
|
+
assert prop.mandatory
|
52
|
+
assert prop.not_null
|
53
|
+
assert_nil prop.min
|
54
|
+
assert_nil prop.min
|
48
55
|
end
|
49
56
|
|
50
57
|
|
@@ -52,7 +59,7 @@ class TestDdo < Test::Unit::TestCase
|
|
52
59
|
# CREATE CLASS
|
53
60
|
def test_create_class
|
54
61
|
assert_nothing_thrown do @client.create_class(CLASS); end
|
55
|
-
assert_nothing_thrown do @client.get_class(CLASS); end
|
62
|
+
assert_nothing_thrown do @client.get_class(CLASS); end # raises an Error if no class found
|
56
63
|
# already exist
|
57
64
|
assert_raise Orientdb4r::OrientdbError do @client.create_class(CLASS); end
|
58
65
|
|
@@ -77,12 +84,23 @@ class TestDdo < Test::Unit::TestCase
|
|
77
84
|
|
78
85
|
###
|
79
86
|
# DROP TABLE
|
80
|
-
def
|
87
|
+
def test_drop_class
|
88
|
+
super_clazz = "#{CLASS}Sup"
|
89
|
+
@client.drop_class(super_clazz); # just to be sure if previous test failed
|
90
|
+
@client.create_class(super_clazz);
|
91
|
+
@client.create_class(CLASS);
|
81
92
|
assert_nothing_thrown do @client.drop_class(CLASS); end
|
82
|
-
|
93
|
+
assert_raise ArgumentError do @client.get_class(CLASS); end # no info more
|
83
94
|
# the class is not visible in class list delivered by connect
|
84
95
|
rslt = @client.connect :database => DB, :user => 'admin', :password => 'admin'
|
85
|
-
assert rslt['classes'].select { |i| i
|
96
|
+
assert rslt['classes'].select { |i| i.name == CLASS }.empty?
|
97
|
+
|
98
|
+
# CLASS extends super_class
|
99
|
+
@client.create_class(CLASS, :extends => super_clazz);
|
100
|
+
assert_raise Orientdb4r::OrientdbError do @client.drop_class(super_clazz, :mode => :strict); end
|
101
|
+
assert_nothing_thrown do @client.get_class(super_clazz); end # still there
|
102
|
+
@client.drop_class(CLASS);
|
103
|
+
assert_nothing_thrown do @client.drop_class(super_clazz, :mode => :strict); end
|
86
104
|
end
|
87
105
|
|
88
106
|
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'orientdb4r'
|
3
|
+
|
4
|
+
###
|
5
|
+
# This class tests Data Manipulation Operarions.
|
6
|
+
class TestDocumentCrud < Test::Unit::TestCase
|
7
|
+
include Orientdb4r::Utils
|
8
|
+
|
9
|
+
CLASS = 'testing'
|
10
|
+
DB = 'temp'
|
11
|
+
Orientdb4r::logger.level = Logger::DEBUG
|
12
|
+
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@client = Orientdb4r.client
|
16
|
+
@client.connect :database => DB, :user => 'admin', :password => 'admin'
|
17
|
+
@client.create_class(CLASS) do |c|
|
18
|
+
c.property 'prop1', :integer, :notnull => :true, :min => 1, :max => 99
|
19
|
+
c.property 'prop2', :string, :mandatory => true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def teardown
|
24
|
+
# remove the testing class after each test
|
25
|
+
@client.drop_class(CLASS)
|
26
|
+
@client.disconnect
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
###
|
31
|
+
# CREATE
|
32
|
+
def test_create_document
|
33
|
+
assert_nothing_thrown do @client.create_document( { '@class' => CLASS, 'prop1' => 99, 'prop2' => 'ipsum lorem' }); end
|
34
|
+
rid = @client.create_document({ '@class' => CLASS, 'prop1' => 1, 'prop2' => 'text' })
|
35
|
+
assert rid =~ /#[0-9]+:[0-9]+$/
|
36
|
+
|
37
|
+
# no effect if a define the version
|
38
|
+
assert_nothing_thrown do
|
39
|
+
@client.create_document({ '@class' => CLASS, '@version' => 2, 'prop1' => 1, 'prop2' => 'text' })
|
40
|
+
end
|
41
|
+
rid = @client.create_document({ '@class' => CLASS, 'prop1' => 1, 'prop2' => 'text' })
|
42
|
+
doc = @client.get_document rid
|
43
|
+
assert_equal 0, doc.doc_version
|
44
|
+
|
45
|
+
# no effect if an unknown class
|
46
|
+
assert_nothing_thrown do
|
47
|
+
@client.create_document({ '@class' => 'unknown_class', 'a' => 1, 'b' => 'text' })
|
48
|
+
end
|
49
|
+
rid = @client.create_document({ '@class' => 'unknown_class', 'a' => 11, 'b' => 'text1' })
|
50
|
+
doc = @client.get_document rid
|
51
|
+
assert_nil doc.doc_class
|
52
|
+
assert_equal 11, doc['a']
|
53
|
+
assert_equal 'text1', doc['b']
|
54
|
+
|
55
|
+
# no mandatory property
|
56
|
+
assert_raise Orientdb4r::DataError do @client.create_document({ '@class' => CLASS, 'prop1' => 1 }); end
|
57
|
+
# notNull is null, or lesser/bigger
|
58
|
+
assert_raise Orientdb4r::DataError do
|
59
|
+
@client.create_document({ '@class' => CLASS, 'prop1' => nil, 'prop2' => 'text' })
|
60
|
+
end
|
61
|
+
assert_raise Orientdb4r::DataError do
|
62
|
+
@client.create_document({ '@class' => CLASS, 'prop1' => 0, 'prop2' => 'text' })
|
63
|
+
end
|
64
|
+
assert_raise Orientdb4r::DataError do
|
65
|
+
@client.create_document({ '@class' => CLASS, 'prop1' => 100, 'prop2' => 'text' })
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
###
|
70
|
+
# GET
|
71
|
+
def test_get_document
|
72
|
+
rid = @client.create_document( { '@class' => CLASS, 'prop1' => 1, 'prop2' => 'text' })
|
73
|
+
|
74
|
+
doc = @client.get_document rid
|
75
|
+
assert_equal CLASS, doc.doc_class
|
76
|
+
assert_equal rid, doc.doc_rid
|
77
|
+
assert_equal 0, doc.doc_version
|
78
|
+
assert_equal 'd', doc.doc_type
|
79
|
+
assert_equal 1, doc['prop1']
|
80
|
+
assert_equal 'text', doc['prop2']
|
81
|
+
assert_nil doc['unknown_property']
|
82
|
+
|
83
|
+
# not existing RID
|
84
|
+
rid1 = rid.sub(/[0-9]+$/, (rid.split(':')[1].to_i + 1).to_s) # '#6:0' > '#6:1' or '#6:11' > '#6:12'
|
85
|
+
assert_raise Orientdb4r::NotFoundError do @client.get_document rid1; end
|
86
|
+
end
|
87
|
+
|
88
|
+
###
|
89
|
+
# UPDATE
|
90
|
+
def test_update_document
|
91
|
+
rid = @client.create_document( { '@class' => CLASS, 'prop1' => 1, 'prop2' => 'text' })
|
92
|
+
doc = @client.get_document rid
|
93
|
+
|
94
|
+
doc['prop1'] = 2
|
95
|
+
doc['prop2'] = 'unit'
|
96
|
+
assert_nothing_thrown do @client.update_document doc; end
|
97
|
+
doc = @client.get_document rid
|
98
|
+
assert_equal 2, doc['prop1']
|
99
|
+
assert_equal 'unit', doc['prop2']
|
100
|
+
|
101
|
+
# bad version
|
102
|
+
doc = @client.get_document rid
|
103
|
+
doc['@version'] = 2
|
104
|
+
assert_raise Orientdb4r::DataError do @client.update_document doc; end
|
105
|
+
|
106
|
+
# class cannot be changed
|
107
|
+
doc = @client.get_document rid
|
108
|
+
doc['@class'] = 'OUser'
|
109
|
+
assert_nothing_thrown do @client.update_document doc; end
|
110
|
+
assert_equal CLASS, @client.get_document(rid).doc_class
|
111
|
+
|
112
|
+
# no mandatory property
|
113
|
+
doc = @client.get_document rid
|
114
|
+
doc.delete 'prop2'
|
115
|
+
assert_raise Orientdb4r::DataError do @client.update_document doc; end
|
116
|
+
# notNull is null, or lesser/bigger
|
117
|
+
doc = @client.get_document rid
|
118
|
+
doc['prop1'] = nil
|
119
|
+
assert_raise Orientdb4r::DataError do @client.update_document doc; end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
###
|
124
|
+
# DELETE
|
125
|
+
def test_delete_document
|
126
|
+
rid = @client.create_document( { '@class' => CLASS, 'prop1' => 1, 'prop2' => 'text' })
|
127
|
+
doc = @client.get_document rid
|
128
|
+
assert_not_nil doc
|
129
|
+
|
130
|
+
# already deleted
|
131
|
+
@client.delete_document rid
|
132
|
+
assert_raise Orientdb4r::NotFoundError do @client.get_document rid; end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
data/test/test_utils.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'orientdb4r'
|
3
|
+
|
4
|
+
###
|
5
|
+
# This class tests Utils methods.
|
6
|
+
class TestDmo < Test::Unit::TestCase
|
7
|
+
include Orientdb4r::Utils
|
8
|
+
|
9
|
+
def test_verify_options
|
10
|
+
opt_pattern = {:a => :mandatory, :b => :optional, :c => 'predefined', :d => [1, false]}
|
11
|
+
assert_nothing_thrown do verify_options({:a => 'A', :b => 'B', :c => 'C', :d => 1}, opt_pattern); end
|
12
|
+
|
13
|
+
# missing mandatory
|
14
|
+
assert_raise ArgumentError do verify_options({}, opt_pattern); end
|
15
|
+
# unknown key
|
16
|
+
assert_raise ArgumentError do verify_options({:a => 1, :z => 2}, opt_pattern); end
|
17
|
+
# value not in predefined set
|
18
|
+
assert_raise ArgumentError do verify_options({:a => 1, :d => 3}, opt_pattern); end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_verify_and_sanitize_options
|
22
|
+
opt_pattern = {:a => 'A', :b => 'B'}
|
23
|
+
options = {:a => 'X'}
|
24
|
+
verify_and_sanitize_options(options, opt_pattern)
|
25
|
+
assert_equal 2, options.size
|
26
|
+
assert_equal 'X', options[:a]
|
27
|
+
assert_equal 'B', options[:b]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orientdb4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -41,16 +41,18 @@ files:
|
|
41
41
|
- README.rdoc
|
42
42
|
- Rakefile
|
43
43
|
- lib/orientdb4r.rb
|
44
|
+
- lib/orientdb4r/chained_error.rb
|
44
45
|
- lib/orientdb4r/client.rb
|
45
|
-
- lib/orientdb4r/document.rb
|
46
46
|
- lib/orientdb4r/rest/client.rb
|
47
|
-
- lib/orientdb4r/rest/
|
47
|
+
- lib/orientdb4r/rest/model.rb
|
48
48
|
- lib/orientdb4r/utils.rb
|
49
49
|
- lib/orientdb4r/version.rb
|
50
50
|
- orientdb4r.gemspec
|
51
51
|
- test/test_database.rb
|
52
52
|
- test/test_ddo.rb
|
53
53
|
- test/test_dmo.rb
|
54
|
+
- test/test_document_crud.rb
|
55
|
+
- test/test_utils.rb
|
54
56
|
homepage: http://github.com/veny/orientdb4r
|
55
57
|
licenses: []
|
56
58
|
post_install_message:
|
@@ -80,3 +82,5 @@ test_files:
|
|
80
82
|
- test/test_database.rb
|
81
83
|
- test/test_ddo.rb
|
82
84
|
- test/test_dmo.rb
|
85
|
+
- test/test_document_crud.rb
|
86
|
+
- test/test_utils.rb
|
data/lib/orientdb4r/document.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module Orientdb4r
|
2
|
-
|
3
|
-
###
|
4
|
-
# This module represents API to OrientDB's class.
|
5
|
-
module OClass
|
6
|
-
|
7
|
-
###
|
8
|
-
# Gets name of the class.
|
9
|
-
def name
|
10
|
-
get_mandatory_attribute :name
|
11
|
-
end
|
12
|
-
|
13
|
-
###
|
14
|
-
# Gets properties of the class.
|
15
|
-
def properties
|
16
|
-
get_mandatory_attribute :properties
|
17
|
-
end
|
18
|
-
|
19
|
-
###
|
20
|
-
# Gets a property with the given name.
|
21
|
-
def property(name)
|
22
|
-
props = properties.select { |i| i['name'] == name.to_s }
|
23
|
-
raise ArgumentError, "unknown property, name=#{name}" if props.empty?
|
24
|
-
raise ArgumentError, "too many properties found, name=#{name}" if props.size > 1 # just to be sure
|
25
|
-
props[0]
|
26
|
-
end
|
27
|
-
|
28
|
-
###
|
29
|
-
# Gets the super-class.
|
30
|
-
def super_class
|
31
|
-
get_mandatory_attribute :superClass
|
32
|
-
end
|
33
|
-
|
34
|
-
###
|
35
|
-
# Gets clusters of the class.
|
36
|
-
def clusters
|
37
|
-
get_mandatory_attribute :clusters
|
38
|
-
end
|
39
|
-
|
40
|
-
###
|
41
|
-
# Gets the default cluster.
|
42
|
-
def default_cluster
|
43
|
-
get_mandatory_attribute :defaultCluster
|
44
|
-
end
|
45
|
-
|
46
|
-
#------------------------------------------------------------------- Helpers
|
47
|
-
|
48
|
-
###
|
49
|
-
# Gets an attribute value that has to be presented.
|
50
|
-
def get_mandatory_attribute(name)
|
51
|
-
key = name.to_s
|
52
|
-
raise ArgumentError "unknown attribute, name=#{key}" unless self.include? key
|
53
|
-
self[key]
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|