active-orient 0.79 → 0.80
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 +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
|