active-orient 0.5 → 0.6

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -2
  3. data/README.md +78 -35
  4. data/VERSION +1 -1
  5. data/active-orient.gemspec +4 -4
  6. data/bin/active-orient-console +8 -5
  7. data/config/boot.rb +2 -4
  8. data/config/config.yml +1 -1
  9. data/config/connect.yml +2 -2
  10. data/examples/time_graph.md +162 -0
  11. data/gratefuldeadconcerts.md +94 -0
  12. data/lib/active-orient.rb +4 -2
  13. data/lib/base.rb +53 -20
  14. data/lib/base_properties.rb +2 -3
  15. data/lib/class_utils.rb +3 -4
  16. data/lib/database_utils.rb +14 -5
  17. data/lib/init.rb +11 -1
  18. data/lib/model/edge.rb +12 -10
  19. data/lib/model/model.rb +17 -3
  20. data/lib/model/the_class.rb +60 -40
  21. data/lib/model/the_record.rb +63 -51
  22. data/lib/model/vertex.rb +114 -10
  23. data/lib/orient.rb +24 -33
  24. data/lib/orientdb_private.rb +31 -31
  25. data/lib/other.rb +55 -5
  26. data/lib/rest/change.rb +17 -4
  27. data/lib/rest/create.rb +38 -24
  28. data/lib/rest/delete.rb +3 -2
  29. data/lib/rest/operations.rb +37 -27
  30. data/lib/rest/read.rb +2 -2
  31. data/lib/rest/rest.rb +4 -3
  32. data/lib/support.rb +17 -16
  33. data/linkmap.md +75 -0
  34. data/namespace.md +111 -0
  35. data/rails.md +125 -0
  36. data/rails/activeorient.rb +53 -0
  37. data/{examples/time_graph/config → rails}/config.yml +3 -1
  38. data/{examples/time_graph/config → rails}/connect.yml +2 -2
  39. data/usecase_oo.md +3 -1
  40. metadata +21 -38
  41. data/examples/createTime.rb +0 -91
  42. data/examples/time_graph/Gemfile +0 -21
  43. data/examples/time_graph/Guardfile +0 -26
  44. data/examples/time_graph/README.md +0 -129
  45. data/examples/time_graph/bin/active-orient-console +0 -35
  46. data/examples/time_graph/config/boot.rb +0 -119
  47. data/examples/time_graph/config/init_db.rb +0 -59
  48. data/examples/time_graph/createTime.rb +0 -51
  49. data/examples/time_graph/lib/createTime.rb +0 -82
  50. data/examples/time_graph/model/day_of.rb +0 -3
  51. data/examples/time_graph/model/e.rb +0 -6
  52. data/examples/time_graph/model/edge.rb +0 -53
  53. data/examples/time_graph/model/monat.rb +0 -19
  54. data/examples/time_graph/model/stunde.rb +0 -16
  55. data/examples/time_graph/model/tag.rb +0 -29
  56. data/examples/time_graph/model/time_base.rb +0 -6
  57. data/examples/time_graph/model/time_of.rb +0 -4
  58. data/examples/time_graph/model/v.rb +0 -3
  59. data/examples/time_graph/model/vertex.rb +0 -32
  60. data/examples/time_graph/spec/lib/create_time_spec.rb +0 -50
  61. data/examples/time_graph/spec/rest_helper.rb +0 -37
  62. data/examples/time_graph/spec/spec_helper.rb +0 -46
  63. data/usecase.md +0 -104
@@ -2,17 +2,36 @@
2
2
 
3
3
  class Array
4
4
  def to_orient
5
- map &:to_orient
5
+ map( &:to_orient) # .join(',')
6
6
  end
7
7
 
8
8
  def from_orient
9
9
  map &:from_orient
10
10
  end
11
11
 
