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.
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
@@ -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