active-orient 0.4 → 0.5
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/.gitignore +1 -0
- data/Gemfile +8 -3
- data/Guardfile +12 -4
- data/README.md +221 -201
- data/VERSION +1 -1
- data/active-orient.gemspec +3 -2
- data/bin/active-orient-console +35 -0
- data/config/boot.rb +84 -16
- data/config/config.yml +10 -0
- data/config/connect.yml +6 -2
- data/create_project +19 -0
- data/examples/books.rb +86 -39
- data/examples/createTime.rb +91 -0
- data/examples/streets.rb +85 -84
- data/examples/test_commands.rb +92 -0
- data/examples/test_commands_2.rb +54 -0
- data/examples/test_commands_3.rb +48 -0
- data/examples/test_commands_4.rb +28 -0
- data/examples/time_graph/Gemfile +21 -0
- data/examples/time_graph/Guardfile +26 -0
- data/examples/time_graph/README.md +129 -0
- data/examples/time_graph/bin/active-orient-console +35 -0
- data/examples/time_graph/config/boot.rb +119 -0
- data/examples/time_graph/config/config.yml +8 -0
- data/examples/time_graph/config/connect.yml +17 -0
- data/examples/time_graph/config/init_db.rb +59 -0
- data/examples/time_graph/createTime.rb +51 -0
- data/examples/time_graph/lib/createTime.rb +82 -0
- data/examples/time_graph/model/day_of.rb +3 -0
- data/examples/time_graph/model/e.rb +6 -0
- data/examples/time_graph/model/edge.rb +53 -0
- data/examples/time_graph/model/monat.rb +19 -0
- data/examples/time_graph/model/stunde.rb +16 -0
- data/examples/time_graph/model/tag.rb +29 -0
- data/examples/time_graph/model/time_base.rb +6 -0
- data/examples/time_graph/model/time_of.rb +4 -0
- data/examples/time_graph/model/v.rb +3 -0
- data/examples/time_graph/model/vertex.rb +32 -0
- data/examples/time_graph/spec/lib/create_time_spec.rb +50 -0
- data/examples/time_graph/spec/rest_helper.rb +37 -0
- data/examples/time_graph/spec/spec_helper.rb +46 -0
- data/lib/active-orient.rb +56 -6
- data/lib/base.rb +149 -147
- data/lib/base_properties.rb +40 -41
- data/lib/class_utils.rb +301 -0
- data/lib/database_utils.rb +97 -0
- data/lib/init.rb +35 -0
- data/lib/java-api.rb +437 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/edge.rb +53 -0
- data/lib/model/model.rb +77 -0
- data/lib/model/the_class.rb +480 -0
- data/lib/model/the_record.rb +310 -0
- data/lib/model/vertex.rb +32 -0
- data/lib/orient.rb +113 -50
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +280 -0
- data/lib/query.rb +71 -73
- data/lib/rest/change.rb +124 -0
- data/lib/rest/create.rb +474 -0
- data/lib/rest/delete.rb +133 -0
- data/lib/rest/operations.rb +150 -0
- data/lib/rest/read.rb +150 -0
- data/lib/rest/rest.rb +111 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support.rb +387 -296
- data/old_lib_functions/two_general_class.rb +139 -0
- data/usecase.md +49 -36
- data/usecase_oo.md +59 -0
- metadata +73 -9
- data/lib/model.rb +0 -461
- data/lib/rest.rb +0 -1036
- data/test.rb +0 -4
data/lib/rest/change.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module RestChange
|
2
|
+
|
3
|
+
############### DATABASE ####################
|
4
|
+
|
5
|
+
# Changes the working-database to {name}
|
6
|
+
|
7
|
+
def change_database name
|
8
|
+
@classes = []
|
9
|
+
@database = name
|
10
|
+
ActiveOrient.database = name
|
11
|
+
end
|
12
|
+
|
13
|
+
############# OBJECTS #################
|
14
|
+
|
15
|
+
=begin
|
16
|
+
Convient update of the dataset by calling sql-patch
|
17
|
+
|
18
|
+
The argument record can be specified as ActiveOrient::Model-instance or as rid-string( #0:0 )
|
19
|
+
|
20
|
+
called from ModelRecord#update
|
21
|
+
|
22
|
+
if the update was successful, the updated ActiveOrient::Model-record is returned.
|
23
|
+
=end
|
24
|
+
|
25
|
+
def update record, attributes , version=0 # :nodoc:
|
26
|
+
r = if record.is_a?(String) && record.rid?
|
27
|
+
ActiveOrient::Model.autoload record
|
28
|
+
else
|
29
|
+
record
|
30
|
+
end
|
31
|
+
return(false) unless r.is_a?(ActiveOrient::Model)
|
32
|
+
version = r.version if version.zero?
|
33
|
+
result = patch_record(r.rid) do
|
34
|
+
attributes.merge({'@version' => version, '@class' => r.class.ref_name })
|
35
|
+
end
|
36
|
+
# returns a new instance of ActiveOrient::Model and updates any reference on rid
|
37
|
+
# if the patch is not successfull no string is returned and thus no record is fetched
|
38
|
+
# puts JSON.parse(result) if result.is_a?(String)
|
39
|
+
ActiveOrient::Model.orientdb_class(name: r.class.ref_name, superclass: :find_ME ).new(JSON.parse(result)) if result.is_a?(String)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
=begin
|
44
|
+
Example:
|
45
|
+
ORD.update_documents classname, set: {:symbol => 'TWR'}, where: {con_id: 340}
|
46
|
+
|
47
|
+
Replaces the symbol to TWR in each record where the con_id is 340
|
48
|
+
|
49
|
+
Both set and where take multiple attributes
|
50
|
+
|
51
|
+
Returns the JSON-Response.
|
52
|
+
=end
|
53
|
+
|
54
|
+
def update_records o_class, set:, where: {}
|
55
|
+
url = "UPDATE #{classname(o_class)} SET #{generate_sql_list(set)} #{compose_where(where)}"
|
56
|
+
response = @res[URI.encode("/command/#{ActiveOrient.database}/sql/" << url)].post ''
|
57
|
+
end
|
58
|
+
alias update_documents update_records
|
59
|
+
|
60
|
+
# Lazy Updating of the given Record.
|
61
|
+
|
62
|
+
def patch_record rid # :nodoc: (used by Model#update )
|
63
|
+
logger.progname = 'RestChange#PatchRecord'
|
64
|
+
content = yield
|
65
|
+
if content.is_a? Hash
|
66
|
+
begin
|
67
|
+
@res["/document/#{ActiveOrient.database}/#{rid}"].patch content.to_orient.to_json
|
68
|
+
rescue Exception => e
|
69
|
+
logger.error{e.message}
|
70
|
+
end
|
71
|
+
else
|
72
|
+
logger.error{"FAILED: The Block must provide an Hash with properties to be updated"}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
alias patch_document patch_record
|
76
|
+
|
77
|
+
|
78
|
+
#### EXPERIMENTAL ##########
|
79
|
+
|
80
|
+
=begin
|
81
|
+
Used to add restriction or other properties to the Property of a Class.
|
82
|
+
See http://orientdb.com/docs/2.1/SQL-Alter-Property.html
|
83
|
+
=end
|
84
|
+
|
85
|
+
def alter_property o_class, property:, attribute: "DEFAULT", alteration: # :nodoc: because untested
|
86
|
+
logger.progname = 'RestChange#AlterProperty'
|
87
|
+
begin
|
88
|
+
attribute.to_s! unless attribute.is_a? String
|
89
|
+
attribute.capitalize_first_letter
|
90
|
+
case attribute
|
91
|
+
when "LINKEDCLASS", "LINKEDTYPE", "NAME", "REGEX", "TYPE", "REGEX", "COLLATE", "CUSTOM"
|
92
|
+
unless alteration.is_a? String
|
93
|
+
logger.error{"#{alteration} should be a String."}
|
94
|
+
return 0
|
95
|
+
end
|
96
|
+
when "MIN", "MAX"
|
97
|
+
unless alteration.is_a? Integer
|
98
|
+
logger.error{"#{alteration} should be an Integer."}
|
99
|
+
return 0
|
100
|
+
end
|
101
|
+
when "MANDATORY", "NOTNULL", "READONLY"
|
102
|
+
unless alteration.is_a? TrueClass or alteration.is_a? FalseClass
|
103
|
+
logger.error{"#{alteration} should be an Integer."}
|
104
|
+
return 0
|
105
|
+
end
|
106
|
+
when "DEFAULT"
|
107
|
+
else
|
108
|
+
logger.error{"Wrong attribute."}
|
109
|
+
return 0
|
110
|
+
end
|
111
|
+
|
112
|
+
name_class = classname(o_class)
|
113
|
+
execute name_class, transaction: false do # To execute commands
|
114
|
+
[{ type: "cmd",
|
115
|
+
language: 'sql',
|
116
|
+
command: "ALTER PROPERTY #{name_class}.#{property} #{attribute} #{alteration}"}]
|
117
|
+
end
|
118
|
+
rescue Exception => e
|
119
|
+
logger.error{e.message}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
end
|
data/lib/rest/create.rb
ADDED
@@ -0,0 +1,474 @@
|
|
1
|
+
module RestCreate
|
2
|
+
|
3
|
+
######### DATABASE ##########
|
4
|
+
|
5
|
+
=begin
|
6
|
+
Creates a database with the given name and switches to this database as working-database. Types are either 'plocal' or 'memory'
|
7
|
+
|
8
|
+
Returns the name of the working-database
|
9
|
+
=end
|
10
|
+
|
11
|
+
def create_database type: 'plocal', database: nil
|
12
|
+
logger.progname = 'RestCreate#CreateDatabase'
|
13
|
+
old_d = ActiveOrient.database
|
14
|
+
ActiveOrient.database_classes = []
|
15
|
+
ActiveOrient.database = database if database.present?
|
16
|
+
begin
|
17
|
+
response = @res["database/#{ActiveOrient.database}/#{type}"].post ""
|
18
|
+
if response.code == 200
|
19
|
+
logger.info{"Database #{ActiveOrient.database} successfully created and stored as working database"}
|
20
|
+
else
|
21
|
+
ActiveOrient.database = old_d
|
22
|
+
logger.error{"Database #{name} was NOT created. Working Database is still #{ActiveOrient.database}"}
|
23
|
+
end
|
24
|
+
rescue RestClient::InternalServerError => e
|
25
|
+
ActiveOrient.database = old_d
|
26
|
+
logger.error{"Database #{name} was NOT created. Working Database is still #{ActiveOrient.database}"}
|
27
|
+
end
|
28
|
+
ActiveOrient.database
|
29
|
+
end
|
30
|
+
|
31
|
+
######### CLASS ##########
|
32
|
+
=begin
|
33
|
+
Creates classes and class-hierarchies in OrientDB and in Ruby.
|
34
|
+
Takes a String, Array or Hash as argument and returns a (nested) Array of
|
35
|
+
successfull allocated Ruby-Classes.
|
36
|
+
If a block is provided, this is used to allocate the class to this superclass.
|
37
|
+
|
38
|
+
Examples
|
39
|
+
|
40
|
+
create_class "a_single_class"
|
41
|
+
create_class :a_single_class
|
42
|
+
create_class( :a_single_class ){ :a_super_class }
|
43
|
+
create_class( :a_single_class ){ superclass: :a_super_class, abstract: true }
|
44
|
+
create_class( ["c",:l,:A,:SS] ){ :V } --> vertices
|
45
|
+
create_class( ["c",:l,:A,:SS] ){ superclass: :V, abstract: true } --> abstract vertices
|
46
|
+
create_class( { V: [ :A, :B, C: [:c1,:c3,:c2] ], E: [:has_content, :becomes_hot ]} )
|
47
|
+
=end
|
48
|
+
|
49
|
+
|
50
|
+
=begin
|
51
|
+
General method to create database classes
|
52
|
+
|
53
|
+
Accepts
|
54
|
+
* a string or symbol
|
55
|
+
|
56
|
+
creates a single class and returns the ActiveOrient::Model-Class
|
57
|
+
* an arrray of strings or symbols
|
58
|
+
|
59
|
+
creates alltogether and returns an array of created ActiveOrient::Model-Classes
|
60
|
+
* a (nested) Hash
|
61
|
+
|
62
|
+
then creates a hierarchy of database-classes and returns them as hash
|
63
|
+
|
64
|
+
takes an optional block to specify a superclass. This class MUST exist.
|
65
|
+
|
66
|
+
|
67
|
+
eg.
|
68
|
+
create_classes( :test ){ :V }
|
69
|
+
|
70
|
+
creates a vertex-class, returns just Test ( < ActiveOrient::Model)
|
71
|
+
|
72
|
+
a,b,c = create_classes( :test1, :test2, test3 ) { :V }
|
73
|
+
|
74
|
+
creates three vertex-classes and assigns them to var's a,b, and c
|
75
|
+
|
76
|
+
create_classes( test: [:test1, :test2, test3] ) { :V }
|
77
|
+
|
78
|
+
creates a vertex-class Test and three clild-classes
|
79
|
+
|
80
|
+
create_classes( :V => :test)
|
81
|
+
|
82
|
+
creates a vertex-class, too, returns the Hash
|
83
|
+
|
84
|
+
#todo
|
85
|
+
#check if a similar classname already exists --> Contract == contract == conTract
|
86
|
+
#and assign to this existing one.
|
87
|
+
=end
|
88
|
+
def create_classes *classes, &b
|
89
|
+
returt if classes.empty?
|
90
|
+
|
91
|
+
classes = classes.pop if classes.size == 1
|
92
|
+
consts = allocate_classes_in_ruby( classes , &b )
|
93
|
+
all_classes = consts.is_a?( Array) ? consts.flatten : [consts]
|
94
|
+
dc = database_classes(requery: true)
|
95
|
+
selected_classes = all_classes.map do | this_class |
|
96
|
+
this_class unless dc.include?( this_class.ref_name ) rescue nil
|
97
|
+
end.compact.uniq
|
98
|
+
|
99
|
+
command= selected_classes.map do | database_class |
|
100
|
+
## improper initialized ActiveOrient::Model-classes lack a ref_name class-variable
|
101
|
+
if database_class.ref_name.blank?
|
102
|
+
logger.error{ "Improper initialized ActiveOrient::Model #{database_class}" }
|
103
|
+
raise ArgumentError
|
104
|
+
end
|
105
|
+
database_class.require_model_file
|
106
|
+
c = if database_class.superclass == ActiveOrient::Model || database_class.superclass.ref_name.blank?
|
107
|
+
"CREATE CLASS #{database_class.ref_name}"
|
108
|
+
else
|
109
|
+
"CREATE CLASS #{database_class.ref_name} EXTENDS #{database_class.superclass.ref_name}"
|
110
|
+
end
|
111
|
+
c << " ABSTRACT" if database_class.abstract
|
112
|
+
{ type: "cmd", language: 'sql', command: c } # return value 4 command
|
113
|
+
end
|
114
|
+
# execute anything as batch, don't roll back in case of an error
|
115
|
+
|
116
|
+
execute transaction: false, tolerated_error_code: /already exists in current database/ do
|
117
|
+
command
|
118
|
+
end
|
119
|
+
# update the internal class hierarchy
|
120
|
+
database_classes requery: true
|
121
|
+
# return all allocated classes, no matter whether they had to be created in the DB or not.
|
122
|
+
# keep the format of the input-parameter
|
123
|
+
#consts.shift if block_given? && consts.is_a?( Array) # remove the first element
|
124
|
+
# remove traces of superclass-allocations
|
125
|
+
if classes.is_a? Hash
|
126
|
+
consts = Hash[ consts ]
|
127
|
+
consts.each_key{ |x| consts[x].delete_if{|y| y == x} if consts[x].is_a? Array }
|
128
|
+
end
|
129
|
+
consts
|
130
|
+
|
131
|
+
rescue ArgumentError => e
|
132
|
+
logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# create_general_class singleclass, behaviour: behaviour, extended_class: extended_class, properties: properties
|
137
|
+
|
138
|
+
# when Hash
|
139
|
+
# classes.keys.each do |superclass|
|
140
|
+
# create_general_class superclass, behaviour: "SUPERCLASS", extended_class: nil, properties: nil
|
141
|
+
# create_general_class classes[superclass], behaviour: "EXTENDEDCLASS", extended_class: superclass, properties: properties
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# else
|
145
|
+
# name_class = classes.to_s.capitalize_first_letter
|
146
|
+
# unless @classes.downcase.include?(name_class.downcase)
|
147
|
+
#
|
148
|
+
# if behaviour == "NORMALCLASS"
|
149
|
+
# command = "CREATE CLASS #{name_class}"
|
150
|
+
# elsif behaviour == "SUPERCLASS"
|
151
|
+
# command = "CREATE CLASS #{name_class} ABSTRACT"
|
152
|
+
# elsif behaviour == "EXTENDEDCLASS"
|
153
|
+
# name_superclass = extended_class.to_s
|
154
|
+
# command = "CREATE CLASS #{name_class} EXTENDS #{name_superclass}"
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# #print "\n #{command} \n"
|
158
|
+
#
|
159
|
+
# execute transaction: false do
|
160
|
+
# [{ type: "cmd",
|
161
|
+
# language: "sql",
|
162
|
+
# command: command}]
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# @classes << name_class
|
166
|
+
#
|
167
|
+
# # Add properties
|
168
|
+
# unless properties.nil?
|
169
|
+
# create_properties name_class, properties
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
#
|
173
|
+
# consts << ActiveOrient::Model.orientdb_class(name: name_class)
|
174
|
+
# end
|
175
|
+
|
176
|
+
# return consts
|
177
|
+
#
|
178
|
+
# rescue RestClient::InternalServerError => e
|
179
|
+
# logger.progname = 'RestCreate#CreateGeneralClass'
|
180
|
+
# response = JSON.parse(e.response)['errors'].pop
|
181
|
+
# logger.error{"#{response['content'].split(':').last }"}
|
182
|
+
# nil
|
183
|
+
# end
|
184
|
+
#end
|
185
|
+
|
186
|
+
|
187
|
+
############## OBJECT #############
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
=begin
|
192
|
+
Creates a Record (NOT edge) in the Database and returns this as ActiveOrient::Model-Instance
|
193
|
+
Creates a Record with the attributes provided in the attributes-hash e.g.
|
194
|
+
create_record @classname, attributes: {con_id: 343, symbol: 'EWTZ'}
|
195
|
+
|
196
|
+
untested: for hybrid and schema-less documents the following syntax is supported
|
197
|
+
create_document Account, attributes: {date: 1350426789, amount: 100.34, "@fieldTypes" => "date = t, amount = c"}
|
198
|
+
|
199
|
+
The supported special types are:
|
200
|
+
'f' for float
|
201
|
+
'c' for decimal
|
202
|
+
'l' for long
|
203
|
+
'd' for double
|
204
|
+
'b' for byte and binary
|
205
|
+
'a' for date
|
206
|
+
't' for datetime
|
207
|
+
's' for short
|
208
|
+
'e' for Set, because arrays and List are serialized as arrays like [3,4,5]
|
209
|
+
'x' for links
|
210
|
+
'n' for linksets
|
211
|
+
'z' for linklist
|
212
|
+
'm' for linkmap
|
213
|
+
'g' for linkbag
|
214
|
+
=end
|
215
|
+
|
216
|
+
def create_record o_class, attributes: {} # :nodoc: # use Model#create instead
|
217
|
+
logger.progname = 'RestCreate#CreateRecord'
|
218
|
+
attributes = yield if attributes.empty? && block_given?
|
219
|
+
# @class must not quoted! Quote only attributes(strings)
|
220
|
+
post_argument = {'@class' => classname(o_class)}.merge(attributes.to_orient)
|
221
|
+
begin
|
222
|
+
response = @res["/document/#{ActiveOrient.database}"].post post_argument.to_json
|
223
|
+
data = JSON.parse(response.body)
|
224
|
+
if o_class.is_a?(Class) && o_class.new.is_a?(ActiveOrient::Model)
|
225
|
+
o_class.new data
|
226
|
+
else
|
227
|
+
ActiveOrient::Model.orientdb_class(name: data['@class'], superclass: :find_ME).new data
|
228
|
+
end
|
229
|
+
rescue RestClient::InternalServerError => e
|
230
|
+
response = JSON.parse(e.response)['errors'].pop
|
231
|
+
logger.error{response['content'].split(':')[1..-1].join(':')}
|
232
|
+
logger.error{"No Object allocated"}
|
233
|
+
nil # return_value
|
234
|
+
end
|
235
|
+
end
|
236
|
+
alias create_document create_record
|
237
|
+
|
238
|
+
=begin
|
239
|
+
Used to create multiple records at once
|
240
|
+
For example:
|
241
|
+
$r.create_multiple_records "Month", ["date", "value"], [["June", 6], ["July", 7], ["August", 8]]
|
242
|
+
It is equivalent to this three functios:
|
243
|
+
$r.create_record "Month", attributes: {date: "June", value: 6}
|
244
|
+
$r.create_record "Month", attributes: {date: "July", value: 7}
|
245
|
+
$r.create_record "Month", attributes: {date: "August", value: 8}
|
246
|
+
|
247
|
+
The function $r.create_multiple_records "Month", ["date", "value"], [["June", 6], ["July", 7], ["August", 8]] will return an array with three element of class "Active::Model::Month".
|
248
|
+
=end
|
249
|
+
|
250
|
+
def create_multiple_records o_class, values, new_records # :nodoc: # untested
|
251
|
+
command = "INSERT INTO #{o_class} ("
|
252
|
+
values.each do |val|
|
253
|
+
command += "#{val},"
|
254
|
+
end
|
255
|
+
command[-1] = ")"
|
256
|
+
command += " VALUES "
|
257
|
+
new_records.each do |new_record|
|
258
|
+
command += "("
|
259
|
+
new_record.each do |record_value|
|
260
|
+
case record_value
|
261
|
+
when String
|
262
|
+
command += "\'#{record_value}\',"
|
263
|
+
when Integer
|
264
|
+
command += "#{record_value},"
|
265
|
+
when ActiveOrient::Model
|
266
|
+
command += "##{record_value.rid},"
|
267
|
+
when Array
|
268
|
+
if record_value[0].is_a? ActiveOrient::Model
|
269
|
+
command += "["
|
270
|
+
record_value.rid.each do |rid|
|
271
|
+
command += "##{rid},"
|
272
|
+
end
|
273
|
+
command[-1] = "]"
|
274
|
+
command += ","
|
275
|
+
else
|
276
|
+
command += "null,"
|
277
|
+
end
|
278
|
+
else
|
279
|
+
command += "null,"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
command[-1] = ")"
|
283
|
+
command += ","
|
284
|
+
end
|
285
|
+
command[-1] = ""
|
286
|
+
execute transaction: false do # To execute commands
|
287
|
+
[{ type: "cmd",
|
288
|
+
language: 'sql',
|
289
|
+
command: command}]
|
290
|
+
end
|
291
|
+
end
|
292
|
+
# UPDATE <class>|CLUSTER:<cluster>|<recordID>
|
293
|
+
# [SET|INCREMENT|ADD|REMOVE|PUT <field-name> = <field-value>[,]*]|[CONTENT|MERGE <JSON>]
|
294
|
+
# [UPSERT]
|
295
|
+
# [RETURN <returning> [<returning-expression>]]
|
296
|
+
# [WHERE <conditions>]
|
297
|
+
# [LOCK default|record]
|
298
|
+
# [LIMIT <max-records>] [TIMEOUT <timeout>]
|
299
|
+
|
300
|
+
=begin
|
301
|
+
update or insert one record is implemented as upsert.
|
302
|
+
The where-condition is merged into the set-attributes if its a hash.
|
303
|
+
Otherwise it's taken unmodified.
|
304
|
+
|
305
|
+
The method returns the included or the updated dataset
|
306
|
+
|
307
|
+
## to do
|
308
|
+
# yield works for updated and for inserted datasets
|
309
|
+
# upsert ( ) do | what, record |
|
310
|
+
# if what == :insert
|
311
|
+
# do stuff with insert
|
312
|
+
# if what == :update
|
313
|
+
# do stuff with update
|
314
|
+
# end
|
315
|
+
=end
|
316
|
+
def upsert o_class, set: {}, where: {} # :nodoc: use Model#Upsert instead
|
317
|
+
logger.progname = 'RestCreate#Upsert'
|
318
|
+
if where.blank?
|
319
|
+
new_record = create_record(o_class, attributes: set)
|
320
|
+
yield new_record if block_given? # in case if insert execute optional block
|
321
|
+
new_record # return_value
|
322
|
+
else
|
323
|
+
specify_return_value = block_given? ? "" : "return after @this"
|
324
|
+
set.merge! where if where.is_a?( Hash ) # copy where attributes to set
|
325
|
+
command = "Update #{classname(o_class)} set #{generate_sql_list( set ){','}} upsert #{specify_return_value} #{compose_where where}"
|
326
|
+
|
327
|
+
|
328
|
+
# puts "COMMAND: #{command} "
|
329
|
+
result = execute tolerated_error_code: /found duplicated key/, raw: true do # To execute commands
|
330
|
+
[ { type: "cmd", language: 'sql', command: command}]
|
331
|
+
end
|
332
|
+
result =result.pop if result.is_a? Array
|
333
|
+
# puts "RESULT: #{result.inspect}, #{result.class}"
|
334
|
+
if result.has_key?('@class')
|
335
|
+
if o_class.is_a?(Class) && o_class.new.is_a?(ActiveOrient::Model)
|
336
|
+
o_class.new result
|
337
|
+
else
|
338
|
+
AddctiveOrient::Model.orientdb_class(name: data['@class'], superclass: :find_ME).new data
|
339
|
+
end
|
340
|
+
elsif result.has_key?('value')
|
341
|
+
the_record= get_records(from: o_class, where: where, limit: 1).pop
|
342
|
+
## process Code if a new dataset is inserted
|
343
|
+
if result['value'].to_i == 1
|
344
|
+
yield the_record if block_given?
|
345
|
+
logger.info{ "Dataset updated" }
|
346
|
+
elsif result['value'].to_i == 0
|
347
|
+
logger.info{ "Dataset inserted"}
|
348
|
+
end
|
349
|
+
the_record # return_value
|
350
|
+
|
351
|
+
else
|
352
|
+
logger.error{ "Unexpected result form Query \n #{command} \n Result: #{result}" }
|
353
|
+
raise ArgumentError
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
end
|
358
|
+
############### PROPERTIES #############
|
359
|
+
|
360
|
+
=begin
|
361
|
+
Creates properties and optional an associated index as defined in the provided block
|
362
|
+
create_properties(classname or class, properties as hash){index}
|
363
|
+
|
364
|
+
The default-case
|
365
|
+
create_properties(:my_high_sophisticated_database_class,
|
366
|
+
con_id: {type: :integer},
|
367
|
+
details: {type: :link, linked_class: 'Contracts'}) do
|
368
|
+
contract_idx: :notunique
|
369
|
+
end
|
370
|
+
|
371
|
+
A composite index
|
372
|
+
create_properties(:my_high_sophisticated_database_class,
|
373
|
+
con_id: {type: :integer},
|
374
|
+
symbol: {type: :string}) do
|
375
|
+
{name: 'indexname',
|
376
|
+
on: [:con_id, :details] # default: all specified properties
|
377
|
+
type: :notunique # default: :unique
|
378
|
+
}
|
379
|
+
end
|
380
|
+
=end
|
381
|
+
|
382
|
+
def create_properties o_class, all_properties, &b
|
383
|
+
logger.progname = 'RestCreate#CreateProperties'
|
384
|
+
all_properties_in_a_hash = HashWithIndifferentAccess.new
|
385
|
+
all_properties.each{|field, args| all_properties_in_a_hash.merge! translate_property_hash(field, args)}
|
386
|
+
count=0
|
387
|
+
begin
|
388
|
+
if all_properties_in_a_hash.is_a?(Hash)
|
389
|
+
response = @res["/property/#{ActiveOrient.database}/#{classname(o_class)}"].post all_properties_in_a_hash.to_json
|
390
|
+
# response.body.to_i returns response.code, only to_f.to_i returns the correrect value
|
391
|
+
count= response.body.to_f.to_i if response.code == 201
|
392
|
+
end
|
393
|
+
rescue RestClient::InternalServerError => e
|
394
|
+
logger.progname = 'RestCreate#CreateProperties'
|
395
|
+
response = JSON.parse(e.response)['errors'].pop
|
396
|
+
error_message = response['content'].split(':').last
|
397
|
+
logger.error{"Properties in #{classname(o_class)} were NOT created"}
|
398
|
+
logger.error{"The Error was: #{response['content'].split(':').last}"}
|
399
|
+
nil
|
400
|
+
end
|
401
|
+
### index
|
402
|
+
if block_given?# && count == all_properties_in_a_hash.size
|
403
|
+
index = yield
|
404
|
+
if index.is_a?(Hash)
|
405
|
+
puts "index_class: #{o_class}"
|
406
|
+
puts "index: "+index.inspect
|
407
|
+
if index.size == 1
|
408
|
+
create_index o_class, name: index.keys.first, on: all_properties_in_a_hash.keys, type: index.values.first
|
409
|
+
else
|
410
|
+
index_hash = HashWithIndifferentAccess.new(type: :unique, on: all_properties_in_a_hash.keys).merge index
|
411
|
+
create_index o_class, name: index_hash[:name], on: index_hash[:on], type: index_hash[:type]
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
count # return_value
|
416
|
+
end
|
417
|
+
|
418
|
+
=begin
|
419
|
+
Create a single property on class-level.
|
420
|
+
Supported types: https://orientdb.com/docs/last/SQL-Create-Property.html
|
421
|
+
If index is to be specified, it's defined in the optional block
|
422
|
+
create_property(class, field){:unique | :notunique} --> creates an automatic-Index on the given field
|
423
|
+
create_property(class, field){{»name« => :unique | :notunique | :full_text}} --> creates a manual index
|
424
|
+
=end
|
425
|
+
|
426
|
+
def create_property o_class, field, index: nil, **args, &b
|
427
|
+
logger.progname = 'RestCreate#CreateProperty'
|
428
|
+
args= { type: :integer} if args.blank? # the default case
|
429
|
+
c = create_properties o_class, {field => args}
|
430
|
+
if index.nil? && block_given?
|
431
|
+
index = yield
|
432
|
+
end
|
433
|
+
if index.present?
|
434
|
+
if index.is_a?(String) || index.is_a?(Symbol)
|
435
|
+
create_index o_class, name: field, type: index
|
436
|
+
elsif index.is_a? Hash
|
437
|
+
bez = index.keys.first
|
438
|
+
create_index o_class, name: bez, type: index[bez], on: [field]
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
################# INDEX ###################
|
444
|
+
|
445
|
+
# Used to create an index
|
446
|
+
|
447
|
+
def create_index o_class, name:, on: :automatic, type: :unique
|
448
|
+
logger.progname = 'RestCreate#CreateIndex'
|
449
|
+
begin
|
450
|
+
c = classname o_class
|
451
|
+
puts "CREATE INDEX: class: #{c.inspect}"
|
452
|
+
execute transaction: false do
|
453
|
+
command = if on == :automatic
|
454
|
+
"CREATE INDEX #{c}.#{name} #{type.to_s.upcase}"
|
455
|
+
elsif on.is_a? Array
|
456
|
+
"CREATE INDEX #{name} ON #{c}(#{on.join(', ')}) #{type.to_s.upcase}"
|
457
|
+
else
|
458
|
+
"CREATE INDEX #{name} ON #{c}(#{on.to_s}) #{type.to_s.upcase}"
|
459
|
+
#nil
|
460
|
+
end
|
461
|
+
#puts "command: #{command}"
|
462
|
+
{type: "cmd", language: 'sql', command: command} if command.present?
|
463
|
+
end
|
464
|
+
logger.info{"Index on #{c} based on #{name} created."}
|
465
|
+
rescue RestClient::InternalServerError => e
|
466
|
+
response = JSON.parse(e.response)['errors'].pop
|
467
|
+
error_message = response['content'].split(':').last
|
468
|
+
logger.error{"Index not created."}
|
469
|
+
logger.error{"Error-code #{response['code']} --> #{response['content'].split(':').last }"}
|
470
|
+
nil
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
end
|