active-orient 0.79 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.graphs.txt.swp +0 -0
- data/Gemfile +2 -6
- data/README.md +29 -27
- data/VERSION +1 -1
- data/active-orient.gemspec +4 -3
- data/bin/active-orient-console +18 -6
- data/changelog.md +60 -0
- data/config/connect.yml +8 -8
- data/examples/books.rb +134 -97
- data/graphs.txt +70 -0
- data/lib/active-orient.rb +2 -0
- data/lib/base.rb +38 -17
- data/lib/base_properties.rb +15 -14
- data/lib/class_utils.rb +11 -50
- data/lib/database_utils.rb +23 -22
- data/lib/init.rb +4 -3
- data/lib/model/custom.rb +7 -4
- data/lib/model/e.rb +6 -0
- data/lib/model/edge.rb +74 -30
- data/lib/model/the_class.rb +181 -131
- data/lib/model/the_record.rb +115 -68
- data/lib/model/vertex.rb +261 -126
- data/lib/other.rb +93 -41
- data/lib/rest/change.rb +23 -20
- data/lib/rest/create.rb +71 -63
- data/lib/rest/delete.rb +80 -64
- data/lib/rest/operations.rb +79 -68
- data/lib/rest/read.rb +42 -24
- data/lib/rest/rest.rb +38 -30
- data/lib/support/conversions.rb +42 -0
- data/lib/support/default_formatter.rb +7 -0
- data/lib/support/errors.rb +41 -0
- data/lib/support/orient.rb +167 -58
- data/lib/support/orientquery.rb +526 -348
- data/lib/support/query.rb +92 -0
- metadata +34 -18
- data/examples/test_commands.rb +0 -97
- data/examples/test_commands_2.rb +0 -59
- data/examples/test_commands_3.rb +0 -55
- data/examples/test_commands_4.rb +0 -33
- data/examples/time_graph.md +0 -162
data/lib/rest/delete.rb
CHANGED
@@ -12,7 +12,10 @@ module RestDelete
|
|
12
12
|
old_ds = ActiveOrient.database
|
13
13
|
change_database database
|
14
14
|
begin
|
15
|
-
|
15
|
+
response = nil
|
16
|
+
ActiveOrient.db_pool.checkout do | conn |
|
17
|
+
response = conn["/database/#{ActiveOrient.database}"].delete
|
18
|
+
end
|
16
19
|
if database == old_ds
|
17
20
|
change_database 'temp'
|
18
21
|
logger.info{"Working database deleted, switched to temp"}
|
@@ -30,77 +33,93 @@ module RestDelete
|
|
30
33
|
######### CLASS ##########
|
31
34
|
|
32
35
|
=begin
|
33
|
-
|
34
|
-
todo: remove all instances of the class
|
35
|
-
=end
|
36
|
+
Deletes the specified class and returns true on success
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
38
|
+
The class-entries in ActiveOrient.database_classes and ORD.database_classes are removed.
|
39
|
+
|
40
|
+
The Ruby-Class itself is untouched.
|
41
|
+
However, any furter operation leads to an Error.
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
43
|
+
todo: remove all instances of the class
|
44
|
+
=end
|
45
|
+
|
46
|
+
def delete_class o_class
|
47
|
+
cl = classname(o_class).to_s
|
48
|
+
return if cl.nil?
|
49
|
+
logger.progname = 'RestDelete#DeleteClass'
|
50
|
+
|
51
|
+
begin
|
52
|
+
## to do: if cl contains special characters, enclose with backticks
|
53
|
+
response = nil
|
54
|
+
ActiveOrient.db_pool.checkout do | conn |
|
55
|
+
response = conn["/class/#{ActiveOrient.database}/#{cl}"].delete
|
56
|
+
end
|
57
|
+
if response.code == 204
|
58
|
+
logger.info{"Class #{cl} deleted."}
|
59
|
+
|
60
|
+
ActiveOrient.database_classes.delete(cl)
|
61
|
+
end
|
62
|
+
rescue RestClient::InternalServerError => e
|
63
|
+
sentence= JSON.parse( e.response)['errors'].last['content']
|
64
|
+
if ActiveOrient.database_classes.has_key? cl
|
65
|
+
logger.error{"Class #{cl} still present."}
|
66
|
+
logger.error{ sentence }
|
67
|
+
false
|
68
|
+
else
|
69
|
+
logger.error{e.inspect}
|
70
|
+
true
|
71
|
+
end
|
72
|
+
rescue Exception => e
|
73
|
+
logger.error{e.message}
|
74
|
+
logger.error{e.inspect}
|
75
|
+
end
|
76
|
+
end
|
64
77
|
|
65
78
|
############## RECORD #############
|
66
79
|
|
67
80
|
=begin
|
68
81
|
Deletes a single Record when providing a single rid-link (#00:00) or a record
|
82
|
+
|
69
83
|
Deletes multible Records when providing a list of rid-links or a record
|
70
|
-
|
84
|
+
|
85
|
+
Todo: implement delete_edges after querying the database in one statement
|
71
86
|
|
72
87
|
Example:
|
73
|
-
|
74
|
-
|
88
|
+
V.create_class :test
|
89
|
+
record = Test.new something: 'something'
|
90
|
+
V.db.delete_record record
|
75
91
|
|
76
|
-
|
77
|
-
|
92
|
+
records= (1..100).map{|x| Test.create something: x }
|
93
|
+
V.db.delete_record *records
|
78
94
|
|
79
95
|
delete_records provides the removal of datasets after quering the database.
|
80
96
|
=end
|
81
97
|
|
82
|
-
def delete_record *
|
98
|
+
def delete_record *o
|
83
99
|
logger.progname = "ActiveOrient::RestDelete#DeleteRecord"
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
100
|
+
#o.map( &:to_orient ).map do |r|
|
101
|
+
o.orient_flatten.map do |r|
|
102
|
+
rr = r.to_human
|
103
|
+
begin
|
104
|
+
ActiveOrient::Base.remove_rid r
|
105
|
+
# rest_resource["/document/#{ActiveOrient.database}/#{r[1..-1].to_or}"].delete
|
106
|
+
ActiveOrient.db_pool.checkout do | conn |
|
107
|
+
conn["/document/#{ActiveOrient.database}/#{r.rid}"].delete
|
108
|
+
end
|
109
|
+
|
110
|
+
rescue RestClient::InternalServerError => e
|
111
|
+
logger.error{"Record #{rr} NOT deleted"}
|
112
|
+
rescue RestClient::ResourceNotFound
|
113
|
+
logger.error{"Record #{rr} does not exist in the database"}
|
114
|
+
rescue RestClient::BadRequest => e
|
115
|
+
logger.error{"tried to delete #{rr}, but something went wrong"}
|
116
|
+
raise
|
117
|
+
else
|
118
|
+
logger.info{"Record #{rr} deleted"}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
alias delete_document delete_record
|
104
123
|
|
105
124
|
=begin
|
106
125
|
Deletes records. They are defined by a query. All records which match the attributes are deleted.
|
@@ -109,12 +128,7 @@ module RestDelete
|
|
109
128
|
|
110
129
|
def delete_records o_class, where: {}
|
111
130
|
logger.progname = 'RestDelete#DeleteRecords'
|
112
|
-
|
113
|
-
if records_to_delete.empty?
|
114
|
-
logger.info{"No record found"}
|
115
|
-
else
|
116
|
-
delete_record records_to_delete
|
117
|
-
end
|
131
|
+
get_records(from: o_class, where: where).each{|y| delete_record y}
|
118
132
|
end
|
119
133
|
alias delete_documents delete_records
|
120
134
|
|
@@ -123,8 +137,10 @@ module RestDelete
|
|
123
137
|
def delete_property o_class, field
|
124
138
|
logger.progname = 'RestDelete#DeleteProperty'
|
125
139
|
begin
|
126
|
-
|
127
|
-
|
140
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
141
|
+
r = conn["/property/#{ActiveOrient.database}/#{classname(o_class)}/#{field}"].delete
|
142
|
+
true if r.code == 204
|
143
|
+
end
|
128
144
|
rescue RestClient::InternalServerError => e
|
129
145
|
logger.error{"Property #{field} in class #{classname(o_class)} NOT deleted" }
|
130
146
|
false
|
data/lib/rest/operations.rb
CHANGED
@@ -7,7 +7,8 @@ module RestOperations
|
|
7
7
|
# puts "uri:#{function_uri { args.join('/') } }"
|
8
8
|
begin
|
9
9
|
term = args.join('/')
|
10
|
-
|
10
|
+
rest_resource = Thread.current['resource'] || get_resource
|
11
|
+
rest_resource["/function/#{@database}/#{term}"].post ''
|
11
12
|
rescue RestClient::InternalServerError => e
|
12
13
|
puts JSON.parse(e.http_body)
|
13
14
|
end
|
@@ -19,7 +20,7 @@ module RestOperations
|
|
19
20
|
def count **args
|
20
21
|
logger.progname = 'RestOperations#CountRecords'
|
21
22
|
query = OrientSupport::OrientQuery.new args
|
22
|
-
query.projection
|
23
|
+
query.projection 'COUNT(*)'
|
23
24
|
result = get_records raw: true, query: query
|
24
25
|
result.first["COUNT(*)"] rescue 0 # return_value
|
25
26
|
end
|
@@ -98,56 +99,82 @@ Multible statements are transmitted at once if the Block provides an Array of st
|
|
98
99
|
|
99
100
|
=end
|
100
101
|
|
101
|
-
def read_transaction
|
102
|
-
|
103
|
-
end
|
104
|
-
|
102
|
+
def read_transaction
|
103
|
+
@transaction
|
104
|
+
end
|
105
|
+
|
106
|
+
def manage_transaction kind, command
|
105
107
|
@transaction = [] unless @transaction.is_a?(Array)
|
106
|
-
if block_given?
|
107
|
-
command = yield
|
108
|
-
command.is_a?(Array) ? command.each{|c| @transaction << c} : @transaction << command
|
109
|
-
else
|
110
|
-
logger.error { "No Block provided to execute" }
|
111
|
-
return nil
|
112
|
-
end
|
113
108
|
|
114
|
-
#
|
115
|
-
|
109
|
+
# in any case: add statement to array
|
110
|
+
command.is_a?(Array) ? command.each{|c| @transaction << c} : @transaction << command
|
111
|
+
|
112
|
+
# if kind is prepare, we a done.
|
113
|
+
# now, combine anything
|
114
|
+
unless kind == :prepare
|
116
115
|
commands = @transaction.map{|y| y if y.is_a? String }.compact
|
117
116
|
@transaction.delete_if{|y| y if y.is_a?(String)}
|
118
117
|
#puts "tn #{commands.inspect}"
|
119
|
-
|
120
|
-
|
121
|
-
@transaction
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
118
|
+
@transaction << { type: 'script', language: 'sql', script: commands } unless commands.empty?
|
119
|
+
# elsif transaction == false
|
120
|
+
# @transaction = commands.first
|
121
|
+
# else
|
122
|
+
# transaction = true
|
123
|
+
# @transaction << { type: 'cmd', language: 'sql', command: commands.first }
|
124
|
+
|
125
|
+
# transaction is true only for multible statements
|
126
|
+
# batch[:transaction] = transaction & batch[:operations].size >1
|
127
|
+
# logger.info{ @transaction.map{|y|y[:command]}.join(";\n ") }
|
128
|
+
# logger.info{ @transaction.map{|y|y[:script]}.join(";\n ") }
|
129
|
+
# batch= { transaction: transaction, operations: @transaction }
|
130
|
+
# puts "batch: #{batch.inspect}"
|
131
|
+
|
132
|
+
# @res["/batch/#{ActiveOrient.database}"].post batch.to_json
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# execute the command
|
137
|
+
#
|
138
|
+
# thread-safe ( transaction = false)
|
139
|
+
#
|
140
|
+
#
|
141
|
+
def execute transaction: nil,
|
142
|
+
command: nil,
|
143
|
+
tolerated_error_code: nil,
|
144
|
+
process_error: true,
|
145
|
+
raw: nil
|
146
|
+
|
147
|
+
if block_given?
|
148
|
+
command = yield
|
149
|
+
end
|
150
|
+
unless command.present?
|
151
|
+
logger.error { "No Command provided to execute" }
|
152
|
+
return nil
|
153
|
+
end
|
154
|
+
if ( transaction.present? || command.is_a?(Array) )
|
155
|
+
logger.error "calling manage_transaction NOT IMPLEMENTED YET!"
|
156
|
+
manage_transaction transaction, command
|
157
|
+
end
|
158
|
+
|
159
|
+
logger.info command.to_s
|
160
|
+
_execute( tolerated_error_code, process_error, raw) do
|
161
|
+
|
162
|
+
ActiveOrient.db_pool.checkout do | conn |
|
163
|
+
conn["/command/#{ActiveOrient.database}/sql"].post command.to_s #.to_json
|
164
|
+
end
|
129
165
|
end
|
166
|
+
|
167
|
+
# rest_resource.delete #if resource.present?
|
168
|
+
|
130
169
|
end
|
131
170
|
|
132
171
|
|
133
|
-
|
172
|
+
def _execute tolerated_error_code, process_error, raw
|
134
173
|
|
135
174
|
logger.progname= "Execute"
|
175
|
+
|
136
176
|
begin
|
137
|
-
response =
|
138
|
-
@transaction.compact!
|
139
|
-
return nil if @transaction.empty?
|
140
|
-
# transaction is true only for multible statements
|
141
|
-
# batch[:transaction] = transaction & batch[:operations].size >1
|
142
|
-
logger.info{ @transaction.map{|y|y[:command]}.join(";\n ") }
|
143
|
-
logger.info{ @transaction.map{|y|y[:script]}.join(";\n ") }
|
144
|
-
batch= { transaction: transaction, operations: @transaction }
|
145
|
-
puts "batch: #{batch.inspect}"
|
146
|
-
@res["/batch/#{ActiveOrient.database}"].post batch.to_json
|
147
|
-
else
|
148
|
-
logger.info{ @transaction }
|
149
|
-
@res["/command/#{ActiveOrient.database}/sql"].post @transaction #.to_json
|
150
|
-
end
|
177
|
+
response = yield
|
151
178
|
rescue RestClient::BadRequest => f
|
152
179
|
# extract the misspelled query in logfile and abort
|
153
180
|
sentence= JSON.parse( f.response)['errors'].last['content']
|
@@ -155,8 +182,13 @@ end
|
|
155
182
|
puts "Query not recognized"
|
156
183
|
puts sentence
|
157
184
|
raise
|
185
|
+
rescue RestClient::Conflict => e # (409)
|
186
|
+
# most probably the server is busy. we wait for a second print an Error-Message and retry
|
187
|
+
sleep(1)
|
188
|
+
logger.error{ e.inspect }
|
189
|
+
logger.error{ "RestClient::Error(409): Server is signaling a conflict ... retrying" }
|
190
|
+
retry
|
158
191
|
rescue RestClient::InternalServerError => e
|
159
|
-
@transaction = []
|
160
192
|
sentence= JSON.parse( e.response)['errors'].last['content']
|
161
193
|
if tolerated_error_code.present? && e.response =~ tolerated_error_code
|
162
194
|
logger.debug('RestOperations#Execute'){ "tolerated_error::#{e.message}"}
|
@@ -164,8 +196,6 @@ end
|
|
164
196
|
nil # return value
|
165
197
|
else
|
166
198
|
if process_error
|
167
|
-
# puts batch.to_json
|
168
|
-
# logger.error{e.response}
|
169
199
|
logger.error{sentence}
|
170
200
|
#logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
171
201
|
# logger.error{e.message.to_s}
|
@@ -177,35 +207,16 @@ end
|
|
177
207
|
sleep(2)
|
178
208
|
retry
|
179
209
|
else # code to execute if no exception is raised
|
180
|
-
@transaction = []
|
181
210
|
if response.code == 200
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
result.map do |x|
|
186
|
-
if x.is_a? Hash
|
187
|
-
y = x.transform_keys{|y| y.delete('@').split('=').first.underscore.to_sym}
|
188
|
-
if y[:type] == 'd' #0.present? # == 'd' # x.has_key?("@type") &&
|
189
|
-
if y.has_key?(:class)
|
190
|
-
the_object = ActiveOrient::Model.orientdb_class( name: y[:class] ).new x
|
191
|
-
ActiveOrient::Base.store_rid( the_object ) # update cache
|
192
|
-
else # create a dummy class and fill with attributes from result-set
|
193
|
-
ActiveOrient::Model.orientdb_class(name: 'query' ).new x
|
194
|
-
end
|
195
|
-
else
|
196
|
-
# return the result or the corresponding dataset
|
197
|
-
r= y.map{ | _,v | v.is_a?(String) && v.rid? ? ActiveOrient::Model.get( v ): v }
|
198
|
-
y.size ==1 ? r.first : r # return raw instead of array if only one value is present
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end.compact # return_value
|
211
|
+
result=JSON.parse(response.body)['result']
|
212
|
+
if raw.present?
|
213
|
+
result
|
202
214
|
else
|
203
|
-
|
204
|
-
end
|
215
|
+
result.from_orient
|
216
|
+
end # raw present?
|
205
217
|
else
|
206
|
-
|
218
|
+
logger.error { "code : #{response.code}" }
|
207
219
|
end
|
208
220
|
end
|
209
221
|
end
|
210
|
-
|
211
222
|
end
|
data/lib/rest/read.rb
CHANGED
@@ -7,7 +7,10 @@ module RestRead
|
|
7
7
|
# ORD.get_databases
|
8
8
|
# => ["temp", "GratefulDeadConcerts", (...)]
|
9
9
|
def get_databases
|
10
|
-
|
10
|
+
|
11
|
+
ActiveOrient.db_pool.checkout do | conn |
|
12
|
+
JSON.parse(conn["/listDatabases"].get.body)['databases']
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
=begin
|
@@ -20,18 +23,20 @@ Returns an Array with (unmodified) Class-attribute-hash-Elements
|
|
20
23
|
(...) ]
|
21
24
|
=end
|
22
25
|
def get_classes *attributes
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
begin
|
27
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
28
|
+
conn["/database/#{ActiveOrient.database}"].get
|
29
|
+
end
|
30
|
+
if response.code == 200
|
31
|
+
classes = JSON.parse(response.body)['classes']
|
32
|
+
unless attributes.empty?
|
33
|
+
classes.map{|y| y.select{|v,_| attributes.include?(v)}}
|
34
|
+
else
|
35
|
+
classes
|
36
|
+
end
|
37
|
+
else
|
38
|
+
[]
|
39
|
+
end
|
35
40
|
rescue Exception => e
|
36
41
|
logger.progname = 'RestRead#GetClasses'
|
37
42
|
logger.error{e.message}
|
@@ -48,11 +53,13 @@ Returns an Array with (unmodified) Class-attribute-hash-Elements
|
|
48
53
|
# => {"name"=>"a", "superClass"=>"V", "superClasses"=>["V"], "alias"=>nil, "abstract"=>false, "strictmode"=>false, "clusters"=>[65, 66, 67, 68], "defaultCluster"=>65, "clusterSelection"=>"round-robin", "records"=>3}
|
49
54
|
#
|
50
55
|
def get_class_properties o_class
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
ActiveOrient.db_pool.checkout do | conn |
|
57
|
+
JSON.parse(conn["/class/#{ActiveOrient.database}/#{classname(o_class)}"].get)
|
58
|
+
end
|
59
|
+
rescue => e
|
60
|
+
logger.error e.message
|
61
|
+
nil
|
62
|
+
end
|
56
63
|
|
57
64
|
|
58
65
|
def print_class_properties o_class
|
@@ -86,7 +93,10 @@ The rid-cache is not used or updated
|
|
86
93
|
begin
|
87
94
|
logger.progname = 'RestRead#GetRecord'
|
88
95
|
if rid.rid?
|
89
|
-
|
96
|
+
|
97
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
98
|
+
conn["/document/#{ActiveOrient.database}/#{rid.to_orient[1..-1]}"].get
|
99
|
+
end
|
90
100
|
raw_data = JSON.parse(response.body)
|
91
101
|
# ActiveOrient::Model.use_or_allocate( raw_data['@rid'] ) do
|
92
102
|
the_object= ActiveOrient::Model.orientdb_class(name: raw_data['@class']).new raw_data
|
@@ -107,6 +117,13 @@ The rid-cache is not used or updated
|
|
107
117
|
logger.error { "RID: #{rid} ---> No Record present " }
|
108
118
|
ActiveOrient::Model.remove_rid rid # remove rid from cache
|
109
119
|
nil
|
120
|
+
rescue NoMethodError => e
|
121
|
+
logger.fatal { "---------------- Serious Trouble ----------------" }
|
122
|
+
logger.fatal { "GetRecord raw-data: #{raw_data}" }
|
123
|
+
logger.error { "GetRecord could not allocate Model-Instance" }
|
124
|
+
logger.error { "is a model file required but missing?" }
|
125
|
+
raise
|
126
|
+
|
110
127
|
rescue Exception => e
|
111
128
|
logger.error { "Something went wrong" }
|
112
129
|
logger.error { "RID: #{rid} - #{e.message}" }
|
@@ -129,9 +146,11 @@ In this case cached data are used in favour and its not checked if the database
|
|
129
146
|
query = OrientSupport::OrientQuery.new(args) if query.nil?
|
130
147
|
begin
|
131
148
|
logger.progname = 'RestRead#GetRecords'
|
132
|
-
|
133
|
-
|
134
|
-
|
149
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
150
|
+
url = "/query/#{ActiveOrient.database}/sql/" + query.compose(destination: :rest) + "/#{query.get_limit}"
|
151
|
+
conn[URI.encode(url)].get
|
152
|
+
end
|
153
|
+
JSON.parse(response.body)['result'].map do |record|
|
135
154
|
if raw
|
136
155
|
record
|
137
156
|
# query returns an anonymus class: Use the provided Block or the Dummy-Model MyQuery
|
@@ -160,8 +179,7 @@ In this case cached data are used in favour and its not checked if the database
|
|
160
179
|
logger.error{"Invalid URI detected"}
|
161
180
|
logger.error query.to_s
|
162
181
|
logger.info{"Trying batch processing"}
|
163
|
-
|
164
|
-
response = execute{[sql_cmd[query.to_s]]}
|
182
|
+
response = execute{ query.to_s}
|
165
183
|
logger.info{"Success: to avoid this delay use ActiveOrient::Model#query_database instead"}
|
166
184
|
response
|
167
185
|
end
|