active-orient 0.79 → 0.80

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,70 @@
1
+ Graphen
2
+ ======
3
+
4
+ Die Felder `in` und `out` bündeln die Verknüpfungen zu anderen Vertices.
5
+
6
+ Die Verknüpfungen erfolgen über `Edges`, die wiederum Eigenschaften haben. Zuerst sind die `Edges` Klassen und
7
+ unterscheiden sich üder den Namen. Zusätzlich besteht Vererbung.
8
+
9
+ Beispielgraph
10
+ @db.create_vertex_class :v1
11
+ @db.create_class( :v2 ){ V1 }
12
+ @db.create_edge_class "e1"
13
+ @db.create_class( :e2 ){ E1 }
14
+ @db.create_class( :e3 ){ E1 }
15
+
16
+ vertices = (1..10).map{|y| V2.create node: y}
17
+ E2.create from: V1.create( item: 1 ), to: vertices
18
+
19
+ v1 = V.first.to_human => "<V1[#25:0]: out: {E2=>10}, item : 1>"
20
+ v2 = V.last.to_human => "<V2[#40:0]: in: {E2=>1}, node : 8>"
21
+
22
+ Boardmittel von ActiveOrient
23
+ ----------------------------
24
+
25
+ ## Edges anlisten
26
+
27
+ #### Nur Links
28
+
29
+ v1.edges => ["#49:0", "#50:0", "#51:0", "#52:0", "#53:0", "#54:0", "#55:0", "#56:0", "#49:1", "#50:1"]
30
+ v2.edges => ["#56:0"]
31
+
32
+
33
+ #### Auflösung der Objekte
34
+
35
+ v2.in.map &:to_human => ["<E2: in : #<V2:0x000000000397fcb8>, out : #<V1:0x0000000002ed0060>>"]
36
+
37
+ #### Verfügbare Methoden
38
+ v2.in v2.in_e v2.in_e2 v2.in_e2= v2.in_edges
39
+
40
+
41
+ ### Selektive Auswahl
42
+
43
+ Beispiel: TimeGrid
44
+
45
+ Der Vertex hat folgende Struktur
46
+
47
+ t.to_human
48
+ => "<Tag[82:8927]: in: {TG::DAY_OF=>1, TG::GRID_OF=>1}, out: {ML::L_OHLC=>1, TG::GRID_OF=>1}, value : 25>"
49
+
50
+ dann listet t.detect_edges :out, /ml/ die Edges der ML-Klassen auf:
51
+
52
+ t.detect_edges( :out , /ml/).to_human
53
+ => ["<L_OHLC[#151:16] -i-> #161:22 { } -o-> #82:8927>"]
54
+
55
+
56
+ #### Node
57
+
58
+ Ein Node ist ein direkt über eine Edge verbundener Vertex
59
+
60
+ Q = OrientSupport::OrientQuery
61
+ s= Q.new projection: "expand( outE('e1').in[node <5])"
62
+ s.from = '#25:0'
63
+ s.to_s => select expand( outE('v1').in[node <5]) from #25:0
64
+
65
+ Aufruf in OrientQuery: Q.node Edge_class, condition
66
+
67
+ Fügt den Node in das Porjections-Array ein.
68
+
69
+
70
+
@@ -31,6 +31,7 @@ require 'active_model'
31
31
  require_relative "support/orientquery.rb"
32
32
  require_relative "support/conversions.rb"
33
33
  #require_relative "support/logging.rb"
34
+ require_relative "support/errors.rb"
34
35
  require_relative "base.rb"
35
36
  require_relative "base_properties.rb"
36
37
  require_relative "support/orient.rb"
@@ -55,6 +56,7 @@ require_relative "railtie" if defined?(Rails)
55
56
 
56
57
  module ActiveOrient
57
58
  mattr_accessor :database
59
+ mattr_accessor :db_pool
58
60
  mattr_accessor :database_classes
59
61
  mattr_accessor :default_server
60
62
 
@@ -29,6 +29,7 @@ module ActiveOrient
29
29
  Any Change of the Object is thus synchonized to any allocated variable.
30
30
  =end
31
31
  @@rid_store = Hash.new
32
+ @@mutex = Mutex.new
32
33
 
