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/other.rb
CHANGED
@@ -1,8 +1,26 @@
|
|
1
1
|
|
2
2
|
class Array
|
3
|
+
|
4
|
+
@@accepted_methods = []
|
5
|
+
## dummy for refining
|
6
|
+
|
7
|
+
def method_missing method, *args, &b
|
8
|
+
return if [:to_hash, :to_str].include? method
|
9
|
+
if @@accepted_methods.include? method
|
10
|
+
self.map{|x| x.public_send(method, *args, &b)}
|
11
|
+
else
|
12
|
+
raise ArgumentError.new("Method #{method} does not exist")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
3
17
|
# Class extentions to manage to_orient and from_orient
|
4
18
|
def to_orient
|
5
|
-
|
19
|
+
if all?{ |x| x.respond_to?(:rid?)} && any?( &:rid? )
|
20
|
+
"["+ map{|x| x.rid? ? x.rid : x.to_or }.join(', ') + ']'
|
21
|
+
else
|
22
|
+
map(&:to_orient) # .join(',')
|
23
|
+
end
|
6
24
|
end
|
7
25
|
|
8
26
|
def to_or
|
@@ -16,6 +34,7 @@ class Array
|
|
16
34
|
def to_human
|
17
35
|
map &:to_human
|
18
36
|
end
|
37
|
+
|
19
38
|
# used to enable
|
20
39
|
# def abc *key
|
21
40
|
# where key is a Range, an comma separated List or an item
|
@@ -28,8 +47,15 @@ class Array
|
|
28
47
|
else
|
29
48
|
self
|
30
49
|
end
|
31
|
-
|
32
50
|
end
|
51
|
+
|
52
|
+
def orient_flatten
|
53
|
+
while( first.is_a?(Array) )
|
54
|
+
self.flatten!(1)
|
55
|
+
end
|
56
|
+
self.compact!
|
57
|
+
self ## return object
|
58
|
+
end
|
33
59
|
end
|
34
60
|
|
35
61
|
class Symbol
|
@@ -44,7 +70,7 @@ class Symbol
|
|
44
70
|
"'"+self.to_orient+"'"
|
45
71
|
end
|
46
72
|
|
47
|
-
# inserted to prevent error message while
|
73
|
+
# inserted to prevent error message while initializing a model-recorda
|
48
74
|
=begin
|
49
75
|
2.6.1 :008 > ii.first.attributes
|
50
76
|
=> {:zwoebelkuchen=>[7, 9, 9, 7, 8, 8, 3, 6, 9, ":zt:", ":zt:", ":zg:", ":zg:", ":tzu:", ":grotte:"], :created_at=>Wed, 27 Mar 2019 14:59:45 +0000}
|
@@ -85,9 +111,9 @@ iv [7, 9, 9, 7, 8, 8, 3, 6, 9, ":zt:", ":zt:", ":zg:", ":zg:", ":tzu:", ":grotte
|
|
85
111
|
./active-orient-console:51:in `<main>'
|
86
112
|
=end
|
87
113
|
|
88
|
-
def coerce a #nodoc#
|
89
|
-
|
90
|
-
end
|
114
|
+
#def coerce a #nodoc#
|
115
|
+
# nil
|
116
|
+
#end
|
91
117
|
end
|
92
118
|
|
93
119
|
class Object
|
@@ -101,6 +127,23 @@ class Object
|
|
101
127
|
end
|
102
128
|
|
103
129
|
|
130
|
+
|
131
|
+
class Time
|
132
|
+
def to_or
|
133
|
+
"date(\'#{self.strftime("%Y%m%d%H%M%S")}\',\'yyyyMMddHHmmss\')"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class Object
|
138
|
+
def to_or
|
139
|
+
self
|
140
|
+
end
|
141
|
+
end
|
142
|
+
class NilClass
|
143
|
+
def to_or
|
144
|
+
"NULL"
|
145
|
+
end
|
146
|
+
end
|
104
147
|
class Date
|
105
148
|
def to_orient
|
106
149
|
if RUBY_PLATFORM == 'java'
|
@@ -109,8 +152,16 @@ class Date
|
|
109
152
|
self
|
110
153
|
end
|
111
154
|
end
|
155
|
+
def to_or
|
156
|
+
"date(\'#{self.to_s}\',\'yyyy-MM-dd\')"
|
157
|
+
end
|
112
158
|
end
|
113
159
|
|
160
|
+
class DateTime
|
161
|
+
def to_or
|
162
|
+
"date(\'#{self.strftime("%Y%m%d%H%M%S")}\',\'yyyyMMddHHmmss\')"
|
163
|
+
end
|
164
|
+
end
|
114
165
|
|
115
166
|
class Numeric
|
116
167
|
|
@@ -143,11 +194,18 @@ class String
|
|
143
194
|
end
|
144
195
|
end
|
145
196
|
|
197
|
+
# from orient translates the database response into active-orient objects
|
198
|
+
#
|
199
|
+
# symbols are representated via ":{something]:}"
|
200
|
+
#
|
201
|
+
# database records respond to the "rid"-method
|
202
|
+
#
|
203
|
+
# other values are not modified
|
146
204
|
def from_orient
|
147
205
|
if rid?
|
148
206
|
ActiveOrient::Model.autoload_object self
|
149
|
-
elsif
|
150
|
-
|
207
|
+
elsif self =~ /^:.*:$/
|
208
|
+
# symbol-representation in the database
|
151
209
|
self[1..-2].to_sym
|
152
210
|
else
|
153
211
|
self
|
@@ -169,6 +227,7 @@ class String
|
|
169
227
|
def rid
|
170
228
|
self["#"].nil? ? self : self[1..-1] if rid?
|
171
229
|
end
|
230
|
+
alias rrid rid
|
172
231
|
|
173
232
|
def to_classname
|
174
233
|
if self[0] == '$'
|
@@ -200,71 +259,64 @@ class String
|
|
200
259
|
end
|
201
260
|
end
|
202
261
|
|
203
|
-
def coerce a #nodoc#
|
204
|
-
nil
|
205
|
-
end
|
262
|
+
# def coerce a #nodoc#
|
263
|
+
# nil
|
264
|
+
# end
|
206
265
|
|
207
266
|
def to_human
|
208
267
|
self
|
209
268
|
end
|
210
269
|
end
|
211
270
|
|
212
|
-
class Hash
|
271
|
+
class Hash
|
213
272
|
|
214
|
-
# converts
|
215
|
-
#
|
273
|
+
# converts :abc => {anything} to "abc" => {anything}
|
274
|
+
#
|
275
|
+
# converts nn => {anything} to nn => {anything}
|
276
|
+
#
|
277
|
+
# leaves "abc" => {anything} untouched
|
216
278
|
def to_orient # converts hast from activeorient to db
|
217
|
-
|
218
|
-
# puts "here to hash"
|
219
|
-
#keys.each{|k| puts self[k].inspect}
|
220
|
-
keys.each do |k|
|
279
|
+
map do | k, v|
|
221
280
|
orient_k = case k
|
222
281
|
when Numeric
|
223
282
|
k
|
224
283
|
when Symbol, String
|
225
284
|
k.to_s
|
226
285
|
else
|
227
|
-
|
286
|
+
raise "not supported key: #[k} -- must a sting, symbol or number"
|
228
287
|
end
|
229
|
-
|
230
|
-
end
|
231
|
-
substitute_hash
|
288
|
+
[orient_k, v.to_orient]
|
289
|
+
end.to_h
|
232
290
|
end
|
233
291
|
|
234
|
-
|
292
|
+
# converts hash from db to activeorient
|
293
|
+
#
|
294
|
+
#
|
295
|
+
def from_orient
|
235
296
|
#puts "here hash.from_orient --> #{self.inspect}"
|
236
297
|
if keys.include?("@class" )
|
237
298
|
ActiveOrient::Model.orientdb_class( name: self["@class"] ).new self
|
299
|
+
# create a dummy class and fill with attributes from result-set
|
300
|
+
elsif keys.include?("@type") && self["@type"] == 'd'
|
301
|
+
ActiveOrient::Model.orientdb_class(name: 'query' ).new self
|
238
302
|
else
|
239
|
-
|
240
|
-
|
303
|
+
# populate the hash by converting keys: stings to symbols, values: proprocess through :from_orient
|
304
|
+
map do |k,v|
|
241
305
|
orient_k = if k.to_s.to_i.to_s == k.to_s
|
242
306
|
k.to_i
|
243
307
|
else
|
244
308
|
k.to_sym
|
245
309
|
end
|
246
310
|
|
247
|
-
|
248
|
-
end
|
249
|
-
substitute_hash
|
311
|
+
[orient_k, v.from_orient]
|
312
|
+
end.to_h
|
250
313
|
end
|
251
|
-
|
314
|
+
end
|
252
315
|
|
253
316
|
# converts a hash to a string appropiate to include in raw queries
|
254
317
|
def to_or
|
255
|
-
"{ " + to_orient.map{|k,v| "#{k.
|
318
|
+
"{ " + to_orient.map{|k,v| "#{k.to_or}: #{v.to_or}"}.join(',') + "}"
|
256
319
|
end
|
257
|
-
## needs testing!!
|
258
|
-
# def as_json o=nli
|
259
|
-
# #puts "here hash"
|
260
|
-
# substitute_hash = Hash.new
|
261
|
-
# keys.each{|k| substitute_hash[k] = self[k].as_json}
|
262
|
-
# substitute_hash
|
263
|
-
# end
|
264
|
-
# def nested_under_indifferent_access
|
265
|
-
# HashWithIndifferentAccess.new self
|
266
|
-
# self
|
267
|
-
# end
|
268
320
|
end
|
269
321
|
|
270
322
|
#class RecordList
|
data/lib/rest/change.rb
CHANGED
@@ -31,6 +31,7 @@ module RestChange
|
|
31
31
|
def update record, attributes , version=0
|
32
32
|
r = ActiveOrient::Model.autoload_object record.rid
|
33
33
|
return(false) unless r.is_a?(ActiveOrient::Model)
|
34
|
+
raise "Cannot update the record, version-information missing. please reload ! " if version.nil?
|
34
35
|
version = r.version if version.zero?
|
35
36
|
result = patch_record(r.rid) do
|
36
37
|
attributes.merge({'@version' => version, '@class' => r.class.ref_name })
|
@@ -82,20 +83,27 @@ Returns the JSON-Response.
|
|
82
83
|
def patch_record rid # :nodoc: (used by #update )
|
83
84
|
logger.progname = 'RestChange#PatchRecord'
|
84
85
|
content = yield
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
86
|
+
if content.is_a? Hash
|
87
|
+
begin
|
88
|
+
ActiveOrient.db_pool.checkout do | conn |
|
89
|
+
conn["/document/#{ActiveOrient.database}/#{rid}"].patch content.to_orient.to_json
|
90
|
+
end
|
91
|
+
rescue RestClient::Conflict => e # (409)
|
92
|
+
# most probably the server is busy. we wait for a second print an Error-Message and retry
|
93
|
+
sleep(1)
|
94
|
+
logger.error{ "RestClient::Error(409): Server is signaling a conflict ... retrying" }
|
95
|
+
retry
|
96
|
+
rescue RestClient::InternalServerError => e
|
97
|
+
sentence= JSON.parse( e.response)['errors'].last['content']
|
98
|
+
logger.error{sentence}
|
99
|
+
logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
100
|
+
logger.error{e.message.to_s}
|
101
|
+
end
|
102
|
+
else
|
103
|
+
logger.error{"PATCH FAILED: The Block must provide an Hash with properties to be updated"}
|
104
|
+
end
|
105
|
+
end
|
106
|
+
alias patch_document patch_record
|
99
107
|
|
100
108
|
|
101
109
|
#### EXPERIMENTAL ##########
|
@@ -132,12 +140,7 @@ Returns the JSON-Response.
|
|
132
140
|
return 0
|
133
141
|
end
|
134
142
|
|
135
|
-
|
136
|
-
execute name_class, transaction: false do # To execute commands
|
137
|
-
[{ type: "cmd",
|
138
|
-
language: 'sql',
|
139
|
-
command: "ALTER PROPERTY #{name_class}.#{property} #{attribute} #{alteration}"}]
|
140
|
-
end
|
143
|
+
execute { "ALTER PROPERTY #{class_name(o_class)}.#{property} #{attribute} #{alteration}"}
|
141
144
|
rescue Exception => e
|
142
145
|
logger.error{e.message}
|
143
146
|
end
|
data/lib/rest/create.rb
CHANGED
@@ -13,19 +13,21 @@ module RestCreate
|
|
13
13
|
old_d = ActiveOrient.database
|
14
14
|
ActiveOrient.database_classes = {}
|
15
15
|
ActiveOrient.database = database
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
begin
|
17
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
18
|
+
conn["database/#{ActiveOrient.database}/#{type}"].post ""
|
19
|
+
end
|
20
|
+
if response.code == 200
|
21
|
+
logger.info{"Database #{ActiveOrient.database} successfully created and stored as working database"}
|
22
|
+
else
|
23
|
+
logger.error{"Database #{ActiveOrient.database} was NOT created. Working Database is still #{ActiveOrient.database}"}
|
24
|
+
ActiveOrient.database = old_d
|
25
|
+
end
|
26
|
+
rescue RestClient::InternalServerError => e
|
21
27
|
logger.error{"Database #{ActiveOrient.database} was NOT created. Working Database is still #{ActiveOrient.database}"}
|
22
28
|
ActiveOrient.database = old_d
|
23
29
|
end
|
24
|
-
|
25
|
-
logger.error{"Database #{ActiveOrient.database} was NOT created. Working Database is still #{ActiveOrient.database}"}
|
26
|
-
ActiveOrient.database = old_d
|
27
|
-
end
|
28
|
-
ActiveOrient.database # return_value
|
30
|
+
ActiveOrient.database # return_value
|
29
31
|
end
|
30
32
|
|
31
33
|
|
@@ -51,26 +53,23 @@ def create_this_class *db_classname #nodoc#
|
|
51
53
|
abstract = nil
|
52
54
|
end
|
53
55
|
#
|
54
|
-
|
56
|
+
db_classname.map do | database_class |
|
55
57
|
c = if superclass.present?
|
56
58
|
"CREATE CLASS #{database_class} EXTENDS #{superclass}"
|
57
59
|
else
|
58
60
|
"CREATE CLASS #{database_class} "
|
59
61
|
end
|
60
62
|
c << " ABSTRACT" if abstract.present?
|
61
|
-
|
62
|
-
c
|
63
|
+
execute( tolerated_error_code: /already exists/ ){ c }
|
63
64
|
end
|
64
65
|
# execute anything as batch, don't roll back in case of an error
|
65
66
|
|
66
|
-
execute transaction: false, tolerated_error_code: /already exists/ do
|
67
|
-
command
|
68
|
-
end
|
67
|
+
# execute transaction: false, tolerated_error_code: /already exists/ do
|
68
|
+
# command
|
69
|
+
# end
|
69
70
|
|
70
71
|
rescue ArgumentError => e
|
71
72
|
logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
72
|
-
rescue ActiveOrient::Error::ServerError
|
73
|
-
# do nothing
|
74
73
|
end
|
75
74
|
|
76
75
|
|
@@ -88,37 +87,44 @@ Creates a Record with the attributes provided in the attributes-hash e.g.
|
|
88
87
|
|
89
88
|
Puts the database-response into the cache by default
|
90
89
|
|
90
|
+
Argument: silence
|
91
|
+
if silence is specified, no Error-Messages are raised. Instead
|
92
|
+
|
93
|
+
* if a record failes to be created, because an index-error occured, it is replaced by that specified in the database response
|
91
94
|
|
92
95
|
=end
|
93
96
|
|
94
|
-
def create_record o_class, attributes: {}, cache: true # use Model#create instead
|
97
|
+
def create_record o_class, attributes: {}, cache: true, silence: true # use Model#create instead
|
95
98
|
logger.progname = 'RestCreate#CreateRecord'
|
96
99
|
attributes = yield if attributes.empty? && block_given?
|
97
100
|
# @class must not quoted! Quote only attributes(strings)
|
98
101
|
post_argument = {'@class' => classname(o_class)}.merge(attributes.to_orient)
|
102
|
+
response = nil
|
99
103
|
begin
|
100
|
-
|
104
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
105
|
+
conn["/document/#{ActiveOrient.database}"].post post_argument.to_json
|
106
|
+
end
|
101
107
|
data = JSON.parse(response.body)
|
102
108
|
the_object = ActiveOrient::Model.orientdb_class(name: data['@class']).new data ## return_value
|
103
109
|
if cache
|
104
|
-
|
110
|
+
ActiveOrient::Base.store_rid( the_object )
|
105
111
|
else
|
106
|
-
|
112
|
+
the_object
|
107
113
|
end
|
108
114
|
rescue RestClient::InternalServerError => e
|
109
115
|
sentence= JSON.parse( e.response)['errors'].last['content']
|
110
|
-
# puts sentence.to_s
|
111
116
|
if sentence =~ /found duplicated key/
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
117
|
+
raise "Duplicate Key" unless silence
|
118
|
+
rid = sentence.split("#").last
|
119
|
+
logger.info{ "found duplicated Key --> loaded #{rid} instead of creating "}
|
120
|
+
## reading database content -- maybe update attributes?
|
121
|
+
get_record rid
|
122
|
+
else
|
123
|
+
response = JSON.parse(e.response)['errors'].pop
|
124
|
+
logger.error{response['content'].split(':')[1..-1].join(':')}
|
125
|
+
logger.error{"No Object allocated"}
|
126
|
+
nil # return_value
|
127
|
+
end
|
122
128
|
rescue Errno::EADDRNOTAVAIL => e
|
123
129
|
sleep(2)
|
124
130
|
retry
|
@@ -190,22 +196,24 @@ A composite index
|
|
190
196
|
logger.progname = 'RestCreate#CreateProperties'
|
191
197
|
all_properties_in_a_hash = Hash.new #WithIndifferentAccess.new
|
192
198
|
all_properties.each{|field, args| all_properties_in_a_hash.merge! translate_property_hash(field, args)}
|
193
|
-
count=0
|
199
|
+
count, response = 0, nil
|
194
200
|
# puts "all_properties_in_a_hash #{all_properties_in_a_hash.to_json}"
|
195
|
-
|
196
|
-
|
197
|
-
response =
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
+
if all_properties_in_a_hash.is_a?(Hash)
|
202
|
+
begin
|
203
|
+
response = ActiveOrient.db_pool.checkout do | conn |
|
204
|
+
conn["/property/#{ActiveOrient.database}/#{classname(o_class)}"].post all_properties_in_a_hash.to_json
|
205
|
+
end
|
206
|
+
# puts response.inspect
|
207
|
+
# response.body.to_i returns response.code, only to_f.to_i returns the correct value
|
208
|
+
count= response.body.to_f.to_i if response.code == 201
|
209
|
+
rescue RestClient::InternalServerError => e
|
210
|
+
logger.progname = 'RestCreate#CreateProperties'
|
211
|
+
response = JSON.parse(e.response)['errors'].pop
|
212
|
+
error_message = response['content'].split(':').last
|
213
|
+
logger.error{"Properties in #{classname(o_class)} were NOT created"}
|
214
|
+
logger.error{"The Error was: #{response['content'].split(':').last}"}
|
215
|
+
nil
|
201
216
|
end
|
202
|
-
rescue RestClient::InternalServerError => e
|
203
|
-
logger.progname = 'RestCreate#CreateProperties'
|
204
|
-
response = JSON.parse(e.response)['errors'].pop
|
205
|
-
error_message = response['content'].split(':').last
|
206
|
-
logger.error{"Properties in #{classname(o_class)} were NOT created"}
|
207
|
-
logger.error{"The Error was: #{response['content'].split(':').last}"}
|
208
|
-
nil
|
209
217
|
end
|
210
218
|
### index
|
211
219
|
if block_given?# && count == all_properties_in_a_hash.size
|
@@ -236,22 +244,22 @@ If an index is to be specified, it's defined in the optional block
|
|
236
244
|
--> creates a manual index
|
237
245
|
=end
|
238
246
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
247
|
+
def create_property o_class, field, index: nil, **args, &b
|
248
|
+
logger.progname = 'RestCreate#CreateProperty'
|
249
|
+
args= { type: :string} if args.blank? # the default case
|
250
|
+
c = create_properties o_class, {field => args}
|
251
|
+
if index.nil? && block_given?
|
252
|
+
index = yield
|
253
|
+
end
|
254
|
+
if index.present?
|
255
|
+
if index.is_a?(String) || index.is_a?(Symbol)
|
256
|
+
create_index o_class, name: field, type: index
|
257
|
+
elsif index.is_a? Hash
|
258
|
+
bez = index.keys.first
|
259
|
+
create_index o_class, name: bez, type: index[bez], on: [field]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
255
263
|
|
256
264
|
################# INDEX ###################
|
257
265
|
|