12
- def method_missing(method)
13
- unless method == :to_hash || method == :to_str
14
- return self.map{|x| x.public_send(method)}
12
+ def method_missing(method, *key)
13
+ #if method == :to_int
14
+ # return self.first
15
+ #else
16
+
17
+ unless method == :to_hash || method == :to_str #|| method == :to_int
18
+ return self.map{|x| x.public_send(method, *key)}
19
+ # end
20
+ end
21
+ end
22
+ # used to enable
23
+ # def abc *key
24
+ # where key is a Range, an comma separated List or an item
25
+ # aimed to support #compose_where
26
+ def analyse
27
+ if first.is_a?(Range)
28
+ first
29
+ elsif size ==1
30
+ first
31
+ else
32
+ self
15
33
  end
34
+
16
35
  end
17
36
  end
18
37
 
@@ -22,6 +41,20 @@ end
22
41
  # end
23
42
  #end
24
43
  if RUBY_PLATFORM == 'java'
44
+
45
+ ## JavaMath:.BigDecimal does not premit mathematical operations
46
+ ## We convert it to RubyBigDecimal to represent it (if present in the DB) and upon loading from the DB
47
+
48
+ class Java::JavaMath::BigDecimal
49
+ def to_f
50
+ BigDecimal.new self.to_s
51
+ end
52
+
53
+ def from_orient
54
+ BigDecimal.new self.to_s
55
+ end
56
+
57
+ end
25
58
  class Java::ComOrientechnologiesOrientCoreDbRecordRidbag::ORidBag
26
59
  def from_orient
27
60
  to_a.from_orient
@@ -108,6 +141,9 @@ class Symbol
108
141
  def from_orient
109
142
  self
110
143
  end
144
+ def to_a
145
+ [ self ]
146
+ end
111
147
  end
112
148
  class FalseClass
113
149
  def from_orient
@@ -165,6 +201,7 @@ class NilClass
165
201
  def from_orient
166
202
  nil
167
203
  end
204
+
168
205
  end
169
206
 
170
207
  class Numeric
@@ -179,6 +216,10 @@ class Numeric
179
216
  def to_or
180
217
  "#{self.to_s}"
181
218
  end
219
+
220
+ def to_a
221
+ [ self ]
222
+ end
182
223
  end
183
224
 
184
225
  class String
@@ -186,6 +227,12 @@ class String
186
227
  self.sub(/^(.)/) { $1.capitalize }
187
228
  end
188
229
 
230
+ def where **args
231
+ if rid?
232
+ from_orient.where **args
233
+ end
234
+ end
235
+
189
236
  def from_orient
190
237
  if rid?
191
238
  ActiveOrient::Model.autoload_object self
@@ -233,7 +280,10 @@ class String
233
280
  def to_or
234
281
  quote
235
282
  end
236
-
283
+
284
+ def to_a
285
+ [ self ]
286
+ end
237
287
 
238
288
  def quote
239
289
  str = self.dup
@@ -51,11 +51,24 @@ Both set and where take multiple attributes
51
51
  Returns the JSON-Response.
52
52
  =end
53
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 ''
54
+ def update_records o_class, set:{}, where: {}, remove: nil
55
+ logger.progname = 'RestChange#UpdateRecords'
56
+ url = if set.present?
57
+ "UPDATE #{classname(o_class)} SET #{generate_sql_list(set)} #{compose_where(where)}"
58
+ elsif remove.present?
59
+ "UPDATE #{classname(o_class)} remove #{remove} #{compose_where(where)}"
60
+ end
61
+ r = @res[URI.encode("/command/#{ActiveOrient.database}/sql/" << url)].post ''
62
+ count_of_updated_records = (JSON.parse( r))['result'].first['value']
63
+ ## remove all records of the class from cache
64
+ ActiveOrient::Base.display_rid.delete_if{|x,y| y.is_a? o_class } if count_of_updated_records > 0 && o_class.is_a?(Class)
65
+ count_of_updated_records # return_value
66
+ rescue Exception => e
67
+ logger.error{e.message}
68
+ nil
69
+
70
+
57
71
  end
