active-orient 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Gemfile +8 -3
  4. data/Guardfile +12 -4
  5. data/README.md +221 -201
  6. data/VERSION +1 -1
  7. data/active-orient.gemspec +3 -2
  8. data/bin/active-orient-console +35 -0
  9. data/config/boot.rb +84 -16
  10. data/config/config.yml +10 -0
  11. data/config/connect.yml +6 -2
  12. data/create_project +19 -0
  13. data/examples/books.rb +86 -39
  14. data/examples/createTime.rb +91 -0
  15. data/examples/streets.rb +85 -84
  16. data/examples/test_commands.rb +92 -0
  17. data/examples/test_commands_2.rb +54 -0
  18. data/examples/test_commands_3.rb +48 -0
  19. data/examples/test_commands_4.rb +28 -0
  20. data/examples/time_graph/Gemfile +21 -0
  21. data/examples/time_graph/Guardfile +26 -0
  22. data/examples/time_graph/README.md +129 -0
  23. data/examples/time_graph/bin/active-orient-console +35 -0
  24. data/examples/time_graph/config/boot.rb +119 -0
  25. data/examples/time_graph/config/config.yml +8 -0
  26. data/examples/time_graph/config/connect.yml +17 -0
  27. data/examples/time_graph/config/init_db.rb +59 -0
  28. data/examples/time_graph/createTime.rb +51 -0
  29. data/examples/time_graph/lib/createTime.rb +82 -0
  30. data/examples/time_graph/model/day_of.rb +3 -0
  31. data/examples/time_graph/model/e.rb +6 -0
  32. data/examples/time_graph/model/edge.rb +53 -0
  33. data/examples/time_graph/model/monat.rb +19 -0
  34. data/examples/time_graph/model/stunde.rb +16 -0
  35. data/examples/time_graph/model/tag.rb +29 -0
  36. data/examples/time_graph/model/time_base.rb +6 -0
  37. data/examples/time_graph/model/time_of.rb +4 -0
  38. data/examples/time_graph/model/v.rb +3 -0
  39. data/examples/time_graph/model/vertex.rb +32 -0
  40. data/examples/time_graph/spec/lib/create_time_spec.rb +50 -0
  41. data/examples/time_graph/spec/rest_helper.rb +37 -0
  42. data/examples/time_graph/spec/spec_helper.rb +46 -0
  43. data/lib/active-orient.rb +56 -6
  44. data/lib/base.rb +149 -147
  45. data/lib/base_properties.rb +40 -41
  46. data/lib/class_utils.rb +301 -0
  47. data/lib/database_utils.rb +97 -0
  48. data/lib/init.rb +35 -0
  49. data/lib/java-api.rb +437 -0
  50. data/lib/jdbc.rb +211 -0
  51. data/lib/model/edge.rb +53 -0
  52. data/lib/model/model.rb +77 -0
  53. data/lib/model/the_class.rb +480 -0
  54. data/lib/model/the_record.rb +310 -0
  55. data/lib/model/vertex.rb +32 -0
  56. data/lib/orient.rb +113 -50
  57. data/lib/orientdb_private.rb +48 -0
  58. data/lib/other.rb +280 -0
  59. data/lib/query.rb +71 -73
  60. data/lib/rest/change.rb +124 -0
  61. data/lib/rest/create.rb +474 -0
  62. data/lib/rest/delete.rb +133 -0
  63. data/lib/rest/operations.rb +150 -0
  64. data/lib/rest/read.rb +150 -0
  65. data/lib/rest/rest.rb +111 -0
  66. data/lib/rest_disabled.rb +24 -0
  67. data/lib/support.rb +387 -296
  68. data/old_lib_functions/two_general_class.rb +139 -0
  69. data/usecase.md +49 -36
  70. data/usecase_oo.md +59 -0
  71. metadata +73 -9
  72. data/lib/model.rb +0 -461
  73. data/lib/rest.rb +0 -1036
  74. data/test.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d00a72ebc77faf7333a31a4b5c73f17554ccfc88
4
- data.tar.gz: 62cd8f3823a629dba2f10e8b91b7841c9359c29d
3
+ metadata.gz: 5968de1064555bed8ecadc417fbad4f4af9c78d1
4
+ data.tar.gz: 3f06f99417522ab20a776412f5b2eca1295664f2
5
5
  SHA512:
