arcadedb 0.3.1 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,194 @@
1
+ ##
2
+ ## This example realises a bidirectional 1:n relation using Edges & Vertices
3
+ #
4
+ ## The schema is implemented in modelfiles located in spec/model
5
+ ## /spec/models/ex/human.rb # Vertex
6
+ ## /spec/models/ex/depend_on.rb # Edge
7
+ #
8
+ # This script runs in the test environment.
9
+ ##
10
+ require 'bundler/setup'
11
+ require 'zeitwerk'
12
+ require 'arcade'
13
+
14
+ include Arcade
15
+ ## require modelfiles
16
+ loader = Zeitwerk::Loader.new
17
+ loader.push_dir ("#{__dir__}/../spec/model")
18
+ loader.setup
19
+
20
+ ## clear test database
21
+
22
+ databases = Arcade::Api.databases
23
+ if databases.include?(Arcade::Config.database[:test])
24
+ Arcade::Api.drop_database Arcade::Config.database[:test]
25
+ end
26
+ Arcade::Api.create_database Arcade::Config.database[:test]
27
+
28
+ ## Universal Database handle
29
+ DB = Arcade::Init.connect 'test'
30
+
31
+ ## ------------------------------------------------------ End Setup ------------------------------------- ##
32
+ ##
33
+ ## We are realising a self referencing relation
34
+ ## parent <--> children
35
+ #
36
+
37
+
38
+ Ex::Human.create_type # initialize the database
39
+ Ex::DependOn.create_type
40
+
41
+ nodes = %w( Guthorn Fulkerson Sniezek Tomasulo Portwine Keala Revelli Jacks Gorby Alcaoa ).map do | name |
42
+ Ex::Human.insert name: name, birth: 2022 - rand(99), married: rand(2)==1
43
+ end
44
+
45
+ puts Ex::Human.count.to_s + " Human Vertices created"
46
+
47
+ puts "------------------------------ get a sorted list of married humans ---------------------------------"
48
+ puts
49
+
50
+ merried = Ex::Human.query( where: { married: true })
51
+ merried.order 'birth'
52
+ new_merried = Query.new projection: 'name, 2022-birth as age ', from: merried # merge two queries
53
+ puts new_merried.query
54
+
55
+ puts "------------------------------ and one for not married humans ---------------------------------"
56
+ puts
57
+
58
+ singles = Ex::Human.query( where: { married: false })
59
+ singles.order 'birth'
60
+ new_singles = Query.new projection: 'name, 2022-birth as age ', from: singles # merge two queries
61
+ puts new_singles.query
62
+
63
+
64
+ puts "------------------------------ connect married humans with children ------------------------------"
65
+ children = singles.query.allocate_model
66
+
67
+ begin
68
+ children_enumerator = children.each
69
+ merried.query.allocate_model.map do | parent |
70
+ parent.assign via: Ex::DependOn, vertex: children_enumerator.next
71
+ end
72
+ rescue StopIteration
73
+ puts "No more children"
74
+ end
75
+
76
+ # Ex::Human.parents is essential
77
+ # EX::Human.query projection: 'out()' , whee: { married: true }
78
+ # Ex::Human.children is essential
79
+ # EX::Human.query projection: 'out()' , whee: { married: true }
80
+ puts "--------------------------- Parent and Children ---------------------------------------------------"
81
+ puts
82
+ puts "%10s %7s %10s %30s " % ["Parent", "Age", "Child", "sorted by Child"]
83
+ puts "- " * 50
84
+ Ex::Human.parents( order: 'name' ).each do |parent| # note: order: 'name' is included
85
+ # in the query
86
+ puts "%10s %7d %10s " % [parent.name, 2022 - parent.birth, parent.out.first.name]
87
+ end
88
+
89
+ puts "--------------------------- child and parent -----------------------------------------------------"
90
+ puts
91
+ puts "%10s %7s %10s %30s " % ["Child", "Age", "Parent", "sorted by Parent"]
92
+ puts "- " * 50
93
+ Ex::Human.children( order: 'name' ).each do |child|
94
+ puts "%10s %7d %10s " % [child.name, 2022 - child.birth, child.in.first.name]
95
+ end
96
+
97
+ puts "--------------------------- Add child to a parent -----------------------------------------------"
98
+ puts
99
+
100
+ Ex::Human.parents.first.assign via: Ex::DependOn, vertex: Ex::Human.insert( name: "TestBaby", birth: 2022, married: false)
101
+
102
+ puts "Parent: " + Ex::Human.parents.first.to_human
103
+ puts "Children: \n " + Ex::Human.parents.first.out.to_human.join("\n ")
104
+
105
+ ## Expected output
106
+ __END__
107
+
108
+ Using default database credentials and settings fron /home/ubuntu/workspace/arcadedb
109
+ 27.04.(18:35:05) INFO->Q: create vertex type ex_human
110
+ 27.04.(18:35:05) INFO->Q: CREATE PROPERTY ex_human.name STRING
111
+ 27.04.(18:35:05) INFO->Q: CREATE PROPERTY ex_human.married BOOLEAN
112
+ 27.04.(18:35:05) INFO->Q: CREATE INDEX `Example[human]` ON ex_human ( name ) UNIQUE
113
+ 27.04.(18:35:05) INFO->Q: create edge type ex_depend_on
114
+ 27.04.(18:35:05) INFO->Q: CREATE INDEX depends_out_in ON ex_depend_on (`@out`, `@in`) UNIQUE
115
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Guthorn","birth":1962,"married":false}
116
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Fulkerson","birth":1962,"married":true}
117
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Sniezek","birth":1972,"married":true}
118
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Tomasulo","birth":1953,"married":false}
119
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Portwine","birth":1975,"married":true}
120
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Keala","birth":1961,"married":false}
121
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Revelli","birth":1948,"married":true}
122
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Jacks","birth":1993,"married":true}
123
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Gorby","birth":1979,"married":false}
124
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"Alcaoa","birth":1960,"married":false}
125
+ 27.04.(18:35:05) INFO->Q: select count(*) from ex_human
126
+ 10 Human Vertices created
127
+ ------------------------------ get a sorted list of married humans ---------------------------------
128
+
129
+ 27.04.(18:35:05) INFO->Q: select name, 2022-birth as age from ( select from ex_human where married = true order by birth )
130
+ {:name=>"Revelli", :age=>74}
131
+ {:name=>"Fulkerson", :age=>60}
132
+ {:name=>"Sniezek", :age=>50}
133
+ {:name=>"Portwine", :age=>47}
134
+ {:name=>"Jacks", :age=>29}
135
+ ------------------------------ and one for not married humans ---------------------------------
136
+
137
+ 27.04.(18:35:05) INFO->Q: select name, 2022-birth as age from ( select from ex_human where married = false order by birth )
138
+ {:name=>"Tomasulo", :age=>69}
139
+ {:name=>"Alcaoa", :age=>62}
140
+ {:name=>"Keala", :age=>61}
141
+ {:name=>"Guthorn", :age=>60}
142
+ {:name=>"Gorby", :age=>43}
143
+ ------------------------------ connect married humans with children ------------------------------
144
+ 27.04.(18:35:05) INFO->Q: select from ex_human where married = false order by birth
145
+ 27.04.(18:35:05) INFO->Q: select from ex_human where married = true order by birth
146
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #19:0 to #10:0 CONTENT {"set":{}}
147
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #4:0 to #4:1 CONTENT {"set":{}}
148
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #7:0 to #16:0 CONTENT {"set":{}}
149
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #13:0 to #1:0 CONTENT {"set":{}}
150
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #22:0 to #1:1 CONTENT {"set":{}}
151
+ --------------------------- Parent and Children ---------------------------------------------------
152
+
153
+ Parent Age Child sorted by Child
154
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
155
+ 27.04.(18:35:05) INFO->Q: select in() from ex_human where married = false order by name
156
+ 27.04.(18:35:05) INFO->Q: select out() from #4:0
157
+ Fulkerson 60 Alcaoa
158
+ 27.04.(18:35:05) INFO->Q: select out() from #22:0
159
+ Jacks 29 Gorby
160
+ 27.04.(18:35:05) INFO->Q: select out() from #13:0
161
+ Portwine 47 Guthorn
162
+ 27.04.(18:35:05) INFO->Q: select out() from #7:0
163
+ Sniezek 50 Keala
164
+ 27.04.(18:35:05) INFO->Q: select out() from #19:0
165
+ Revelli 74 Tomasulo
166
+ --------------------------- child and parent -----------------------------------------------------
167
+
168
+ Child Age Parent sorted by Parent
169
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
170
+ 27.04.(18:35:05) INFO->Q: select out() from ex_human where married = true order by name
171
+ 27.04.(18:35:05) INFO->Q: select in() from #4:1
172
+ Alcaoa 62 Fulkerson
173
+ 27.04.(18:35:05) INFO->Q: select in() from #1:1
174
+ Gorby 43 Jacks
175
+ 27.04.(18:35:05) INFO->Q: select in() from #1:0
176
+ Guthorn 60 Portwine
177
+ 27.04.(18:35:05) INFO->Q: select in() from #10:0
178
+ Tomasulo 69 Revelli
179
+ 27.04.(18:35:05) INFO->Q: select in() from #16:0
180
+ Keala 61 Sniezek
181
+ --------------------------- Add child to a parent -----------------------------------------------
182
+
183
+ 27.04.(18:35:05) INFO->Q: select in() from ex_human where married = false
184
+ 27.04.(18:35:05) INFO->Q: INSERT INTO ex_human CONTENT {"name":"TestBaby","birth":2022,"married":false}
185
+ 27.04.(18:35:05) INFO->Q: create edge ex_depend_on from #13:0 to #7:1 CONTENT {"set":{}}
186
+ 27.04.(18:35:05) INFO->Q: select in() from ex_human where married = false
187
+ Parent: <ex_human[#13:0]: {0->}{->2}}, birth: 1975, married: true, name: Portwine>
188
+ 27.04.(18:35:05) INFO->Q: select in() from ex_human where married = false
189
+ 27.04.(18:35:05) INFO->Q: select out() from #13:0
190
+ Children:
191
+ <ex_human[#1:0]: {->}{->}}, birth: 1962, married: false, name: Guthorn>
192
+ <ex_human[#7:1]: {->}{->}}, birth: 2022, married: false, name: TestBaby>
193
+
194
+
@@ -0,0 +1,257 @@
1
+ module Arcade
2
+ module Api
3
+ extend Primitives
4
+ =begin
5
+ This is a simple admin interface
6
+
7
+ $ Arcade::Api.databases # returns an Array of known databases
8
+ $ Arcade::Api.create_database <a string> # returns true if succesfull
9
+ $ Arcade::Api.drop_database <a string> # returns true if successfull
10
+
11
+ $ Arcade::Api.create_document <database>, <type>, attributes
12
+ $ Arcade::Api.execute( <database> ) { <query> }
13
+ $ Arcade::Api.query( <database> ) { <query> }
14
+ $ Arcade::Api.get_record <database>, rid # returns a hash
15
+
16
+
17
+ <query> is either a string
18
+ or a hash { :query => " ",
19
+ :language => one of :sql, :cypher, :gmelion: :neo4j ,
20
+ :params => a hash of parameters,
21
+ :limit => a number ,
22
+ :serializer: one of :graph, :record }
23
+
24
+ =end
25
+
26
+ # ------------------------------ Service methods ------------------------------------------------- #
27
+ # ------------------------------ ------------------------------------------------- #
28
+ # ------------------------------ databases ------------------------------------------------- #
29
+ # returns an array of databases present on the database-server #
30
+
31
+ def self.databases
32
+ get_data 'databases'
33
+ end
34
+
35
+ # ------------------------------ create database ------------------------------------------------- #
36
+ # creates a database if not present #
37
+ def self.create_database name
38
+ return if databases.include?( name.to_s )
39
+ payload = { "command" => "create database #{name}" }
40
+ post_data "server", payload
41
+ rescue HTTPX::HTTPError => e
42
+ logger.fatal "Create database #{name} through \"POST create/#{name}\" failed"
43
+ logger.fatal e
44
+ raise
45
+ end
46
+
47
+ # ------------------------------ drop database ------------------------------------------------- #
48
+ # deletes the given database #
49
+ def self.drop_database name
50
+ return unless databases.include?( name.to_s )
51
+ payload = {"command" => "drop database #{name}" }
52
+ post_data "server", payload
53
+ rescue HTTPX::HTTPError => e
54
+ logger.fatal "Drop database #{name} through \"POST drop database/#{name}\" failed"
55
+ raise
56
+ end
57
+ # ------------------------------ create document ------------------------------------------------- #
58
+ # adds a document to the specified database table
59
+ #
60
+ # specify database-fields as hash-type parameters
61
+ #
62
+ # i.e Arcade::Api.create_document 'devel', 'documents', name: 'herta meyer', age: 56, sex: 'f'
63
+ #
64
+ # returns the rid of the inserted dataset
65
+ #
66
+ def self.create_document database, type, **attributes
67
+ payload = { "@type" => type }.merge( attributes )
68
+ logger.debug "C: #{payload}"
69
+ options = if session.nil?
70
+ payload
71
+ else
72
+ payload.merge headers: { "arcadedb-session-id" => session }
73
+ end
74
+ post_data "document/#{database}", options
75
+ end
76
+
77
+ # ------------------------------ execute ------------------------------------------------- #
78
+ # executes a sql-query in the specified database
79
+ #
80
+ # the query is provided as block
81
+ #
82
+ # returns an Array of results (if propriate)
83
+ # i.e
84
+ # Arcade::Api.execute( "devel" ) { 'select from test ' }
85
+ # =y [{"@rid"=>"#57:0", "@type"=>"test", "name"=>"Hugo"}, {"@rid"=>"#60:0", "@type"=>"test", "name"=>"Hubert"}]
86
+ #
87
+ def self.execute database, query=nil, session_id= nil
88
+ pl = query.nil? ? provide_payload(yield) : provide_payload(query)
89
+ if session_id.nil? && session.nil?
90
+ post_data "command/#{database}" , pl
91
+ else
92
+ post_transaction "command/#{database}" , pl, session_id || session
93
+ end
94
+ end
95
+
96
+ # ------------------------------ query ------------------------------------------------- #
97
+ # same for idempotent queries
98
+ def self.query database, query
99
+ post_data "query/#{database}" , provide_payload(query)
100
+ end
101
+
102
+ # ------------------------------ get_record ------------------------------------------------- #
103
+ # fetches a record by providing database and rid
104
+ # and returns the result as hash
105
+ #
106
+ # > Api.get_record 'devel', '225:6'
107
+ # > Api.get_record 'devel', 225, 6
108
+ # > Api.get_record 'devel', '#225:6'
109
+ # => {:@out=>0, :@rid=>"#225:6", :@in=>0, :@type=>"my_names", :name=>"Zaber", :@cat=>"v"}
110
+
111
+ def self.get_record database, *rid
112
+ rid = rid.join(':')
113
+ rid = rid[1..-1] if rid[0]=="#"
114
+ if rid.rid?
115
+ get_data "document/#{database}/#{rid}"
116
+ else
117
+ raise Error "Get requires a rid input"
118
+ end
119
+ end
120
+
121
+ # ------------------------------ property ------------------------------------------------- #
122
+ # Adds properties to the type
123
+ #
124
+ # call via
125
+ # Api.property <database>, <type>, name1: a_format , name2: a_format
126
+ #
127
+ # Format is one of
128
+ # Boolean, Integer, Short, Long, Float, Double, String
129
+ # Datetime, Binary, Byte, Decimal, Link
130
+ # Embedded, EmbeddedList, EmbeddedMap
131
+ #
132
+ # In case of an Error, anything is rolled back and nil is returned
133
+ #
134
+ def self.property database, type, **args
135
+
136
+ begin_transaction database
137
+ success = args.map do | name, format |
138
+ r= execute(database) {" create property #{type.to_s}.#{name.to_s} #{format.to_s} " } &.first
139
+ puts "R: #{r.inspect}"
140
+ if r.nil?
141
+ false
142
+ else
143
+ r[:operation] == 'create property'
144
+ end
145
+ end.uniq
146
+ if success == [true]
147
+ commit database
148
+ true
149
+ else
150
+ rollback database
151
+ end
152
+
153
+
154
+ end
155
+
156
+ # ------------------------------ index ------------------------------------------------- #
157
+ def self.index database, type, name , *properties
158
+ properties = properties.map( &:to_s )
159
+ unique_requested = "unique" if properties.delete("unique")
160
+ unique_requested = "notunique" if properties.delete("notunique" )
161
+ automatic = true if
162
+ properties << name if properties.empty?
163
+ # puts " create index #{type.to_s}[#{name.to_s}] on #{type} ( #{properties.join(',')} ) #{unique_requested}"
164
+ # VV 22.10: providing an index-name raises an Error ( Encountered " "(" "( "" at line 1, column 44. Was expecting one of: <EOF> <SCHEMA> ... <NULL_STRATEGY> ... ";" ... "," ... )) )
165
+ # named indices droped for now
166
+ success = execute(database) {" create index IF NOT EXISTS on #{type} (#{properties.join(', ')}) #{unique_requested}" } &.first
167
+ # puts "success: #{success}"
168
+ success[:operation] == 'create index'
169
+
170
+ end
171
+
172
+
173
+ private
174
+
175
+ def self.logger
176
+ Database.logger
177
+ end
178
+
179
+ def self.session
180
+ @session_id
181
+ end
182
+
183
+ def self. provide_payload( the_yield, action: :post )
184
+ unless the_yield.is_a? Hash
185
+ logger.info "Q: #{the_yield}"
186
+ the_yield = { :query => the_yield }
187
+ end
188
+ { language: 'sql' }.merge(
189
+ the_yield.map do | key, value |
190
+ case key
191
+ when :query
192
+ action == :post ? [ :command, value ] : [ :query, value ]
193
+ when :limit
194
+ [ :limit , value ]
195
+ when :params
196
+ if value.is_a? Hash
197
+ [ :params, value ]
198
+ end
199
+ # serializer (optional) specify the serializer used for the result:
200
+ # graph: returns as a graph separating vertices from edges
201
+ # record: returns everything as records
202
+ # by default it’s like record but with additional metadata for vertex records,
203
+ # such as the number of outgoing edges in @out property and total incoming edges
204
+ # in @in property. This serialzier is used by Studio
205
+ when :serializer
206
+ if [:graph, :record].include? value.to_sym
207
+ [ :serializer, value.to_sym ]
208
+ end
209
+ when :language
210
+ if [:sql, :cypher, :gremlin, :neo4j ].include? value.to_sym
211
+ [ :language, value.to_sym ]
212
+ end
213
+ end # case
214
+ end .to_h ) # map
215
+ end
216
+
217
+
218
+
219
+ # returns the json-response ## retiered
220
+ def self.analyse_result r, command
221
+ if r.success?
222
+ return nil if r.status == 204 # no content
223
+ result = JSON.parse( r.response_body, symbolize_names: true )[:result]
224
+ if result == [{}]
225
+ []
226
+ else
227
+ result
228
+ end
229
+ elsif r.timed_out?
230
+ raise Error "Timeout Error", caller
231
+ []
232
+ elsif r.response_code > 0
233
+ logger.error "Execution Failure – Code: #{ r.response_code } – #{r.status_message} "
234
+ error_message = JSON.parse( r.response_body, symbolize_names: true )
235
+ logger.error "ErrorMessage: #{ error_message[:detail]} "
236
+ if error_message[:detail] =~ /Duplicated key/
237
+ raise IndexError, error_message[:detail]
238
+ else
239
+ # available fields: :detail, :exception, error
240
+ puts error_message[:detail]
241
+ #raise error_message[:detail], caller
242
+ end
243
+ end
244
+ end
245
+ def self.auth
246
+ @a ||= { httpauth: :basic,
247
+ username: Config.admin[:user],
248
+ password: Config.admin[:pass] }
249
+ end
250
+
251
+ # not tested
252
+ def self.delete_data command
253
+ result = HTTPX.delete Config.base_uri + command, auth
254
+ analyse_result(result, command)
255
+ end
256
+ end
257
+ end
@@ -0,0 +1,98 @@
1
+ module Arcade
2
+ module Api
3
+ module Primitives
4
+
5
+ # This module handles the interaction with the database through HTTPX
6
+ #
7
+ # ------------------------------ http ------------------------------------------------------------ #
8
+ # persistent http handle to the database
9
+
10
+ def http
11
+ break_on = -> (response) { response.status == 500 }
12
+ @http ||= HTTPX.plugin(:basic_auth).basic_auth(auth[:username], auth[:password])
13
+ .plugin(:persistent)
14
+ .plugin(:circuit_breaker)
15
+ # .plugin(:circuit_breaker, circuit_breaker_break_on: break_on)
16
+ end
17
+
18
+ # ------------------------------ get data -------------------------------------------------------- #
19
+ def get_data command
20
+ response = http.get( Config.base_uri + command )
21
+ response.raise_for_status
22
+
23
+ JSON.parse( response.body, symbolize_names: true )[:result]
24
+ # alternative to `raise for status `
25
+ # case response = http.basic_auth(auth[:username], auth[:password]).get( Config.base_uri + command )
26
+ # in { status: 200..203, body: }
27
+ # puts "success: #{JSON.parse(body, symbolize_names: true)[:result]}"
28
+ # in { status: 400..499, body: }
29
+ # puts "client error: #{body.json}"
30
+ # in { status: 500.., body: }
31
+ # puts "server error: #{body.to_s}"
32
+ # in { error: error }
33
+ # puts "error: #{error.message}"
34
+ # else
35
+ # raise "unexpected: #{response}"
36
+ # end
37
+ # puts "result : #{response}"
38
+ # puts "code: #{response.status}"
39
+ # analyse_result(response, command)
40
+ end
41
+
42
+ # ------------------------------ post data -------------------------------------------------------- #
43
+ def post_data command, payload
44
+ # http = HTTPX.plugin(:basic_auth)
45
+ # .basic_auth(auth[:username], auth[:password])
46
+ response = http.post( Config.base_uri + command, json: payload )
47
+ response.raise_for_status
48
+ JSON.parse( response.body, symbolize_names: true )[:result]
49
+ end
50
+
51
+ # ------------------------------ transaction ------------------------------------------------- #
52
+ #
53
+ def begin_transaction database
54
+ result = http.post Config.base_uri + "begin/#{database}"
55
+ @session_id = result.headers["arcadedb-session-id"]
56
+ # returns the session-id
57
+ end
58
+
59
+ # ------------------------------ post transaction ------------------------------------------------- #
60
+ def post_transaction command, params, session_id= @session_id
61
+ # http = HTTPX.plugin(:basic_auth)
62
+ # .basic_auth(auth[:username], auth[:password])
63
+ # .with( headers: { "arcadedb-session-id"=>session }, debug_level: 1)
64
+ http_a = http.with( headers: { "arcadedb-session-id" => session_id } , debug_level: 1)
65
+ response = http_a.post( Config.base_uri + command, json: params )
66
+ response.raise_for_status
67
+ JSON.parse( response.body, symbolize_names: true )[:result]
68
+
69
+ end
70
+
71
+ # ------------------------------ commit ------------------------------------------------- #
72
+ def commit database, session_id = @session_id
73
+ http_a = http.with( headers: { "arcadedb-session-id" => session_id } , debug_level: 1)
74
+ response = http_a.post( Config.base_uri + "commit/#{database}" )
75
+ response.raise_for_status
76
+ @session_id = nil
77
+ response.status # returns 204 --> success
78
+ # 403 --> incalid credentials
79
+ # 500 --> Transaction not begun
80
+
81
+ end
82
+
83
+ # ------------------------------ rollback ------------------------------------------------- #
84
+ def rollback database, session_id = @session_id, publish_error=true
85
+ # http = HTTPX.plugin(:basic_auth)
86
+ # .basic_auth(auth[:username], auth[:password])
87
+ # .with( headers: { "arcadedb-session-id"=>session_id }, debug_level: 1)
88
+ http_a = http.with( headers: { "arcadedb-session-id" => session_id } , debug_level: 1)
89
+ response = http_a.post( Config.base_uri + "rollback/#{database}" )
90
+ response.raise_for_status
91
+ @session_id = nil
92
+ logger.error "A Transaction has been rolled back" # if publish_error
93
+ response.status
94
+ end
95
+ end
96
+ end
97
+ end
98
+