active-orient 0.4 → 0.80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.graphs.txt.swp +0 -0
  4. data/Gemfile +9 -5
  5. data/Guardfile +12 -4
  6. data/README.md +70 -281
  7. data/VERSION +1 -1
  8. data/active-orient.gemspec +9 -7
  9. data/bin/active-orient-0.6.gem +0 -0
  10. data/bin/active-orient-console +97 -0
  11. data/changelog.md +60 -0
  12. data/config/boot.rb +70 -17
  13. data/config/config.yml +10 -0
  14. data/config/connect.yml +11 -6
  15. data/examples/books.rb +154 -65
  16. data/examples/streets.rb +89 -85
  17. data/graphs.txt +70 -0
  18. data/lib/active-orient.rb +78 -6
  19. data/lib/base.rb +266 -168
  20. data/lib/base_properties.rb +76 -65
  21. data/lib/class_utils.rb +187 -0
  22. data/lib/database_utils.rb +99 -0
  23. data/lib/init.rb +80 -0
  24. data/lib/java-api.rb +442 -0
  25. data/lib/jdbc.rb +211 -0
  26. data/lib/model/custom.rb +29 -0
  27. data/lib/model/e.rb +6 -0
  28. data/lib/model/edge.rb +114 -0
  29. data/lib/model/model.rb +134 -0
  30. data/lib/model/the_class.rb +657 -0
  31. data/lib/model/the_record.rb +313 -0
  32. data/lib/model/vertex.rb +371 -0
  33. data/lib/orientdb_private.rb +48 -0
  34. data/lib/other.rb +423 -0
  35. data/lib/railtie.rb +68 -0
  36. data/lib/rest/change.rb +150 -0
  37. data/lib/rest/create.rb +287 -0
  38. data/lib/rest/delete.rb +150 -0
  39. data/lib/rest/operations.rb +222 -0
  40. data/lib/rest/read.rb +189 -0
  41. data/lib/rest/rest.rb +120 -0
  42. data/lib/rest_disabled.rb +24 -0
  43. data/lib/support/conversions.rb +42 -0
  44. data/lib/support/default_formatter.rb +7 -0
  45. data/lib/support/errors.rb +41 -0
  46. data/lib/support/logging.rb +38 -0
  47. data/lib/support/orient.rb +305 -0
  48. data/lib/support/orientquery.rb +647 -0
  49. data/lib/support/query.rb +92 -0
  50. data/rails.md +154 -0
  51. data/rails/activeorient.rb +32 -0
  52. data/rails/config.yml +10 -0
  53. data/rails/connect.yml +17 -0
  54. metadata +89 -30
  55. data/lib/model.rb +0 -461
  56. data/lib/orient.rb +0 -98
  57. data/lib/query.rb +0 -88
  58. data/lib/rest.rb +0 -1036
  59. data/lib/support.rb +0 -347
  60. data/test.rb +0 -4
  61. data/usecase.md +0 -91
@@ -1,6 +1,7 @@
1
1
  =begin
2
- Streets Example
2
+ ---> The Streets Example does not work as the structure of external data used changed!
3
3
 
4
+ Streets Example
4
5
 
5
6
  We load german cities from wikipedia and parse the document for cities and countries(states).
6
7
  Further we load a collection of popular streetnames from a web-side called »strassen-in-deutschland«
@@ -15,115 +16,118 @@ At last we print the connected cities.
15
16
  module DataImport
16
17
  def read_german_street_names
17
18
  doc = Nokogiri::HTML(open('http://www.strassen-in-deutschland.de/die-haeufigsten-strassennamen-in-deutschland.html'))
18
- strassen = doc.css('#strassen-in-deutschland_main a' ) # identified via css-inspector in browser
19
+ strassen = doc.css("td[data-header='Straßenname: '] a") # identified via css-inspector in browser
19
20
  # search for the css and include only links, then display the text-part
20
21
  strassen.children.map( &:to_s )[3..-1] # omit the first three (strassen in deutschland, straßenverzeichnis, straßen)
21
22
  end
22
23
 
23
- def read_german_cities_from_wikipedia
24
- # we extract <li> -elements and use the text until "("
24
+ def read_german_cities_from_wikipedia
25
+ # we extract <li> -elements and use the text until "("
25
26
  #doc.xpath("//li").at(80)