58
- alias update_documents update_records
59
72
 
60
73
  # Lazy Updating of the given Record.
61
74
 
@@ -8,24 +8,24 @@ module RestCreate
8
8
  Returns the name of the working-database
9
9
  =end
10
10
 
11
- def create_database type: 'plocal', database: nil
11
+ def create_database type: 'plocal', database:
12
12
  logger.progname = 'RestCreate#CreateDatabase'
13
- old_d = ActiveOrient.database
14
- ActiveOrient.database_classes = []
15
- ActiveOrient.database = database if database.present?
16
- begin
13
+ old_d = ActiveOrient.database
14
+ ActiveOrient.database_classes = []
15
+ ActiveOrient.database = database
16
+ begin
17
17
  response = @res["database/#{ActiveOrient.database}/#{type}"].post ""
18
18
  if response.code == 200
19
- logger.info{"Database #{ActiveOrient.database} successfully created and stored as working database"}
19
+ logger.info{"Database #{ActiveOrient.database} successfully created and stored as working database"}
20
20
  else
21
- ActiveOrient.database = old_d
22
- logger.error{"Database #{name} was NOT created. Working Database is still #{ActiveOrient.database}"}
21
+ logger.error{"Database #{ActiveOrient.database} was NOT created. Working Database is still #{ActiveOrient.database}"}
22
+ ActiveOrient.database = old_d
23
23
  end
24
24
  rescue RestClient::InternalServerError => e
25
+ logger.error{"Database #{ActiveOrient.database} was NOT created. Working Database is still #{ActiveOrient.database}"}
25
26
  ActiveOrient.database = old_d
26
- logger.error{"Database #{name} was NOT created. Working Database is still #{ActiveOrient.database}"}
27
27
  end
28
- ActiveOrient.database
28
+ ActiveOrient.database # return_value
29
29
  end
30
30
 
31
31
  ######### CLASS ##########
@@ -86,7 +86,7 @@ creates a vertex-class, too, returns the Hash
86
86
  #and assign to this existing one.
87
87
  =end
88
88
  def create_classes *classes, &b
89
- returt if classes.empty?
89
+ return if classes.empty?
90
90
 
91
91
  classes = classes.pop if classes.size == 1
92
92
  consts = allocate_classes_in_ruby( classes , &b )
@@ -218,6 +218,7 @@ creates a vertex-class, too, returns the Hash
218
218
  attributes = yield if attributes.empty? && block_given?
219
219
  # @class must not quoted! Quote only attributes(strings)
220
220
  post_argument = {'@class' => classname(o_class)}.merge(attributes.to_orient)
221
+ # puts post_argument.inspect
221
222
  begin
222
223
  response = @res["/document/#{ActiveOrient.database}"].post post_argument.to_json
223
224
  data = JSON.parse(response.body)
@@ -227,10 +228,22 @@ creates a vertex-class, too, returns the Hash
227
228
  ActiveOrient::Model.orientdb_class(name: data['@class'], superclass: :find_ME).new data
228
229
  end
229
230
  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
231
+ sentence= JSON.parse( e.response)['errors'].last['content']
232
+ puts sentence.to_s
233
+ if sentence =~ /found duplicated key/
234
+ rid = sentence.split("#").last
235
+ logger.info{ "found duplicated Key --> loaded #{rid} instead of creating "}
236
+ ## reading database content -- maybe update attributes?
237
+ get_record rid
238
+ else
239
+ response = JSON.parse(e.response)['errors'].pop
240
+ logger.error{response['content'].split(':')[1..-1].join(':')}
241
+ logger.error{"No Object allocated"}
242
+ nil # return_value
243
+ end
244
+ rescue Errno::EADDRNOTAVAIL => e
245
+ sleep(2)
246
+ retry
234
247
  end
235
248
  end
236
249
  alias create_document create_record
@@ -312,6 +325,7 @@ The method returns the included or the updated dataset
312
325
  # if what == :update
