active-orient 0.4 → 0.80

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.graphs.txt.swp +0 -0
  4. data/Gemfile +9 -5
  5. data/Guardfile +12 -4
  6. data/README.md +70 -281
  7. data/VERSION +1 -1
  8. data/active-orient.gemspec +9 -7
  9. data/bin/active-orient-0.6.gem +0 -0
  10. data/bin/active-orient-console +97 -0
  11. data/changelog.md +60 -0
  12. data/config/boot.rb +70 -17
  13. data/config/config.yml +10 -0
  14. data/config/connect.yml +11 -6
  15. data/examples/books.rb +154 -65
  16. data/examples/streets.rb +89 -85
  17. data/graphs.txt +70 -0
  18. data/lib/active-orient.rb +78 -6
  19. data/lib/base.rb +266 -168
  20. data/lib/base_properties.rb +76 -65
  21. data/lib/class_utils.rb +187 -0
  22. data/lib/database_utils.rb +99 -0
  23. data/lib/init.rb +80 -0
  24. data/lib/java-api.rb +442 -0
  25. data/lib/jdbc.rb +211 -0
  26. data/lib/model/custom.rb +29 -0
  27. data/lib/model/e.rb +6 -0
  28. data/lib/model/edge.rb +114 -0
  29. data/lib/model/model.rb +134 -0
  30. data/lib/model/the_class.rb +657 -0
  31. data/lib/model/the_record.rb +313 -0
  32. data/lib/model/vertex.rb +371 -0
  33. data/lib/orientdb_private.rb +48 -0
  34. data/lib/other.rb +423 -0
  35. data/lib/railtie.rb +68 -0
  36. data/lib/rest/change.rb +150 -0
  37. data/lib/rest/create.rb +287 -0
  38. data/lib/rest/delete.rb +150 -0
  39. data/lib/rest/operations.rb +222 -0
  40. data/lib/rest/read.rb +189 -0
  41. data/lib/rest/rest.rb +120 -0
  42. data/lib/rest_disabled.rb +24 -0
  43. data/lib/support/conversions.rb +42 -0
  44. data/lib/support/default_formatter.rb +7 -0
  45. data/lib/support/errors.rb +41 -0
  46. data/lib/support/logging.rb +38 -0
  47. data/lib/support/orient.rb +305 -0
  48. data/lib/support/orientquery.rb +647 -0
  49. data/lib/support/query.rb +92 -0
  50. data/rails.md +154 -0
  51. data/rails/activeorient.rb +32 -0
  52. data/rails/config.yml +10 -0
  53. data/rails/connect.yml +17 -0
  54. metadata +89 -30
  55. data/lib/model.rb +0 -461
  56. data/lib/orient.rb +0 -98
  57. data/lib/query.rb +0 -88
  58. data/lib/rest.rb +0 -1036
  59. data/lib/support.rb +0 -347
  60. data/test.rb +0 -4
  61. data/usecase.md +0 -91
@@ -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