6
- metadata.gz: bdae72102cee0e3c39c07c74715e9167878e9be90f27d12da827dbae7419c0105adf77bb9cc43ecc6bcd5ae80c1f394bff8795865d3014d70758bc9f562a4d8b
7
- data.tar.gz: 54415683a7bda1bfac78d73cf668fc93be875f654de0257e67f9c2a85963ef1315e156c2517b795713a4067635b6269710294a1cc2d74f09069de011a751b5ef
6
+ metadata.gz: 05ae6ba2fd2e933661e6f36fc1db77bef5ecd944b90f490c4d8d49d737b97aaf82ac61c0bcdff4055ac393fde2fe70e54228a30afdbef28d61134f0081f84779
7
+ data.tar.gz: 854f1efe44dd9a4056b5a37d882ed887487f7b7d734447c5d289648b118444e126352da92d2bf74935ce304f4eeecc92faed329f80a54fb85fbdb0a2b0f394ef
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ *~
data/Gemfile CHANGED
@@ -1,15 +1,20 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
3
  gem 'activesupport' , "~>4.2"
4
- gem 'activemodel'
5
- gem 'rest-client', :git => 'git://github.com/rest-client/rest-client.git'
4
+ gem 'activemodel', "~>4.2"
5
+ gem 'rest-client' , :git => 'git://github.com/rest-client/rest-client.git'
6
6
  gem 'nokogiri', '~> 1.6.6' #, :git => 'git://github.com/sparklemotion/nokogiri.git'
7
+ gem 'orientdb' , :path => '/home/topo/orientdb-jruby' , :platforms => :jruby
8
+ #gem 'orientdb' , :git => 'git://github.com/topofocus/orientdb-jruby.git', :branch => '2.1.2', :platforms => :jruby
7
9
  group :development, :test do
10
+ gem "awesome_print"
8
11
  gem "rspec"
12
+ gem 'rspec-legacy_formatters'
9
13
  gem 'rspec-its'
10
14
  gem 'rspec-collection_matchers'
11
15
  gem 'rspec-context-private'
12
- gem 'guard'
16
+ gem 'guard-jruby-rspec', :platforms => :jruby, :git => 'git://github.com/jkutner/guard-jruby-rspec.git'
17
+ gem 'guard'#, :platforms => :ruby
13
18
  gem 'guard-rspec'
14
19
  ## gem 'database_cleaner'
15
20
  gem 'rb-inotify'
data/Guardfile CHANGED
@@ -1,7 +1,6 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
-
4
- guard :rspec, cmd: "bundle exec rspec" do
3
+ def fire
5
4
  require "ostruct"
6
5
 
7
6
  # Generic Ruby apps
@@ -12,10 +11,19 @@ guard :rspec, cmd: "bundle exec rspec" do
12
11
 
13
12
 
14
13
  watch(%r{^spec/.+_spec\.rb$})
15
- watch(%r{^spec/usecase/(.+).rb$})
14
+ # watch(%r{^spec/usecase/(.+)\.rb$})
16
15
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
16
+ # watch(%r{^examples/time_graph/spec/(.+)_spec\.rb$})
17
+ watch('examples/time_graph/spec/create_time_spec.rb')
17
18
  watch('spec/spec_helper.rb') { "spec" }
18
19
 
19
- watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
21
  end
21
22
 
23
+
24
+ interactor :simple
25
+ if RUBY_PLATFORM == 'java'
26
+ guard( 'jruby-rspec') {fire} #', :spec_paths => ["spec"]
27
+ else
28
+ guard( :rspec, cmd: "bundle exec rspec") { fire }
29
+ end
data/README.md CHANGED
@@ -2,324 +2,344 @@
2
2
  Use OrientDB to persistently store dynamic Ruby-Objects and use database queries to manage even very large
3
3
  datasets.
4
4
 
5
- The Package ist tested with Ruby 2.2.1 and Orientdb 2.1.
5
+ You need a ruby 2.3 or a jruby 9.1x Installation and a working OrientDB-Instance (Version 2.2 prefered).
6
+ The jruby-part is experimental.
6
7
 
