arcadedb 0.3.3 → 0.5.0

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.
data/lib/arcade/base.rb CHANGED
@@ -5,7 +5,7 @@ module Arcade
5
5
  # schema schema.strict # -- throws an error if specified keys are missing
6
6
  transform_keys{ |x| x[0] == '@' ? x[1..-1].to_sym : x.to_sym }
7
7
  # Types::Rid --> only accept #000:000, raises an Error, if rid is not present
8
- attribute :rid, Types::Rid
8
+ attribute :rid?, Types::Rid
9
9
  # maybe there are edges ## removed in favour of instance methods
10
10
  # attribute :in?, Types::Nominal::Any
11
11
  # attribute :out?, Types::Nominal::Any
@@ -27,6 +27,16 @@ module Arcade
27
27
  self.name.snake_case
28
28
  end
29
29
 
30
+ def begin_transaction
31
+ db.begin_transaction
32
+ end
33
+ def commit
34
+ db.commit
35
+ end
36
+ def rollback
37
+ db.rollback
38
+ end
39
+
30
40
  def create_type
31
41
  the_class = nil # declare as local var
32
42
  parent_present = ->(cl){ db.hierarchy.flatten.include? cl }
@@ -41,12 +51,7 @@ module Arcade
41
51
  if the_class.respond_to?(:demodulize)
42
52
  if [ 'Document','Vertex', 'Edge'].include?(the_class.demodulize)
43
53
  if the_class == superclass # no inheritance
44
- ## we have to use demodulize as the_class actually is Arcade::Vertex, ...
45
- unless parent_present[ to_s.snake_case ]
46
54
  db.create_type the_class.demodulize, to_s.snake_case
47
- else
48
- db.logger.warn "Type #{ to_s.snake_case } is present, process skipped"
49
- end
50
55
  else
51
56
  if superclass.is_a? Class # maybe its a module.
52
57
  extended = superclass.to_s.snake_case
@@ -72,10 +77,10 @@ module Arcade
72
77
  the_command = command[0 .. -2] # remove '\n'
73
78
  next if the_command == ''
74
79
  # db.logger.info "Custom Setup:: #{the_command}"
75
- db.execute { the_command }
80
+ db.transmit { the_command }
76
81
  end unless custom_setup.nil?
77
82
 
78
- rescue Arcade::RollbackError => e
83
+ rescue RollbackError => e
79
84
  db.logger.warn e
80
85
  rescue RuntimeError => e
81
86
  db.logger.warn e
@@ -123,9 +128,11 @@ module Arcade
123
128
  # (not supported (jet): [RETURN <expression>] [FROM <query>] )
124
129
 
125
130
  def insert **attributes
126
- db.insert type: database_name, **attributes
131
+ db.insert type: database_name, session_id: attributes.delete(:session_id), **attributes
127
132
  end
128
133
 
134
+ alias create insert
135
+
129
136
  ## ----------------------------------------- create ---------------------------------- ##
130
137
  #
131
138
  # Adds a record to the database
@@ -133,21 +140,21 @@ module Arcade
133
140
  # returns the model dataset
134
141
  # ( depreciated )
135
142
 
136
- def create **attributes
137
- Api.begin_transaction db.database
138
- attributes.merge!( created: DateTime.now ) if timestamps
139
- record = insert **attributes
140
- Api.commit db.database
141
- record
142
- rescue QueryError => e
143
- db.logger.error "Dataset NOT created"
144
- db.logger.error "Provided Attributes: #{ attributes.inspect }"
145
- # Api.rollback db.database ---> raises "transactgion not begun"
146
- rescue Dry::Struct::Error => e
147
- Api.rollback db.database
148
- db.logger.error "#{ rid } :: Validation failed, record deleted."
149
- db.logger.error e.message
150
- end
143
+ # def create **attributes
144
+ # s = Api.begin_transaction db.database
145
+ # attributes.merge!( created: DateTime.now ) if timestamps
146
+ # record = insert **attributes
147
+ # Api.commit db.database, s
148
+ # record
149
+ # rescue HTTPX::HTTPError => e
150
+ # db.logger.error "Dataset NOT created"
151
+ # db.logger.error "Provided Attributes: #{ attributes.inspect }"
152
+ # Api.rollback db.database # ---> raises "transactgion not begun"
153
+ # rescue Dry::Struct::Error => e
154
+ # Api.rollback db.database
155
+ # db.logger.error "#{ rid } :: Validation failed, record deleted."
156
+ # db.logger.error e.message
157
+ # end
151
158
 