313
326
  # do stuff with update
314
327
  # end
328
+ # returns nil if no insert and no update was made, ie. the dataset is identical to the given attributes
315
329
  =end
316
330
  def upsert o_class, set: {}, where: {} # :nodoc: use Model#Upsert instead
317
331
  logger.progname = 'RestCreate#Upsert'
@@ -323,14 +337,12 @@ The method returns the included or the updated dataset
323
337
  specify_return_value = block_given? ? "" : "return after @this"
324
338
  set.merge! where if where.is_a?( Hash ) # copy where attributes to set
325
339
  command = "Update #{classname(o_class)} set #{generate_sql_list( set ){','}} upsert #{specify_return_value} #{compose_where where}"
326
-
327
-
328
- # puts "COMMAND: #{command} "
340
+ # puts "COMMAND: #{command} "
329
341
  result = execute tolerated_error_code: /found duplicated key/, raw: true do # To execute commands
330
342
  [ { type: "cmd", language: 'sql', command: command}]
331
343
  end
332
344
  result =result.pop if result.is_a? Array
333
- # puts "RESULT: #{result.inspect}, #{result.class}"
345
+ if result.is_a? Hash
334
346
  if result.has_key?('@class')
335
347
  if o_class.is_a?(Class) && o_class.new.is_a?(ActiveOrient::Model)
336
348
  o_class.new result
@@ -352,8 +364,10 @@ The method returns the included or the updated dataset
352
364
  logger.error{ "Unexpected result form Query \n #{command} \n Result: #{result}" }
353
365
  raise ArgumentError
354
366
  end
355
-
356
- end
367
+ else
368
+ logger.debug{ "No Insert or Update nessesary \n #{command} " }
369
+ end
370
+ end
357
371
  end
358
372
  ############### PROPERTIES #############
359
373
 
@@ -402,8 +416,8 @@ The method returns the included or the updated dataset
402
416
  if block_given?# && count == all_properties_in_a_hash.size
403
417
  index = yield
404
418
  if index.is_a?(Hash)
405
- puts "index_class: #{o_class}"
406
- puts "index: "+index.inspect
419
+ # puts "index_class: #{o_class}"
420
+ # puts "index: "+index.inspect
407
421
  if index.size == 1
408
422
  create_index o_class, name: index.keys.first, on: all_properties_in_a_hash.keys, type: index.values.first
409
423
  else
@@ -448,7 +462,7 @@ The method returns the included or the updated dataset
448
462
  logger.progname = 'RestCreate#CreateIndex'
449
463
  begin
450
464
  c = classname o_class
451
- puts "CREATE INDEX: class: #{c.inspect}"
465
+ # puts "CREATE INDEX: class: #{c.inspect}"
452
466
  execute transaction: false do
453
467
  command = if on == :automatic
454
468
  "CREATE INDEX #{c}.#{name} #{type.to_s.upcase}"
@@ -47,9 +47,10 @@ module RestDelete
47
47
  ActiveOrient.database_classes.delete(cl)
48
48
  end
49
49
  rescue RestClient::InternalServerError => e
50
- if get_database_classes(requery: true).include?(cl)
50
+ sentence= JSON.parse( e.response)['errors'].last['content']
51
+ if database_classes(requery: true).include?(cl)
51
52
  logger.error{"Class #{cl} still present."}
52
- logger.error{e.inspect}
53
+ logger.error{ sentence }
53
54
  false
54
55
  else
55
56
  logger.error{e.inspect}
@@ -24,32 +24,38 @@ module RestOperations
24
24
  result.first['COUNT'] rescue 0 # return_value
25
25
  end
26
26
 