33
34
  def self.display_rid
34
35
  @@rid_store
@@ -43,8 +44,14 @@ thus a string or a Model-Object is accepted
43
44
  =end
44
45
 
45
46
  def self.remove_rid obj
46
- @@rid_store.delete obj.rid if obj.rid.present?
47
- end
47
+ if obj &.rid.present?
48
+ @@mutex.synchronize do
49
+ @@rid_store.delete obj.rid
50
+ end
51
+ else
52
+ logger.error "Cache entry not removed: #{obj} "
53
+ end
54
+ end
48
55
 
49
56
  def self.get_rid rid
50
57
  rid = rid[1..-1] if rid[0]=='#'
@@ -63,17 +70,20 @@ and the cached obj is returned
63
70
 
64
71
  =end
65
72
  def self.store_rid obj
66
- if obj.rid.present? && obj.rid.rid?
67
- if @@rid_store[obj.rid].present?
68
- @@rid_store[obj.rid].transfer_content from: obj
69
- else
70
- @@rid_store[obj.rid] = obj
71
- end
72
- @@rid_store[obj.rid]
73
- else
74
- nil
75
- end
76
- end
73
+
74
+ @@mutex.synchronize do
75
+ if obj.rid.present? && obj.rid.rid?
76
+ if @@rid_store[obj.rid].present?
77
+ @@rid_store[obj.rid].transfer_content from: obj
78
+ else
79
+ @@rid_store[obj.rid] = obj
80
+ end
81
+ @@rid_store[obj.rid]
82
+ else
83
+ obj
84
+ end
85
+ end
86
+ end
77
87
 
78
88
 
79
89
  # rails compatibility
@@ -91,7 +101,7 @@ The model instance fields are then set automatically from the opts Hash.
91
101
  def initialize attributes = {}, opts = {}
92
102
  logger.progname = "ActiveOrient::Base#initialize"
93
103
  @metadata = Hash.new # HashWithIndifferentAccess.new
94
- @d = nil
104
+ @d = nil if RUBY_PLATFORM == 'java' && attributes.is_a?( Document )
95
105
  run_callbacks :initialize do
96
106
  if RUBY_PLATFORM == 'java' && attributes.is_a?( Document )
97
107
  @d = attributes
@@ -201,7 +211,17 @@ The model instance fields are then set automatically from the opts Hash.
201
211
 
202
212
  iv = attributes[key]
203
213
  if my_metadata( key: key) == "t"
204
- iv =~ /00:00:00/ ? Date.parse(iv) : DateTime.parse(iv)
214
+ # needed in case of
215
+ # obj.date = {some-date}
216
+ # --> perfrom an action on the date without saving prior
217
+ case iv
218
+ when String
219
+ iv =~ /00:00:00/ ? Date.parse(iv) : DateTime.parse(iv)
220
+ when Date, DateTime
221
+ iv
222
+ else
223
+ raise "incompatable type used: #{iv} (#{iv.class}) -- Date or DateTime required"
224
+ end
205
225
  elsif my_metadata( key: key) == "x"
206
226
  iv = ActiveOrient::Model.autoload_object iv
207
227
  elsif iv.is_a? Array
@@ -227,9 +247,9 @@ The model instance fields are then set automatically from the opts Hash.
227
247
  when Array
228
248
  if val.first.is_a?(Hash)
229
249
  v = val.map{ |x| x }
230
- OrientSupport::Array.new(work_on: self, work_with: v )
250
+ OrientSupport::Array.new(work_on: self, work_with: v ){ key_to_sym }
231
251
  else
232
- OrientSupport::Array.new(work_on: self, work_with: val )
252
+ OrientSupport::Array.new(work_on: self, work_with: val ){ key_to_sym }
233
253
  end
234
254
  when Hash
235
255
  if val.keys.include?("@class" )
@@ -280,6 +300,7 @@ The model instance fields are then set automatically from the opts Hash.
280
300
  # end
281
301
  #
282
302
  =begin
303
+ (Experimental)
283
304
  Exclude some properties from loading via get, reload!, get_document, get_record
284
305
  =end
285
306
  def self.exclude_the_following_properties *args
@@ -8,19 +8,19 @@ module ActiveOrient
8
8
 