152
159
  def count **args
153
160
  command = "count(*)"
@@ -222,12 +229,11 @@ module Arcade
222
229
  # Finds the first matching record providing the parameters of a `where` query
223
230
  # Strategie.find symbol: 'Still'
224
231
  # is equivalent to
225
- # Strategie.all.find{|y| y.symbol == 'Still'
226
- # }
232
+ # Strategie.all.find{|y| y.symbol == 'Still' }
227
233
  def find **args
228
- f= where(**args).first
229
- f= where( "#{ args.keys.first } like #{ args.values.first.to_or }" ).first if f.nil? || f.empty?
230
- f
234
+ where(**args).first
235
+ # f= where( "#{ args.keys.first } like #{ args.values.first.to_or }" ).first if f.nil? || f.empty?
236
+ # f
231
237
  end
232
238
  # update returns a list of updated records
233
239
  #
@@ -278,14 +284,14 @@ module Arcade
278
284
  end
279
285
  result= query( **( { kind: :upsert }.merge statement ) ).execute do | answer|
280
286
  z= answer[:"$current"] &.allocate_model(false) # do not autoload modelfiles
281
- raise Arcade::LoadError "Upsert failed" unless z.is_a? Arcade::Base
287
+ raise LoadError "Upsert failed" unless z.is_a? Base
282
288
  z # return record
283
289
  end
284
290
  end
285
291
 
286
292
 
287
293
  def query **args
288
- Arcade::Query.new( **{ from: self }.merge(args) )
294
+ Query.new( **{ from: self }.merge(args) )
289
295
  end
290
296
 
291
297
  # immutable support
@@ -332,7 +338,7 @@ module Arcade
332
338
  end
333
339
 
334
340
  def query **args
335
- Arcade::Query.new( **{ from: rid }.merge(args) )
341
+ Query.new( **{ from: rid }.merge(args) )
336
342
  end
337
343
 
338
344
  # to JSON controlls the serialisation of Arcade::Base Objects for the HTTP-JSON API
@@ -364,7 +370,7 @@ module Arcade
364
370
 
365
371
  "<#{ self.class.to_s.snake_case }" + rid? ? "[#{ rid }]: " : " " + invariant_attributes.map do |attr, value|
366
372
  v= case value
367
- when Arcade::Base
373
+ when Base
368
374
  "< #{ self.class.to_s.snake_case }: #{ value.rid } >"
369
375
  when Array
370
376
  value.map{|x| x.to_s}
@@ -373,59 +379,85 @@ module Arcade
373
379
  end
374
380
  "%s : %s" % [ attr, v] unless v.nil?
375
381
  end.compact.sort.join(', ') + ">".gsub('"' , ' ')
382
+
383
+ rescue TypeError => e
384
+ attributes
376
385
  end
377
386
 
378
- alias to_s to_human
387
+
388
+ # configure irb-output to to_human for all Arcade::Base-Objects
389
+ #
390
+ def inspect
391
+ to_human
392
+ end
393
+
394
+
395
+ def html_attributes
396
+ invariant_attributes
397
+ end
398
+
399
+ def in_and_out_attributes
400
+ _modul, _class = self.class.to_s.split "::"
401
+ the_class = _modul == 'Arcade' ? _class : self.class.to_s
402
+ the_attributes = { :"CLASS" => the_class, :"IN" => self.in.count, :"OUT" => self.out.count, :"RID" => rid }
403
+ end
379
404
 
380
405
  def to_html # iruby
406
+ in_and_out = ->(r) { "[#{r}] : {#{self.in.count}->}{->#{self.out.count }}" }
407
+ the_rid = rid? && rid != "0:0" ? in_and_out[rid] : ""
381
408
  _modul, _class = self.class.to_s.split "::"
382
409
  the_class = _modul == 'Arcade' ? _class : self.class.to_s