27
-
28
- def manipulate_relation record, method, array, items # :nodoc: #
29
- execute_array = Array.new
30
- method = method.to_s.upcase
31
-
32
- add_2_execute_array = -> (it) do
33
- command = "UPDATE ##{record.rid} #{method} #{array} = #{it.to_orient } " #updating}"
34
- command.gsub!(/\"/,"") if it.is_a? Array
35
- #puts "COMMAND:: #{command}"
36
- execute_array << {type: "cmd", language: "sql", command: command}
37
- end
38
-
39
- items.each{|x| add_2_execute_array[x] }
40
- r= execute{ execute_array }
41
-
42
- if r.present?
43
- case method
44
- when 'ADD'
45
- items.each{|x| record.attributes[array] << x}
46
- when 'REMOVE'
47
- items.map{|x| record.attributes[array].delete x.is_a?(ActiveOrient::Model) ? x.rid : x}
48
- else
49
- end
50
- record.increment_version
51
- end
52
- end
27
+ ## historic method
28
+ # def manipulate_relation record, method, array, items # :nodoc: #
29
+ # execute_array = Array.new
30
+ # method = method.to_s.upcase
31
+ #
32
+ # add_2_execute_array = -> (it) do
33
+ # command = "UPDATE ##{record.rid} #{method} #{array} = #{it.to_or } " #updating}"
34
+ # command.gsub!(/\"/,"") if it.is_a? Array
35
+ # puts "COMMAND:: #{command}"
36
+ # execute_array << {type: "cmd", language: "sql", command: command}
37
+ # end
38
+ #
39
+ # items.to_a.each{|x| add_2_execute_array[x] }
40
+ ## puts "******************"
41
+ ## puts record.inspect
42
+ ## puts "-----"
43
+ ## puts execute_array.join('\n')
44
+ # r= execute{ execute_array }
45
+ # puts record.inspect
46
+ # puts r.inspect
47
+ ## puts "******************"
48
+ # if r.present?
49
+ # case method
50
+ # when 'ADD'
51
+ # items.each{|x| record.attributes[array] << x}
52
+ # when 'REMOVE'
53
+ # items.map{|x| record.attributes[array].delete x}
54
+ # else
55
+ # end
56
+ # record.increment_version
57
+ # end
58
+ # end
53
59
  =begin
54
60
  Executes a list of commands and returns the result-array (if present)
55
61
 
@@ -90,6 +96,7 @@ Multible statements are transmitted at once if the Block provides an Array of st
90
96
  def execute transaction: true, tolerated_error_code: nil, process_error: true, raw: nil # Set up for classes
91
97
  batch = {transaction: transaction, operations: yield}
92
98
  logger.progname= "Execute"
99
+ # puts "batch: #{batch[:operations]}"
93
100
  unless batch[:operations].blank?
94
101
  batch[:operations] = {:type=>"cmd", :language=>"sql", :command=> batch[:operations]} if batch[:operations].is_a? String
95
102
  batch[:operations] = [batch[:operations]] unless batch[:operations].is_a? Array
@@ -122,10 +129,13 @@ Multible statements are transmitted at once if the Block provides an Array of st
122
129
  raise
123
130
  end
124
131
  end
132
+ rescue Errno::EADDRNOTAVAIL => e
133
+ sleep(2)
134
+ retry
125
135
  end
126
136
  if response.present? && response.code == 200
127
137
  if response.body['result'].present?
128
- result= JSON.parse(response.body)['result']
138
+ result=JSON.parse(response.body)['result']
129
139
  return result if raw.present?
130
140
  result.map do |x|
131
141
  if x.is_a? Hash
@@ -113,8 +113,8 @@ module RestRead
113
113
  begin
114
114
  logger.progname = 'RestRead#GetRecords'
115
115
  url = "/query/#{ActiveOrient.database}/sql/" + query.compose(destination: :rest) + "/#{query.get_limit}"
116
- # puts "URL"
117
- # puts query.compose( destination: :rest).to_s
116
+ # puts "REST_READ#GET_RECORDS.URL"
117
+ # puts query.compose( destination: :rest).to_s
118
118
  # puts url.to_s
119
119
  response = @res[URI.encode(url)].get
120
120
  JSON.parse(response.body)['result'].map do |record|
@@ -53,7 +53,7 @@ A Sample:
53
53
  initialises the Database-Connection and publishes the Instance to any ActiveOrient::Model-Object
54
54
  =end
55
55
 
56
- def initialize database: nil, connect: true, preallocate: true
56
+ def initialize database: nil, connect: true, preallocate: true, model_dir: nil
57
57
  self.logger = Logger.new('/dev/stdout') unless logger.present?
58
58
  # self.default_server = {
59
59
  # :server => 'localhost',
@@ -70,7 +70,8 @@ A Sample:
70
70
  database_classes # initialize @classes-array
71
71
  ActiveOrient::Model.orientdb = self
72
72
  ActiveOrient::Model.db = self
73
- preallocate_classes if preallocate
73
+ ActiveOrient::Model.keep_models_without_file ||= nil
74
+ preallocate_classes(model_dir) if preallocate
74
75
 
75
76
  end
76
77
 
@@ -99,7 +100,7 @@ A Sample:
99
100
  if first_tentative
100
101
  logger.info{"Database #{database} NOT present --> creating"}
101
102
  first_tentative = false
102
- create_database
103
+ create_database database: database
103
104
  retry
104
105
  else
105
106
  Kernel.exit
@@ -41,8 +41,12 @@ designs a list of "Key = Value" pairs combined by "and" or the fillword provide
41
41
  "#{key} = #{value.rrid}"
42
42
  when Numeric
43
43
  "#{key} = #{value}"
44
- when Array
45
- "#{key}= #{value.to_orient}"
44
+ when ::Array
45
+ "#{key} in [#{value.to_orient}]"
46
+ when Range
47
+ "#{key} between #{value.first} and #{value.last} "
48
+ when DateTime
49
+ "#{key} = date(\'#{value.strftime("%Y%m%d%H%M%S")}\',\'yyyyMMddHHmmss\')"
46
50
  when Date
47
51
  "#{key} = date(\'#{value.to_s}\',\'yyyy-MM-dd\')"
48
52
  else # String, Symbol, Time, Trueclass, Falseclass ...
@@ -304,15 +308,17 @@ end
304
308
  def from arg = nil
305
309
  if arg.present?
306
310
  @database = case arg
307
- when ActiveOrient::Model
311
+ when ActiveOrient::Model # a single record
308
312
  arg.rrid
309
- when OrientQuery
313
+ when OrientQuery # result of a query
310
314
  ' ( '+ arg.to_s + ' ) '
315
+ when Class
316
+ arg.ref_name
311
317
  else
312
- if arg.to_s.rid?
318
+ if arg.to_s.rid? # a string with "#ab:cd"
313
319
  arg
314
- else
315
- ORD.classname(arg)
320
+ else # a databas-class-name
321
+ arg.to_s
316
322
  end
317
323
  end
318
324
  compose # return the complete query
@@ -360,15 +366,12 @@ end
360
366
  end
361
367
 
362
368
  def distinct d
363
- @projection << case d
369
+ @projection << case d
364
370
  when String, Symbol
365
371
  "distinct( #{d.to_s} )"
366
- when Array
367
- "distinct( #{d.first} ) as #{d.last}"
368
- when Hash
369
- "distinct( #{d.first.first} ) as #{d.first.last}"
370
- else
371
- ""
372
+ else
373
+ dd= d.to_a.flatten
374
+ "distinct( #{dd.first.to_s} ) as #{dd.last}"
372
375
  end
373
376
  compose # return the hole query
374
377
  end
@@ -419,8 +422,6 @@ end
419
422
  unless @order.empty?
420
423
  # the [@order] is nessesary to enable query.order= "..." oder query.order= { a: :b }
421
424
  "order by " << [@order].flatten.map do |o|
422
- #puts "CLASS : "+o.class.to_s
423
- #puts o.to_s
424
425
  case o
425
426
  when String, Symbol, Array
426
427
  o.to_s