9
9
  # Default presentation of ActiveOrient::Model-Objects
10
10
 
11
- def to_human
12
- "<#{self.class.to_s.demodulize}: " + content_attributes.map do |attr, value|
13
- v= case value
14
- when ActiveOrient::Model
15
- "< #{self.class.to_.demodulize} : #{value.rrid} >"
16
- when OrientSupport::Array
17
- value.rrid #.to_human #.map(&:to_human).join("::")
18
- else
19
- value.from_orient
20
- end
21
- "%s : %s" % [ attr, v] unless v.nil?
22
- end.compact.sort.join(', ') + ">".gsub('"' , ' ')
23
- end
11
+ def to_human
12
+ "<#{self.class.to_s.demodulize}: " + content_attributes.map do |attr, value|
13
+ v= case value
14
+ when ActiveOrient::Model
15
+ "< #{self.class.to_.demodulize} : #{value.rrid} >"
16
+ when OrientSupport::Array
17
+ value.rrid #.to_human #.map(&:to_human).join("::")
18
+ else
19
+ value.from_orient
20
+ end
21
+ "%s : %s" % [ attr, v] unless v.nil?
22
+ end.compact.sort.join(', ') + ">".gsub('"' , ' ')
23
+ end
24
24
 
25
25
  # Comparison support
26
26
 
@@ -30,8 +30,9 @@ module ActiveOrient
30
30
  attr.to_s =~ /(_count)\z/ || attr.to_s =~ /^in_/ || attr.to_s =~ /^out_/ || [:created_at, :updated_at, :type, :id, :order_id, :contract_id].include?(attr.to_sym)
31
31
  end]
32
32
  end
33
-
34
33
  # return a string ready to include as embedded document
34
+ # used by Model.to_or
35
+ #
35
36
  def embedded
36
37
  { "@type" => 'd', "@class" => self.class.ref_name }
37
38
  .merge(content_attributes)
@@ -3,6 +3,8 @@ module ClassUtils
3
3
 
4
4
  =begin
5
5
  Returns a valid database-class name, nil if the class does not exists
6
+
7
+ works on the cached hash (ActiveOrient.database_classes)
6
8
  =end
7
9
 
8
10
  def classname name_or_class # :nodoc:
@@ -21,9 +23,11 @@ module ClassUtils
21
23
  end
22
24
  end
23
25
  end
24
- def allocate_class_in_ruby db_classname, &b
25
- # retrieve the superclass recursively
26
26
 
27
+ # Updates ActiveOrient.database_classes
28
+ def allocate_class_in_ruby db_classname, &b
29
+
30
+ # first retrieve the superclass recursively
27
31
  unless ActiveOrient.database_classes[ db_classname ].is_a? Class
28
32
 
29
33
  s = get_db_superclass( db_classname )
@@ -46,10 +50,9 @@ module ClassUtils
46
50
  elsif ActiveOrient::Model.namespace.send( :const_get, classname).ancestors.include?( ActiveOrient::Model )
47
51
  ActiveOrient::Model.namespace.send( :const_get, classname)
48
52
  else
49
- t= ActiveOrient::Model.send :const_set, classname, Class.new( superclass )
50
- logger.warn{ "Unable to allocate class #{classname} in Namespace #{ActiveOrient::Model.namespace}"}
51
- logger.warn{ "Allocation took place with namespace ActiveOrient::Model" }
52
- t
53
+ logger.error{ "Unable to allocate class #{classname} in Namespace #{ActiveOrient::Model.namespace}"}
54
+ logger.error{ "Allocation took place with namespace ActiveOrient::Model" }
55
+ ActiveOrient::Model.send :const_set, classname, Class.new( superclass )
53
56
  end
54
57
  the_class.ref_name = db_classname
55
58
  keep_the_dataset = block_given? ? yield( the_class ) : true
@@ -70,7 +73,7 @@ module ClassUtils
70
73
  nil # return-value
71
74
  end
72
75
  else
73
- # return previosly allocated ruby-class
76
+ # return previously allocated ruby-class
74
77
  ActiveOrient.database_classes[db_classname]
75
78
  end
76
79
  end
