active-orient 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
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