26
- # => #<Nokogiri::XML::Element:0x1ba551c name="li" children=[#<Nokogiri::XML::Element:0x1ba533c name="a" attributes=[#<Nokogiri::XML::Attr:0x1ba52d8 name="href" value="/wiki/Angerm%C3%BCnde">, #<Nokogiri::XML::Attr:0x1ba52c4 name="title" value="Angermünde">] children=[#<Nokogiri::XML::Text:0x1ba4c84 "Angermünde">]>, #<Nokogiri::XML::Text:0x1ba4ae0 " (Brandenburg)">]>
27
+ # => #<Nokogiri::XML::Element:0x1ba551c name="li" children=[#<Nokogiri::XML::Element:0x1ba533c name="a" attributes=[#<Nokogiri::XML::Attr:0x1ba52d8 name="href" value="/wiki/Angerm%C3%BCnde">, #<Nokogiri::XML::Attr:0x1ba52c4 name="title" value="Angermünde">] children=[#<Nokogiri::XML::Text:0x1ba4c84 "Angermünde">]>, #<Nokogiri::XML::Text:0x1ba4ae0 " (Brandenburg)">]>
27
28
 
28
29
  doc = Nokogiri::HTML(open('https://en.wikipedia.org/wiki/List_of_cities_and_towns_in_Germany'))
30
+ print doc
29
31
  doc.xpath("//li").map{|x| x.text[0 .. x.text.index('(')-2] if x.text.index('(').present? }.compact
30
32
  end
31
33
 
32
- def read_german_cities_and_states_fom_wikipedia
34
+ def read_german_cities_and_states_from_wikipedia
33
35
  doc =
34
- Nokogiri::HTML(open('https://en.wikipedia.org/wiki/List_of_cities_and_towns_in_Germany'))
35
- doc.xpath("//li").map do |x|
36
- if x.text.index('(').present?
37
- [ x.text[0 .. x.text.index('(')-2] , x.text[ x.text.index('(')+1 .. x.text.index(')')-1] ]
36
+ Nokogiri::HTML(open('https://en.wikipedia.org/wiki/List_of_cities_and_towns_in_Germany'))
37
+ doc.xpath("//li").map do |x|
38
+ if x.text.index('(').present?
39
+ [ x.text[0 .. x.text.index('(')-2] , x.text[ x.text.index('(')+1 .. x.text.index(')')-1] ]
38
40
  end
39
41
  end.compact
40
- end
42
+ end
41
43
 
42
44
  end # module
43
45
 
44
- class StreetExample
45
-
46
- include DataImport
47
- def initialize db, rebuild: true
48
- if rebuild
49
- ActiveOrient::OrientDB.logger.progname = "StreetsExample#Initialize"
50
- db.delete_class :state
51
- db.delete_class :city
52
- db.delete_class :street
53
- db.delete_class :connects
54
- db.create_vertex_class :state
55
- db.create_vertex_class :city
56
- db.create_vertex_class :street
57
- db.create_edge_class :connects
58
- ActiveOrient::Model::State.create_property( :name, type: :string, index: :unique )
59
- ActiveOrient::Model::City.create_properties( { name: { type: :string },
60
- state: { type: :link, :linked_class => 'State' } }
61
- ) do
62
- { citi_idx: :unique }
63
- end
64
- ActiveOrient::Model::Street.create_property :name , type: :string, index: :notunique
65
- ActiveOrient::Model::Connects.create_property :distance, type: :integer, index: :notunique
66
- ActiveOrient::OrientDB.logger.info { "Vertex- and Edge-Classes rebuilded" }
67
- end
46
+ class StreetExample
47
+
48
+ include DataImport
49
+ def initialize db, rebuild: true
50
+ if rebuild
51
+ db.delete_class :State
52
+ db.delete_class :City
53
+ db.delete_class :Street
54
+ db.delete_class :CONNECTS
55
+ db.create_vertex_class :state, :city, :street
56
+ db.create_edge_class :CONNECTS
57
+ State.create_property( :name, type: :string, index: :unique )
58
+ City.create_properties( { name: { type: :string },
59
+ state: { type: :link, :linked_class => 'State' } }
60
+ ) do
61
+ { citi_idx: :unique }
62
+ end
63
+ Street.create_property :name , type: :string, index: :notunique
64
+ CONNECTS.create_property :distance, type: :integer, index: :notunique
65
+ logger.progname = "StreetsExample#Initialize"
66
+ logger.info { "Vertex- and Edge-Classes rebuilded" }
68
67
  end