383
- IRuby.display IRuby.html "<b style=\"color: #50953DFF\"><#{ the_class}</b>"
384
- + rid? ? "[#{ rid }]: " : " " + invariant_attributes.map do |attr, value|
385
- v= case value
386
- when Arcade::Base
387
- "< #{ self.class.to_s.snake_case }: #{ value.rid } >"
388
- when Array
389
- value.map{|x| x.to_s}
390
- else
391
- value.from_db
392
- end
393
- "%s : %s" % [ attr, v] unless v.nil?
394
- end.compact.sort.join(', ') + ">".gsub('"' , ' ')
410
+ # the_attribute = ->(v) do
411
+ # case v
412
+ # when Base
413
+ # "< #{ self.class.to_s.snake_case }: #{ v.rid } >"
414
+ # when Array
415
+ # v.map{|x| x.to_s}
416
+ # else
417
+ # v.to_s
418
+ # end
419
+ # end
420
+ # last_part = invariant_attributes.map do |attr, value|
421
+ # [ attr, the_attribute[value] ].join(": ")
422
+ # end.join(', ')
423
+
424
+ # IRuby.display( [IRuby.html("<span style=\"color: #50953DFF\"><b>#{the_class}</b><#{ the_class }</b>#{the_rid}</span><br/> ") , IRuby.table(html_attributes) ] )
425
+ IRuby.display IRuby.html("<span style=\"color: #50953DFF\"><b>#{the_class}</b><#{ the_class }</b>#{the_rid}</span>< #{ html_attributes.map{|_,v| v }.join(', ') } >")
395
426
  end
396
427
 
428
+
397
429
  def update **args
398
- Arcade::Query.new( from: rid , kind: :update, set: args).execute
430
+ Query.new( from: rid , kind: :update, set: args).execute
399
431
  refresh
400
432
  end
401
433
 
402
434
  # inserts or updates a embedded document
403
435
  def insert_document name, obj
404
- value = if obj.is_a? Arcade::Document
436
+ value = if obj.is_a? Document
405
437
  obj.to_json
406
438
  else
407
439
  obj.to_or
408
440
  end
409
441
  # if send( name ).nil? || send( name ).empty?
410
- db.execute { "update #{ rid } set #{ name } = #{ value }" }.first[:count]
442
+ db.transmit { "update #{ rid } set #{ name } = #{ value }" }.first[:count]
411
443
  # end
412
444
  end
413
445
 
414
446
  # updates a single property in an embedded document
415
447
  def update_embedded embedded, embedded_property, value
416
- db.execute{ " update #{rid} set `#{embedded}`.`#{embedded_property}` = #{value.to_or}" }
448
+ db.transmit { " update #{rid} set `#{embedded}`.`#{embedded_property}` = #{value.to_or}" }
417
449
  end
418
450
 
419
451
  def update_list list, value
420
- value = if value.is_a? Arcade::Document
452
+ value = if value.is_a? Document
421
453
  value.to_json
422
454
  else
423
455
  value.to_or
424
456
  end
425
457
  if send( list ).nil? || send( list ).empty?
426
- db.execute { "update #{ rid } set #{ list } = [#{ value }]" }
458
+ db.transmit { "update #{ rid } set #{ list } = [#{ value }]" }
427
459
  else
428
- db.execute { "update #{ rid } set #{ list } += #{ value }" }
460
+ db.transmit { "update #{ rid } set #{ list } += #{ value }" }
429
461
  end
430
462
  refresh
431
463
  end
@@ -433,14 +465,14 @@ module Arcade
433
465
  # updates a map property , actually adds the key-value pair to the property
434
466
  def update_map m, key, value
435
467
  if send( m ).nil?
436
- db.execute { "update #{ rid } set #{ m } = MAP ( #{ key.to_s.to_or } , #{ value.to_or } ) " }
468
+ db.transmit { "update #{ rid } set #{ m } = MAP ( #{ key.to_s.to_or } , #{ value.to_or } ) " }
437
469
  else
438
- db.execute { "update #{ rid } set #{ m }.`#{ key.to_s }` = #{ value.to_or }" }
470
+ db.transmit { "update #{ rid } set #{ m }.`#{ key.to_s }` = #{ value.to_or }" }
439
471
  end
440
472
  refresh
441
473
  end
