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,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