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,80 @@
1
+ module ActiveOrient
2
+ module Init
3
+
4
+ =begin
5
+ Connects to an OrientDB-Server
6
+
7
+ A sample configuration:
8
+
9
+ config_file = File.expand_path('../../config/connect.yml', __FILE__)
10
+ if config_file.present?
11
+ connectyml = YAML.load_file( config_file )[:orientdb]
12
+ else
13
+ puts "config/connect.yml not found or misconfigurated"
14
+ Kernel.exit
15
+ end
16
+
17
+ ActiveOrient::Init.connect database: database,
18
+ server: connectyml[:server],
19
+ port: 2480,
20
+ user: connectyml[:admin][:user],
21
+ password: connectyml[:admin][:pass]
22
+
23
+
24
+ We are setting up Base-classes E and V which is required for a proper initialisation
25
+ and allocate the logger.
26
+
27
+ No other class is loaded.
28
+
29
+ This has to be done in subsequent calls of
30
+ ao = ActiveOrient::OrientDB.new
31
+
32
+
33
+ returns the active OrientDB-Instance
34
+
35
+
36
+ =end
37
+ def self.connect **defaults
38
+ define_namespace namespace: :object
39
+ ActiveOrient::OrientDB.configure_logger defaults[:logger]
40
+ ao = ActiveOrient::OrientDB.new **(defaults.merge( preallocate: false))
41
+ ao.create_class 'E'
42
+ ao.create_class 'V'
43
+ ao # return client instance
44
+ end
45
+ =begin
46
+ Parameters:
47
+ yml: hash from config.yml ,
48
+ namespace: Class to use as Namespace, one of [ :self, :object, :active_orient ]
49
+
50
+
51
+ A custom Constant can be provided via Block
52
+
53
+ i.e.
54
+ configyml = YAML.load_file (...) # with an entry "namespace:"
55
+ ActiveOrient.Init.define_namespace yml: configyml
56
+ #or
57
+ ActiveOrient.Init.define_namespace namespace: :self | :object | :active_orient
58
+ #or
59
+ module IB; end # first declare the Module-Const
60
+ # then assign to the namespace
61
+ ActiveOrient.Init.define_namespace { IB }
62
+
63
+ =end
64
+ def self.define_namespace( yml: {}, namespace: nil )
65
+ n = namespace.presence || yml[:namespace].presence || :object
66
+ ActiveOrient::Model.namespace = if block_given?
67
+ yield
68
+ else
69
+ case n
70
+ when :self
71
+ ActiveOrient::Model
72
+ when :object
73
+ Object
74
+ when :active_orient
75
+ ActiveOrient
76
+ end
77
+ end
78
+ end # define namespace
79
+ end # module Init
80
+ end # module ActiveOrient
@@ -0,0 +1,442 @@
1
+ require 'orientdb'
2
+ require_relative "database_utils.rb" #common methods without rest.specific content
3
+ require_relative "class_utils.rb" #common methods without rest.specific content
4
+ require_relative "orientdb_private.rb"
5
+ =begin
6
+ EXPERIMENTAL CODE
7
+
8
+ accessing the java-api through jruby
9
+ =end
10
+
11
+ module OrientDB
12
+
13
+ class Document
14
+ def update_attributes attributes
15
+ attributes.each do |y,x|
16
+ self[ y ] = x.to_orient
17
+ end
18
+ end
19
+ end # class Document
20
+ end
21
+
22
+ module ActiveOrient
23
+ # class Date
24
+ # def proxy_object
25
+ # java.util.Date.new year, month - 1, day, 0, 0, 0
26
+ # end
27
+ # end
28
+ # class DateTime
29
+ # def proxy_object
30
+ # java.util.Date.new year, month - 1, day, hour, min, sec
31
+ # end
32
+ # end
33
+
34
+ class API
35
+ include OrientSupport::Support
36
+ include DatabaseUtils
37
+ include ClassUtils
38
+ include OrientDbPrivate
39
+ include OrientDB
40
+
41
+ mattr_accessor :logger # borrowed from active_support
42
+ attr_reader :database # Used to read the working database
43
+
44
+ #### INITIALIZATION ####
45
+
46
+
47
+ def initialize database: nil, connect: true, preallocate: true
48
+ self.logger = Logger.new('/dev/stdout') unless logger.present?
49
+ ActiveOrient.database= database if database.present?
50
+ connect() if connect
51
+ ActiveOrient::Model.db = self
52
+ preallocate_classes if preallocate
53
+
54
+ end
55
+
56
+ def db
57
+ @db
58
+ end
59
+
60
+ # Used for the connection on the server
61
+ #
62
+
63
+ # Used to connect to the database
64
+
65
+ def connect
66
+ begin
67
+ logger.progname = 'JavaApi#connect'
68
+ @db = DocumentDatabase.connect("remote:#{ActiveOrient.default_server[:server]}/#{ActiveOrient.database}",
69
+ ActiveOrient.default_server[:user], ActiveOrient.default_server[:password] )
70
+ rescue Java::ComOrientechnologiesOrientCoreException::OConfigurationException => e
71
+ logger.fatal{ e.message}
72
+ logger.fatal{ "ServerAdim not implemented in ActiveOrient#JavaApi "}
73
+ # OrientDB::ServerAdmin("remote:localhost").connect( default_server[:user], default_server[:password] )
74
+ # OrientDB::ServerAdmin.createDatabase(@database, "document", "remote");
75
+ # OrientDB::ServerAdmin.close();
76
+ Kernel.exit
77
+ end
78
+ database_classes( requery:true ) # returns all allocated database_classes
79
+ end
80
+
81
+
82
+
83
+ def get_classes *attributes
84
+ classes= @db.metadata.schema.classes.map{|x| { 'name' => x.name , 'superClass' => x.get_super_class.nil? ? '': x.get_super_class.name } }
85
+ unless attributes.empty?
86
+ classes.map{|y| y.select{|v,_| attributes.include?(v)}}
87
+ else
88
+ classes
89
+ end
90
+
91
+ end
92
+
93
+
94
+ def create_classes classes , &b
95
+ consts = allocate_classes_in_ruby( classes , &b )
96
+
97
+ all_classes = consts.is_a?( Array) ? consts.flatten : [consts]
98
+ database_classes(requery: true)
99
+ selected_classes = all_classes.map do | this_class |
100
+ this_class unless database_classes(requery: true).include?( this_class.ref_name ) rescue nil
101
+ end.compact.uniq
102
+ command= selected_classes.map do | database_class |
103
+ ## improper initialized ActiveOrient::Model-classes lack a ref_name class-variable
104
+ next if database_class.ref_name.blank?
105
+ c = if database_class.superclass == ActiveOrient::Model || database_class.superclass.ref_name.blank?
106
+ puts "CREATE CLASS #{database_class.ref_name} "
107
+ OClassImpl.create @db, database_class.ref_name
108
+ else
109
+ puts "CREATE CLASS #{database_class.ref_name} EXTENDS #{database_class.superclass.ref_name}"
110
+ OClassImpl.create @db, database_class.ref_name, superClass: database_class.superclass.ref_name
111
+ end
112
+ end
113
+
114
+ # update the internal class hierarchy
115
+ database_classes requery: true
116
+ # return all allocated classes, no matter whether they had to be created in the DB or not.
117
+ # keep the format of the input-parameter
118
+ consts.shift if block_given? && consts.is_a?( Array) # remove the first element
119
+ # remove traces of superclass-allocations
120
+ if classes.is_a? Hash
121
+ consts = Hash[ consts ]
122
+ consts.each_key{ |x| consts[x].delete_if{|y| y == x} if consts[x].is_a? Array }
123
+ end
124
+ consts
125
+ end
126
+
127
+
128
+
129
+ def delete_class o_class
130
+ begin
131
+ logger.progname = 'JavaApi#DeleteClass'
132
+ @db.schema.drop_class classname(o_class)
133
+ rescue Java::ComOrientechnologiesOrientCoreException::OSchemaException => e
134
+ logger.error{ e.message }
135
+ end
136
+ database_classes requery: true
137
+ end
138
+ =begin
139
+ Creates properties and optional an associated index as defined in the provided block
140
+ create_properties(classname or class, properties as hash){index}
141
+
142
+ The default-case
143
+ create_properties(:my_high_sophisticated_database_class,
144
+ con_id: {type: :integer},
145
+ details: {type: :link, linked_class: 'Contracts'}) do
146
+ contract_idx: :notunique
147
+ end
148
+
149
+ A composite index
150
+ create_properties(:my_high_sophisticated_database_class,
151
+ con_id: {type: :integer},
152
+ symbol: {type: :string}) do
153
+ {name: 'indexname',
154
+ on: [:con_id, :details] # default: all specified properties
155
+ type: :notunique # default: :unique
156
+ }
157
+ end
158
+ supported types:
159
+ {
160
+ :bool => "BOOLEAN",
161
+ :double => "BYTE",
162
+ :datetime => "DATE",
163
+ :float => "FLOAT",
164
+ :decimal => "DECIMAL",
165
+ :embedded_list => "EMBEDDEDLIST",
166
+ :list => "EMBEDDEDLIST",
167
+ :embedded_map => "EMBEDDEDMAP",
168
+ :map => "EMBEDDEDMAP",
169
+ :embedded_set => "EMBEDDEDSET",
170
+ :set => "EMBEDDEDSET",
171
+ :int => "INTEGER",
172
+ :integer => "INTEGER",
173
+ :link_list => "LINKLIST",
174
+ :link_map => "LINKMAP",
175
+ :link_set => "LINKSET",
176
+ }
177
+
178
+ =end
179
+ def create_properties o_class, **all_properties, &b
180
+ logger.progname = 'JavaApi#CreateProperties'
181
+ ap = all_properties
182
+ index = ap.is_a?(Hash) ? ap[:index] : nil
183
+ created_properties = ap.map do |property, specification |
184
+ field_type = ( specification.is_a?( Hash) ? specification[:type] : specification ).downcase.to_sym rescue :string
185
+ if specification.is_a?(Hash)
186
+ the_other_class = specification[:other_class].presence || specification[:linked_class]
187
+ other_class = @db.get_class( the_other_class.to_sym ) if the_other_class.present?
188
+ if other_class.present?
189
+ @db.get_class(classname(o_class)).add property,[ field_type, other_class ], { :index => index }
190
+ else
191
+ @db.get_class(classname(o_class)).add property, field_type, { :index => index }
192
+ end
193
+ end
194
+ end
195
+ if block_given?
196
+ attr = yield
197
+ index_parameters = case attr
198
+ when String, Symbol
199
+ { name: attr }
200
+ when Hash
201
+ { name: attr.keys.first , type: attr.values.first, on: all_properties.keys.map(&:to_s) }
202
+ else
203
+ nil
204
+ end
205
+ create_index o_class, **index_parameters unless index_parameters.blank?
206
+ end
207
+ created_properties.size # return_value
208
+
209
+ end
210
+
211
+ def get_properties o_class
212
+ @db.get_class(classname(o_class)).propertiesMap
213
+ end
214
+
215
+
216
+
217
+ def create_index o_class, name:, on: :automatic, type: :unique
218
+ logger.progname = 'JavaApi#CreateIndex'
219
+ begin
220
+ c = @db.get_class( classname( o_class ))
221
+ index = if on == :automatic
222
+ nil # not implemented
223
+ elsif on.is_a? Array
224
+ c.createIndex name.to_s, INDEX_TYPES[type], *on
225
+ else
226
+ c.createIndex name.to_s, INDEX_TYPES[type], on
227
+ end
228
+ end
229
+ end
230
+ def create_record o_class, attributes: {}
231
+ logger.progname = 'JavaApi#CreateRecord'
232
+ attributes = yield if attributes.empty? && block_given?
233
+ new_record = insert_document( classname(o_class), attributes.to_orient )
234
+
235
+
236
+ end
237
+ alias create_document create_record
238
+
239
+ def upsert o_class, set: {}, where: {}
240
+ logger.progname = 'JavaApi#Upsert'
241
+ if where.blank?
242
+ new_record = create_record(o_class, attributes: set)
243
+ yield new_record if block_given? # in case if insert execute optional block
244
+ new_record # return_value
245
+ else
246
+ specify_return_value = block_given? ? "" : "return after @this"
247
+ set.merge! where if where.is_a?( Hash ) # copy where attributes to set
248
+ command = "Update #{classname(o_class)} set #{generate_sql_list( set ){','}} upsert #{specify_return_value} #{compose_where where}"
249
+ result = @db.run_command command
250
+
251
+ case result
252
+ when Java::JavaUtil::ArrayList
253
+ update_document result[0]
254
+ when ActiveOrient::Model
255
+ result # just return the result
256
+ when String, Numeric
257
+ the_record= get_records(from: o_class, where: where, limit: 1).pop
258
+ if result.to_i == 1 # one dataset inserted, block is specified
259
+ yield the_record
260
+ end
261
+ the_record # return_value
262
+ else
263
+ logger.error{ "Unexpected result form Query \n #{command} \n Result: #{result}" }
264
+ end
265
+ end
266
+ end
267
+ def get_records raw: false, query: nil, **args
268
+ query = OrientSupport::OrientQuery.new(args) if query.nil?
269
+ logger.progname = 'JavaApi#GetRecords'
270
+ result = @db.custom query.compose
271
+ result.map do |record|
272
+ update_document record
273
+ end
274
+ end
275
+ alias get_documents get_records
276
+
277
+ # called by Model.autoload
278
+ def get_record rid
279
+ logger.progname = 'JavaApi#GetRecord'
280
+ rid = "#"+ rid unless rid[0]=='#'
281
+ record = @db.custom "select from #{rid}"
282
+ if record.count.zero?
283
+ logger.error{ "No record found for rid= #{rid}" }
284
+ else
285
+ yield( record[0] ) if block_given?
286
+ update_document record[0]
287
+ end
288
+ end
289
+ alias get_document get_record
290
+
291
+ =begin
292
+ executes a command as sql-query
293
+
294
+
295
+ =end
296
+ def execute transaction: true, tolerated_error_code: nil , process_error: true# Set up for classes
297
+ batch = {transaction: transaction, operations: yield}
298
+
299
+ logger.progname= "Execute"
300
+ unless batch[:operations].blank?
301
+ unless batch[:operations].is_a? Array
302
+ batch[:operations] = [batch[:operations]]
303
+ was_array = true
304
+ else
305
+ was_array = false
306
+ end
307
+ answer = batch[:operations].map do |command_record|
308
+ return if command_record.blank?
309
+ begin
310
+ response = @db.run_command command_record.is_a?(Hash) ? command_record[:command] : command_record
311
+ rescue Java::ComOrientechnologiesOrientCoreStorage::ORecordDuplicatedException => e
312
+ # puts e.inspect
313
+ # puts "GetMESSAGE: "+e.getMessage.split(/\r/).first
314
+ # puts "GetComponentName: "+e.getComponentName.to_s
315
+ # puts e.getMessage =~ tolerated_error_code
316
+ # puts "----"
317
+ if tolerated_error_code.present? && e.getMessage =~ tolerated_error_code
318
+ logger.info{ "tolerated_error::#{ e.get_message.split(/\r/).first }"}
319
+ next
320
+ else
321
+ # if process_error
322
+ logger.progname = 'JavaApi#Execute'
323
+ logger.error{ e }
324
+ # else
325
+ # puts e.inspect
326
+ # raise ArgumentError, e, caller
327
+ end
328
+ end
329
+ if response.is_a? Fixnum
330
+ response
331
+ else
332
+ response.map do | r |
333
+ if r.is_a? Document
334
+ if r.rid.rid?
335
+ update_document r
336
+ else
337
+ ActiveOrient::Model.orientdb_class( name: 'query').new r
338
+ end
339
+ else
340
+ puts "Strange things happen in execute: #{r.inspect}"
341
+ r.values
342
+ end
343
+ end # map response
344
+ end # branch response_is_a
345
+ end # map batch
346
+ answer.pop if answer.size==1 && answer.first.is_a?(Array)
347
+ end # unless
348
+ end
349
+
350
+
351
+ def delete_record *object_or_rid
352
+ object_or_rid.map do |o|
353
+ d= case o
354
+ when String
355
+ @db.custom "select from #{o}" if o.rid?
356
+ when ActiveOrient::Model
357
+ @db.custom "select from #{o.to_orient}"
358
+ when Array
359
+ o.map{|y| delete_record y }
360
+ return o
361
+ else
362
+ o
363
+ end
364
+ if d.is_a? Java::ComOrientechnologiesOrientCoreSqlQuery::OConcurrentResultSet
365
+ d.each &:delete
366
+ else
367
+ logger.progname = 'JavaApi#DeleteRecord'
368
+ logger.error{ "Removal Failed: #{d.inspect} " }
369
+ end
370
+ end
371
+ end
372
+
373
+ =begin
374
+ Transfer changes in attributes to document first and save the document
375
+ No SQL involved
376
+ =end
377
+
378
+ def update rid, attributes=nil, version=nil
379
+ record = ActiveOrient::Model.autoload_object rid.rid
380
+ record.document.update_attributes attributes if attributes.present?
381
+ record.document.save
382
+ record.attributes.merge! attributes if attributes.present?
383
+ record # return_value
384
+ end
385
+
386
+ # old code
387
+ # get_record( rid.rid ) do | db_obj |
388
+ # db_obj.update_attributes attributes
389
+ ## puts db_obj.inspect
390
+ # db_obj.save
391
+ # end if rid.rid.present?
392
+ # end
393
+
394
+
395
+
396
+ #private
397
+
398
+ def insert_document o_class, attributes
399
+ logger.progname = 'JavaApi#InsertDocument'
400
+ d = Document.new classname(o_class)
401
+ d.update_attributes attributes
402
+ d.save
403
+ ActiveOrient::Model.get_model_class(o_class).new d
404
+ rescue Java::ComOrientechnologiesOrientCoreException::ODatabaseException => e
405
+ logger.fatal{ "Insert failed => #{d.inspect}"}
406
+ logger.error{ "Parameter: Class: #{classname(o_class)} attributes: #{attributes.inspect}" }
407
+ logger.fatal{ e }
408
+ rescue Java::ComOrientechnologiesOrientCoreException::OSchemaException => e
409
+ logger.error{ e }
410
+
411
+ logger.error{ "Parameter: DB: #{@db.name}, Class: #{classname(o_class)} attributes: #{attributes.inspect}" }
412
+ logger.error{ database_classes.inspect }
413
+ end
414
+ # returns a valid model-instance
415
+ def update_document java_document
416
+ if java_document.is_a? Document
417
+ o_class = java_document.class_name
418
+ java_document.save
419
+ d = java_document
420
+ ActiveOrient::Model.get_model_class(o_class).new java_document
421
+ else
422
+ logger.progname = 'JavaApi#UpdateDocument'
423
+ logger.error{ "Wrong Parameter: #{java_document.inspect} "}
424
+ end
425
+ end #def
426
+
427
+
428
+ def manipulate_relation record, method, array, items
429
+ java_document = record.document
430
+ method = method.to_s.downcase.to_sym
431
+ case method
432
+ when :add
433
+ items.each{|x| java_document[array] << x}
434
+ when :remove
435
+ items.each{|x| java_document[array].delete x}
436
+ else
437
+
438
+ end
439
+ java_document.save
440
+ end
441
+ end
442
+ end