68
+ end
69
69
 
70
70
 
71
- def read_from_web
72
- ActiveOrient::OrientDB.logger.progname = "StreetsExample#ReadFromWeb"
73
- read_german_cities_and_states_fom_wikipedia.each do |city,state|
74
- state = State.update_or_create( where: { name: state }).first
75
- City.create name: city, state: state.link
76
- end
77
- ActiveOrient::OrientDB.logger.info { "#{City.count} Cities imported from Wikipedia " }
78
-
79
- cities_rids = City.all.map &:link
80
- read_german_street_names.each_with_index do |street, i|
81
- street_record = Street.create name: street
82
- count = i
83
- cities = Array.new
84
- while count < cities_rids.size && cities.size < 5 do
85
- cities << cities_rids[count]
86
- count = count + i
87
- end
88
- C.create_edge :from => street_record, :to => cities
71
+ def read_from_web
72
+ read_german_cities_and_states_from_wikipedia.each do |city,state|
73
+ state = State.update_or_create( where: { name: state }).first
74
+ City.create name: city, state: "##{state.rid}"
75
+ end
76
+ logger.progname = "StreetsExample#ReadFromWeb"
77
+ logger.info { "#{City.count} Cities imported from Wikipedia " }
78
+
79
+ cities_rids = City.all.map &:rid
80
+ read_german_street_names.each_with_index do |street, i|
81
+ street_record = Street.create name: street
82
+ count = i
83
+ cities = Array.new
84
+ while count < cities_rids.size && cities.size < 5 do
85
+ cities << cities_rids[count]
86
+ count = count + i
89
87
  end
90
- ActiveOrient::OrientDB.logger.info { "#{C.count} Edges between Streets and Cities created " }
88
+ CONNECTS.create_edge :from => street_record, :to => cities
91
89
  end
92
-
93
- def display_streets_per_state
94
- State.all.each do |state|
95
- streets= Street.all.map do |street |
96
- if street.connects.in.detect{|x| x.state == state }
97
- street.name + " verbindet " + street.connects.in.map( &:name ).join('; ')
98
- end
99
- end.compact
100
- unless streets.empty?
101
- puts "..................................."
102
- puts state.name
103
- puts "..................................."
104
- puts streets.join("\n")
105
- end
90
+ logger.progname = "StreetsExample#ReadFromWeb"
91
+ logger.info { "#{CONNECTS.count} Edges between Streets and Cities created " }
92
+ end
93
+
94
+ def display_streets_per_state
95
+ State.all.each do |state|
96
+ streets= Street.all.map do |street |
97
+ if street.connects.in.detect{|x| x.state == state }
98
+ street.name + " connects " + street.connects.in.map( &:name ).join('; ')
99
+ end
100
+ end.compact
101
+ unless streets.empty?
102
+ puts "..................................."
103
+ puts state.name
104
+ puts "..................................."
105
+ puts streets.join("\n")
106
106
  end
107
107
  end
108
- end
108
+ end
109
+ end
109
110
 
110
111
  if $0 == __FILE__
111
112
 
112
- require '../config/boot'
113
- require 'open-uri'
114
- require 'nokogiri'
115
-
116
- ActiveOrient::OrientDB.default_server= { user: 'hctw', password: 'hc' }
117
- r = ActiveOrient::OrientDB.new database: 'StreetTest'
118
- ActiveOrient::OrientDB.logger.level = Logger::INFO
119
- s= StreetExample.new r, rebuild: true
120
-
121
- City = r.open_class :city
122
- State = r.open_class :state
123
- Street = r.open_class :street
124
- C = r.open_class :connects
125
-
126
- s.read_from_web if City.count.zero?
127
- s.display_streets_per_state
113
+ require '../config/boot'
114
+ require 'open-uri'
115
+ require 'nokogiri'
116
+
117
+ ActiveOrient::OrientDB.default_server= { user: 'root', password: 'tretretre' }
118
+ r = ActiveOrient::OrientDB.new database: 'StreetTest'
119
+ ActiveOrient::OrientDB.logger.level = Logger::INFO
120
+ s= StreetExample.new r, rebuild: true
121
+
122
+ def to_orient
123
+ #puts "here hash"
124
+ substitute_hash = Hash.new
125
+ keys.each{|k| substitute_hash[k] = self[k].to_orient}
126
+ substitute_hash
127
+ end
128
+
129
+
130
+ s.read_from_web if City.count.zero?
131
+ s.display_streets_per_state
128
132
 
