active-orient 0.4 → 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Gemfile +8 -3
- data/Guardfile +12 -4
- data/README.md +221 -201
- data/VERSION +1 -1
- data/active-orient.gemspec +3 -2
- data/bin/active-orient-console +35 -0
- data/config/boot.rb +84 -16
- data/config/config.yml +10 -0
- data/config/connect.yml +6 -2
- data/create_project +19 -0
- data/examples/books.rb +86 -39
- data/examples/createTime.rb +91 -0
- data/examples/streets.rb +85 -84
- data/examples/test_commands.rb +92 -0
- data/examples/test_commands_2.rb +54 -0
- data/examples/test_commands_3.rb +48 -0
- data/examples/test_commands_4.rb +28 -0
- data/examples/time_graph/Gemfile +21 -0
- data/examples/time_graph/Guardfile +26 -0
- data/examples/time_graph/README.md +129 -0
- data/examples/time_graph/bin/active-orient-console +35 -0
- data/examples/time_graph/config/boot.rb +119 -0
- data/examples/time_graph/config/config.yml +8 -0
- data/examples/time_graph/config/connect.yml +17 -0
- data/examples/time_graph/config/init_db.rb +59 -0
- data/examples/time_graph/createTime.rb +51 -0
- data/examples/time_graph/lib/createTime.rb +82 -0
- data/examples/time_graph/model/day_of.rb +3 -0
- data/examples/time_graph/model/e.rb +6 -0
- data/examples/time_graph/model/edge.rb +53 -0
- data/examples/time_graph/model/monat.rb +19 -0
- data/examples/time_graph/model/stunde.rb +16 -0
- data/examples/time_graph/model/tag.rb +29 -0
- data/examples/time_graph/model/time_base.rb +6 -0
- data/examples/time_graph/model/time_of.rb +4 -0
- data/examples/time_graph/model/v.rb +3 -0
- data/examples/time_graph/model/vertex.rb +32 -0
- data/examples/time_graph/spec/lib/create_time_spec.rb +50 -0
- data/examples/time_graph/spec/rest_helper.rb +37 -0
- data/examples/time_graph/spec/spec_helper.rb +46 -0
- data/lib/active-orient.rb +56 -6
- data/lib/base.rb +149 -147
- data/lib/base_properties.rb +40 -41
- data/lib/class_utils.rb +301 -0
- data/lib/database_utils.rb +97 -0
- data/lib/init.rb +35 -0
- data/lib/java-api.rb +437 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/edge.rb +53 -0
- data/lib/model/model.rb +77 -0
- data/lib/model/the_class.rb +480 -0
- data/lib/model/the_record.rb +310 -0
- data/lib/model/vertex.rb +32 -0
- data/lib/orient.rb +113 -50
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +280 -0
- data/lib/query.rb +71 -73
- data/lib/rest/change.rb +124 -0
- data/lib/rest/create.rb +474 -0
- data/lib/rest/delete.rb +133 -0
- data/lib/rest/operations.rb +150 -0
- data/lib/rest/read.rb +150 -0
- data/lib/rest/rest.rb +111 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support.rb +387 -296
- data/old_lib_functions/two_general_class.rb +139 -0
- data/usecase.md +49 -36
- data/usecase_oo.md +59 -0
- metadata +73 -9
- data/lib/model.rb +0 -461
- data/lib/rest.rb +0 -1036
- data/test.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5968de1064555bed8ecadc417fbad4f4af9c78d1
|
4
|
+
data.tar.gz: 3f06f99417522ab20a776412f5b2eca1295664f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05ae6ba2fd2e933661e6f36fc1db77bef5ecd944b90f490c4d8d49d737b97aaf82ac61c0bcdff4055ac393fde2fe70e54228a30afdbef28d61134f0081f84779
|
7
|
+
data.tar.gz: 854f1efe44dd9a4056b5a37d882ed887487f7b7d734447c5d289648b118444e126352da92d2bf74935ce304f4eeecc92faed329f80a54fb85fbdb0a2b0f394ef
|
data/.gitignore
CHANGED
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/(.+)
|
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$})
|
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
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
-
|
19
|
-
|
20
|
-
```ruby
|
21
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
M
|
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
|
-
|
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
|
-
|
47
|
-
|
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
|
-
|
50
|
-
|
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
|
-
|
62
|
-
M.create_property
|
63
|
-
M.create_property
|
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
|
-
|
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
|
71
|
-
M
|
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
|
-
|
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
|
-
|
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
|
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.
|
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.
|
124
|
+
query = OrientSupport::OrientQuery.new {paramter}
|
125
|
+
M.query_database query
|
110
126
|
|
111
127
|
```
|
112
128
|
|
113
|
-
|
114
|
-
|
115
|
-
|
129
|
+
Graph-support:
|
116
130
|
|
117
131
|
```ruby
|
118
|
-
|
119
|
-
|
120
|
-
|
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
|
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
|
-
|
143
|
+
#### Links and LinkLists
|
128
144
|
|
129
|
-
|
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.
|
132
|
-
|
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
|
-
|
136
|
-
|
153
|
+
ORD.create_class 'test_link'
|
154
|
+
ORD.create_class 'test_base'
|
137
155
|
|
138
|
-
link_document =
|
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
|
-
|
151
|
-
|
152
|
-
|
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 =
|
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
|
183
|
+
the graph elements can be explored by joining the objects (a[6].b[5].c[9].d)
|
165
184
|
|
166
|
-
|
185
|
+
Refer to the "Time-Graph"-Example for an Implementation of an bidirectional Graph with the same Interface
|
167
186
|
|
168
|
-
Edges
|
187
|
+
#### Edges
|
188
|
+
Edges provide bidirectional Links. They are easily handled
|
169
189
|
```ruby
|
170
|
-
|
171
|
-
|
190
|
+
ORD.create_vertex_class :the_vertex # --> TheVertex
|
191
|
+
ORD.create_edge_class :the_edge # --> TheEdge
|
172
192
|
|
173
|
-
start =
|
174
|
-
the_end
|
175
|
-
the_edge =
|
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
|
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.
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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
|
-
|
196
|
-
|
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
|
-
|
205
|
-
|
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 =
|
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
|
-
|
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
|
-
|
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 =
|
238
|
-
q.let << {
|
239
|
-
q.let << {
|
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
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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
|
-
|
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
|
-
|
274
|
-
|
275
|
-
|
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
|
-
|
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
|
-
|
288
|
-
|
289
|
-
|
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
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
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
|
-
|
343
|
+
The result-set has two attributes: Industries and Subcategories, pointing to the filtered datasets.
|
320
344
|
|
321
|
-
|
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.
|