active-orient 0.4 → 0.80
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 +5 -5
- data/.gitignore +1 -0
- data/.graphs.txt.swp +0 -0
- data/Gemfile +9 -5
- data/Guardfile +12 -4
- data/README.md +70 -281
- data/VERSION +1 -1
- data/active-orient.gemspec +9 -7
- data/bin/active-orient-0.6.gem +0 -0
- data/bin/active-orient-console +97 -0
- data/changelog.md +60 -0
- data/config/boot.rb +70 -17
- data/config/config.yml +10 -0
- data/config/connect.yml +11 -6
- data/examples/books.rb +154 -65
- data/examples/streets.rb +89 -85
- data/graphs.txt +70 -0
- data/lib/active-orient.rb +78 -6
- data/lib/base.rb +266 -168
- data/lib/base_properties.rb +76 -65
- data/lib/class_utils.rb +187 -0
- data/lib/database_utils.rb +99 -0
- data/lib/init.rb +80 -0
- data/lib/java-api.rb +442 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/custom.rb +29 -0
- data/lib/model/e.rb +6 -0
- data/lib/model/edge.rb +114 -0
- data/lib/model/model.rb +134 -0
- data/lib/model/the_class.rb +657 -0
- data/lib/model/the_record.rb +313 -0
- data/lib/model/vertex.rb +371 -0
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +423 -0
- data/lib/railtie.rb +68 -0
- data/lib/rest/change.rb +150 -0
- data/lib/rest/create.rb +287 -0
- data/lib/rest/delete.rb +150 -0
- data/lib/rest/operations.rb +222 -0
- data/lib/rest/read.rb +189 -0
- data/lib/rest/rest.rb +120 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support/conversions.rb +42 -0
- data/lib/support/default_formatter.rb +7 -0
- data/lib/support/errors.rb +41 -0
- data/lib/support/logging.rb +38 -0
- data/lib/support/orient.rb +305 -0
- data/lib/support/orientquery.rb +647 -0
- data/lib/support/query.rb +92 -0
- data/rails.md +154 -0
- data/rails/activeorient.rb +32 -0
- data/rails/config.yml +10 -0
- data/rails/connect.yml +17 -0
- metadata +89 -30
- data/lib/model.rb +0 -461
- data/lib/orient.rb +0 -98
- data/lib/query.rb +0 -88
- data/lib/rest.rb +0 -1036
- data/lib/support.rb +0 -347
- data/test.rb +0 -4
- data/usecase.md +0 -91
@@ -0,0 +1,657 @@
|
|
1
|
+
module ModelClass
|
2
|
+
require 'stringio'
|
3
|
+
include OrientSupport::Support
|
4
|
+
|
5
|
+
|
6
|
+
########### CLASS FUNCTIONS ######### SELF ####
|
7
|
+
|
8
|
+
|
9
|
+
######## INITIALIZE A RECORD FROM A CLASS ########
|
10
|
+
|
11
|
+
|
12
|
+
=begin
|
13
|
+
NamingConvention provides a translation from database-names to class-names.
|
14
|
+
|
15
|
+
It can be overwritten to provide different conventions for different classes, eg. Vertexes or edges
|
16
|
+
and to introduce distinct naming-conventions in different namespaces
|
17
|
+
|
18
|
+
To overwrite use
|
19
|
+
class Model # < ActiveOrient::Model[:: ...]
|
20
|
+
def self.naming_convention
|
21
|
+
( conversion code )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
=end
|
25
|
+
def naming_convention name=nil
|
26
|
+
nc = name.present?? name.to_s : ref_name
|
27
|
+
if namespace_prefix.present?
|
28
|
+
nc.split(namespace_prefix).last.camelize
|
29
|
+
else
|
30
|
+
nc.camelize
|
31
|
+
end
|
32
|
+
rescue
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
=begin
|
38
|
+
Set the namespace_prefix for database-classes.
|
39
|
+
|
40
|
+
If a namespace is set by
|
41
|
+
ActiveOrient::Init.define_namespace { ModuleName }
|
42
|
+
ActiveOrient translates this to
|
43
|
+
ModuleName::CamelizedClassName
|
44
|
+
The database-class becomes
|
45
|
+
modulename_class_name
|
46
|
+
|
47
|
+
If the namespace is set to a class (Object, ActiveOrient::Model ) namespace_prefix returns an empty string.
|
48
|
+
|
49
|
+
Override to change its behavior
|
50
|
+
=end
|
51
|
+
def namespace_prefix
|
52
|
+
namespace.is_a?(Class )? '' : namespace.to_s.downcase+'_'
|
53
|
+
end
|
54
|
+
=begin
|
55
|
+
orientdb_class is used to refer a ActiveOrient:Model-Object providing its name
|
56
|
+
|
57
|
+
Parameter: name: string or symbol
|
58
|
+
=end
|
59
|
+
|
60
|
+
def orientdb_class name:, superclass: nil # :nodoc: # public method: autoload_class
|
61
|
+
|
62
|
+
ActiveOrient.database_classes[name.to_s].presence || ActiveOrient::Model
|
63
|
+
rescue NoMethodError => e
|
64
|
+
logger.error { "Error in orientdb_class: is ActiveOrient.database_classes initialized ? \n\n\n" }
|
65
|
+
logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
66
|
+
Kernel.exit
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
=begin
|
71
|
+
setter method to initialise a dummy ActiveOrient::Model class to enable multi-level
|
72
|
+
access to links and linklists
|
73
|
+
=end
|
74
|
+
|
75
|
+
def link_list *property
|
76
|
+
property.each do |p|
|
77
|
+
|
78
|
+
the_dummy_class = orientdb.allocate_class_in_ruby("dummy_"+p.to_s)
|
79
|
+
the_dummy_class.ref_name = ref_name + "." + p.to_s
|
80
|
+
singleton_class.send :define_method, p do
|
81
|
+
the_dummy_class
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
=begin
|
88
|
+
requires the file specified in the model-dir
|
89
|
+
|
90
|
+
In fact, the model-files are loaded instead of required.
|
91
|
+
Thus, even after recreation of a class (Class.delete_class, ORD.create_class classname)
|
92
|
+
custom methods declared in the model files are present.
|
93
|
+
|
94
|
+
If a class is destroyed (i.e. the database class is deleted), the ruby-class and its methods vanish, too.
|
95
|
+
|
96
|
+
The directory specified is expanded by the namespace. The parameter itself is the base-dir.
|
97
|
+
|
98
|
+
Example:
|
99
|
+
Namespace: HC
|
100
|
+
model_dir : 'lib/model'
|
101
|
+
searched directory: 'lib/model/hc'
|
102
|
+
|
103
|
+
|
104
|
+
ActiveOrient::Model.modeldir is aimed to be set to the application dir. It may be a String, Pathname or
|
105
|
+
an array of strings or pathnames.
|
106
|
+
|
107
|
+
The parameter `dir` is used internally and by gems to ensure that basic methods are loaded first.
|
108
|
+
|
109
|
+
|
110
|
+
=end
|
111
|
+
def require_model_file dir = nil
|
112
|
+
logger.progname = 'ModelClass#RequireModelFile'
|
113
|
+
# model-dir can either be a string or an array of string or pathnames
|
114
|
+
default = [ActiveOrient::Model.model_dir].flatten
|
115
|
+
# access the default dir's first
|
116
|
+
the_directories = case dir
|
117
|
+
when String, Pathname
|
118
|
+
default.present? ? [dir] + default : [dir]
|
119
|
+
when Array
|
120
|
+
default.present? ? dir + default : dir
|
121
|
+
else
|
122
|
+
default.present? ? default : []
|
123
|
+
end.uniq.compact
|
124
|
+
the_directories.uniq.map do |raw_directory|
|
125
|
+
the_directory = Pathname( raw_directory )
|
126
|
+
if File.exists?( the_directory )
|
127
|
+
model= self.to_s.underscore + ".rb"
|
128
|
+
filename = the_directory + model
|
129
|
+
if File.exists?(filename )
|
130
|
+
if load filename
|
131
|
+
logger.debug{ "#{filename} sucessfully loaded" }
|
132
|
+
self #return_value
|
133
|
+
else
|
134
|
+
logger.error{ "#{filename} load error" }
|
135
|
+
nil #return_value
|
136
|
+
end
|
137
|
+
else
|
138
|
+
logger.debug{ "model-file not present: #{filename} --> skipping" }
|
139
|
+
nil #return_value
|
140
|
+
end
|
141
|
+
else
|
142
|
+
logger.error{ "Directory #{ the_directory } not present " }
|
143
|
+
nil #return_value
|
144
|
+
end
|
145
|
+
end.compact.present? # return true only if at least one model-file is present
|
146
|
+
|
147
|
+
rescue TypeError => e
|
148
|
+
puts "THE CLASS#require_model_file -> TypeError: #{e.message}"
|
149
|
+
puts "Working on #{self.to_s} -> #{self.superclass}"
|
150
|
+
puts "Class_hierarchy: #{orientdb.class_hierarchy.inspect}."
|
151
|
+
print e.backtrace.join("\n")
|
152
|
+
raise
|
153
|
+
#
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# creates an inherent class
|
158
|
+
def create_class *c
|
159
|
+
orientdb.create_class( *c ){ self }
|
160
|
+
end
|
161
|
+
|
162
|
+
########## CREATE ############
|
163
|
+
|
164
|
+
=begin
|
165
|
+
Universal method to create a new record.
|
166
|
+
It's overloaded to create specific kinds, eg. edge and vertex and is called only for abstract classes
|
167
|
+
|
168
|
+
Example:
|
169
|
+
V.create_class :test
|
170
|
+
Test.create string_attribute: 'a string', symbol_attribute: :a_symbol, array_attribute: [34,45,67]
|
171
|
+
Test.create link_attribute: Test.create( :a_new_attribute => 'new' )
|
172
|
+
|
173
|
+
=end
|
174
|
+
def create **attributes
|
175
|
+
attributes.merge :created_at => DateTime.new
|
176
|
+
result = db.create_record self, attributes: attributes
|
177
|
+
if result.nil
|
178
|
+
logger.error('Model::Class'){ "Table #{refname}: create failed: #{attributes.inspect}" }
|
179
|
+
elsif block_given?
|
180
|
+
yield result
|
181
|
+
else
|
182
|
+
result # return value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# returns a OrientSupport::OrientQuery
|
188
|
+
def query **args
|
189
|
+
OrientSupport::OrientQuery.new( **( {from: self}.merge args))
|
190
|
+
end
|
191
|
+
|
192
|
+
=begin
|
193
|
+
Creates or updates records.
|
194
|
+
Parameter:
|
195
|
+
- set: A hash of attributes to insert or update unconditionally
|
196
|
+
- where: A string or hash as condition which should return just one record.
|
197
|
+
|
198
|
+
The where-part should be covered with an unique-index.
|
199
|
+
|
200
|
+
|
201
|
+
returns the affected record, if the where-condition is set properly.
|
202
|
+
Otherwise upsert acts as »update« and returns all updated records (as array).
|
203
|
+
=end
|
204
|
+
def upsert set: nil, where: , **args
|
205
|
+
set = where if set.nil?
|
206
|
+
query( **args.merge( kind: :upsert, set: set, where: where )).execute(reduce: true){|y| y[:$current].reload!}
|
207
|
+
end
|
208
|
+
=begin
|
209
|
+
Sets a value to certain attributes, overwrites existing entries, creates new attributes if necessary
|
210
|
+
|
211
|
+
returns the count of affected records
|
212
|
+
|
213
|
+
IB::Account.update connected: false
|
214
|
+
IB::Account.update where: "account containsText 'F'", set:{ connected: false }
|
215
|
+
# or
|
216
|
+
IB::Account.update connected: false, where: "account containsText 'F'"
|
217
|
+
=end
|
218
|
+
|
219
|
+
def update! where: nil , set: {}, **arg
|
220
|
+
query( kind: :update!, set: set.merge(arg), where: where).execute(reduce: true){|y| y[:count]}
|
221
|
+
end
|
222
|
+
|
223
|
+
alias update_all update!
|
224
|
+
|
225
|
+
|
226
|
+
# same as update!, but returns a list of updated records
|
227
|
+
def update where: , set: {}, **arg
|
228
|
+
# In OrientDB V.3 the database only returns the affected rid's
|
229
|
+
# We have to update the contents manually, this is done in the execute-block
|
230
|
+
query( kind: :update, set: set.merge(arg), where: where).execute{|y| y[:$current].reload!}
|
231
|
+
end
|
232
|
+
|
233
|
+
=begin
|
234
|
+
Create a Property in the Schema of the Class and optionally create an automatic index
|
235
|
+
|
236
|
+
Examples:
|
237
|
+
|
238
|
+
create_property :customer_id, type: :integer, index: :unique
|
239
|
+
create_property( :name, type: :string ) { :unique }
|
240
|
+
create_property( :name, type: :string ) { name: 'some_index', on: :automatic, type: :unique }
|
241
|
+
create_property :in, type: :link, linked_class: V (used by edges)
|
242
|
+
|
243
|
+
:call-seq: create_property(field (required),
|
244
|
+
type: :a_supported_type',
|
245
|
+
linked_class: nil
|
246
|
+
|
247
|
+
supported types:
|
248
|
+
:bool :double :datetime = :date :float :decimal
|
249
|
+
:embedded_list = :list :embedded_map = :map :embedded_set = :set
|
250
|
+
:int :integer :link_list :link_map :link_set
|
251
|
+
|
252
|
+
If `:list`, `:map`, `:set`, `:link`, `:link_list`, `:link_map` or `:link_set` is specified
|
253
|
+
a `linked_class:` parameter can be specified. Argument is the OrientDB-Class-Constant
|
254
|
+
=end
|
255
|
+
def create_property field, type: :integer, index: nil, **args
|
256
|
+
arguments = args.values.map do |y|
|
257
|
+
if y.is_a?(Class) && ActiveOrient.database_classes.values.include?(y)
|
258
|
+
y.ref_name
|
259
|
+
elsif ActiveOrient.database_classes.keys.include?(y.to_s)
|
260
|
+
y
|
261
|
+
else
|
262
|
+
puts ActiveOrient.database_classes.inspect
|
263
|
+
puts "YY : #{y.to_s} #{y.class}"
|
264
|
+
raise ArgumentError , "database class #{y.to_s} not allocated"
|
265
|
+
end
|
266
|
+
end.compact.join(',')
|
267
|
+
|
268
|
+
supported_types = {
|
269
|
+
:bool => "BOOLEAN",
|
270
|
+
:double => "BYTE",
|
271
|
+
:datetime => "DATE",
|
272
|
+
:date => "DATE",
|
273
|
+
:float => "FLOAT",
|
274
|
+
:decimal => "DECIMAL",
|
275
|
+
:embedded_list => "EMBEDDEDLIST",
|
276
|
+
:list => "EMBEDDEDLIST",
|
277
|
+
:embedded_map => "EMBEDDEDMAP",
|
278
|
+
:map => "EMBEDDEDMAP",
|
279
|
+
:embedded_set => "EMBEDDEDSET",
|
280
|
+
:set => "EMBEDDEDSET",
|
281
|
+
:string => "STRING",
|
282
|
+
:int => "INTEGER",
|
283
|
+
:integer => "INTEGER",
|
284
|
+
:link => "LINK",
|
285
|
+
:link_list => "LINKLIST",
|
286
|
+
:link_map => "LINKMAP",
|
287
|
+
:link_set => "LINKSET",
|
288
|
+
}
|
289
|
+
|
290
|
+
## if the »type« argument is a string, it is used unchanged
|
291
|
+
type = supported_types[type] if type.is_a?(Symbol)
|
292
|
+
|
293
|
+
raise ArgumentError , "unsupported type" if type.nil?
|
294
|
+
s= " CREATE PROPERTY #{ref_name}.#{field} #{type} #{arguments}"
|
295
|
+
puts s
|
296
|
+
db.execute { s }
|
297
|
+
|
298
|
+
i = block_given? ? yield : index
|
299
|
+
## supported format of block: index: { name: 'something' , on: :automatic, type: :unique }
|
300
|
+
## or { name: 'something' , on: :automatic, type: :unique } #
|
301
|
+
## or { some_name: :unique } # manual index
|
302
|
+
## or { :unique } # automatic index
|
303
|
+
if i.is_a? Hash
|
304
|
+
att= i.key( :index ) ? i.values.first : i
|
305
|
+
name, on, type = if att.size == 1 && att[:type].nil?
|
306
|
+
[att.keys.first, field, att.values.first ]
|
307
|
+
else
|
308
|
+
[ att[:name] || field , att[:on] || field , att[:type] || :unique ]
|
309
|
+
end
|
310
|
+
create_index( name , on: on, type: type)
|
311
|
+
elsif i.is_a?(Symbol) || i.is_a?(String)
|
312
|
+
create_index field, type: i
|
313
|
+
end
|
314
|
+
|
315
|
+
# orientdb.create_property self, field, **keyword_arguments, &b
|
316
|
+
end
|
317
|
+
|
318
|
+
# Create more Properties in the Schema of the Class
|
319
|
+
|
320
|
+
def create_properties argument_hash, &b
|
321
|
+
orientdb.create_properties self, argument_hash, &b
|
322
|
+
end
|
323
|
+
|
324
|
+
|
325
|
+
# Add an Index
|
326
|
+
#
|
327
|
+
# Parameters:
|
328
|
+
# name (string / symbol),
|
329
|
+
# [ on: :automatic / single Column, Array of Columns,
|
330
|
+
# [ type: :unique, :nonunique, :dictionary,:fulltext, {other supported index-types} ]]
|
331
|
+
#
|
332
|
+
# Default:
|
333
|
+
# on: :automatic
|
334
|
+
# type: :unique
|
335
|
+
#
|
336
|
+
# Example
|
337
|
+
#
|
338
|
+
# ORD.create_vertex_class :pagination
|
339
|
+
# Pagination.create_property :col1 , type: :string
|
340
|
+
# Pagination.create_property :col2, type: :integer
|
341
|
+
# Pagination.create_property :col3, type: :string
|
342
|
+
# Pagination.create_property :col4, type: :integer
|
343
|
+
# Pagination.create_index :composite, :on => [:col1, :col2, :col3], type: 'dictionary'
|
344
|
+
|
345
|
+
def create_index name, **attributes
|
346
|
+
orientdb.create_index self, name: name, **attributes
|
347
|
+
end
|
348
|
+
|
349
|
+
# list all Indexes
|
350
|
+
def indexes
|
351
|
+
properties[:indexes]
|
352
|
+
end
|
353
|
+
|
354
|
+
|
355
|
+
def migrate_property property, to: , linked_class: nil, via: 'tzr983'
|
356
|
+
if linked_class.nil?
|
357
|
+
create_property via, type: to
|
358
|
+
else
|
359
|
+
create_property via, type: to, linked_class: linked_class
|
360
|
+
end
|
361
|
+
# my_count = query.kind(:update!).set( "#{via} = #{property} ").execute(reduce: true){|c| c[:count]}
|
362
|
+
# logger.info{" migrate property: #{count} records prosessed"}
|
363
|
+
all.each{ |r| r.update set:{ via => r[property.to_sym] }}
|
364
|
+
nullify = query.kind(:update!).set( property: nil ).execute(reduce: true){|c| c[:count]}
|
365
|
+
# raise "migrate property: count of erased items( #{nullify} differs from total count (#{my_count}) " if nullify != my_count
|
366
|
+
db.execute{" alter property #{ref_name}.#{via} name '#{property}' "}
|
367
|
+
logger.info{ "successfully migrated #{property} to #{:to} " }
|
368
|
+
|
369
|
+
|
370
|
+
|
371
|
+
|
372
|
+
|
373
|
+
|
374
|
+
|
375
|
+
|
376
|
+
end
|
377
|
+
########## GET ###############
|
378
|
+
|
379
|
+
def classname # :nodoc: #
|
380
|
+
ref_name
|
381
|
+
end
|
382
|
+
|
383
|
+
# get elements by rid
|
384
|
+
|
385
|
+
def get rid
|
386
|
+
if @excluded.blank?
|
387
|
+
db.get_record(rid)
|
388
|
+
else
|
389
|
+
db.execute{ "select expand( @this.exclude( #{@excluded.map(&:to_or).join(",")})) from #{rid} "}
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
# get all the elements of the class
|
394
|
+
|
395
|
+
def all
|
396
|
+
query.execute
|
397
|
+
end
|
398
|
+
|
399
|
+
# get the first element of the class
|
400
|
+
|
401
|
+
def first **args
|
402
|
+
query( **( { order: "@rid" , limit: 1 }.merge args)).execute(reduce: true)
|
403
|
+
end
|
404
|
+
# db.get_records(from: self, where: where, limit: 1).pop
|
405
|
+
#end
|
406
|
+
|
407
|
+
# get the last element of the class
|
408
|
+
def last **args
|
409
|
+
query( **( { order: {"@rid" => 'desc'} , limit: 1 }.merge args)).execute(reduce: true)
|
410
|
+
end
|
411
|
+
|
412
|
+
# Used to count of the elements in the class
|
413
|
+
#
|
414
|
+
# Examples
|
415
|
+
# TestClass.count where: 'last_access is NULL' # only records where 'last_access' is not set
|
416
|
+
# TestClass.count # all records
|
417
|
+
def count **args
|
418
|
+
query( **( { projection: 'COUNT(*)' }.merge args )).execute(reduce: true){|x| x[:"COUNT(*)"]}
|
419
|
+
end
|
420
|
+
|
421
|
+
# Get the properties of the class
|
422
|
+
|
423
|
+
def properties
|
424
|
+
object = orientdb.get_class_properties self
|
425
|
+
{:properties => object['properties'], :indexes => object['indexes']}
|
426
|
+
end
|
427
|
+
alias get_class_properties properties
|
428
|
+
|
429
|
+
# Print the properties of the class
|
430
|
+
|
431
|
+
def print_properties
|
432
|
+
orientdb.print_class_properties self
|
433
|
+
end
|
434
|
+
|
435
|
+
=begin
|
436
|
+
»GetRecords« uses the REST-Interface to query the database. The alternative »QueryDatabase« submits
|
437
|
+
the query via Execute.
|
438
|
+
|
439
|
+
Both methods rely on OrientSupport::OrientQuery and its capacity to support complex query-builds.
|
440
|
+
The method requires a hash of arguments. The following keys are supported:
|
441
|
+
|
442
|
+
*projection:*
|
443
|
+
|
444
|
+
SQL-Queries use »select« to specify a projection (ie. `select sum(a), b+5 as z from class where ...`)
|
445
|
+
|
446
|
+
In ruby »select« is a method of enumeration. To specify what to »select« from in the query-string
|
447
|
+
we use »projection«, which accepts different arguments
|
448
|
+
|
449
|
+
projection: a_string --> inserts the sting as it appears
|
450
|
+
projection: an OrientSupport::OrientQuery-Object --> performs a sub-query and uses the result for further querying though the given parameters.
|
451
|
+
projection: [a, b, c] --> "a, b, c" (inserts a comma-separated list)
|
452
|
+
projection: {a: b, "sum(x)" => f} --> "a as b, sum(x) as f" (renames properties and uses functions)
|
453
|
+
|
454
|
+
*distinct:*
|
455
|
+
|
456
|
+
Constructs a query like »select distinct(property) [as property] from ...«
|
457
|
+
|
458
|
+
distinct: :property --> the result is mapped to the property »distinct«.
|
459
|
+
distinct: [:property] --> the result replaces the property
|
460
|
+
distinct: {property: :some_name} --> the result is mapped to ModelInstance.some_name
|
461
|
+
|
462
|
+
*order:*
|
463
|
+
|
464
|
+
Sorts the result-set. If new properties were introduced via select:, distinct: etc. Sorting takes place on these properties
|
465
|
+
|
466
|
+
order: :property {property: asc, property: desc}[property, property, .. ](orderdirection is 'asc')
|
467
|
+
|
468
|
+
|
469
|
+
Further supported Parameter:
|
470
|
+
|
471
|
+
group_by
|
472
|
+
skip
|
473
|
+
limit
|
474
|
+
unwind
|
475
|
+
|
476
|
+
see orientdb- documentation (https://orientdb.com/docs/last/SQL-Query.html)
|
477
|
+
|
478
|
+
*query:*
|
479
|
+
|
480
|
+
Instead of providing the parameter to »get_records«, a OrientSupport::OrientQuery can build and
|
481
|
+
tested prior to the method-call. The OrientQuery-Object is then provided with the query-parameter. I.e.
|
482
|
+
|
483
|
+
q = OrientSupport::OrientQuery.new
|
484
|
+
ORD.create_class :test_model
|
485
|
+
q.from TestModel
|
486
|
+
q.where {name: 'Thomas'}
|
487
|
+
count = TestModel.count query: q
|
488
|
+
q.limit 10
|
489
|
+
0.step(count,10) do |x|
|
490
|
+
q.skip = x
|
491
|
+
puts TestModel.get_documents(query: q).map{|x| x.adress }.join('\t')
|
492
|
+
end
|
493
|
+
prints a Table with 10 columns.
|
494
|
+
=end
|
495
|
+
|
496
|
+
def get_records **args
|
497
|
+
db.get_records(from: self, **args){self}
|
498
|
+
end
|
499
|
+
alias get_documents get_records
|
500
|
+
|
501
|
+
|
502
|
+
=begin
|
503
|
+
Performs a query on the Class and returns an Array of ActiveOrient:Model-Records.
|
504
|
+
|
505
|
+
Fall-back method, is overloaded by Vertex.where
|
506
|
+
|
507
|
+
Is aliased by »custom_where»
|
508
|
+
|
509
|
+
Example:
|
510
|
+
Log.where priority: 'high'
|
511
|
+
--> submitted database-request: query/hc_database/sql/select from Log where priority = 'high'/-1
|
512
|
+
=> [ #<Log:0x0000000480f7d8 @metadata={ ... }, ...
|
513
|
+
|
514
|
+
Multiple arguments are joined via "and" eg:
|
515
|
+
Aktie.where symbol: 'TSL, exchange: 'ASX'
|
516
|
+
---> select from aktie where symbol = 'TLS' and exchange = 'ASX'
|
517
|
+
|
518
|
+
=end
|
519
|
+
|
520
|
+
def where *attributes
|
521
|
+
q= OrientSupport::OrientQuery.new where: attributes
|
522
|
+
query_database( q)
|
523
|
+
end
|
524
|
+
|
525
|
+
alias custom_where where
|
526
|
+
=begin
|
527
|
+
QueryDatabase sends the Query directly to the database.
|
528
|
+
|
529
|
+
The query returns a hash if a result set is expected
|
530
|
+
select {something} as {result} (...)
|
531
|
+
leads to
|
532
|
+
[ { :{result} => {result of query} } ]
|
533
|
+
|
534
|
+
It can be modified further by passing a block, ie.
|
535
|
+
|
536
|
+
q = OrientSupport::OrientQuery.new( from: :base )
|
537
|
+
.projection( 'first_list[5].second_list[9] as second_list' )
|
538
|
+
.where( label: 9 )
|
539
|
+
|
540
|
+
q.to_s => 'select first_list[5].second_list[9] as second_list from base where label = 9 '
|
541
|
+
|
542
|
+
second_list = Base.query_database( q ){|x| x[:second_list]}.first
|
543
|
+
|
544
|
+
|
545
|
+
The query returns (a list of) documents of type ActiveOrient::Model if a document is queried i.e.
|
546
|
+
|
547
|
+
q = OrientSupport::OrientQuery.new from: :base
|
548
|
+
q.projection 'expand( first_list[5].second_list[9])' #note: no 'as' statement
|
549
|
+
result2 = Base.query_database( q ).first
|
550
|
+
=> #<SecondList:0x000000000284e840 @metadata={}, @d=nil, @attributes={:zobel=>9, "@class"=>"second_list"}>
|
551
|
+
|
552
|
+
|
553
|
+
|
554
|
+
|
555
|
+
|
556
|
+
query_database is used on model-level and submits
|
557
|
+
select (...) from class
|
558
|
+
|
559
|
+
#query performs queries on the instance-level and submits
|
560
|
+
select (...) from #{a}:{b}
|
561
|
+
|
562
|
+
=end
|
563
|
+
|
564
|
+
def query_database query, set_from: true
|
565
|
+
# note: the parameter is not used anymore
|
566
|
+
query.from self if query.is_a?(OrientSupport::OrientQuery) && query.from.nil?
|
567
|
+
result = db.execute{ query.to_s }
|
568
|
+
result = if block_given?
|
569
|
+
result.is_a?(Array) ? result.map{|x| yield(x) } : yield(result)
|
570
|
+
else
|
571
|
+
result
|
572
|
+
end
|
573
|
+
if result.is_a? Array
|
574
|
+
OrientSupport::Array.new work_on: self, work_with: result
|
575
|
+
else
|
576
|
+
result
|
577
|
+
end # return value
|
578
|
+
end
|
579
|
+
|
580
|
+
########### DELETE ###############
|
581
|
+
|
582
|
+
# Delete a property from the class
|
583
|
+
|
584
|
+
def delete_property field
|
585
|
+
orientdb.delete_property self, field
|
586
|
+
end
|
587
|
+
|
588
|
+
# Delete record(s) specified by their rid's
|
589
|
+
|
590
|
+
def delete_record *rid
|
591
|
+
db.delete_record rid
|
592
|
+
end
|
593
|
+
alias delete_document delete_record
|
594
|
+
|
595
|
+
# Query the database and delete the records of the resultset
|
596
|
+
#
|
597
|
+
# Returns the count of datasets effected
|
598
|
+
def delete_records where: {} , **args
|
599
|
+
if args[:all] == true
|
600
|
+
where = {}
|
601
|
+
else
|
602
|
+
where.merge!(args) if where.is_a?(Hash)
|
603
|
+
return 0 if where.empty?
|
604
|
+
end
|
605
|
+
orientdb.delete_records( self, where: where ).count
|
606
|
+
end
|
607
|
+
alias delete delete_records
|
608
|
+
|
609
|
+
|
610
|
+
|
611
|
+
##################### EXPERIMENT #################
|
612
|
+
|
613
|
+
=begin
|
614
|
+
Suppose that you created a graph where vertexes month is connected with
|
615
|
+
the vertexes day by the edge TIMEOF.
|
616
|
+
Suppose we want to find all the days in the first month and in the third month..
|
617
|
+
|
618
|
+
Usually we can do in the following way.
|
619
|
+
|
620
|
+
ORD.create_class :month
|
621
|
+
(.. put some records into Month ... )
|
622
|
+
firstmonth = Month.first
|
623
|
+
thirdmonth = Month.all[2]
|
624
|
+
days_firstmonth = firstmonth.out_TIMEOF.map{|x| x.in}
|
625
|
+
days_thirdmonth = thirdmonth.out_TIMEOF.map{|x| x.in}
|
626
|
+
|
627
|
+
However we can obtain the same result with the following command
|
628
|
+
|
629
|
+
Month.add_edge_link name: "days", direction: "out", edge: TIME_OF
|
630
|
+
firstmonth = month.first
|
631
|
+
thirdmonth = month.all[2]
|
632
|
+
days_firstmonth = firstmonth.days
|
633
|
+
days_thirdmonth = thirdmonth.days
|
634
|
+
|
635
|
+
To get their value you can do:
|
636
|
+
thirdmonth.days.value
|
637
|
+
=end
|
638
|
+
|
639
|
+
|
640
|
+
def add_edge_link name:, direction: :out, edge:
|
641
|
+
dir = direction.to_s == "out" ? :out : :in
|
642
|
+
define_method(name.to_sym) do
|
643
|
+
return self["#{dir}_#{edge.classname}"].map{|x| x["in"]}
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
=begin
|
648
|
+
See http://orientdb.com/docs/2.1/SQL-Alter-Property.html
|
649
|
+
=end
|
650
|
+
|
651
|
+
def alter_property property, attribute: "DEFAULT", alteration: # :nodoc:
|
652
|
+
orientdb.alter_property self, property: property, attribute: attribute, alteration: alteration
|
653
|
+
end
|
654
|
+
|
655
|
+
|
656
|
+
|
657
|
+
end
|