129
133
  end
@@ -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
+
@@ -1,7 +1,79 @@
1
- require "support.rb"
2
- require "base.rb"
3
- require "base_properties.rb"
4
1
 
5
- require "model.rb"
6
- require "orient.rb"
7
- require "rest.rb"
2
+ module OrientDB
3
+ UsingJava = RUBY_PLATFORM == 'java' ? true : false
4
+ unless UsingJava
5
+ DocumentDatabase = nil
6
+ DocumentDatabasePool = nil
7
+ DocumentDatabasePooled = nil
8
+ GraphDatabase = nil
9
+ OTraverse = nil
10
+ Document = nil
11
+ IndexType = nil
12
+ OClassImpl = nil
13
+ PropertyImpl = nil
14
+ Schema = nil
15
+ SchemaProxy = nil
16
+ SchemaType = nil
17
+ SQLCommand = nil
18
+ SQLSynchQuery = nil
19
+ User = nil
20
+ RemoteStorage = nil
21
+ ServerAdmin = nil
22
+ # defined in other.rb
23
+ #JavaDate
24
+ #RecordList = nil
25
+ # RidBag = nil
26
+ # RecordSet = nil
27
+ end
28
+ end # module OrientDB
29
+ require 'active_model'
30
+ #require 'active_model/serializers'
31
+ require_relative "support/orientquery.rb"
32
+ require_relative "support/conversions.rb"
33
+ #require_relative "support/logging.rb"
34
+ require_relative "support/errors.rb"
35
+ require_relative "base.rb"
36
+ require_relative "base_properties.rb"
37
+ require_relative "support/orient.rb"
38
+ #require_relative "query.rb"
39
+ if OrientDB::UsingJava
40
+ require_relative 'java-api.rb'
41
+ end
42
+ require_relative "orientdb_private.rb" # manage private functions
43
+ require_relative "database_utils.rb" #common methods without rest.specific content
44
+ require_relative "class_utils.rb" #common methods without rest.specific content
45
+ require_relative "other.rb"
46
+ require_relative "rest/rest.rb"
47
+ require_relative "model/model.rb"
48
+ require 'active_support/core_ext/string' # provides blank?, present?, presence etc
49
+ require_relative 'init.rb'
50
+ # create Base Classes
51
+
52
+ require_relative "model/vertex.rb"
53
+ require_relative "model/edge.rb"
54
+
55
+ require_relative "railtie" if defined?(Rails)
56
+
57
+ module ActiveOrient
58
+ mattr_accessor :database
59
+ mattr_accessor :db_pool
60
+ mattr_accessor :database_classes
61
+ mattr_accessor :default_server
62
+
63
+ ## displays all allocated classes
64
+ ##
65
+ ## usage:
66
+ ## puts ActiveOrient::show_classes
67
+ #
68
+ #
69
+ def self.show_classes
70
+
71
+ '-'* 45+"\n"+
72
+ "Database Class -> ActiveOrient ClassName\n"+
73
+ '-'* 45+"\n"+
74
+ ActiveOrient.database_classes.map{|x,y| "#{"%15s"% x} -> #{y.to_s}" }.join("\n") + "\n"+
75
+ '-'* 45 + "\n"
76
+ end
77
+
78
+ end
79
+
@@ -1,220 +1,318 @@
1
1
  module ActiveOrient
2
- require 'active_model'
3
- #
4
- # Base class for tableless IB data Models, extends ActiveModel API
2
+
3
+
4
+ # Base class for tableless IB data Models, extends ActiveModel API
5
+
5
6
  class Base
7
+ # include OrientSupport::Logging
6
8
  extend ActiveModel::Naming
7
9
  extend ActiveModel::Callbacks
8
10
  include ActiveModel::Validations
9
11
  include ActiveModel::Serialization
10
- include ActiveModel::Serializers::Xml
12
+ # include ActiveModel::Serializers::Xml
11
13
  include ActiveModel::Serializers::JSON