7
-
8
- To start you need a ruby 2.x Installation and a working OrientDB-Instance.
9
- Install the Gem the usual way
10
-
11
- For a quick start, go to the home directory of the package and start an irb-session
12
-
13
- ```ruby
14
- require 'bundler/setup'
15
- require 'active-orient'
8
+ For a quick start, clone the project, run bundle install & bundle update, update config/connect.yml, create the documentation by calling »rdoc«
9
+ and start an irb-session:
10
+ ```
11
+ cd bin
12
+ ./active-orient-console test # or d)develpoment, p)roduction environment as defined in config/connect.yml
16
13
  ```
17
14
 
18
- First, the Database-Server has to be specified. Then we can connect to a database.
19
- Assuming, the server is located on localhost, we just define »default-server«
20
- ```ruby
21
- ActiveOrient::OrientDB.default_server= { user: 'your user', password: 'your password' }
15
+ »ORD« is the Database-Instance itself. If the Database noticed is not present, it is created on startup.
16
+ A simple SQL-Query is submitted by providing a Block to »execute«
17
+ ```ruby
18
+ result = ORD.execute { "select * from Stock" }
19
+ ```
20
+ Obviously, the class »Stock« has to exist.
21
+ Let's create some classes
22
+
23
+ ```ruby
24
+ ORD.create_class 'ClassDocumentName' # creates or opens a basic document-class
25
+ ORD.create_vertex_class 'ClassVertexName' # creates or opens a vertex-class
26
+ ORD.create_edge_class 'ClassEdgeName' # creates or opens an edge-class, providing bidirectional links between documents
27
+ {Classname}.delete_class # removes the class in the database and destroys the ruby-object
28
+ ```
22
29
 
30
+ Classnames appear unchanged as Database-Classes. Strings and Symbols are accepted. Depending on the namespace choosen in 'config/config.yml' Model-Classes are allocated and linked to database-classes. For simplicity, here we omit any namespace ( :namespace: :object in config.yml). Thus the Model-Obects are accessible directly.
23
31
 