442
474
  def delete
443
- response = db.execute { "delete from #{ rid }" }
475
+ response = db.transmit { "delete from #{ rid }" }
444
476
  true if response == [{ count: 1 }]
445
477
  end
446
478
  def == arg
@@ -3,11 +3,11 @@ module Arcade
3
3
  extend Dry::Configurable
4
4
  # central place to initialize constants
5
5
  #
6
- # ProjectRoot has to be a Pathname-Object
6
+ # ProjectRoot should to be a Pathname-Object and has to be defined before `arcadedb` is required
7
7
  #
8
8
  #puts "expand: #{File.expand_path(__dir__)}"
9
- unless Arcade.const_defined?( :ProjectRoot )
10
- Arcade::ProjectRoot = if defined?( Rails.env )
9
+ unless Object.const_defined?( :ProjectRoot )
10
+ ::ProjectRoot = if defined?( Rails.env )
11
11
  Rails.root
12
12
  else
13
13
  STDERR.puts "Using default (arcadedb gem) database credentials and settings"
@@ -15,10 +15,9 @@ module Arcade
15
15
  Pathname.new( File.expand_path( "../../", __FILE__ ))
16
16
  end
17
17
  else
18
- STDERR.puts "Using provided database credentials and settings fron #{Arcade::ProjectRoot}"
18
+ STDERR.puts "Using provided database credentials and settings from #{::ProjectRoot}"
19
19
  end
20
20
 
21
-
22
21
  # initialised a hash { environment => property }
23
22
  setting :username, default: :user, reader: true,
24
23
  constructor: ->(v) { yml(:environment).map{|x,y| [x , y[v.to_s]] }.to_h }
@@ -48,17 +47,19 @@ module Arcade
48
47
  setting :namespace, default: :namespace, reader: true , constructor: ->(v) { yml(v) }
49
48
  setting :secret, reader: true, default: 12, constructor: ->(v) { seed(v) }
50
49
  private
51
- # if a config dir exists, use it
50
+ # if a config dir exists, use it.
51
+ # Standard: ProjectRoot/config.yml
52
52
  def self.config_file
53
- if @cd.nil?
54
- ( cd = ProjectRoot + 'arcade.yml' ).exist? ||
55
- ( cd = ProjectRoot + 'config' + 'arcade.yml' ).exist? ||
56
- ( cd = ProjectRoot + "config.yml" )
57
- @cd = cd
58
- else
59
- @cd
53
+
54
+ configdir = -> do
55
+ pr = ::ProjectRoot.is_a?(Pathname)? ::ProjectRoot : Pathname.new( ::ProjectRoot )
56
+ ( cd = pr + 'arcade.yml' ).exist? || ( cd = pr + 'config' + 'arcade.yml' ).exist? || ( cd = pr + 'config.yml' )
57
+ cd
60
58
  end
59
+
60
+ @cd ||= configdir[]
61
61
  end
62
+
62
63
  def self.yml key=nil
63
64
  y= YAML::load_file( config_file )
64
65
  key.nil? ? y : y[key]
@@ -17,12 +17,12 @@ module Arcade
17
17
  defines :environment
18
18
 
19
19
  def initialize environment=:development
20
- self.class.configure_logger( Config.logger )
21
- @connection = connect environment
20
+ self.class.configure_logger( Config.logger )
22
21
  if self.class.environment.nil? # class attribute is set on the first call
23
22
  # further instances of Database share the same environment
24
23
  self.class.environment environment
25
24
  end
25
+ @session_id = nil # declare session_id
26
26
  self.class.namespace Object.const_get( Config.namespace )
27
27
  end
28
28
 
@@ -39,20 +39,19 @@ module Arcade
39
39
  #
40
40
  def types refresh=false
41
41
  # uses API
42
- if $types.nil? || refresh
43
- $types = Api.query(database, "select from schema:types" )
44
- .map{ |x| x.transform_keys &:to_sym } # symbolize keys
45
- .map{ |y| y.delete_if{|_,b,| b.empty? } } # eliminate empty entries
42
+ if @types.nil? || refresh
43
+ @types = Api.query(database, "select from schema:types" )
44
+ .map{ |y| y.delete_if{|_,b,| b.blank? } } # eliminate empty entries
46
45
  end