12
-
14
+ include OrientDB
15
+ include Conversions # mocking ActiveModel::Conversions
16
+
17
+ mattr_accessor :logger
18
+
19
+ define_model_callbacks :initialize
20
+ # ActiveRecord::Base callback API mocks
21
+ define_model_callbacks :initialize, :only => :after
13
22
 
14
- ##Every Rest::Base-Object is stored in the @@rid_store
15
- ## The Objects are just references to the @@rid_store.
16
- ## any Change of the Object is thus synchonized to any allocated variable
17
- #
18
- @@rid_store = Hash.new
23
+ # Used to read the metadata
24
+ attr_reader :metadata
19
25
 
20
- def self.display_riid
26
+ =begin
27
+ Every Rest::Base-Object is stored in the @@rid_store
28
+ The Objects are just references to the @@rid_store.
29
+ Any Change of the Object is thus synchonized to any allocated variable.
30
+ =end
31
+ @@rid_store = Hash.new
32
+ @@mutex = Mutex.new
33
+
34
+ def self.display_rid
21
35
  @@rid_store
22
36
  end
23
- def self.remove_riid obj
24
- @@rid_store[obj.riid]=nil
25
- end
26
- def self.get_riid link
27
37
 
38
+ =begin
39
+ removes an Item from the cache
40
+
41
+ obj has to provide a method #rid
42
+
43
+ thus a string or a Model-Object is accepted
44
+ =end
45
+
46
+ def self.remove_rid obj
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
55
+
56
+ def self.get_rid rid
57
+ rid = rid[1..-1] if rid[0]=='#'
58
+ @@rid_store[rid]
28
59
  end
29
- def self.store_riid obj
30
- if obj.rid.present? && obj.riid.all?{|x| x.present? && x>=0} # only positive values are stored
31
- ## return the presence of a stored object as true by the block
32
- ## the block is only executed if the presence is confirmed
33
- ## Nothing is returned from the class-method
34
- if @@rid_store[obj.riid].present?
35
- yield if block_given?
36
- end
37
- @@rid_store[obj.riid] = obj
38
- @@rid_store[obj.riid] # return_value
39
- else
40
- obj # no rid-value: just return the obj
41
- end
60
+
61
+ def self.reset_rid_store
62
+ @@rid_store = Hash.new
42
63
  end
43
64
 
65
+ =begin
66
+ Stores the obj in the cache.
44
67
 
45
- define_model_callbacks :initialize
68
+ If the cache-value exists, it is updated by the data provided in obj
69
+ and the cached obj is returned
70
+
71
+ =end
72
+ def self.store_rid obj
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
87
+
88
+
89
+ # rails compatibility
90
+ # remap rid to id unless id is present
91
+ # def id
92
+ # attributes[:id].present? ? attributes[:id] : rrid
93
+ # end
46
94
 
47
- mattr_accessor :logger
48
- # If a opts hash is given, keys are taken as attribute names, values as data.
49
- # The model instance fields are then set automatically from the opts Hash.
50
- def initialize attributes={}, opts={}
51
- logger.progname= "ActiveOrient::Base#initialize"
52
- #possible_link_array_candidates = link_candidates = Hash.new
53
- @metadata = HashWithIndifferentAccess.new
54
- # @edges = HashWithIndifferentAccess.new
55
-
56
- run_callbacks :initialize do
57
- # puts "initialize::attributes: #{attributes.inspect}"
58
-
59
- attributes.keys.each do | att |
60
- unless att[0] == "@" # @ identifies Metadata-attributes
61
- att = att.to_sym if att.is_a?(String)
62
- unless self.class.instance_methods.detect{|x| x == att }
63
- self.class.define_property att, nil
64
- # logger.debug { "property #{att.to_s} assigned to #{self.class.to_s}" }
65
- else
66
- # logger.info{ "property #{att.to_s} NOT assigned " }
67
- end
68
- end
69
- end
70
-
71
- if attributes['@type'] == 'd' # document
72
- @metadata[ :type ] = attributes.delete '@type'
73
- @metadata[ :class ] = attributes.delete '@class'
74
- @metadata[ :version ] = attributes.delete '@version'
75
- @metadata[ :fieldTypes ] = attributes.delete '@fieldTypes'
76
- if attributes.has_key?( '@rid' )
77
- rid = attributes.delete '@rid'
78
- cluster, record = rid[1,rid.size].split(':')
79
- @metadata[ :cluster ] = cluster.to_i
80
- @metadata[ :record ] = record.to_i
81
- end
82
-
83
- #### edges -- remove in_ and out_ and de-capitalize the remaining edge
84
- if @metadata[ :fieldTypes ].present? && (@metadata[ :fieldTypes ] =~ /=g/)
85
- edges = @metadata['fieldTypes'].split(',').find_all{|x| x=~/=g/}.map{|x| x.split('=').first}
86
- edges.each do |edge|
87
- operator, *base_edge = edge.split('_')
88
- base_edge = base_edge.join('_')
89
- unless self.class.instance_methods.detect{|x| x == base_edge }
90
- ## define two methods: out_{Edge}/{in_Edge} -> edge.
91
- self.class.define_property base_edge, nil
92
- self.class.send :alias_method, base_edge.underscore, edge #
93
- # logger.debug { "#{link}:: edge #{edge} assigned to #{self.class.to_s} and remaped to #{base_edge.underscore}" }
94
-
95
- end
96
- end
97
- end
98
- end
99
-
100
-
101
- self.attributes = attributes # set_attribute_defaults is now after_init callback
102
- end
103
- ActiveOrient::Base.store_riid self
104
- end
105
95
 