24
- r = ActiveOrient::OrientDB.new database: 'First'
25
- => I, [2015-08-18T09:49:18.858758 #88831] INFO -- OrientDB#Connect: Connected to database First
26
- => #<ActiveOrient::OrientDB:0x000000048d0488 @res=#<RestClient::Resource:0x00000004927288
27
- @url="http://localhost:2480", @block=nil,
28
- @options={:user=>"xx", :password=>"***"}>, @database="First", @classes=[]>
29
- ```
30
32
 
31
- »r« is the Database-Instance itself. Obviously the database is empty.
33
+ **Naming-Convention:** The name given in the »create-class«-Statement becomes the Database-Classname.
34
+ In Ruby-Space its Camelized, ie: ORD.create_class(:hut_ab) generates a Ruby-Class »HutAb«.
32
35
 
36
+ This can be customized in the "naming_convention"-class-method, which has to be defined in 'config/boot.rb'. The naming_convention changes the ruby-view to the classes. The Database-Class-Name is derived from the argument to #CreateClass, ORD.create_class('HANDS_UP') creates a database-class "HANDS_UP' and a Ruby-Class "HandsUp".
33
37
 
34
- Let's create some classes
38
+ ActiveOrient::Model's can be customized through methods defined in the model-directory. These methods are
39
+ loaded automatically afert executing #CreateClass (and through the preallocation process). Further details in the Examples-Section.
35
40
 
36
- ```ruby
37
- M = r.open_class 'classname' #
38
- M = r.create_class 'classname' # creates or opens a basic document-class
39
- M = r.create_vertex_class 'classname' # creates or opens a vertex-class
40
- M = r.create_edge_class 'classname' # creates or opens an edge-class, providing bidirectional links between documents
41
+ #### CRUD
42
+ The CRUD-Process (create, read = query, update and remove) is performed as
43
+ ```ruby
44
+ ORD.create_class :M
45
+ M.create name: 'Hugo', age: 46, interests: [ 'swimming', 'biking', 'reading' ]
46
+ # or
47
+ new_record = M.new age: 46, interests: [ 'swimming', 'biking', 'reading' ]
48
+ new_record.save # alternative: new_record.update
49
+ ##
50
+ hugo = M.where( name: 'Hugo' ).first
51
+ hugo.update set: { :father => M.create( name: "Volker", age: 76 ) } # we create an internal link
52
+ hugo.father.name # --> volker
53
+ M.remove hugo
54
+ M.delete_class # removes the class from OrientDB and deletes the ruby-object-definition
55
+ ```
56
+
57
+ #### Inherence
41
58
 
42
- r.delete_class M # universal removal-of-the-class-method
59
+ Create a Tree of Objects with create_classes
60
+ ```ruby
61
+ ORD.create_classes sector: [ :industry, :category, :subcategory ]
62
+ => {Sector=>[Industry, Category, Subcategory]}
63
+ Industry.create name: 'Communications' #---> Create an Industry-Record with the attribute "name"
64
+ Sector.where name: 'Communications' #---> an Array with the Industry-Object
65
+ => [#<Industry:0x0000000225e098 @metadata= (...) ]
43
66
  ```
67
+ ***notice*** to create inherent Vertices use ORD.create_classes( sector: [ :industry, :category, :subcategory ]){ :V }
44
68
 
69
+ #### Preallocation of Model-Classes
70
+ All database-classes are preallocated after connecting to the database. Thus you can use Model-Classes from the start.
45
71
 
46
- »M« is the ActiveOrient::Model-Class itself, a constant pointing to the class-definition of the ruby-class.
47
- Its a shortcut for »ActiveOrient::Model::{Classname} and is reused if defined elsewhere.
72
+ If the "rid" is known, any Object can be retrieved and correctly allocated by
73
+ ```ruby
74
+ the_object = ActiveOrient::Model.autoload_object "xx:yy" # or "#xx:yy"
75
+ ---> {ActiveOrient::Model} Object
76
+ ```
48
77
 
49
- If a schema is used, properties can be created and retrieved as well
50
- ```ruby
51
- r.create_properties( M ) do
52
- { symbol: { propertyType: 'STRING' },
53
- con_id: { propertyType: 'INTEGER' },
54
- details: { propertyType: 'LINK', linkedClass: 'Contracts' }
55
- }
78
+ #### Properties
79
+ The schemaless mode has many limitations. ActiveOrient offers a Ruby way to define Properties and Indexes
56
80
 
57
- r.get_class_properties M
58
- ```
59
- or
60
81
  ```ruby
61
- M.create_property 'symbol'
62
- M.create_property 'con_id', type: 'integer'
63
- M.create_property 'details', type: 'link', other_class: 'Contracts'
82
+ ORD.create_class :M, :item
83
+ M.create_property :symbol # the default-case: type: :string, no index
84
+ M.create_property :con_id, type: :integer
85
+ M.create_property :details, type: :link, other_class: 'Contracts'
86
+ M.create_property :items, type: :linklist, :linklist: Item
87
+ M.create_property :name, index: :unique # or M.create_property( 'name' ){ :unique }
64
88
  ```
65
89
 
66
- #### Active Model interface
67
-
68
- Every OrientDB-Database-Class is mirrord as Ruby-Class. The Class itself is defined by
90
+ (Experimental) You can put restrictions on your properties with the command "alter_property":
91
+
69
92
  ```ruby
70
- M = r.create_class 'classname'
71
- M = r.create_class { superclass_name: 'classname' }
72
- Vertex = r.create_vertex_class 'classname'
73
- Edge = r.create_edge_class 'classname'
93
+ M.alter_property property: "value", attribute: "MIN", alteration: 0
94
+ M.alter_property property: "value", attribute: "MAX", alteration: 23
74
95
  ```
75
- and is of TYPE ActiveOrient::Model::{classname}
76
96
 
77
- As for ActiveRecord-Tables, the Class itself provides methods to inspect and to filter datasets form the database.
97
+ #### Active Model interface
98
+
99
+ As for ActiveRecord-Tables, the Model-class itself provides methods to inspect and filter datasets form the database.
78
100
 
79
101
  ```ruby
80
102
  M.all
81
103
  M.first
82
- M.last
83
- ```
84
- returns an Array containing all Documents/Edges of the Class; the first and the last Record.
85
- ```ruby
86
- M.where town: 'Berlin'
87
- ```
88
- performs a query on the class and returns the result as Array
104
+ M.last # notice: last does not work in orientdb version 2.2, because the sorting algorithm for rid's is damaged
105
+ M.all.last # or M.where( ... ).last walkaround for Orientdb V 2.2
106
+ M.where town: 'Berlin'
89
107
 
90
- ```ruby
91
108
  M.count where: { town: 'Berlin' }
92
109
  ```
93
- gets the number of datasets fullfilling the search-criteria. Any parameter defining a valid
94
- SQL-Query in Orientdb can be provided to the count, where, first and last-method.
110
+ »count« gets the number of datasets fulfilling the search-criteria. Any parameter defining a valid SQL-Query in Orientdb can be provided to the »count«, »where«, »first« and »last«-method.
95
111
 
96
- A »normal« Query is submitted via
112
+ A »normal« Query is submitted via
97
113
  ```ruby
98
- M.get_documents projection: { projection-parameter }
99
- distinct: { some parameters }
100
- where: { where-parameter }
101
- order: { sorting-parameters }
102
- group_by: { one grouping-parameter}
103
- unwind:
104
- skip:
105
- limit:
114
+ M.get_records projection: { projection-parameter },
115
+ distinct: { some parameters },
116
+ where: { where-parameter },
117
+ order: { sorting-parameters },
118
+ group_by: { one grouping-parameter},
119
+ unwind: ,
120
+ skip: ,
121
+ limit:
106
122
 
107
123
  # or
108
- query = OrientSupport::OrientQuery.new {paramter}
109
- M.get_documents query: query
124
+ query = OrientSupport::OrientQuery.new {paramter}
125
+ M.query_database query
110
126
 
111
127
  ```
112
128
 
113
- Basic graph-support:
114
-
115
-
129
+ Graph-support:
116
130
 
117
131
  ```ruby
118
- vertex_1 = Vertex.create color: "blue"
119
- vertex_2 = Vertex.create flower: "rose"
120
- Edge.create_edge attributes: { :birthday => Date.today }, from: vertex_1, to: vertex_2
132
+ ORD.create_vertex_class :the_vertex
133
+ ORD.create_edge_class :the_edge
134
+ vertex_1 = TheVertex.create color: "blue"
135
+ vertex_2 = TheVertex.create flower: "rose"
136
+ TheEdge.create_edge attributes: {:birthday => Date.today }, from: vertex_1, to: vertex_2
121
137
  ```
122
- connects the vertices and assigns the attributes to the edge
138
+ It connects the vertexes and assigns the attributes to the edge.
123
139
 
140
+ To query a graph, SQL-like-Queries and Match-statements can be used (see below).
124
141
 
125
- #### Links
126
142
 
127
- A record in a database-class is defined by a »rid«. Every Model-Object comes with a handy »link«-method.
143
+ #### Links and LinkLists
128
144
 
129
- In OrientDB links are used to realise unidirectional 1:1 and 1:n relationships.
145
+ A record in a database-class is defined by a »rid«. If this is stored in a class, a link is set.
146
+ In OrientDB links are used to realize unidirectional 1:1 and 1:n relationships.
130
147
 
131
- ActiveOrient autoloads Model-objects when they are accessed. As a consequence,
132
- if an Object is stored in Cluster 30 and id 2, then "#30:2" fully qualifies the ActiveOrient::Model object.
148
+ ActiveOrient autoloads Model-objects when they are accessed. Example:
149
+ If an Object is stored in Cluster 30 and id 2, then "#30:2" fully qualifies the ActiveOrient::Model object and sets the
150
+ link if stored somewhere.
133
151
 
134
152
  ```ruby
135
- TestLinks = r.create_class 'Test_link_class'
136
- TestBase = r.create_class 'Test_base_class'
153
+ ORD.create_class 'test_link'
154
+ ORD.create_class 'test_base'
137
155
 
138
- link_document = TestLinks.create att: 'one attribute'
139
- base_document = TestBase.create base: 'my_base', single_link: link_document
156
+ link_document = TestLink.create att: 'one attribute'
157
+ base_document = TestBase.create base: 'my_base', single_link: link_document
140
158
  ```
141
- base_document.single_link just contains the rid. When accessed, the ActiveOrient::Model::Testlinkclass-object is autoloaded and
159
+ base_document.single_link just contains the rid. When accessed, the ActiveOrient::Model::Testlinkclass-object is autoloaded and
160
+
142
161
  ``` ruby
143
162
  base_document.single_link.att
144
163
  ```
145
- reads the stored content of link_document.
164
+ reads the stored content of link_document.
146
165
 
147
- To store a list of links to other Database-Objects a simple Array is allocated
166
+ To store a list of links to other Database-Objects, a simple Array is allocated
148
167
  ``` ruby
149
168
  # predefined linkmap-properties
150
- base_document = TestBase.create links: []
151
- ( 0 .. 20 ).each{ |y| base_document.links << TestLinks.create nr: y }
152
- end
169
+ TestLink.create_property :links, type: :linklist, linkedClass: :test_links
170
+ base_document = TestBase.create links: []
171
+ (0 .. 20).each{|y| base_document.links << TestLink.create( nr: y )}
172
+
153
173
  #or in schemaless-mode
154
- base_document = TestBase.create links: (0..20).map{|y| TestLinks.create nr: y }
155
-
156
-
174
+ base_document = TestBase.create links: (0..20).map{|y| TestLink.create nr: y}
175
+ base_document.update
157
176
  ```
158
- base_document.links behaves like a ruby-array.
177
+ base_document.links behaves like a ruby-array.
159
178
 
160
179
  If you got an undirectional graph
161
180
 
162
181
  a --> b ---> c --> d
163
182
 
164
- the graphelements can be explored by joining the objects ( a.b.c.d ), or (a.b[5].c[9].d )
183
+ the graph elements can be explored by joining the objects (a[6].b[5].c[9].d)
165
184
 
166
- #### Edges
185
+ Refer to the "Time-Graph"-Example for an Implementation of an bidirectional Graph with the same Interface
167
186
 
168
- Edges are easily handled
187
+ #### Edges
188
+ Edges provide bidirectional Links. They are easily handled
169
189
  ```ruby
170
- Vertex = r.create_vertex_class 'd1'
171
- Eedge = r.create_edge_class 'e1'
190
+ ORD.create_vertex_class :the_vertex # --> TheVertex
191
+ ORD.create_edge_class :the_edge # --> TheEdge
172
192
 
173
- start = Vertex.create something: 'nice'
174
- the_end = Vertex.create something: 'not_nice'
175
- the_edge = Edge.create_edge attributes: { transform_to: 'very bad' },
193
+ start = TheVertex.create something: 'nice'
194
+ the_end = TheVertex.create something: 'not_nice'
195
+ the_edge = TheEdge.create attributes: {transform_to: 'very bad'},
176
196
  from: start,
177
197
  to: the_end
178
-
198
+
179
199
  (...)
180
- the_edge.delete
200
+ the_edge.delete # To delete the edge
201
+ ```
202
+ The create-Method od Edge-Classes takes a block. Then all statements are transmitted in batch-mode.
203
+ Assume, Vertex1 and Vertex2 are Vertex-Classes and TheEdge is an Edge-Class, then
204
+ ```ruby
205
+ record1 = (1 .. 100).map{|y| Vertex1.create testentry: y }
206
+ record2 = (:a .. :z).map{|y| Vertex2.create testentry: y }
207
+ edges = TheEdge.create attributes: { study: 'Experiment1'} do | attributes |
208
+ # map returns an array, which is further processed by #create_edge
209
+ ('a'.ord .. 'z'.ord).map do |o|
210
+ { from: record1.find{|x| x.testentry == o },
211
+ to: record2.find{ |x| x.testentry.ord == o },
212
+ attributes: attributes.merge( key: o.chr ) }
213
+ end
181
214
  ```
215
+ connects the vertices and provides a variable "key" and a common "study" attribute to each edge.
182
216
 
183
- There is a basic support for traversals throught a graph.
217
+ There is a basic support for traversals through a graph.
184
218
  The Edges are accessed by their names (downcase).
185
-
186
219
  ```ruby
187
- start.e1[0]
188
- --> #<ActiveOrient::Model::E1:0x000000041e4e30
189
- @metadata={"type"=>"d", "class"=>"E1", "version"=>60, "fieldTypes"=>"out=x,in=x",
190
- "cluster"=>16, "record"=>43},
191
- @attributes={"out"=>"#31:23", "in"=>"#31:15", "transform_to"=>"very bad" }>
220
+ start = TheVertex.where: {something: "nice"}
221
+ start[0].e1[0]
222
+ --> #<E1:0x000000041e4e30
223
+ @metadata={"type"=>"d", "class"=>"E1", "version"=>60, "fieldTypes"=>"out=x,in=x", "cluster"=>16, "record"=>43},
224
+ @attributes={"out"=>"#31:23", "in"=>"#31:15", "transform_to"=>"very bad" }>
192
225
  ```
226
+
193
227
  The Attributes "in" and "out" can be used to move across the graph
228
+
229
+ ```ruby
230
+ start[0].e1[0].out.something
231
+ # ---> "not_nice"
232
+ start[0].e1[0].in.something
233
+ # ---> "nice"
234
+ ```
235
+
236
+ (Experimental) In alternative you can "humanize" your code in the following way:
237
+
194
238
  ```ruby
195
- start.e1[0].out.something
196
- ---> "not_nice
197
- start.e1[0].in.something
198
- ---> "nice
239
+ Vertex.add_edge_link name: "ends", edge: TheEdge
240
+ start.ends.something # <-- Similar output as start[0].e1[0].out.something
199
241
  ```
242
+
200
243
  #### Queries
201
- Contrary to traditional SQL-based Databases OrientDB handles subqueries very efficient.
202
- In addition, OrientDB supports precompiled statements (let-Blocks).
203
244
 
204
- ActiveOrient is equipped with a simple QueryGenerator: ActiveSupport::OrientQuery.
205
- It works in two modi: a comprehensive and a subsequent one
245
+ Contrary to traditional SQL-based Databases OrientDB handles sub-queries very efficiently. In addition, OrientDB supports precompiled statements (let-Blocks).
246
+
247
+ ActiveOrient is equipped with a simple QueryGenerator: ActiveSupport::OrientQuery.
248
+ It works in two ways: a comprehensive and a subsequent one
249
+
206
250
  ```ruby
207
-
251
+
208
252
  q = OrientSupport::OrientQuery.new
209
- q.from = Vertex
253
+ q.from = Vertex # If a constant is used, then the correspending
254
+ # ActiveOrient::Model-class is refered
210
255
  q.where << a: 2
211
256
  q.where << 'b > 3 '
212
257
  q.distinct = :profession
213
- q.order = { :name => :asc }
258
+ q.order = {:name => :asc}
214
259
 
215
260
  ```
216
261
  is equivalent to
262
+
217
263
  ```ruby
218
- q = OrientSupport::OrientQuery.new from: Vertex ,
264
+ q = OrientSupport::OrientQuery.new from: Vertex ,
219
265
  where: [{ a: 2 }, 'b > 3 '],
220
266
  distinct: :profession,
221
267
  order: { :name => :asc }
222
268
  q.to_s
223
269
  => select distinct( profession ) from Vertex where a = 2 and b > 3 order by name asc
224
270
  ```
225
- Both modes can be mixed.
226
271
 
227
- If subqueries are nessesary, they can be introduced as OrientSupport::OrientQuery or as »let-block«.
272
+ Both eayss can be mixed.
273
+
274
+ If sub-queries are necessary, they can be introduced as OrientSupport::OrientQuery or as »let-block«.
275
+
228
276
  ```ruby
229
- q = OrientSupport::OrientQuery.new from: 'ModelQuery'
277
+ OQ = OrientSupport::OrientQuery
278
+ q = OQ.new from: 'ModelQuery'
230
279
  q.let << "$city = adress.city"
231
280
  q.where = "$city.country.name = 'Italy' OR $city.country.name = 'France'"
232
281
  q.to_s
233
- => select from ModelQuery let $city = adress.city where $city.country.name = 'Italy' OR $city.country.name = 'France'
282
+ # => select from ModelQuery let $city = adress.city where $city.country.name = 'Italy' OR $city.country.name = 'France'
234
283
  ```
284
+
235
285
  or
286
+
236
287
  ```ruby
237
- q = OrientSupport::OrientQuery.new
238
- q.let << { a: OrientSupport::OrientQuery.new( from: '#5:0' ) }
239
- q.let << { b: OrientSupport::OrientQuery.new( from: '#5:1' ) }
288
+ q = OQ.new
289
+ q.let << {a: OQ.new( from: '#5:0' ) }
290
+ q.let << {b: OQ.new( from: '#5:1' ) }
240
291
  q.let << '$c= UNIONALL($a,$b) '
241
292
  q.projection << 'expand( $c )'
242
- q.to_s
243
- => select expand( $c ) let $a = ( select from #5:0 ), $b = ( select from #5:1 ), $c= UNIONALL($a,$b)
293
+ q.to_s # => select expand( $c ) let $a = ( select from #5:0 ), $b = ( select from #5:1 ), $c= UNIONALL($a,$b)
244
294
  ```
245
295
 
246
-
247
-
248
-
249
- #### Execute SQL-Commands
250
- Sql-commands can be executed as batch
251
-
252
- The ActiveOrient::Query-Class provides a Query-Stack and an Records-Array which keeps the results.
253
- The ActiveOrient::Query-Class acts as Parent-Class for aggregated Records (without a @rid), which are ActiveOrient::Model::Myquery Objects. If a Query returns a database-record, the correct ActiveOrient::Model-Class is instantiated.
296
+ or
254
297
 
255
298
  ```ruby
256
- ach = ActiveOrient::Query.new
257
-
258
- ach.queries << 'create class Contracts ABSTRACT'
259
- ach.queries << 'create property Contracts.subcategory link'
260
- ach.queries << 'create property Contracts.details link'
261
- ach.queries << 'create class Stocks extends Contracts'
262
- ach.queries << 'create class Futures extends Contracts'
263
- result = ach.execute_queries transaction: false
264
-
265
-
299
+ last_12_open_interest_records = OQ.new from: OpenInterest,
300
+ order: { fetch_date: :desc } , limit: 12
301
+ bunch_of_contracts = OQ.new from: last_12_open_interest_records,
302
+ projection: 'expand( contracts )'
303
+ distinct_contracts = OQ.new from: bunch_of_contracts,
304
+ projection: 'expand( distinct(@rid) )'
305
+
306
+ distinct_contracts.to_s
307
+ => "select expand( distinct(@rid) ) from ( select expand( contracts ) from ( select from open_interest order by fetch_date desc limit 12 ) ) "
266
308
 
309
+ cq = ORD.get_documents query: distinct_contracts
267
310
  ```
268
- queries the database as demonstrated above. In addition, the generated query itself is added to the »queries«-Stack and the result can be found in sample_query.records.
269
-
270
- This feature can be used as a substitute for simple functions
311
+ this executes the query and returns the adressed rid's, which are eventually retrieved from the rid-cache.
312
+ #### Match
271
313
 
314
+ A Match-Query starts at the given ActiveOrient::Model-Class. The where-cause narrows the sample to certain
315
+ records. In the simplest version this can be returnd:
316
+
272
317
  ```ruby
273
- roq = ActiveOrient::Query.new
274
- roq.queries =["select name, categories.subcategories.contracts from Industries where name containstext …'ial'"]
275
- roq.execute_queries.each{|x| puts x.name, x.categories.inspect }
276
- --> Basic Materials [["#21:1"]]
277
- --> Financial [["#21:2"]]
278
- --> Industrial [["#23:0", "#23:1"]]
318
+ ORD.create_class :Industry
319
+ Industry.match where:{ name: "Communications" }
320
+ => #<ActiveOrient::Model::Query:0x00000004309608 @metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"Industries=x"}, @attributes={"Industries"=>"#21:1", (...)}>
279
321
  ```
280
322
 
281
- OrientDB supports the execution of SQL-Batch-Commands.
282
- ( http://orientdb.com/docs/2.0/orientdb.wiki/SQL-batch.html )
283
- This is supported simply by using a Array as Argument for ActiveOrient::Query.queries
323
+ The attributes are the return-Values of the Match-Query. Unless otherwise noted, the pluralized Model-Classname is used as attribute in the result-set.
284
324
 
285
- Therefor complex queries can be simplified using database-variables
286
325
  ```ruby
287
- ach = ActiveOrient::Query.new
288
- ach.queries << [ "select expand( contracts ) from Openinterest"
289
- "let con = select expand( contracts ) from Openinterest; ",
290
- "...", ... ]
291
- result = ach.execute_queries
326
+ Industry.match where name: "Communications"
327
+ ## is equal to
328
+ Industry.match( where: { name: 'Communications' }).first.Industries
292
329
  ```
330
+ The Match-Query uses this result-set as start for subsequent queries on connected records.
331
+ If a linear graph: Industry <- Category <- Subcategory <- Stock is build, Subcategories can
332
+ accessed starting at Industry defining
293
333
 
294
- The contract-documents are accessible with
295
334
  ```ruby
296
- r.get_document '21:1'
297
- --><Stocks: con_id: 77680640 currency: EUR details: #18:1 exchange: SMART local_symbol: BAS
298
- primary_exchange: IBIS subcategory: #14:1 symbol: BAS>
299
- ```
300
- or
301
- ```ruby
302
- my_query = ActiveOrient::Query.new
303
- ['Contracts', 'Industries', 'Categories', 'Subcategories'].each do |table|
304
- my_query.queries = [ "select count(*) from #{table}"]
305
-
306
- count = my_query.execute_queries
307
- # count=> [#<ActiveOrient::Model::Myquery:0x00000003b317c8
308
- # @metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"count=l"},
309
- # @attributes={"count"=>4 } ] --> an Array with one Element, therefor count.pop
310
- puts "Table #{table} \t #{count.pop.count} Datasets "
311
- end
312
- -->Table Contracts 56 Datasets
313
- -->Table Industries 8 Datasets
314
- -->Table Categories 22 Datasets
315
- -->Table Subcategories 35 Datasets
316
-
335
+ var = Industry.match( where: { name: 'Communications'}) do | query |
336
+ query.connect :in, count: 2, as: 'Subcategories'
337
+ puts query.to_s # print the query prior sending it to the database
338
+ query # important: block has to return the query
339
+ end
340
+ => MATCH {class: Industry, as: Industries} <-- {} <-- { as: Subcategories } RETURN Industries, Subcategories
317
341
  ```
318
342
 
319
- Note that the fetched Object is of type »Stocks« (ActiveOrient::Model::Stocks).
343
+ The result-set has two attributes: Industries and Subcategories, pointing to the filtered datasets.
320
344
 
321
- The ActiveOrient-API documentation can be found here: https://github.com/orientechnologies/orientdb-docs/wiki/OrientDB-ActiveOrient
322
- and the ActiveModel-documentation is here: http://www.rubydoc.info/gems/activemodel
323
-
324
-
325
-
345
+ By using subsequent »connect« and »statement« method-calls even complex Match-Queries can be constructed.