47
- $types
48
- ## upom startup, this is the first access to the database-server
46
+ @types
47
+ ## upon startup, this is the first access to the database-server
49
48
  rescue NoMethodError => e
50
49
  logger.fatal "Could not read Database Types. \n Is the database running?"
51
50
  Kernel.exit
52
51
  end
53
52
 
54
- def indexes
55
- DB.types.find{|x| x.key? :indexes }[:indexes]
53
+ def indexes refresh=false
54
+ types(refresh).find_all{|x| x.key? :indexes }.map{|y| y[:indexes]}.flatten
56
55
  end
57
56
 
58
57
  # ------------ hierarchy -------------
@@ -108,23 +107,56 @@ module Arcade
108
107
  "create edge type #{type} "
109
108
  end.concat( args.map{|x,y| "#{x} #{y} "}.join)
110
109
  end
111
- db= Api.execute database, &exe
110
+ dbe= Api.execute database, &exe
112
111
  types( true ) # update cached schema
113
- db
114
-
115
- rescue Arcade::QueryError
116
- Arcade::Database.logger.warn "Database type #{type} already present"
112
+ dbe
113
+
114
+ rescue Arcade::QueryError => e
115
+ if e.message =~/Type\s+.+\salready\s+exists/
116
+ Arcade::Database.logger.debug "Database type #{type} already present"
117
+ else
118
+ raise
119
+ end
117
120
  end
118
121
 
119
122
  alias create_class create_type
120
123
 
121
124
  # ------------ drop type -----------
122
125
  # delete any record prior to the attempt to drop a type.
123
- # The `unsafe` option is nit implemented.
126
+ # The `unsafe` option is not implemented.
124
127
  def drop_type type
125
128
  Api.execute database, "drop type #{type} if exists"
126
129
  end
127
130
 
131
+ # ------------------------------ transaction ----------------------------------------------------- #
132
+ # Encapsulates simple transactions
133
+ #
134
+ # nested transactions are not supported.
135
+ # * use the low-leve api.begin_tranaction for that purpose
136
+ # * reuses an existing transaction
137
+ #
138
+ def begin_transaction
139
+ @session_id ||= Api.begin_transaction database
140
+ end
141
+ # ------------------------------ commit ----------------------------------------------------- #
142
+ def commit
143
+ r = Api.commit( database, session_id: session)
144
+ @session_id = nil
145
+ true if r == 204
146
+ end
147
+
148
+ # ------------------------------ rollback ----------------------------------------------------- #
149
+ #
150
+ def rollback
151
+ r = Api.rollback( database, session_id: session)
152
+ @session_id = nil
153
+ true if r == 500
154
+ rescue HTTPX::HTTPError => e
155
+ raise
156
+ end
157
+
158
+
159
+
128
160
  # ------------ create -----------
129
161
  # returns an rid of the successfully created vertex or document
130
162
  #
@@ -136,21 +168,34 @@ module Arcade
136
168
  #
137
169
  def create type, **params
138
170
  # uses API
139
- Api.create_document database, type, **params
171
+ Api.create_document database, type, session_id: session, **params
140
172
  end
141
173
 
174
+ # ------------------------------ insert ------------------------------------------------------ #
175
+ #
176
+ # translates the given parameters to
177
+ # INSERT INTO [TYPE:]<type>|BUCKET:<bucket>|INDEX:<index>
178
+ # [(<field>[,]*) VALUES (<expression>[,]*)[,]*]|
179
+ # [CONTENT {<JSON>}|[{<JSON>}[,]*]]
180
+ #
181
+ # :from and :return are not supported
182
+ #
183
+ # If a transaction is active, the insert is executed in that context.
184
+ # Nested transactions are not supported
142
185
  def insert **params
143
186
 
144
- content_params = params.except( :type, :bucket, :index, :from, :return )
187
+ content_params = params.except( :type, :bucket, :index, :from, :return, :session_id )
145
188
  target_params = params.slice( :type, :bucket, :index )
189
+ # session_id = params[:session_id] # extraxt session_id --> future-use?
146
190
  if target_params.empty?
147
- logger.error "Could not insert: target mising (type:, bucket:, index:)"
191
+ raise "Could not insert: target missing (type:, bucket:, index:)"
148
192
  elsif content_params.empty?