106
- # ActiveModel API (for serialization)
96
+ =begin
97
+ If a opts hash is given, keys are taken as attribute names, values as data.
98
+ The model instance fields are then set automatically from the opts Hash.
99
+ =end
100
+
101
+ def initialize attributes = {}, opts = {}
102
+ logger.progname = "ActiveOrient::Base#initialize"
103
+ @metadata = Hash.new # HashWithIndifferentAccess.new
104
+ @d = nil if RUBY_PLATFORM == 'java' && attributes.is_a?( Document )
105
+ run_callbacks :initialize do
106
+ if RUBY_PLATFORM == 'java' && attributes.is_a?( Document )
107
+ @d = attributes
108
+ attributes = @d.values
109
+ @metadata[:class] = @d.class_name
110
+ @metadata[:version] = @d.version
111
+ @metadata[:cluster], @metadata[:record] = @d.rid[1,@d.rid.size].split(':')
112
+ puts "Metadata: #{@metadata}"
113
+ end
114
+
115
+ # transform $current to :current and $current.mgr to :mgr
116
+ transformers = attributes.keys.map{|x| [x, x[1..-1].split(".").last.to_sym] if x[0] == '$'}.compact
117
+ # transformers: [ [original key, modified key] , [] ]
118
+ transformers.each do |a|
119
+ attributes[a.last] = attributes[a.first]
120
+ attributes.delete a.first
121
+ end
122
+
123
+ attributes.keys.each do |att|
124
+ unless att[0] == "@" # @ identifies Metadata-attributes
125
+ unless self.class.instance_methods.detect{|x| x == att.to_sym}
126
+ self.class.define_property att.to_sym, nil
127
+ else
128
+ #logger.info{"Property #{att.to_s} NOT assigned"}
129
+ end
130
+ end
131
+ end
132
+ if attributes['@type'] == 'd' # document via REST
133
+ @metadata[:type] = attributes.delete '@type'
134
+ @metadata[:class] = attributes.delete '@class'
135
+ @metadata[:version] = attributes.delete '@version'
136
+ @metadata[:fieldTypes] = attributes.delete '@fieldTypes'
137
+
138
+ if attributes.has_key?('@rid')
139
+ rid = attributes.delete '@rid'
140
+ cluster, record = rid[1 .. -1].split(':')
141
+ @metadata[:cluster] = cluster.to_i
142
+ @metadata[:record] = record.to_i
143
+ end
144
+
145
+ if @metadata[:fieldTypes ].present? && (@metadata[:fieldTypes] =~ /=g/)
146
+ @metadata[:edges] = { :in => [], :out => [] }
147
+ edges = @metadata[:fieldTypes].split(',').find_all{|x| x=~/=g/}.map{|x| x.split('=').first}
148
+ # puts "Detected EDGES: #{edges.inspect}"
149
+ edges.each do |edge|
150
+ operator, *base_edge = edge.split('_')
151
+ base_edge = base_edge.join('_')
152
+ @metadata[:edges][operator.to_sym] << base_edge
153
+ end
154
+ # unless self.class.instance_methods.detect{|x| x == base_edge}
155
+ # ## define two methods: out_{Edge}/in_{Edge} -> edge.
156
+ # self.class.define_property base_edge, nil
157
+ # allocate_edge_method = -> (edge) do
158
+ # unless (ee=db.get_db_superclass(edge)) == "E"
159
+ # allocate_edge_method[ee]
160
+ # self.class.send :alias_method, base_edge.underscore, edge
161
+ # ## define inherented classes, tooa
162
+ #
163
+
164
+ # end
165
+ # end
166
+ end
167
+ end
168
+ self.attributes = attributes # set_attribute_defaults is now after_init callback
169
+ end
170
+ # puts "Storing #{self.rid} to rid-store"
171
+ # ActiveOrient::Base.store_rid( self ) do | cache_obj|
172
+ # cache_obj.reload! self
173
+ # end
174
+ end
175
+
176
+ # ActiveModel API (for serialization)
177
+
178
+ def included_links
179
+ meta= Hash[ @metadata[:fieldTypes].split(',').map{|x| x.split '='} ]
180
+ meta.map{|x,y| x if y=='x'}.compact
181
+ end
107
182
 