@@ -161,60 +164,18 @@ Creates one or more edge-classes and allocates the provided properties to each c
161
164
  r = name.map{|n| create_class( n.to_s, properties: properties){ E } }
162
165
  r.size == 1 ? r.pop : r # returns the created classes as array if multible classes are provided
163
166
  end
164
- =begin
165
-
166
- creates a vertex
167
-
168
- =end
169
- def create_vertex( o_class, attributes:{} )
170
-
171
- begin
172
- response = execute(transaction: false, tolerated_error_code: /found duplicated key/) do
173
- "CREATE VERTEX #{classname(o_class)} CONTENT #{attributes.to_orient.to_json}"
174
- end
175
- if response.is_a?(Array) && response.size == 1
176
- response.pop # RETURN_VALUE
177
- else
178
- response # return value (the normal case)
179
- end
180
- rescue ArgumentError => e
181
- puts "CreateVertex:ArgumentError "
182
- puts e.inspect
183
- end # begin
184
-
185
- end
186
167
 
187
- =begin
188
- Deletes the specified vertices and unloads referenced edges from the cache
189
- =end
190
- def delete_vertex *vertex
191
- create_command = -> do
192
- { type: "cmd",
193
- language: 'sql',
194
- command: "DELETE VERTEX #{vertex.map{|x| x.to_orient }.join(',')} "
195
- }
196
- end
197
-
198
- vertex.each{|v| v.edges.each{| e | remove_record_from_hash e} }
199
- execute{ create_command[] }
200
- end
201
168
 
202
169
  =begin
203
170
  Deletes the specified edges and unloads referenced vertices from the cache
204
171
  =end
205
172
  def delete_edge *edge
206
- create_command = -> do
207
- { type: "cmd",
208
- language: 'sql',
209
- command: "DELETE EDGE #{edge.map{|x| x.to_orient }.join(',')} "
210
- }
211
- end
212
173
 
213
174
  edge.each do |r|
214
175
  [r.in, r.out].each{| e | remove_record_from_hash e}
215
176
  remove_record_from_hash r
216
177
  end
217
- execute{ create_command[] }
178
+ execute{ "DELETE EDGE #{edge.map{|x| x.to_orient }.join(',')} "}
218
179
  end
219
180
 
220
181
  private
@@ -13,7 +13,7 @@ if abstract: true is given, only basic classes (Abstact-Classes) are returend
13
13
  ## "ORid" dropped in V2.2
14
14
  extended = ["OIdentity","ORole", "OUser", "OFunction", "_studio"]
15
15
  v3 = ["OGeometryCollection", "OLineString", "OMultiLineString", "OMultiPoint", "OMultiPolygon",
16
- "OPoint", "OPolygon", "ORectangle", "OShape"] ## added in Orentdb 3.0
16
+ "OPoint", "OPolygon", "ORectangle", "OShape", 'OSecurityPolicy'] ## added in Orentdb 3.0 and 3.1
17
17
  if abstract
18
18
  basic
19
19
  else
@@ -33,7 +33,7 @@ To retrieve the class hierarchy from Objects avoid calling `ORD.classname (obj)`
33
33
  =end
34
34
 
35
35
  def class_hierarchy base_class: '', system_classes: nil
36
- @actual_class_hash = get_classes('name', 'superClass') #if requery || @all_classes.blank?
36
+ # @actual_class_hash = get_classes('name', 'superClass') #if requery || @all_classes.blank?
37
37
  fv = ->( s ) { @actual_class_hash.find_all{|x| x['superClass']== s}.map{|v| v['name']} }
38
38
  fx = ->( v ) { fv[v.strip].map{|x| ar = fx[x]; ar.empty? ? x : [x, ar]} }
39
39
  if system_classes.present?
@@ -45,13 +45,15 @@ To retrieve the class hierarchy from Objects avoid calling `ORD.classname (obj)`
45
45
 
46
46
 
47
47
  =begin
48
- Returns an array with all names of the classes of the database. Uses a cached version if possible.
48
+
49
+ Returns an array with all names of the classes of the database.
50
+
51
+ Reads the database-structure and updates the @actual_class_hash (used by class_hierachy and get_db_superclass )
49
52
 
50
- Parameters: system_classes: false|true, requery: false|true
51
53
  =end
52
54
 