149
193
  logger.error "Nothing to Insert"
150
194
  else
151
195
  content = "CONTENT #{ content_params.to_json }"
152
196
  target = target_params.map{|y,z| y==:type ? z : "#{y.to_s} #{ z } "}.join
153
- Api.execute( database, "INSERT INTO #{target} #{content} ") &.first.allocate_model(false)
197
+ result = Api.execute( database, session_id: session ){ "INSERT INTO #{target} #{content} "}
198
+ result &.first.allocate_model(false)
154
199
  end
155
200
  end
156
201
 
@@ -173,89 +218,61 @@ module Arcade
173
218
  rid = rid.join(':')
174
219
  rid = rid[1..-1] if rid[0]=="#"
175
220
  if rid.rid?
176
- Api.query( database, "select from #{rid}" ).first &.allocate_model(autocomplete)
221
+ Api.query( database, "select from #{rid}", session_id: session ).first &.allocate_model(autocomplete)
177
222
  else
178
223
  raise Arcade::QueryError "Get requires a rid input", caller
179
224
  end
180
225
  end
181
226
 
182
- # ------------------------------ property ------------------------------------------------- #
183
- # Adds properties to the type
227
+ # ------------------------------ get ------------------------------------------------------ #
184
228
  #
185
- # call via
186
- # Api.property <database>, <type>, name1: a_format , name2: a_format
229
+ # Delete the specified rid
187
230
  #
188
- # Format is one of
189
- # Boolean, Integer, Short, Long, Float, Double, String
190
- # Datetime, Binary, Byte, Decimal, Link
191
- # Embedded, EmbeddedList, EmbeddedMap
231
+ def delete rid
232
+ r = Api.execute( database, session_id: session ){ "delete from #{rid}" }
233
+ success = r == [{ :count => 1 }]
234
+ end
235
+
236
+ # ------------------------------ transmit ------------------------------------------------------ #
237
+ # transmits a command which potentially modifies the database
192
238
  #
193
- # In case of an Error, anything is rolled back and nil is returned
239
+ # Uses the given session_id for transaction-based operations
194
240
  #
195
- def self.property database, type, **args
196
-
197
- begin_transaction database
198
- success = args.map do | name, format |
199
- r= execute(database) {" create property #{type.to_s}.#{name.to_s} #{format.to_s} " } &.first
200
- if r.nil?
201
- false
202
- else
203
- r.keys == [ :propertyName, :typeName, :operation ] && r[:operation] == 'create property'
204
- end
205
- end.uniq
206
- if success == [true]
207
- commit database
208
- true
241
+ # Otherwise just performs the operation
242
+
243
+ def transmit &block
244
+ response = Api.execute database, session_id: session, &block
245
+ if response.is_a? Hash
246
+ _allocate_model res
209
247
  else
210
- rollback database
248
+ response
211
249
  end
212
-
213
-
214
- end
215
-
216
- # ------------------------------ index ------------------------------------------------- #
217
- def self.index database, type, name , *properties
218
- properties = properties.map( &:to_s )
219
- unique_requested = "unique" if properties.delete("unique")
220
- unique_requested = "notunique" if properties.delete("notunique" )
221
- automatic = true if
222
- properties << name if properties.empty?
223
250
  end
224
-
225
- def delete rid
226
- r = Api.execute( database ){ "delete from #{rid}" }
227
- success = r == [{ :count => 1 }]
228
- end
229
-
251
+ # ------------------------------ execute ------------------------------------------------------ #
230
252
  # execute a command which modifies the database
231
253
  #
232
254
  # The operation is performed via Transaction/Commit
233
255
  # If an Error occurs, its rolled back
234
256
  #
257
+ # If a transaction is already active, a nested transation is initiated
258
+ #
235
259
  def execute &block
236
- Api.begin_transaction database
237
- response = Api.execute database, &block
238
- # puts response.inspect # debugging
260
+ # initiate a new transaction
261
+ s= Api.begin_transaction database
262
+ response = Api.execute database, session_id: s, &block
239
263
  r= if response.is_a? Hash