108
183
  def attributes
109
- @attributes ||= HashWithIndifferentAccess.new
184
+ @attributes ||= Hash.new # WithIndifferentAccess.new
110
185
  end
111
186
 
112
187
  def attributes= attrs
113
- attrs.keys.each { |key| self.send("#{key}=", attrs[key]) }
188
+ attrs.keys.each{|key| self.send("#{key}=", attrs[key])}
114
189
  end
115
190
 
116
- # ActiveModel-style read/write_attribute accessors
117
- # Here we define the autoload mechanism
118
- def [] key
119
-
120
- iv= attributes[key.to_sym]
121
- # iv.from_orient unless iv.nil?
122
- if iv.is_a?(String) && iv.rid? #&& @metadata[:fieldTypes].present? && @metadata[:fieldTypes].include?( key.to_s+"=x" )
123
- # puts "autoload: #{iv}"
124
- ActiveOrient::Model.autoload_object iv
125
- elsif iv.is_a?(Array) # && @metadata[:fieldTypes].present? && @metadata[:fieldTypes].match( key.to_s+"=[znmgx]" )
126
- # puts "autoload: #{iv.inspect}"
127
- OrientSupport::Array.new self, *iv.map{|y| (y.is_a?(String) && y.rid?) ? ActiveOrient::Model.autoload_object( y ) : y }
128
- else
129
-
130
- iv
131
- end
132
- end
191
+ def my_metadata key: nil, symbol: nil
192
+ if @metadata[:fieldTypes].present?
193
+ meta= Hash[ @metadata[:fieldTypes].split(',').map{|x| x.split '='} ]
194
+ if key.present?
195
+ meta[key.to_s]
196
+ elsif symbol.present?
197
+ meta.map{|x,y| x if y == symbol.to_s }.compact
198
+ else
199
+ meta
200
+ end
201
+ end
202
+ end
133
203
 
134
- def update_attribute key, value
135
- @attributes[key] = value
136
- end
137
204
  =begin
138
- Here we define how the attributes are initialized
139
- Key and val are set by the RestCliend
205
+ ActiveModel-style read/write_attribute accessors
206
+
207
+ Autoload mechanism and data conversion are defined in the method "from_orient" of each class
140
208
  =end