53
- def database_classes system_classes: nil, requery: false
54
- class_hierarchy system_classes: system_classes #requery: true
55
+ def database_classes system_classes: nil
56
+ @actual_class_hash = get_classes('name', 'superClass')
55
57
  all_classes = get_classes('name').map(&:values).sort.flatten
56
58
  all_user_classes = all_classes - system_classes()
57
59
 
@@ -65,8 +67,8 @@ Service-Method for Model#OrientdbClass
65
67
  =end
66
68
 
67
69
  def get_db_superclass name #:nodoc:
68
- @actual_class_hash = get_classes( 'name', 'superClass') if @actual_class_hash.nil?
69
- z= @actual_class_hash.find{|x,y| x['name'] == name.to_s }
70
+ # @actual_class_hash = get_classes( 'name', 'superClass') if @actual_class_hash.nil?
71
+ z= @actual_class_hash.find{|x,y| x['name'] == name.to_s }
70
72
  z['superClass'] unless z.nil?
71
73
  end
72
74
 
@@ -74,24 +76,23 @@ Service-Method for Model#OrientdbClass
74
76
  preallocate classes reads any class from the @classes-Array and allocates adequat Ruby-Objects
75
77
  =end
76
78
  def preallocate_classes from_model_dir= nil # :nodoc:
77
- # always scan for E+V model-file and include
79
+ # always scan for E+V model-files and include
78
80
  [E,V].each{|y| y.require_model_file(from_model_dir) }
79
81
 
80
82
  ActiveOrient.database_classes.each do | db_name, the_class |
81
83
  allocate_class_in_ruby( db_name ) do |detected_class|
82
- keep_the_dataset = true
83
- # keep the class if it is already noted in database_classes
84
- if ![E,V].include?(detected_class) &&
85
- !ActiveOrient.database_classes.key( detected_class) &&
86
- !detected_class.require_model_file(from_model_dir) &&
87
- !ActiveOrient::Model.keep_models_without_file
88
-
89
- logger.info{ "#{detected_class.name} --> Class NOT allocated"}
90
- ActiveOrient.database_classes[ detected_class.ref_name ] = "no model file"
91
- keep_the_dataset = false
92
- end
93
- keep_the_dataset # return_value
94
- end # block
84
+ # keep the class if it is already noted in database_classes
85
+ if [E,V].include?(detected_class) ||
86
+ ActiveOrient.database_classes.key( detected_class) ||
87
+ detected_class.require_model_file(from_model_dir) ||
88
+ ActiveOrient::Model.keep_models_without_file
89
+ true # return_value
90
+ else
91
+ logger.info{ "#{detected_class.name} --> Class NOT allocated"}
92
+ ActiveOrient.database_classes[ detected_class.ref_name ] = "no model file"
93
+ false # return_value
94
+ end
95
+ end # block
95
96
  end # each iteration
96
97
  end # def
97
98
 
@@ -37,7 +37,7 @@ returns the active OrientDB-Instance
37
37
  def self.connect **defaults
38
38
  define_namespace namespace: :object
39
39
  ActiveOrient::OrientDB.configure_logger defaults[:logger]
40
- ao = ActiveOrient::OrientDB.new defaults.merge preallocate: false
40
+ ao = ActiveOrient::OrientDB.new **(defaults.merge( preallocate: false))
41
41
  ao.create_class 'E'
42
42
  ao.create_class 'V'
43
43
  ao # return client instance
@@ -45,7 +45,8 @@ returns the active OrientDB-Instance
45
45
  =begin
46
46
  Parameters:
47
47
  yml: hash from config.yml ,
48
- namespace: Class to use as Namespace
48
+ namespace: Class to use as Namespace, one of [ :self, :object, :active_orient ]
49
+
49
50
 
50
51
  A custom Constant can be provided via Block
51
52
 
@@ -55,7 +56,7 @@ i.e.
55
56
  #or
56
57
  ActiveOrient.Init.define_namespace namespace: :self | :object | :active_orient
57
58
  #or
58
- module IBi; end # first declare the Module-Const
59
+ module IB; end # first declare the Module-Const
59
60
  # then assign to the namespace
60
61
  ActiveOrient.Init.define_namespace { IB }
61
62