240
- _allocate_model res
241
- # elsif response.is_a? Array
242
- # remove empty results
243
- # response.delete_if{|y| y.empty?}
244
- # response.map do | res |
245
- # if res.key? :"@rid"
246
- # allocate_model res
247
- # else
248
- # res
249
- # end
250
- # end
264
+ _allocate_model response
251
265
  else
252
266
  response
253
267
  end
254
- Api.commit database
255
- r # return associated array of Arcade::Base-objects
268
+ if Api.commit( database, session_id: s) == 204
269
+ r # return associated array of Arcade::Base-objects
270
+ else
271
+ []
272
+ end
256
273
  rescue Dry::Struct::Error, Arcade::QueryError => e
257
- Api.rollback database
258
- logger.error "Execution FAILED --> #{e.exception}"
274
+ Api.rollback database, session_id: s, log: false
275
+ logger.info "Execution FAILED --> Status #{e.status}"
259
276
  [] # return empty result
260
277
  end
261
278
 
@@ -264,7 +281,7 @@ module Arcade
264
281
  # detects database-records and allocates them as model-objects
265
282
  #
266
283
  def query query_object
267
- Api.query database, query_object.to_s
284
+ Api.query database, query_object.to_s, session_id: session
268
285
  end
269
286
 
270
287
  # returns an array of rid's (same logic as create)
@@ -272,11 +289,13 @@ module Arcade
272
289
 
273
290
  content = attributes.empty? ? "" : "CONTENT #{attributes.to_json}"
274
291
  cr = ->( f, t ) do
275
- edges = Api.execute( database, "create edge #{edge_class} from #{f.rid} to #{t.rid} #{content}").allocate_model(false)
276
- #else
277
- # logger.error "Could not create Edge #{edge_class} from #{f} to #{t}"
278
- ## logger.error edges.to_s
279
- #end
292
+ begin
293
+ cmd = -> (){ "create edge #{edge_class} from #{f.rid} to #{t.rid} #{content}" }
294
+ edges = transmit( &cmd ).allocate_model(false)
295
+ rescue Arcade::QueryError => e
296
+ raise unless e.message =~ /Found duplicate key/
297
+ puts "#"+e.detail.split("#").last[0..-3]
298
+ end
280
299
  end
281
300
  from = [from] unless from.is_a? Array
282
301
  to = [to] unless to.is_a? Array
@@ -287,52 +306,12 @@ module Arcade
287
306
 
288
307
  end
289
308
 
290
-
291
- # query all: select @rid, * from {database}
292
-
293
- # not used
294
- # def get_schema
295
- # query( "select from schema:types" ).map do |a|
296
- # puts "a: #{a}"
297
- # class_name = a["name"]
298
- # inherent_class = a["parentTypes"].empty? ? [Object,nil] : a["parentTypes"].map(&:camelcase_and_namespace)
299
- # namespace, type_name = a["type"].camelcase_and_namespace
300
- # namespace= Arcade if namespace.nil?
301
- # klass= Dry::Core::ClassBuilder.new( name: type_name,
302
- # parent: nil,
303
- # namespace: namespace).call
304
- # end
305
- # rescue NameError
306
- # logger.error "Dataset type #{e} not defined."
307
- # raise
308
- # end
309
- # Postgres is not implemented
310
- # connects to the database and initialises @connection
311
- def connection
312
- @connection
309
+ def session
310
+ @session_id
313
311
  end
314
312
 
315
- def connect environment=:development # environments: production devel test
316
- if [:production, :development, :test].include? environment
317
-
318
- # connect through the ruby postgres driver
319
- # c= PG::Connection.new dbname: Config.database[environment],
320
- # user: Config.username[environment],
321
- # password: Config.password[environment],
322
- # host: Config.pg[:host],
323
- # port: Config.pg[:port]
324
- #
325
- end
326
- rescue PG::ConnectionBad => e
327
- if e.to_s =~ /Credentials/
328
- logger.error "NOT CONNECTED ! Either Database is not present or credentials (#{ Config.username[environment]} / #{Config.password[environment]}) are wrong"
329
- nil
330
- else
331
- raise
332
- end
333
- end # def
334
-
335
-
336
-
313
+ def session?
314
+ !session.nil?
315
+ end
337
316
  end # class
338
317
  end # module