141
- def []= key, val
142
- val = val.rid if val.is_a? ActiveOrient::Model
143
- # if val.is_a?(Array) # && @metadata[:fieldTypes].present? && @metadata[:fieldTypes].include?( key.to_s+"=n" )
144
- # if @metadata[ :fieldTypes ] =~ /out=x,in=x/
145
- # puts "VAL is a ARRAY"
146
- # else
147
- # puts "METADATA: #{ @metadata[ :fieldTypes ]} "
148
- # end
149
- # val# = val.map{|x| if val.is_a? ActiveOrient::Model then val.rid else val end }
150
- # end
151
- attributes[key.to_sym] = case val
152
- when Array
153
- if val.first.is_a?(Hash)
154
- v=val.map do |x|
155
- if x.is_a?( Hash )
156
- HashWithIndifferentAccess.new(x)
157
- else
158
- x
159
- end
160
- end
161
- OrientSupport::Array.new( self, *v )
162
- else
163
- OrientSupport::Array.new( self, *val )
164
- end
165
- when Hash
166
- HashWithIndifferentAccess.new(val)
167
- else
168
- val
169
- end
170
-
209
+
210
+ def [] key
211
+
212
+ iv = attributes[key]
213
+ if my_metadata( key: key) == "t"
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
225
+ elsif my_metadata( key: key) == "x"
226
+ iv = ActiveOrient::Model.autoload_object iv
227
+ elsif iv.is_a? Array
228
+ OrientSupport::Array.new( work_on: self, work_with: iv.from_orient){ key.to_sym }
229
+ elsif iv.is_a? Hash
230
+ # if iv.keys.include?("@class" )
231
+ # ActiveOrient::Model.orientdb_class( name: iv["@class"] ).new iv
232
+ # else
233
+ # iv
234
+ OrientSupport::Hash.new( self, iv.from_orient){ key.to_sym }
235
+ # end
236
+ # elsif iv.is_a? RecordMap
237
+ # iv
238
+ # puts "RecordSet detected"
239
+ else
240
+ iv.from_orient
241
+ end
242
+ end
243
+
244
+ def []= key, val
245
+ val = val.rid if val.is_a?( ActiveOrient::Model ) && val.rid.rid?
246
+ attributes[key.to_sym] = case val
247
+ when Array
248
+ if val.first.is_a?(Hash)
249
+ v = val.map{ |x| x }
250
+ OrientSupport::Array.new(work_on: self, work_with: v ){ key_to_sym }
251
+ else
252
+ OrientSupport::Array.new(work_on: self, work_with: val ){ key_to_sym }
253
+ end
254
+ when Hash
255
+ if val.keys.include?("@class" )
256
+ OrientSupport::Array.new( work_on: self, work_with: val.from_orient){ key.to_sym }
257
+ else
258
+ OrientSupport::Hash.new( self, val )
259
+ end
260
+ else
261
+ val
262
+ end
263
+ end
264
+
265
+ def update_attribute key, value
266
+ @attributes[key] = value
171
267
  end
172
268
 
173
- def to_model
269
+ def to_model # :nodoc:
174
270
  self
175
271
  end
176
272
 
273
+ # Noop methods mocking ActiveRecord::Base macros
177
274
 
178
-
179
- ### Noop methods mocking ActiveRecord::Base macros
180
-
181
275
  def self.attr_protected *args
182
276
  end
183
277
 
184
278
  def self.attr_accessible *args
185
279
  end
186
280
 
187
- ### ActiveRecord::Base association API mocks
188
-
189
- def self.belongs_to model, *args
281
+ # ActiveRecord::Base association API mocks
282
+ #
283
+ def self.belongs_to model, *args # :nodoc:
190
284
  attr_accessor model
191
285
  end
192
-
193
- def self.has_one model, *args
286
+ #
287
+ def self.has_one model, *args # :nodoc:
194
288
  attr_accessor model
195
289
  end
196
-
197
- def self.has_many models, *args
290
+ #
291
+ def self.has_many models, *args # :nodoc:
198
292
  attr_accessor models
199
-
200
293
  define_method(models) do
201
- self.instance_variable_get("@#{models}") ||
202
- self.instance_variable_set("@#{models}", [])
294
+ self.instance_variable_get("@#{models}") || self.instance_variable_set("@#{models}", [])
203
295
  end
204
296
  end
205
-
206
- def self.find *args
207
- []
297
+ #
298
+ # def self.find *args
299
+ # []
300
+ # end
301
+ #
302
+ =begin
303
+ (Experimental)
304
+ Exclude some properties from loading via get, reload!, get_document, get_record
305
+ =end
306
+ def self.exclude_the_following_properties *args
307
+ puts "excluding #{args}"
308
+ @excluded = (@excluded.is_a?( Array))? @excluded + args : args
309
+ puts "#{self.inspect} --> excluded #{@excluded}"
208
310
  end
209
311
 
210
- ### ActiveRecord::Base callback API mocks
211
-
212
- define_model_callbacks :initialize, :only => :after
213
-
214
- ### ActiveRecord::Base misc
215
-
216
- def self.serialize *properties
312
+ # ActiveRecord::Base misc
313
+ def self.serialize *properties # :nodoc:
217
314
  end
218
-
315
+ # Enable lazy loading
316
+ ActiveSupport.run_load_hooks(:active_orient, self)
219
317
  end # Model
220
- end # module
318
+ end # module