active-orient 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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/Gemfile +16 -0
- data/Guardfile +21 -0
- data/LICENSE +22 -0
- data/README.md +275 -0
- data/acitve-orient.gemspec +27 -0
- data/config/boot.rb +24 -0
- data/config/connect.yml +13 -0
- data/lib/base.rb +220 -0
- data/lib/base_properties.rb +147 -0
- data/lib/model.rb +441 -0
- data/lib/orient.rb +98 -0
- data/lib/query.rb +88 -0
- data/lib/rest.rb +942 -0
- data/lib/support.rb +315 -0
- data/test.rb +4 -0
- data/usecase.md +91 -0
- metadata +104 -0
data/lib/orient.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module OrientSupport
|
2
|
+
=begin
|
3
|
+
This Module fences specialized ruby objects
|
4
|
+
=end
|
5
|
+
|
6
|
+
class Array < Array
|
7
|
+
include Support
|
8
|
+
=begin
|
9
|
+
Initialisation method stores the modelinstance in @orient.
|
10
|
+
|
11
|
+
Further a list of array-elements is expected, which are forwarded (as Array) to Array
|
12
|
+
|
13
|
+
|
14
|
+
=end
|
15
|
+
def initialize modelinstance, *args
|
16
|
+
@orient = modelinstance
|
17
|
+
super args
|
18
|
+
@name = modelinstance.attributes.key(self)
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def << arg
|
23
|
+
@orient.add_item_to_property( @name, arg ) if @name.present?
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
=begin
|
28
|
+
Updating of single items
|
29
|
+
|
30
|
+
this only works if the hole embedded Array is previosly loaded into the ruby-array.
|
31
|
+
=end
|
32
|
+
|
33
|
+
def []= key, value
|
34
|
+
super
|
35
|
+
@orient.update set: { @name => self } if @name.present?
|
36
|
+
end
|
37
|
+
|
38
|
+
def [] *arg
|
39
|
+
# puts "[] ARG: #{arg.inspect}"
|
40
|
+
# arg.each{|u| puts "[] #{u.inspect} : #{u.class} " }
|
41
|
+
super
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete_at *pos
|
46
|
+
if @name.present?
|
47
|
+
delete self[*pos]
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
# old version: works only if the hole array is loaded into memory
|
52
|
+
# self[*pos]=nil
|
53
|
+
# @orient.update set:{ @name => self.compact }
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_if
|
57
|
+
if @name.present?
|
58
|
+
delete *self.map{|y| y if yield(y) }.compact # if the block returns true then delete the item
|
59
|
+
else
|
60
|
+
super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete *item
|
65
|
+
@orient.remove_item_from_property( @name ) { item } if @name.present?
|
66
|
+
end
|
67
|
+
|
68
|
+
def where *item
|
69
|
+
where_string = item.map{|m| where_string = compose_where m }.join( ' and ' )
|
70
|
+
query = "select from ( select expand( #{@name} ) from #{@orient.classname}) #{where_string} "
|
71
|
+
puts query
|
72
|
+
@orient.query query
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
def method_missing *args
|
77
|
+
map{|x| x.send args.first }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
class LinkMap < OrientSupport::Array
|
81
|
+
|
82
|
+
def []= arg
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
#
|
87
|
+
# class Hash < Hash_with_indifferent_access
|
88
|
+
# # additional and overlayed methods for Hash-Objects in OrientDB
|
89
|
+
# def initialize modelinstance, *args
|
90
|
+
# @orient = modelinstance
|
91
|
+
# super args
|
92
|
+
# @name = modelinstance.attributes.key(self)
|
93
|
+
#
|
94
|
+
# end
|
95
|
+
#
|
96
|
+
# end
|
97
|
+
|
98
|
+
end
|
data/lib/query.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
|
2
|
+
module ActiveOrient
|
3
|
+
class Query < ActiveOrient::Model
|
4
|
+
|
5
|
+
has_many :records
|
6
|
+
has_many :queries
|
7
|
+
|
8
|
+
def reset_records
|
9
|
+
self.records= []
|
10
|
+
end
|
11
|
+
alias reset_results reset_records
|
12
|
+
|
13
|
+
def reset_queries
|
14
|
+
self.queries = []
|
15
|
+
end
|
16
|
+
=begin
|
17
|
+
calls ActiveOrient::ActiveOrient#GetDocuments
|
18
|
+
stores the query in the query-stack and saves the result in the record-Array
|
19
|
+
|
20
|
+
returns the count of assigned records
|
21
|
+
=end
|
22
|
+
|
23
|
+
def get_documents o_class , **args
|
24
|
+
|
25
|
+
query = OrientSupport::OrientQuery.new class_name(o_class), args
|
26
|
+
self.queries << query.compose
|
27
|
+
count= 0
|
28
|
+
orientdb.get_documents( o_class , query: query.compose ).each{|c| records << c; count+=1 }
|
29
|
+
count
|
30
|
+
end
|
31
|
+
|
32
|
+
=begin
|
33
|
+
All predefined queries are send to the database.
|
34
|
+
The result is stored in the records.
|
35
|
+
Unknown Records are of Type ActiveOrient::Model::Myquery, uses ActiveOrient::Orientdb.execute which tries to autosuggest the ActiveOrient::Model::{Class}
|
36
|
+
|
37
|
+
example: Multible Records
|
38
|
+
ach = ActiveOrient::Query.new
|
39
|
+
ach.queries << 'create class Contracts ABSTRACT'
|
40
|
+
ach.queries << 'create property Contracts.details link'
|
41
|
+
ach.queries << 'create class Stocks extends Contracts'
|
42
|
+
result = ach.execute_queries transaction: false
|
43
|
+
|
44
|
+
example: Batch
|
45
|
+
q = ActiveOrient::Query.new
|
46
|
+
q.queries << [
|
47
|
+
"select expand( contracts ) from Openinterest"
|
48
|
+
"let con = select expand( contracts ) from Openinterest; ",
|
49
|
+
"let sub = select from Subcategories where contracts in $con;",
|
50
|
+
"let cat = select from Categories where subcategories in $sub;",
|
51
|
+
"let ind = select from Industries where categories in $cat;",
|
52
|
+
"SELECT expand(unionall) FROM (SELECT unionall( $con, $cat))"
|
53
|
+
]
|
54
|
+
q.execute_queries.each{|x| puts "X #{x.inspect}" }
|
55
|
+
|
56
|
+
=end
|
57
|
+
def execute_queries reset: true, transaction: true
|
58
|
+
reset_records if reset
|
59
|
+
begin
|
60
|
+
orientdb.execute( transaction: transaction ) do
|
61
|
+
result = queries.map do |q|
|
62
|
+
# command: words are seperated by one space only, thus squeeze multible spaces
|
63
|
+
sql_cmd = -> (command) { { type: "cmd", language: "sql", command: command.squeeze(' ') } }
|
64
|
+
batch_cmd = ->( command_array ){ {type: "script", language: "sql", script: command_array } }
|
65
|
+
case q
|
66
|
+
when String
|
67
|
+
sql_cmd[ q ]
|
68
|
+
when Hash
|
69
|
+
q
|
70
|
+
when Array
|
71
|
+
batch_cmd[ q ]
|
72
|
+
else
|
73
|
+
nil
|
74
|
+
end # case
|
75
|
+
end.compact
|
76
|
+
# save the result in records
|
77
|
+
result.each{|y| records << y }
|
78
|
+
|
79
|
+
end # block
|
80
|
+
rescue RestClient::InternalServerError => e
|
81
|
+
puts e.inspect
|
82
|
+
end
|
83
|
+
|
84
|
+
end # def execute_queries
|
85
|
+
|
86
|
+
end # class
|
87
|
+
|
88
|
+
end # module
|
data/lib/rest.rb
ADDED
@@ -0,0 +1,942 @@
|
|
1
|
+
module ActiveOrient
|
2
|
+
require 'cgi'
|
3
|
+
require 'rest-client'
|
4
|
+
require 'active_support/core_ext/string' # provides blank?, present?, presence etc
|
5
|
+
#require 'model'
|
6
|
+
=begin
|
7
|
+
OrientDB performs queries to a OrientDB-Database
|
8
|
+
|
9
|
+
The communication is based on the ActiveOrient-API.
|
10
|
+
|
11
|
+
The OrientDB-Server is specified in config/connect.yml
|
12
|
+
|
13
|
+
A Sample:
|
14
|
+
:orientdb:
|
15
|
+
:server: localhost
|
16
|
+
:port: 2480
|
17
|
+
:database: working-database
|
18
|
+
:admin:
|
19
|
+
:user: admin-user
|
20
|
+
:pass: admin-password
|
21
|
+
|
22
|
+
|
23
|
+
=end
|
24
|
+
|
25
|
+
class OrientDB
|
26
|
+
mattr_accessor :logger ## borrowed from active_support
|
27
|
+
include OrientSupport::Support
|
28
|
+
|
29
|
+
=begin
|
30
|
+
Contructor: OrientDB is conventionally initialized.
|
31
|
+
Thus several instances pointing to the same or different databases can coexist
|
32
|
+
|
33
|
+
A simple
|
34
|
+
xyz = ActiveOrient::OrientDB.new
|
35
|
+
uses the database specified in the yaml-file »config/connect.yml« and connects
|
36
|
+
xyz = ActiveOrient::OrientDB.new database: my_fency_database
|
37
|
+
accesses the database »my_fency_database«. The database is created if its not existing.
|
38
|
+
|
39
|
+
*USECASE*
|
40
|
+
xyz = ActiveOrient::Model.orientdb = ActiveOrient::OrientDB.new
|
41
|
+
initialises the Database-Connection and publishes the Instance to any ActiveOrient::Model-Object
|
42
|
+
=end
|
43
|
+
|
44
|
+
def initialize database: nil, connect: true
|
45
|
+
@res = get_ressource
|
46
|
+
@database = database.presence || YAML::load_file( File.expand_path('../../config/connect.yml',__FILE__))[:orientdb][:database]
|
47
|
+
# @database=@database#.camelcase
|
48
|
+
connect() if connect
|
49
|
+
# save existing classes
|
50
|
+
@classes = []
|
51
|
+
ActiveOrient::Model.orientdb = self
|
52
|
+
end
|
53
|
+
|
54
|
+
## included for development , should be removed in production release
|
55
|
+
def ressource
|
56
|
+
@res
|
57
|
+
end
|
58
|
+
##
|
59
|
+
|
60
|
+
def connect
|
61
|
+
i = 0
|
62
|
+
begin
|
63
|
+
logger.progname = 'OrientDB#Connect'
|
64
|
+
r= @res["/connect/#{ @database }" ].get
|
65
|
+
if r.code == 204
|
66
|
+
logger.info{ "Connected to database #{@database} " }
|
67
|
+
true
|
68
|
+
else
|
69
|
+
logger.error{ "Connection to database #{@database} could NOT be established" }
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
rescue RestClient::Unauthorized => e
|
73
|
+
if i.zero?
|
74
|
+
logger.info{ "Database #{@database} NOT present --> creating" }
|
75
|
+
i=i+1
|
76
|
+
create_database
|
77
|
+
retry
|
78
|
+
else
|
79
|
+
Kernel.exit
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
## -----------------------------------------------------------------------------------------
|
86
|
+
##
|
87
|
+
## Database stuff
|
88
|
+
##
|
89
|
+
## get_databases
|
90
|
+
## create_database
|
91
|
+
## change_database
|
92
|
+
## delete_database
|
93
|
+
## -----------------------------------------------------------------------------------------
|
94
|
+
|
95
|
+
=begin
|
96
|
+
returns an Array with available Database-Names as Elements
|
97
|
+
=end
|
98
|
+
def get_databases
|
99
|
+
JSON.parse( @res["/listDatabases"].get.body)['databases']
|
100
|
+
end
|
101
|
+
|
102
|
+
=begin
|
103
|
+
Creates a database with the given name and switches to this database as working-database
|
104
|
+
Types are either 'plocal' or 'memory'
|
105
|
+
|
106
|
+
returns the name of the working-database
|
107
|
+
=end
|
108
|
+
def create_database type: 'plocal' , database: @database
|
109
|
+
logger.progname = 'OrientDB#CreateDatabase'
|
110
|
+
old_d = @database
|
111
|
+
@classes = []
|
112
|
+
@database = database
|
113
|
+
begin
|
114
|
+
response = @res[database_uri{ type }].post ""
|
115
|
+
if response.code == 200
|
116
|
+
logger.info{ "Database #{@database} successfully created and stored as working database"}
|
117
|
+
else
|
118
|
+
@database = old_d
|
119
|
+
logger.error{ "Database #{name} was NOT created. Working Database is still #{@database} "}
|
120
|
+
end
|
121
|
+
rescue RestClient::InternalServerError => e
|
122
|
+
@database = old_d
|
123
|
+
logger.error{ "Database #{name} was NOT created. Working Database is still #{@database} "}
|
124
|
+
end
|
125
|
+
@database
|
126
|
+
|
127
|
+
end
|
128
|
+
=begin
|
129
|
+
changes the working-database to {name}
|
130
|
+
=end
|
131
|
+
def change_database name
|
132
|
+
@classes = []
|
133
|
+
@database = name
|
134
|
+
|
135
|
+
end
|
136
|
+
=begin
|
137
|
+
deletes the database and returns true on success
|
138
|
+
|
139
|
+
after the removal of the database, the working-database might be empty
|
140
|
+
=end
|
141
|
+
def delete_database database:
|
142
|
+
@classes = []
|
143
|
+
logger.progname = 'OrientDB#DropDatabase'
|
144
|
+
old_ds = @database
|
145
|
+
change_database database
|
146
|
+
begin
|
147
|
+
response = @res[database_uri].delete
|
148
|
+
if database == old_ds
|
149
|
+
change_database ""
|
150
|
+
logger.info{ "Working database deleted" }
|
151
|
+
else
|
152
|
+
change_database old_ds
|
153
|
+
logger.info{ "Database #{database} deleted, working database is still #{@database} "}
|
154
|
+
end
|
155
|
+
rescue RestClient::InternalServerError => e
|
156
|
+
logger.info{ "Database #{database} NOT deleted" }
|
157
|
+
change_database old_ds
|
158
|
+
end
|
159
|
+
!response.nil? && response.code == 204 ? true : false
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
## -----------------------------------------------------------------------------------------
|
164
|
+
##
|
165
|
+
## Inspect, Create and Delete Classes
|
166
|
+
##
|
167
|
+
## inspect_classes
|
168
|
+
## create_class
|
169
|
+
## delete_class
|
170
|
+
##
|
171
|
+
## -----------------------------------------------------------------------------------------
|
172
|
+
|
173
|
+
=begin
|
174
|
+
returns an Array with (unmodified) Class-attribute-hash-Elements
|
175
|
+
|
176
|
+
get_classes 'name', 'superClass'
|
177
|
+
returns
|
178
|
+
[ {"name"=>"E", "superClass"=>""},
|
179
|
+
{"name"=>"OFunction", "superClass"=>""},
|
180
|
+
{"name"=>"ORole", "superClass"=>"OIdentity"}
|
181
|
+
(...)
|
182
|
+
]
|
183
|
+
=end
|
184
|
+
|
185
|
+
def get_classes *attributes
|
186
|
+
i = 0
|
187
|
+
begin
|
188
|
+
response = @res[database_uri].get
|
189
|
+
if response.code == 200
|
190
|
+
classes= JSON.parse( response.body )['classes' ]
|
191
|
+
unless attributes.empty?
|
192
|
+
classes.map{|y| y.select{| v,_| attributes.include?(v) } }
|
193
|
+
else
|
194
|
+
classes
|
195
|
+
end
|
196
|
+
|
197
|
+
#.map{ |y| y.name }
|
198
|
+
else
|
199
|
+
[]
|
200
|
+
end
|
201
|
+
rescue JSON::ParserError
|
202
|
+
if i.zero?
|
203
|
+
i = i + 1
|
204
|
+
retry
|
205
|
+
else
|
206
|
+
raise
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
=begin
|
212
|
+
returns the class_hierachie
|
213
|
+
|
214
|
+
to fetch all Vertices
|
215
|
+
class_hiearchie( base_class: 'V').flatten
|
216
|
+
to fetch all Edges
|
217
|
+
class_hierachie( base_class: 'E').flatten
|
218
|
+
|
219
|
+
Notice: base_class has to be noted as String! There is no implicit conversion from Symbol or Class
|
220
|
+
=end
|
221
|
+
|
222
|
+
def class_hierachie base_class: '', requery: false
|
223
|
+
@all_classes = get_classes( 'name', 'superClass') if requery || @all_classes.blank?
|
224
|
+
def fv s # :nodoc:
|
225
|
+
@all_classes.find_all{ |x| x[ 'superClass' ]== s }.map{| v| v[ 'name' ]} #.camelize }
|
226
|
+
end
|
227
|
+
|
228
|
+
def fx v # :nodoc:
|
229
|
+
fv(v).map{ |x| ar = fx( x ) ; ar.empty? ? x : [ x , ar ] }
|
230
|
+
end
|
231
|
+
|
232
|
+
fx base_class
|
233
|
+
end
|
234
|
+
=begin
|
235
|
+
returns an array with all names of the classes of the database
|
236
|
+
caches the result.
|
237
|
+
|
238
|
+
parameter: include_system_classes: false|true, requery: false|true
|
239
|
+
=end
|
240
|
+
def database_classes include_system_classes: false, requery: false
|
241
|
+
requery = true if @classes.empty?
|
242
|
+
if requery
|
243
|
+
class_hierachie requery: true
|
244
|
+
system_classes = ["OFunction", "OIdentity", "ORIDs", "ORestricted", "ORole", "OSchedule", "OTriggered", "OUser", "_studio"]
|
245
|
+
all_classes = get_classes( 'name' ).map( &:values).flatten
|
246
|
+
@classes = include_system_classes ? all_classes : all_classes - system_classes
|
247
|
+
end
|
248
|
+
@classes
|
249
|
+
end
|
250
|
+
|
251
|
+
alias inspect_classes database_classes
|
252
|
+
|
253
|
+
=begin
|
254
|
+
Creates classes and class-hierachies in OrientDB and in Ruby.
|
255
|
+
|
256
|
+
|
257
|
+
Takes an Array or a Hash as argument and returns an Array of
|
258
|
+
successfull allocated Ruby-Classes
|
259
|
+
|
260
|
+
If the argument is an array, Basic-Classes are build.
|
261
|
+
|
262
|
+
Otherwise key/value pairs are assumend to follow this terminology
|
263
|
+
{ SuperClass => [ class, class, ...], SuperClass => [] , ... }
|
264
|
+
=end
|
265
|
+
|
266
|
+
def create_classes classes
|
267
|
+
# rebuild cashed classes-array
|
268
|
+
# first the classes-string is camelized (this is used to allocate the ruby-class)
|
269
|
+
# Then the database is queried for this string or the underscored string-variant
|
270
|
+
# the name-building process is independend from the method »class_name«
|
271
|
+
database_classes requery: true
|
272
|
+
consts = Array.new
|
273
|
+
execute transaction: false do
|
274
|
+
class_cmd = ->(s,n) do
|
275
|
+
n = n.to_s.camelize
|
276
|
+
consts << ActiveOrient::Model.orientdb_class( name: n)
|
277
|
+
unless database_classes.include?(n) || database_classes.include?(n.underscore)
|
278
|
+
{ type: "cmd", language: 'sql', command: "create class #{n} extends #{s}" }
|
279
|
+
|
280
|
+
end
|
281
|
+
end ## class_cmd
|
282
|
+
|
283
|
+
if classes.is_a?(Array)
|
284
|
+
classes.map do | n |
|
285
|
+
n = n.to_s.camelize # capitalize
|
286
|
+
consts << ActiveOrient::Model.orientdb_class( name: n)
|
287
|
+
unless database_classes.include?( n ) || database_classes.include?(n.underscore)
|
288
|
+
{ type: "cmd", language: 'sql', command: "create class #{n} " }
|
289
|
+
end
|
290
|
+
end
|
291
|
+
elsif classes.is_a?(Hash)
|
292
|
+
classes.keys.map do | superclass |
|
293
|
+
items = Array.new
|
294
|
+
superClass = superclass.to_s.camelize
|
295
|
+
items << { type: "cmd", language: 'sql', command: "create class #{superClass} abstract" } unless database_classes.flatten.include?( superClass ) || database_classes.flatten.include?( superClass.underscore )
|
296
|
+
items << if classes[superclass].is_a?( String ) || classes[superclass].is_a?( Symbol )
|
297
|
+
class_cmd[superClass, classes[superclass] ]
|
298
|
+
elsif classes[superclass].is_a?( Array )
|
299
|
+
classes[superclass].map{|n| class_cmd[superClass, n] }
|
300
|
+
end
|
301
|
+
#puts items.flatten.map{|x| x[:command]}
|
302
|
+
items # returnvalue
|
303
|
+
end.flatten
|
304
|
+
end.compact # erase nil-entries, in case the class is already allocated
|
305
|
+
end
|
306
|
+
# refresh cached class-informations
|
307
|
+
database_classes requery: true
|
308
|
+
# returns an array of allocated Constants/Classes
|
309
|
+
consts
|
310
|
+
end
|
311
|
+
|
312
|
+
=begin
|
313
|
+
creates a class and returns the a ActiveOrient::Model:{Newclass}-Class- (Constant)
|
314
|
+
which is designed to take any documents stored in this class
|
315
|
+
|
316
|
+
Predefined attributes: version, cluster, record
|
317
|
+
|
318
|
+
Other attributes are assigned dynamically upon reading documents
|
319
|
+
|
320
|
+
The classname is Camelized by default, eg: classnames are always Capitalized, underscores ('_') indicate
|
321
|
+
that the following letter is capitalized, too.
|
322
|
+
|
323
|
+
Other class-names can be used if a "$" is placed at the begining of the name-string. However, most of the
|
324
|
+
model-based methods will not work in this case.
|
325
|
+
=end
|
326
|
+
def create_class newclass
|
327
|
+
create_classes( [ newclass ] ).first
|
328
|
+
end
|
329
|
+
|
330
|
+
alias open_class create_class
|
331
|
+
|
332
|
+
def create_vertex_class name , superclass: 'V'
|
333
|
+
create_classes( { superclass => name } ).first
|
334
|
+
end
|
335
|
+
|
336
|
+
def create_edge_class name , superclass: 'E'
|
337
|
+
create_classes( { superclass => name } ).first
|
338
|
+
end
|
339
|
+
|
340
|
+
=begin
|
341
|
+
nexus_edge connects two documents/vertexes
|
342
|
+
The parameter o_class can be either a class or a string
|
343
|
+
=end
|
344
|
+
|
345
|
+
def nexus_edge o_class , attributes: {}, from:, to:, unique: false
|
346
|
+
logger.progname = "ActiveOrient::OrientDB#NexusEdge"
|
347
|
+
if unique
|
348
|
+
wwhere = { out: from.to_orient, in: to.to_orient }.merge(attributes.to_orient)
|
349
|
+
existing_edge = get_documents( from: o_class, where: wwhere )
|
350
|
+
if existing_edge.first.is_a?( ActiveOrient::Model )
|
351
|
+
logger.debug { "reusing edge #{class_name(o_class)} from #{from.to_orient} to #{to.to_orient} " }
|
352
|
+
return existing_edge.first
|
353
|
+
end
|
354
|
+
end
|
355
|
+
logger.debug { "creating edge #{class_name(o_class)} from #{from.to_orient} to #{to.to_orient} " }
|
356
|
+
response= execute( o_class, transaction: false) do
|
357
|
+
#[ { type: "cmd", language: 'sql', command: CGI.escapeHTML("create edge #{class_name(o_class)} from #{translate_to_rid[m]} to #{to.to_roient}; ")} ]
|
358
|
+
attr_string = attributes.blank? ? "" : "set #{ generate_sql_list attributes.to_orient }"
|
359
|
+
[ { type: "cmd", language: 'sql',
|
360
|
+
command: "create edge #{class_name(o_class)} from #{from.to_orient} to #{to.to_orient} #{attr_string}"} ]
|
361
|
+
end
|
362
|
+
if response.is_a?(Array) && response.size == 1
|
363
|
+
response.pop # RETURN_VALUE
|
364
|
+
else
|
365
|
+
response
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
=begin
|
370
|
+
Deletes a single edge when providing a single rid-link (#00:00)
|
371
|
+
Deletes multible edges when providing a list of rid-links
|
372
|
+
Todo: implement delete_edges after querying the database in one statement
|
373
|
+
|
374
|
+
=end
|
375
|
+
def delete_edge *rid
|
376
|
+
rid = rid.map do |mm|
|
377
|
+
if mm.is_a?(String)
|
378
|
+
if mm.rid?
|
379
|
+
mm
|
380
|
+
elsif mm.is_a?(Rest::Model)
|
381
|
+
mm.rid
|
382
|
+
else
|
383
|
+
nil
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end.compact
|
387
|
+
response= execute transaction: false do
|
388
|
+
[ { type: "cmd", language: 'sql', command: CGI.escapeHTML("delete edge #{rid.join(',') }")} ]
|
389
|
+
end
|
390
|
+
if response.is_a?( Array ) && response.size == 1
|
391
|
+
response.pop # RETURN_VALUE
|
392
|
+
else
|
393
|
+
response
|
394
|
+
end
|
395
|
+
end
|
396
|
+
=begin
|
397
|
+
deletes the specified class and returns true on success
|
398
|
+
|
399
|
+
|
400
|
+
todo: remove all instances of the class
|
401
|
+
=end
|
402
|
+
def delete_class o_class
|
403
|
+
cl= class_name(o_class)
|
404
|
+
logger.progname = 'OrientDB#DeleteClass'
|
405
|
+
|
406
|
+
if database_classes.include? cl
|
407
|
+
begin
|
408
|
+
response = @res[class_uri{ cl } ].delete
|
409
|
+
if response.code == 204
|
410
|
+
# return_value: sussess of the removal
|
411
|
+
!database_classes( requery: true ).include?(cl)
|
412
|
+
# don't delete the ruby-class
|
413
|
+
# ActiveOrient::Model.send :remove_const, cl.to_sym if o_class.is_a?(Class)
|
414
|
+
end
|
415
|
+
rescue RestClient::InternalServerError => e
|
416
|
+
if database_classes( requery: true).include?( cl )
|
417
|
+
logger.error{ "Class #{cl} still present" }
|
418
|
+
logger.error{ e.inspect }
|
419
|
+
false
|
420
|
+
else
|
421
|
+
true
|
422
|
+
end
|
423
|
+
end
|
424
|
+
else
|
425
|
+
logger.info { "Class #{cl} not present. "}
|
426
|
+
end
|
427
|
+
|
428
|
+
end
|
429
|
+
|
430
|
+
def create_property o_class, field, type: 'string', linked_class: nil
|
431
|
+
logger.progname= 'OrientDB#CreateProperty'
|
432
|
+
js= if linked_class.nil?
|
433
|
+
{ field => { propertyType: type.upcase } }
|
434
|
+
else
|
435
|
+
{ field => { propertyType: type.upcase, linkedClass: class_name( linked_class ) } }
|
436
|
+
end
|
437
|
+
create_properties( o_class ){ js }
|
438
|
+
|
439
|
+
end
|
440
|
+
## -----------------------------------------------------------------------------------------
|
441
|
+
##
|
442
|
+
## Properties
|
443
|
+
##
|
444
|
+
## create_properties
|
445
|
+
## get_class_properties
|
446
|
+
## delete_properties
|
447
|
+
##
|
448
|
+
## -----------------------------------------------------------------------------------------
|
449
|
+
=begin
|
450
|
+
|
451
|
+
creates properties which are defined as json in the provided block as
|
452
|
+
create_properties( classname or class ) do
|
453
|
+
{ symbol: { propertyType: 'STRING' },
|
454
|
+
con_id: { propertyType: 'INTEGER' } ,
|
455
|
+
details: { propertyType: 'LINK', linkedClass: 'Contracts' }
|
456
|
+
}
|
457
|
+
|
458
|
+
=end
|
459
|
+
def create_properties o_class
|
460
|
+
|
461
|
+
begin
|
462
|
+
all_properties_in_a_hash = yield
|
463
|
+
if all_properties_in_a_hash.is_a? Hash
|
464
|
+
response = @res[ property_uri(class_name(o_class)) ].post all_properties_in_a_hash.to_json
|
465
|
+
if response.code == 201
|
466
|
+
response.body.to_i
|
467
|
+
else
|
468
|
+
0
|
469
|
+
end
|
470
|
+
end
|
471
|
+
rescue RestClient::InternalServerError => e
|
472
|
+
response = JSON.parse( e.response)['errors'].pop
|
473
|
+
error_message = response['content'].split(':').last
|
474
|
+
# if error_message ~= /Missing linked class/
|
475
|
+
logger.progname= 'OrientDB#CreateProperty'
|
476
|
+
logger.error { "Properties in #{class_name(o_class)} were NOT created" }
|
477
|
+
logger.error { "Error-code #{response['code']} --> #{response['content'].split(':').last }" }
|
478
|
+
nil
|
479
|
+
end
|
480
|
+
|
481
|
+
end
|
482
|
+
|
483
|
+
def delete_property o_class, field
|
484
|
+
logger.progname = 'OrientDB#DeleteProperty'
|
485
|
+
begin
|
486
|
+
response = @res[property_uri( class_name(o_class)){ field } ].delete
|
487
|
+
true if response.code == 204
|
488
|
+
rescue RestClient::InternalServerError => e
|
489
|
+
logger.error{ "Property #{ field } in class #{ class_name(o_class) } NOT deleted" }
|
490
|
+
false
|
491
|
+
end
|
492
|
+
|
493
|
+
end
|
494
|
+
|
495
|
+
def get_class_properties o_class # :nodoc:
|
496
|
+
JSON.parse( @res[ class_uri{ class_name(o_class) } ].get )
|
497
|
+
end
|
498
|
+
|
499
|
+
def print_class_properties o_class
|
500
|
+
puts "Detected Properties for class #{class_name(o_class)}"
|
501
|
+
|
502
|
+
rp = get_class_properties o_class
|
503
|
+
n= rp['name']
|
504
|
+
puts rp['properties'].map{|x| [ n+'.'+x['name'], x['type'],x['linkedClass'] ].compact.join(' -> ' )}.join("\n")
|
505
|
+
|
506
|
+
end
|
507
|
+
#
|
508
|
+
## -----------------------------------------------------------------------------------------
|
509
|
+
##
|
510
|
+
## Documents
|
511
|
+
##
|
512
|
+
## create_document get_document delete_document
|
513
|
+
## update_or_create_document patch_document
|
514
|
+
##
|
515
|
+
##
|
516
|
+
## get_documents
|
517
|
+
## update_documents
|
518
|
+
## delete_documents
|
519
|
+
## update_or_create_documents
|
520
|
+
## -----------------------------------------------------------------------------------------
|
521
|
+
|
522
|
+
=begin #nodoc#
|
523
|
+
If properties are allocated on class-level, they can be preinitialized using
|
524
|
+
this method.
|
525
|
+
This is disabled for now, because it does not seem nessesary
|
526
|
+
|
527
|
+
=end
|
528
|
+
def preallocate_class_properties o_class
|
529
|
+
p= get_class_properties( o_class )['properties']
|
530
|
+
unless p.nil? || p.blank?
|
531
|
+
predefined_attributes = p.map do | property |
|
532
|
+
[ property['name'] ,
|
533
|
+
case property['type']
|
534
|
+
when 'LINKMAP'
|
535
|
+
Array.new
|
536
|
+
when 'STRING'
|
537
|
+
''
|
538
|
+
else
|
539
|
+
nil
|
540
|
+
end ]
|
541
|
+
end.to_h
|
542
|
+
else
|
543
|
+
{}
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
=begin
|
548
|
+
Creates an Object in the Database and returns this as ActuveOrient::Model-Instance
|
549
|
+
=end
|
550
|
+
|
551
|
+
def create_document o_class, attributes: {}
|
552
|
+
attributes = yield if attributes.empty? && block_given?
|
553
|
+
# preallocated_attributes = preallocate_class_properties o_class
|
554
|
+
# puts "preallocated_attributes: #{o_class} -->#{preallocated_attributes.inspect }"
|
555
|
+
post_argument = { '@class' => class_name(o_class) }.merge(attributes).to_orient
|
556
|
+
# puts "post_argument: #{post_argument.inspect}"
|
557
|
+
|
558
|
+
response = @res[ document_uri ].post post_argument.to_json
|
559
|
+
data= JSON.parse( response.body )
|
560
|
+
# data = preallocated_attributes.merge data
|
561
|
+
ActiveOrient::Model.orientdb_class( name: data['@class']).new data
|
562
|
+
# o_class.new JSON.parse( response.body)
|
563
|
+
end
|
564
|
+
|
565
|
+
|
566
|
+
def delete_document record_id
|
567
|
+
logger.progname = 'OrientDB#DeleteDocument'
|
568
|
+
begin
|
569
|
+
response = @res[document_uri{ record_id } ].delete
|
570
|
+
true if response.code == 204
|
571
|
+
rescue RestClient::InternalServerError => e
|
572
|
+
logger.error{ "Document #{ record_id } NOT deleted" }
|
573
|
+
false
|
574
|
+
end
|
575
|
+
|
576
|
+
end
|
577
|
+
=begin
|
578
|
+
retrieves documents from a query
|
579
|
+
|
580
|
+
If raw is specified, the JSON-Array is returned, eg
|
581
|
+
{ "@type"=>"d",
|
582
|
+
"@rid"=>"#15:1",
|
583
|
+
"@version"=>1,
|
584
|
+
"@class"=>"DocumebntKlasse10",
|
585
|
+
"con_id"=>343,
|
586
|
+
"symbol"=>"EWTZ"
|
587
|
+
}
|
588
|
+
otherwise a ActiveModel-Instance of o_class is created and returned
|
589
|
+
=end
|
590
|
+
def get_documents limit: -1, raw: false, query: nil, **args
|
591
|
+
query = OrientSupport::OrientQuery.new( args ) if query.nil?
|
592
|
+
i=0
|
593
|
+
begin
|
594
|
+
url = query_sql_uri << query.compose << "/#{limit}"
|
595
|
+
response = @res[URI.encode(url) ].get
|
596
|
+
r=JSON.parse( response.body )['result'].map do |document |
|
597
|
+
if raw
|
598
|
+
document
|
599
|
+
else
|
600
|
+
ActiveOrient::Model.orientdb_class( name: document['@class']).new document
|
601
|
+
end
|
602
|
+
end
|
603
|
+
rescue RestClient::InternalServerError => e
|
604
|
+
response = JSON.parse( e.response)['errors'].pop
|
605
|
+
logger.error { response['content'].split(':').last }
|
606
|
+
i=i+1
|
607
|
+
if i > 1
|
608
|
+
raise
|
609
|
+
else
|
610
|
+
query.dataset_name = query.datatset_name.underscore
|
611
|
+
logger.info { "trying to query using #{o_class}" }
|
612
|
+
retry
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
end
|
617
|
+
|
618
|
+
def count_documents **args
|
619
|
+
logger.progname = 'OrientDB#count_documents'
|
620
|
+
|
621
|
+
query = OrientSupport::OrientQuery.new args
|
622
|
+
query.projection 'COUNT (*)'
|
623
|
+
result = get_documents raw: true, query: query
|
624
|
+
|
625
|
+
result.first['COUNT']
|
626
|
+
|
627
|
+
end
|
628
|
+
|
629
|
+
=begin
|
630
|
+
Inserts a Document with the attributes provided in the attributes-hash
|
631
|
+
eg
|
632
|
+
create_document class_name: @classname, attributes: { con_id: 343, symbol: 'EWTZ' }
|
633
|
+
|
634
|
+
untested: for hybrid and schema-less documents the following syntax is supported
|
635
|
+
create_document class_name: "Account",
|
636
|
+
attributes: { date: 1350426789, amount: 100.34,
|
637
|
+
"@fieldTypes" => "date=t,amount=c" }
|
638
|
+
|
639
|
+
The supported special types are:
|
640
|
+
n
|
641
|
+
'f' for float
|
642
|
+
'c' for decimal
|
643
|
+
'l' for long
|
644
|
+
'd' for double
|
645
|
+
'b' for byte and binary
|
646
|
+
'a' for date
|
647
|
+
't' for datetime
|
648
|
+
's' for short
|
649
|
+
'e' for Set, because arrays and List are serialized as arrays like [3,4,5]
|
650
|
+
'x' for links
|
651
|
+
'n' for linksets
|
652
|
+
'z' for linklist
|
653
|
+
'm' for linkmap
|
654
|
+
'g' for linkbag
|
655
|
+
|
656
|
+
=end
|
657
|
+
=begin
|
658
|
+
Creating a new Database-Entry ( where is omitted )
|
659
|
+
|
660
|
+
otherwise updating the Database-Entry (if present)
|
661
|
+
|
662
|
+
The optional Block should provide a hash with attributes(properties). These are used if
|
663
|
+
a new dataset is created.
|
664
|
+
=end
|
665
|
+
def create_or_update_document o_class , **args, &b
|
666
|
+
logger.progname = 'Rest#CreateOrUpdateDocument'
|
667
|
+
r= update_or_create_documents o_class, **args, &b
|
668
|
+
if r.size > 1
|
669
|
+
logger.error { "multible documents updated by #{ generate_sql_list( where )}" }
|
670
|
+
end
|
671
|
+
r.first # return_value
|
672
|
+
end
|
673
|
+
=begin
|
674
|
+
Based on the query specified in :where records are updated according to :set
|
675
|
+
|
676
|
+
Returns an Array of updated documents
|
677
|
+
|
678
|
+
The optional Block should provide a hash with attributes(properties). These are used if
|
679
|
+
a new dataset is created.
|
680
|
+
|
681
|
+
### das ist noch nicht rund.
|
682
|
+
#
|
683
|
+
=end
|
684
|
+
def update_or_create_documents o_class , set: {}, where: {} , **args , &b
|
685
|
+
logger.progname = 'Rest#UpdateOrCreateDocuments'
|
686
|
+
if where.blank?
|
687
|
+
[ create_document( o_class, attributes: set ) ]
|
688
|
+
else
|
689
|
+
set.extract!( where.keys ) # removes any keys from where in set
|
690
|
+
possible_documents = get_documents from: class_name( o_class ), where: where, **args
|
691
|
+
if possible_documents.empty?
|
692
|
+
if block_given?
|
693
|
+
more_where = yield # do Preparations prior to the creation of the dataset
|
694
|
+
# if the block returns a Hash , it is merged into the insert_query.
|
695
|
+
where.merge! more_where if more_where.is_a?(Hash)
|
696
|
+
end
|
697
|
+
[ create_document( o_class, attributes: set.merge(where) ) ]
|
698
|
+
else
|
699
|
+
possible_documents.map{| doc | doc.update( set: set ) }
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
=begin
|
704
|
+
Deletes documents.
|
705
|
+
They are defined by a query. All records which match the attributes are deleted.
|
706
|
+
An Array with freed index-values is returned
|
707
|
+
=end
|
708
|
+
def delete_documents o_class, where: {}
|
709
|
+
get_documents( from: o_class, where: where).map do |doc|
|
710
|
+
if doc['@type']=='d' # document
|
711
|
+
index = doc['@rid'][1,doc['@rid'].size] # omit the first character ('#')
|
712
|
+
r=@res[ document_uri{ index }].delete
|
713
|
+
index if r.code==204 && r.body.empty? # return_value
|
714
|
+
end
|
715
|
+
|
716
|
+
end
|
717
|
+
|
718
|
+
end
|
719
|
+
=begin
|
720
|
+
Retrieves a Document from the Database as ActiveOrient::Model::{class}
|
721
|
+
The argument can either be a rid (#[x}:{y}) or a link({x}:{y})
|
722
|
+
If no Document is found, nil is returned
|
723
|
+
|
724
|
+
In the optional block, a subset of properties can be defined (as array of names)
|
725
|
+
=end
|
726
|
+
def get_document rid
|
727
|
+
|
728
|
+
rid = rid[1 .. rid.length] if rid[0]=='#'
|
729
|
+
|
730
|
+
response = @res[ document_uri { rid } ].get
|
731
|
+
|
732
|
+
raw_data = JSON.parse( response.body) #.merge( "#no_links" => "#no_links" )
|
733
|
+
ActiveOrient::Model.orientdb_class( name: raw_data['@class']).new raw_data
|
734
|
+
|
735
|
+
rescue RestClient::InternalServerError => e
|
736
|
+
if e.http_body.split(':').last =~ /was not found|does not exist in database/
|
737
|
+
nil
|
738
|
+
else
|
739
|
+
logger.progname 'OrientDB#GetDocument'
|
740
|
+
logger.error "something went wrong"
|
741
|
+
logger.error e.http_body.inspect
|
742
|
+
raise
|
743
|
+
end
|
744
|
+
end
|
745
|
+
=begin
|
746
|
+
Lazy Updating of the given Document.
|
747
|
+
=end
|
748
|
+
def patch_document rid
|
749
|
+
logger.progname = 'Rest#PatchDocument'
|
750
|
+
content = yield
|
751
|
+
if content.is_a? Hash
|
752
|
+
content.each do | key, value |
|
753
|
+
# puts "content: #{key}, #{value.class}"
|
754
|
+
# content[key]= value.to_orient #if value.is_a? ActiveOrient::Model
|
755
|
+
end
|
756
|
+
@res[ document_uri { rid } ].patch content.to_orient.to_json
|
757
|
+
else
|
758
|
+
logger.error { "FAILED: The Block must provide an Hash with properties to be updated"}
|
759
|
+
end
|
760
|
+
end
|
761
|
+
=begin
|
762
|
+
update_documents classname,
|
763
|
+
set: { :symbol => 'TWR' },
|
764
|
+
where: { con_id: 340 }
|
765
|
+
|
766
|
+
replaces the symbol to TWR in each record where the con_id is 340
|
767
|
+
Both set and where take multible attributes
|
768
|
+
returns the JSON-Response.
|
769
|
+
|
770
|
+
=end
|
771
|
+
|
772
|
+
|
773
|
+
def update_documents o_class, set: , where: {}
|
774
|
+
url = "update #{class_name(o_class)} set "<< generate_sql_list(set) << compose_where(where)
|
775
|
+
response = @res[ URI.encode( command_sql_uri << url) ].post '' #url.to_json
|
776
|
+
end
|
777
|
+
|
778
|
+
## -----------------------------------------------------------------------------------------
|
779
|
+
##
|
780
|
+
## Functions and Batch
|
781
|
+
##
|
782
|
+
##
|
783
|
+
## -----------------------------------------------------------------------------------------
|
784
|
+
|
785
|
+
=begin
|
786
|
+
Execute a predefined Function
|
787
|
+
=end
|
788
|
+
def call_function *args
|
789
|
+
#puts "uri:#{function_uri { args.join('/') } }"
|
790
|
+
@res[ function_uri { args.join('/') } ].post ''
|
791
|
+
rescue RestClient::InternalServerError => e
|
792
|
+
puts JSON.parse(e.http_body)
|
793
|
+
end
|
794
|
+
|
795
|
+
|
796
|
+
=begin
|
797
|
+
Executes a list of commands and returns the result-array (if present)
|
798
|
+
|
799
|
+
structure of the provided block:
|
800
|
+
[{ type: "cmd",
|
801
|
+
language: "sql",
|
802
|
+
command: "create class Person extends V"
|
803
|
+
},
|
804
|
+
(...)
|
805
|
+
]
|
806
|
+
|
807
|
+
It's used by ActiveOrient::Query.execute_queries
|
808
|
+
|
809
|
+
=end
|
810
|
+
def execute classname = 'Myquery', transaction: true
|
811
|
+
batch = { transaction: transaction, operations: yield }
|
812
|
+
unless batch[:operations].blank?
|
813
|
+
# puts "batch_uri: #{@res[batch_uri]}"
|
814
|
+
# puts "post: #{batch.to_json}"
|
815
|
+
response = @res[ batch_uri ].post batch.to_json
|
816
|
+
if response.code == 200
|
817
|
+
if response.body['result'].present?
|
818
|
+
result= JSON.parse(response.body)['result']
|
819
|
+
result.map do |x|
|
820
|
+
if x.is_a? Hash
|
821
|
+
if x.has_key?('@class')
|
822
|
+
ActiveOrient::Model.orientdb_class( name: x['@class']).new x
|
823
|
+
elsif x.has_key?( 'value' )
|
824
|
+
x['value']
|
825
|
+
else
|
826
|
+
# puts "ActiveOrient::Execute"
|
827
|
+
# puts "o_class: #{o_class.inspect}"
|
828
|
+
ActiveOrient::Model.orientdb_class( name: classname).new x
|
829
|
+
end
|
830
|
+
end
|
831
|
+
end.compact # return_value
|
832
|
+
|
833
|
+
else
|
834
|
+
response.body
|
835
|
+
end
|
836
|
+
else
|
837
|
+
nil
|
838
|
+
end
|
839
|
+
end
|
840
|
+
rescue RestClient::InternalServerError => e
|
841
|
+
raise
|
842
|
+
|
843
|
+
end
|
844
|
+
=begin
|
845
|
+
Converts a given name to the camelized database-classname
|
846
|
+
|
847
|
+
Converts a given class-constant to the corresponding database-classname
|
848
|
+
|
849
|
+
returns a valid database-class name, nil if the class not exists
|
850
|
+
=end
|
851
|
+
def class_name name_or_class
|
852
|
+
name= if name_or_class.is_a? Class
|
853
|
+
name_or_class.to_s.split('::').last
|
854
|
+
elsif name_or_class.is_a? ActiveOrient::Model
|
855
|
+
name_or_class.classname
|
856
|
+
else
|
857
|
+
name_or_class.to_s.camelize
|
858
|
+
end
|
859
|
+
if database_classes.include?(name)
|
860
|
+
name
|
861
|
+
elsif database_classes.include?(name.underscore)
|
862
|
+
name.underscore
|
863
|
+
else
|
864
|
+
logger.progname = 'OrientDB#ClassName'
|
865
|
+
logger.info{ "Classname #{name} not present in active Database" }
|
866
|
+
nil
|
867
|
+
end
|
868
|
+
end
|
869
|
+
# def compose_where arg
|
870
|
+
# if arg.blank?
|
871
|
+
# ""
|
872
|
+
# elsif arg.is_a? String
|
873
|
+
# if arg =~ /[w|W]here/
|
874
|
+
# arg
|
875
|
+
# else
|
876
|
+
# "where "+arg
|
877
|
+
# end
|
878
|
+
# elsif arg.is_a? Hash
|
879
|
+
# " where " + generate_sql_list(arg)
|
880
|
+
# end
|
881
|
+
# end
|
882
|
+
private
|
883
|
+
|
884
|
+
#def generate_sql_list attributes={}
|
885
|
+
# attributes.map do | key, value |
|
886
|
+
# case value
|
887
|
+
# when Numeric
|
888
|
+
# key.to_s << " = " << value.to_s
|
889
|
+
# else # String, Symbol
|
890
|
+
# key.to_s << ' = ' << "\'#{ value }\'"
|
891
|
+
# # else
|
892
|
+
# # puts "ERROR, value-> #{value}, class -> #{value.class}"
|
893
|
+
# end
|
894
|
+
# end.join( ' and ' )
|
895
|
+
#
|
896
|
+
#end
|
897
|
+
#
|
898
|
+
def property_uri(this_class_name)
|
899
|
+
if block_given?
|
900
|
+
"property/#{ @database }/#{this_class_name}/" << yield
|
901
|
+
else
|
902
|
+
"property/#{ @database }/#{this_class_name}"
|
903
|
+
end
|
904
|
+
end
|
905
|
+
# called in the beginning or after a 404-Error
|
906
|
+
def get_ressource
|
907
|
+
read_yml = ->( key ){ YAML::load_file( File.expand_path('../../config/connect.yml',__FILE__))[:orientdb][key] }
|
908
|
+
login = read_yml[ :admin ].values
|
909
|
+
server_adress = read_yml[ :server ] + ":" + read_yml[ :port ].to_s
|
910
|
+
RestClient::Resource.new('http://' << server_adress, *login )
|
911
|
+
end
|
912
|
+
|
913
|
+
def self.simple_uri *names
|
914
|
+
names.each do | name |
|
915
|
+
m_name = (name.to_s << '_uri').to_sym
|
916
|
+
define_method( m_name ) do | &b |
|
917
|
+
if b
|
918
|
+
"#{name.to_s}/"<< @database << "/" << b.call
|
919
|
+
else
|
920
|
+
"#{name.to_s}/"<< @database
|
921
|
+
end # branch
|
922
|
+
end # def
|
923
|
+
end
|
924
|
+
end
|
925
|
+
|
926
|
+
def self.sql_uri *names
|
927
|
+
names.each do | name |
|
928
|
+
define_method ((name.to_s << '_sql_uri').to_sym) do
|
929
|
+
"#{name.to_s}/" << @database << "/sql/"
|
930
|
+
end
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
simple_uri :database, :document, :class, :batch, :function
|
935
|
+
sql_uri :command , :query
|
936
|
+
|
937
|
+
|
938
|
+
|
939
|
+
end # class
|
940
|
+
end # module
|
941
|
+
__END__
|
942
|
+
|