active-orient 0.6 → 0.42

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/Gemfile +4 -10
  4. data/Guardfile +4 -12
  5. data/README.md +198 -261
  6. data/VERSION +1 -1
  7. data/active-orient-0.4.gem +0 -0
  8. data/active-orient-0.41.gem +0 -0
  9. data/active-orient.gemspec +5 -6
  10. data/config/boot.rb +0 -84
  11. data/config/connect.yml +4 -8
  12. data/examples/books.rb +39 -86
  13. data/examples/streets.rb +84 -85
  14. data/lib/active-orient.rb +9 -57
  15. data/lib/base.rb +145 -172
  16. data/lib/base_properties.rb +44 -40
  17. data/lib/model.rb +468 -0
  18. data/lib/orient.rb +60 -114
  19. data/lib/query.rb +73 -71
  20. data/lib/rest.rb +1059 -0
  21. data/lib/support.rb +319 -386
  22. data/test.rb +4 -0
  23. data/usecase.md +91 -0
  24. metadata +20 -65
  25. data/bin/active-orient-console +0 -38
  26. data/config/config.yml +0 -10
  27. data/create_project +0 -19
  28. data/examples/test_commands.rb +0 -92
  29. data/examples/test_commands_2.rb +0 -54
  30. data/examples/test_commands_3.rb +0 -48
  31. data/examples/test_commands_4.rb +0 -28
  32. data/examples/time_graph.md +0 -162
  33. data/gratefuldeadconcerts.md +0 -94
  34. data/lib/class_utils.rb +0 -300
  35. data/lib/database_utils.rb +0 -106
  36. data/lib/init.rb +0 -45
  37. data/lib/java-api.rb +0 -437
  38. data/lib/jdbc.rb +0 -211
  39. data/lib/model/edge.rb +0 -55
  40. data/lib/model/model.rb +0 -91
  41. data/lib/model/the_class.rb +0 -500
  42. data/lib/model/the_record.rb +0 -322
  43. data/lib/model/vertex.rb +0 -136
  44. data/lib/orientdb_private.rb +0 -48
  45. data/lib/other.rb +0 -330
  46. data/lib/rest/change.rb +0 -137
  47. data/lib/rest/create.rb +0 -488
  48. data/lib/rest/delete.rb +0 -134
  49. data/lib/rest/operations.rb +0 -160
  50. data/lib/rest/read.rb +0 -150
  51. data/lib/rest/rest.rb +0 -112
  52. data/lib/rest_disabled.rb +0 -24
  53. data/linkmap.md +0 -75
  54. data/namespace.md +0 -111
  55. data/old_lib_functions/two_general_class.rb +0 -139
  56. data/rails.md +0 -125
  57. data/rails/activeorient.rb +0 -53
  58. data/rails/config.yml +0 -10
  59. data/rails/connect.yml +0 -17
  60. data/usecase_oo.md +0 -61
@@ -1,211 +0,0 @@
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
-
6
-
7
- module ActiveOrient
8
-
9
-
10
- class API
11
- include OrientSupport::Support
12
- include DatabaseUtils
13
- include ClassUtils
14
- include OrientDbPrivate
15
- include OrientDB
16
-
17
- mattr_accessor :logger # borrowed from active_support
18
- mattr_accessor :default_server
19
- attr_reader :database # Used to read the working database
20
-
21
- #### INITIALIZATION ####
22
-
23
-
24
- def initialize database: nil, connect: true, preallocate: true
25
- self.logger = Logger.new('/dev/stdout') unless logger.present?
26
- self.default_server = {
27
- :server => 'localhost',
28
- :port => 2480,
29
- :protocol => 'http',
30
- :user => 'root',
31
- :password => 'root',
32
- :database => 'temp'
33
- }.merge default_server.presence || {}
34
- @database = database || default_server[:database]
35
- @all_classes=[]
36
- #puts ["remote:#{default_server[:server]}/#{@database}",
37
- # default_server[:user], default_server[:password] ]
38
- connect() if connect
39
- # @db = DocumentDatabase.connect("remote:#{default_server[:server]}/#{@database}",
40
- # default_server[:user], default_server[:password] )
41
- ActiveOrient::Model.api = self
42
- preallocate_classes if preallocate
43
-
44
- end
45
-
46
- def db
47
- @db
48
- end
49
-
50
- # Used for the connection on the server
51
- #
52
-
53
- # Used to connect to the database
54
-
55
- def connect
56
-
57
- @db = DocumentDatabase.connect("remote:#{default_server[:server]}/#{@database}",
58
- default_server[:user], default_server[:password] )
59
- @classes = get_database_classes
60
- end
61
-
62
-
63
-
64
- def get_classes *attributes
65
- classes= @db.metadata.schema.classes.map{|x| { 'name' => x.name , 'superClass' => x.get_super_class.nil? ? '': x.get_super_class.name } }
66
- unless attributes.empty?
67
- classes.map{|y| y.select{|v,_| attributes.include?(v)}}
68
- else
69
- classes
70
- end
71
-
72
- end
73
-
74
-
75
- def create_classes classes , &b
76
- consts = allocate_classes_in_ruby( classes , &b )
77
-
78
- all_classes = consts.is_a?( Array) ? consts.flatten : [consts]
79
- get_database_classes(requery: true)
80
- selected_classes = all_classes.map do | this_class |
81
- this_class unless get_database_classes(requery: false).include?( this_class.ref_name ) rescue nil
82
- end.compact.uniq
83
- command= selected_classes.map do | database_class |
84
- ## improper initialized ActiveOrient::Model-classes lack a ref_name class-variable
85
- next if database_class.ref_name.blank?
86
- c = if database_class.superclass == ActiveOrient::Model || database_class.superclass.ref_name.blank?
87
- puts "CREATE CLASS #{database_class.ref_name} "
88
- OClassImpl.create @db, database_class.ref_name
89
- else
90
- puts "CREATE CLASS #{database_class.ref_name} EXTENDS #{database_class.superclass.ref_name}"
91
- OClassImpl.create @db, superClass: database_class.ref_name
92
- end
93
- end
94
-
95
- # update the internal class hierarchy
96
- get_database_classes requery: true
97
- # return all allocated classes, no matter whether they had to be created in the DB or not.
98
- # keep the format of the input-parameter
99
- consts.shift if block_given? && consts.is_a?( Array) # remove the first element
100
- # remove traces of superclass-allocations
101
- if classes.is_a? Hash
102
- consts = Hash[ consts ]
103
- consts.each_key{ |x| consts[x].delete_if{|y| y == x} if consts[x].is_a? Array }
104
- end
105
- consts
106
- end
107
-
108
-
109
-
110
- def delete_class o_class
111
- @db.schema.drop_class classname(o_class)
112
- get_database_classes requery: true
113
- end
114
- =begin
115
- Creates properties and optional an associated index as defined in the provided block
116
- create_properties(classname or class, properties as hash){index}
117
-
118
- The default-case
119
- create_properties(:my_high_sophisticated_database_class,
120
- con_id: {type: :integer},
121
- details: {type: :link, linked_class: 'Contracts'}) do
122
- contract_idx: :notunique
123
- end
124
-
125
- A composite index
126
- create_properties(:my_high_sophisticated_database_class,
127
- con_id: {type: :integer},
128
- symbol: {type: :string}) do
129
- {name: 'indexname',
130
- on: [:con_id, :details] # default: all specified properties
131
- type: :notunique # default: :unique
132
- }
133
- end
134
- =end
135
-
136
- def create_properties o_class, **all_properties, &b
137
- logger.progname = 'JavaApi#CreateProperties'
138
- ap = all_properties
139
- created_properties = ap.map do |property, specification |
140
- puts "specification: #{specification.inspect}"
141
- field_type = ( specification.is_a?( Hash) ? specification[:type] : specification ).downcase.to_sym rescue :string
142
- the_other_class = specification.is_a?(Hash) ? specification[:other_class] : nil
143
- other_class = if the_other_class.present?
144
- @db.get_class( the_other_class)
145
- end
146
- index = ap.is_a?(Hash) ? ap[:index] : nil
147
- if other_class.present?
148
- @db.get_class(classname(o_class)).add property,[ field_type, other_class ], { :index => index }
149
- else
150
- @db.get_class(classname(o_class)).add property, field_type, { :index => index }
151
- end
152
- end
153
- if block_given?
154
- attr = yield
155
- index_parameters = case attr
156
- when String, Symbol
157
- { name: attr }
158
- when Hash
159
- { name: attr.keys.first , type: attr.values.first, on: all_properties.keys.map(&:to_s) }
160
- else
161
- nil
162
- end
163
- create_index o_class, **index_parameters unless index_parameters.blank?
164
- end
165
- created_properties.size # return_value
166
-
167
- end
168
-
169
- def get_properties o_class
170
- @db.get_class(classname(o_class)).propertiesMap
171
- end
172
-
173
-
174
-
175
- def create_index o_class, name:, on: :automatic, type: :unique
176
- logger.progname = 'JavaApi#CreateIndex'
177
- begin
178
- c = @db.get_class( classname( o_class ))
179
- index = if on == :automatic
180
- nil # not implemented
181
- elsif on.is_a? Array
182
- c.createIndex name.to_s, INDEX_TYPES[type], *on
183
- else
184
- c.createIndex name.to_s, INDEX_TYPES[type], on
185
- end
186
- end
187
- end
188
-
189
- def create_record o_class, attributes: {}
190
- logger.progname = 'HavaApi#CreateRecord'
191
- attributes = yield if attributes.empty? && block_given?
192
- new_record = insert_document( o_class, attributes.to_orient )
193
-
194
-
195
- end
196
- alias create_document create_record
197
-
198
- def insert_document o_class, attributes
199
- d = Document.create @db, classname(o_class), **attributes
200
- d.save
201
- ActiveOrient::Model.get_model_class(classname(o_class)).new attributes.merge( { "@rid" => d.rid,
202
- "@version" => d.version,
203
- "@type" => 'd',
204
- "@class" => classname(o_class) } )
205
-
206
-
207
-
208
- end
209
- end
210
- end
211
-
@@ -1,55 +0,0 @@
1
- # to do
2
- # instead of creating a class, use a module which is included on startup
3
- # then, after specifying the namespace and before autoaccolating the database-classes create the proper E-Base-class and include this stuff
4
- class E < ActiveOrient::Model
5
- ## link to the library-class
6
- class << self
7
- =begin
8
- establish contrains on Edges
9
-
10
- Edges are uniq!
11
-
12
- Creates individual indices for child-classes if applied to the class itself.
13
- =end
14
- def uniq_index
15
- create_property :in, type: :link, linked_class: :V
16
- create_property :out, type: :link, linked_class: :V
17
- create_index "#{ref_name}_idx", on: [ :in, :out ]
18
- end
19
- =begin
20
- Instantiate a new Edge between two Vertices
21
-
22
- The parameters »from« **or** »to« can take a list of model-records. Then subsequent edges are created.
23
-
24
- :call-seq:
25
- Model.create from:, to:, attributes:{}
26
- =end
27
-
28
-
29
- def create **keyword_arguments
30
- new_edge = db.create_edge self, **keyword_arguments
31
- new_edge = new_edge.pop if new_edge.is_a?( Array) && new_edge.size == 1
32
- # to.reload! if to.is_a? ActiveOrient::Model
33
- # from.reload! if from.is_a? ActiveOrient::Model
34
- # vertices must be reloaded
35
-
36
- new_edge # returns the created edge (or an array of created edges
37
- end
38
-
39
- =begin
40
- Edge#delete fires a "delete edge" command to the database.
41
- The where statement can be empty ( "" or {}"), then all edges are removed
42
-
43
- The rid-cache is reseted, too
44
- =end
45
- def delete where:
46
- db.execute { "delete edge #{ref_name} #{db.compose_where(where)}" }
47
- reset_rid_store
48
- end
49
-
50
- # remove works on record-level
51
- end
52
- def remove
53
- db.delete_edge self
54
- end
55
- end
@@ -1,91 +0,0 @@
1
- require_relative "the_class.rb"
2
- require_relative "the_record.rb"
3
-
4
- module ActiveOrient
5
- class Model < ActiveOrient::Base
6
-
7
- include BaseProperties
8
- include ModelRecord # For objects (file: lib/record.rb)
9
- extend ModelClass # For classes
10
-
11
- =begin
12
- Example:
13
- ActiveOrient::Model.autoload_object "#00:00"
14
-
15
- either retrieves the object from the rid_store or loads it from the DB.
16
-
17
- The rid_store is updated!
18
-
19
- To_do: fetch for version in the db and load the object if a change is detected
20
-
21
- Note: This function is not in ModelClass since it needs to use @@rid_store
22
- =end
23
-
24
- def self.autoload_object rid
25
- rid = rid[1..-1] if rid[0]=='#'
26
- if rid.rid?
27
- if @@rid_store[rid].present?
28
- @@rid_store[rid] # return_value
29
- else
30
- db.get_record(rid)
31
- end
32
- else
33
- logger.progname = "ActiveOrient::Model#AutoloadObject"
34
- logger.info{"#{rid} is not a valid rid."}
35
- end
36
- end
37
-
38
- ## to prevent errors when calling to_a
39
- def to_ary # :nodoc:
40
- attributes.to_a
41
- end
42
-
43
- def document # :nodoc:
44
- @d
45
- end
46
-
47
- =begin
48
- Deletes the database class and removes the ruby-class
49
- =end
50
- def self.delete_class what= :all
51
- orientdb.delete_class( self ) if what == :all # remove the database-class
52
- ## namespace is defined in config/boot
53
- ns = namespace.to_s == 'Object' ? "" : namespace.to_s
54
- ns_found = -> ( a_class ) do
55
- to_compare = a_class.to_s.split(':')
56
- if ns == "" && to_compare.size == 1
57
- true
58
- elsif to_compare.first == ns
59
- true
60
- else
61
- false
62
- end
63
- end
64
- self.allocated_classes.delete_if{|x,y| x == self.ref_name && ns_found[y]} if allocated_classes.is_a?(Hash)
65
- namespace.send(:remove_const, naming_convention.to_sym) if namespace.send( :const_defined?, naming_convention)
66
- end
67
-
68
- # provides an unique accessor on the Class
69
- # works with a class-variable, its unique through all Subclasses
70
- mattr_accessor :orientdb # points to the instance of the REST-DB-Client used for Administration
71
- # i.e. creation and deleting of classes and databases
72
- mattr_accessor :db # points to the instance of the Client used for Database-Queries
73
- mattr_accessor :api
74
- # mattr_accessor :logger ... already inherented from ::Base
75
- mattr_accessor :namespace # Namespace in which Model records are initialized, a constant ( defined in config.yml )
76
- mattr_accessor :model_dir # path to model-files
77
- mattr_accessor :keep_models_without_file
78
- mattr_accessor :allocated_classes
79
-
80
- # mattr_accessor :ref_name
81
- # Used to read the metadata
82
- attr_reader :metadata
83
-
84
- # provides an accessor at class level
85
- # its unique on all instances
86
- class << self
87
- attr_accessor :ref_name
88
- attr_accessor :abstract
89
- end
90
- end
91
- end
@@ -1,500 +0,0 @@
1
- module ModelClass
2
-
3
- ########### CLASS FUNCTIONS ######### SELF ####
4
-
5
-
6
- ######## INITIALIZE A RECORD FROM A CLASS ########
7
-
8
-
9
- =begin
10
- NamingConvention provides a translation from database-names to class-names.
11
-
12
- Should provide
13
- to_s.capitalize_first_letter
14
- as minimum.
15
- Can be overwritten to provide different conventions for different classes, eg. Vertexes or edges.
16
-
17
- To overwrite use
18
- class Model < ActiveOrient::Model[:: ...]
19
- def self.naming_convention
20
- ( conversion code )
21
- end
22
- end
23
- =end
24
- def naming_convention name=nil # :nodoc:
25
- name.present? ? name.to_s.camelize : ref_name.camelize
26
- end
27
-
28
- =begin
29
- orientdb_class is used to create or refer a ActiveOrient:Model:{class} by providing its name
30
-
31
- Parameter: name: string or symbol
32
- Parameter: superclass: If class, then this is used unmodified
33
- If string or symbol, its used to reference an existing class
34
- if :find_ME, its derived from the classes-hash
35
- Attention: If a class is created by orientdb_class, its only allocated in ruby-space.
36
- The class is thus not present in the classes-array, which reflects the database-classes.
37
- If a class depending on a superclass is to be created, the superclass is derived from
38
- the classes-array. In such a case, the allocation only works, if the class itself is
39
- used as parameter "superclass"
40
- i.e.
41
- ActiveOrient::Model.orientdb_class name: 'hurra'
42
- AvtiveOrient::Model.orientdb_class name: 'hip_hip' , superclass: Hurra
43
- =end
44
-
45
- def orientdb_class name:, superclass: nil # :nodoc: # public method: autoload_class
46
- logger.progname = "ModelClass#OrientDBClass"
47
- # @s-class is a cash for actual String -> Class relations
48
- self.allocated_classes = HashWithIndifferentAccess.new( V: V, E: E) unless allocated_classes.present?
49
-
50
- #update_my_array = ->(s) { self.allocated_classes[s.ref_name] = s unless allocated_classes[s.ref_name].present? }
51
- update_my_array = ->(s) do
52
- if allocated_classes[s.ref_name].present?
53
- # puts "found ref_name: #{allocated_classes[s.ref_name]}"
54
- else
55
- self.allocated_classes[s.ref_name] = s
56
- end
57
-
58
- end
59
- get_class = ->(n) { allocated_classes[n] }
60
- extract_namespace = -> (n) do
61
- if get_class[n].present?
62
- separated_class_parts = get_class[n].to_s.split(':')
63
- separated_class_parts.size >1 ? separated_class_parts.first.constantize : namespace
64
- else
65
- namespace
66
- end
67
- end
68
-
69
-
70
- ref_name = name.to_s
71
- klass = if superclass.present? # superclass is parameter, use if class, otherwise transfer to class
72
- s= if superclass.is_a? Class
73
- extract_namespace[name].send( :const_get, superclass.to_s )
74
- else
75
- superclass = orientdb.get_db_superclass( ref_name ) if superclass == :find_ME
76
- if superclass.present?
77
- extract_namespace[name].send( :const_get, get_class[superclass].to_s )
78
- else
79
- self
80
- end
81
- end
82
- Class.new(s)
83
- else
84
- Class.new(self)
85
- end
86
- # namespace is defined in config/boot
87
- this_namespace = extract_namespace[ref_name]
88
- name = klass.naming_convention ref_name #
89
- if this_namespace.send :const_defined?, name
90
- retrieved_class = this_namespace.send :const_get, name
91
- else
92
-
93
- new_class = this_namespace.send :const_set, name, klass
94
- new_class.ref_name = ref_name
95
- update_my_array[new_class]
96
- # logger.debug{"created:: Class #{new_class} < #{new_class.superclass} "}
97
- # logger.debug{"database-table:: #{ref_name} "}
98
- new_class # return_value
99
- end
100
- rescue NameError => e
101
- logger.error "ModelClass #{name.inspect} cannot be initialized."
102
- logger.error e.message
103
- logger.error e.backtrace.map {|l| " #{l}\n"}.join
104
- nil # return_value
105
- #end
106
- end
107
- =begin
108
- Retrieves the preallocated class derived from ActiveOrient::Model
109
-
110
- Only classes noted in the @classes-Array of orientdb are fetched.
111
- =end
112
- def get_model_class name
113
- if orientdb.database_classes.include?(name)
114
- orientdb_class name: name, superclass: :find_ME
115
- else
116
- nil
117
- end
118
- end
119
-
120
-
121
-
122
- =begin
123
- requires the file specified in the model-dir
124
-
125
- In fact, the model-files are loaded instead of required. After recreation of a class (Class.delete_class,
126
- ORD.create_class classname) custom methods declared in the model files are present. Required modelfiles are
127
- gone, if the class is destroyed, but the interpreter thinks, they have already been required. Rebuilding the
128
- class does not reestablish the connection to the required model file.
129
-
130
- Actual only a flat directory is supported. However -the Parameter model has the format: [ superclass, class ]. Its possible to extend the method adress a model-tree.
131
- =end
132
- def require_model_file dir=nil
133
- logger.progname = 'ModelClass#RequireModelFile'
134
- dir = dir.presence || ActiveOrient::Model.model_dir
135
- if File.exists?( dir )
136
- model= model.flatten.last if model.is_a?( Array )
137
- filename = dir + "/" + self.to_s.underscore + '.rb'
138
- if File.exists?(filename )
139
- if load filename
140
- logger.info{ "#{filename} sucessfully loaded" }
141
- self #return_value
142
- else
143
- logger.error{ "#{filename} load error" }
144
- nil #return_value
145
- end
146
- else
147
- logger.info{ "model-file not present: #{filename}" }
148
- nil #return_value
149
- end
150
- else
151
- logger.info{ "Directory #{ dir } not present " }
152
- nil #return_value
153
- end
154
- rescue TypeError => e
155
- puts "TypeError: #{e.message}"
156
- puts "Working on #{self.to_s} -> #{self.superclass}"
157
- puts "Class_hierarchy: #{orientdb.class_hierarchy.inspect}."
158
- print e.backtrace.join("\n")
159
- raise
160
- #
161
- end
162
-
163
- ########## CREATE ############
164
-
165
- =begin
166
- Universal method to create a new record.
167
- It's obverloaded to create specific kinds, eg. edges
168
-
169
- Example:
170
- ORD.create_class :test
171
- Test.create string_attribute: 'a string', symbol_attribute: :a_symbol, array_attribute: [34,45,67]
172
- Test.create link_attribute: Test.create( :a_new_attribute => 'new' )
173
-
174
- =end
175
- def create **attributes
176
- attributes.merge :created_at => Time.new
177
- db.create_record self, attributes: attributes
178
- end
179
-
180
- =begin
181
- Creates or updates a record.
182
- Parameter:
183
- set: A hash of attributes to insert or update unconditionally
184
- where: A string or hash as condition which should return just one record.
185
-
186
- The where-part should be covered with an unique-index.
187
- If :where is omitted, #Upsert becomes #Create, attributes are taken from :set.
188
-
189
- returns the affected record
190
- =end
191
- def upsert set: {}, where: {}, &b
192
- db.upsert self, set: set, where: where, &b
193
- end
194
- =begin
195
- Create a new Instance of the Class with the applied attributes if does not exists,
196
- otherwise update it. It returns the freshly instantiated Objects
197
- =end
198
-
199
- def update_or_create_records set: {}, where: {}, **args, &b
200
- db.update_or_create_records self, set: set, where: where, **args, &b
201
- end
202
-
203
- alias update_or_create_documents update_or_create_records
204
-
205
- =begin
206
- Sets a value to certain attributes, overwrites existing entries, creates new attributes if nessesary
207
-
208
- IB::Account.update_all connected: false
209
- IB::Account.update_all where: "account containsText 'F'", set:{ connected: false }
210
-
211
- **note: By calling UpdateAll, all records of the Class previously stored in the rid-cache are removed from the cache. Thus autoload gets the updated records.
212
- =end
213
-
214
- def update_all where: {} , set: {}, **arg
215
- if where.empty?
216
- set.merge! arg
217
- end
218
- db.update_records self, set: set, where: where
219
-
220
- end
221
- #
222
- # removes a property from the collection (where given) or the entire class
223
- def remove attribute, where:{}
224
- db.update_records self, remove: attribute, where: where
225
- end
226
-
227
- =begin
228
- Create a Property in the Schema of the Class
229
- :call-seq: Model.create_property(field (required), type:'string', linked_class: nil, index: nil) do
230
- index
231
- end
232
-
233
- Examples:
234
-
235
- create_property :customer_id, type: integer, index: :unique
236
- create_property :name, type: :string, index: :not_unique
237
- create_property :in, type: :link, linked_class: :V (used by edges)
238
- =end
239
-
240
- def create_property field, **keyword_arguments, &b
241
- orientdb.create_property self, field, **keyword_arguments, &b
242
- end
243
-
244
- # Create more Properties in the Schema of the Class
245
-
246
- def create_properties argument_hash, &b
247
- orientdb.create_properties self, argument_hash, &b
248
- end
249
-
250
-
251
- # Add an Index
252
- def create_index name, **attributes
253
- orientdb.create_index self, name: name, **attributes
254
- end
255
-
256
- ########## GET ###############
257
-
258
- def classname # :nodoc: #
259
- ref_name
260
- end
261
-
262
- # get elements by rid
263
-
264
- def get rid
265
- db.get_record rid
266
- end
267
-
268
- # get all the elements of the class
269
-
270
- def all
271
- db.get_records from: self
272
- end
273
-
274
- # get the first element of the class
275
-
276
- def first where: {}
277
- db.get_records(from: self, where: where, limit: 1).pop
278
- end
279
-
280
- # get the last element of the class
281
-
282
- def last where: {}
283
- db.get_records(from: self, where: where, order: {"@rid" => 'desc'}, limit: 1).pop
284
- end
285
- # Used to count of the elements in the class
286
-
287
- def count **args
288
- orientdb.count from: self, **args
289
- end
290
-
291
- # Get the properties of the class
292
-
293
- def get_properties
294
- object = orientdb.get_class_properties self
295
- HashWithIndifferentAccess.new :properties => object['properties'], :indexes => object['indexes']
296
- end
297
- alias get_class_properties get_properties
298
-
299
- # Print the properties of the class
300
-
301
- def print_class_properties
302
- orientdb.print_class_properties self
303
- end
304
-
305
- =begin
306
- Parameter projection:
307
- »select« is a method of enumeration, we use »projection:« to specify anything between »select« and »from« in the query-string.
308
- projection: a_string --> inserts the sting as it appearsb
309
- an OrientSupport::OrientQuery-Object --> performs a sub-query and uses the result for further querying though the given parameters.
310
- [a, b, c] --> "a, b, c" (inserts a comma-separated list)
311
- {a: b, "sum(x)" => f} --> "a as b, sum(x) as f" (renames properties and uses functions)
312
-
313
- Parameter distinct:
314
- Performs a Query like » select distinct(property) [as property] from ...«
315
- distinct: :property --> the result is mapped to the property »distinct«.
316
- [:property] --> the result replaces the property
317
- {property: :some_name} --> the result is mapped to ModelInstance.some_name
318
-
319
- Parameter Order
320
- Sorts the result-set. If new properties are introduced via select:, distinct: etc. Sorting takes place on these properties
321
- order: :property {property: asc, property: desc}[property, property, .. ](orderdirection is 'asc')
322
-
323
- Further supported Parameter:
324
- group_by
325
- skip
326
- limit
327
- unwind
328
-
329
- see orientdb- documentation (https://orientdb.com/docs/last/SQL-Query.html)
330
-
331
- Parameter query:
332
- Instead of providing the parameter, the OrientSupport::OrientQuery can build and tested before the method-call. The OrientQuery-Object can be provided with the query-parameter. I.e.
333
- q = OrientSupport::OrientQuery.new
334
- ORD.create_class :test_model
335
- q.from TestModel
336
- q.where {name: 'Thomas'}
337
- count = TestModel.count query: q
338
- q.limit 10
339
- 0.step(count,10) do |x|
340
- q.skip = x
341
- puts TestModel.get_documents(query: q).map{|x| x.adress }.join('\t')
342
- end
343
- prints a Table with 10 columns.
344
- =end
345
-
346
- def get_records **args
347
- db.get_records(from: self, **args){self}
348
- end
349
- alias get_documents get_records
350
-
351
- =begin
352
- Performs a query on the Class and returns an Array of ActiveOrient:Model-Records.
353
-
354
- Example:
355
- Log.where priority: 'high'
356
- --> submited database-request: query/hc_database/sql/select from Log where priority = 'high'/-1
357
- => [ #<Log:0x0000000480f7d8 @metadata={ ... }, ...
358
- =end
359
-
360
- def custom_where search_string
361
- q = OrientSupport::OrientQuery.new from: self, where: search_string
362
- #puts q.compose
363
- query_database q
364
- end
365
- def where *attributes
366
- ## puts "ATTRIBUTES: "+attributes.inspect
367
- q = OrientSupport::OrientQuery.new from: self, where: attributes
368
- query_database q
369
- end
370
- =begin
371
- Performs a Match-Query
372
-
373
- The Query starts at the given ActiveOrient::Model-Class. The where-cause narrows the sample to certain
374
- records. In the simplest version this can be returnd:
375
-
376
- Industry.match where:{ name: "Communications" }
377
- => #<ActiveOrient::Model::Query:0x00000004309608 @metadata={"type"=>"d", "class"=>nil, "version"=>0, "fieldTypes"=>"Industries=x"}, @attributes={"Industries"=>"#21:1", (...)}>
378
-
379
- The attributes are the return-Values of the Match-Query. Unless otherwise noted, the pluralized Model-Classname is used as attribute in the result-set.
380
-
381
- I.match( where: { name: 'Communications' }).first.Industries
382
-
383
- is the same then
384
- Industry.where name: "Communications"
385
-
386
-
387
- The Match-Query uses this result-set as start for subsequent queries on connected records.
388
- These connections are defined in the Block
389
-
390
- var = Industry.match do | query |
391
- query.connect :in, count: 2, as: 'Subcategories'
392
- puts query.to_s # print the query send to the database
393
- query # important: block has to return the query
394
- end
395
- => MATCH {class: Industry, as: Industries} <-- {} <-- { as: Subcategories } RETURN Industries, Subcategories
396
-
397
- The result-set has two attributes: Industries and Subcategories, pointing to the filtered datasets.
398
-
399
- By using subsequent »connect« and »statement« method-calls even complex Match-Queries can be clearly constructed.
400
-
401
- =end
402
-
403
- def match where: {}
404
- query= OrientSupport::OrientQuery.new kind: :match, start:{ class: self.classname }
405
- query.match_statements[0].where = where unless where.empty?
406
- if block_given?
407
- query_database yield(query), set_from: false
408
- else
409
- logger.progname = 'ActiveOrient::Model#Match'
410
- logger.error{ "Query-Details have to be specified in a Block" }
411
- end
412
-
413
- end
414
-
415
-
416
- =begin
417
- QueryDatabase sends the Query, direct to the database.
418
- The result is not nessessary an Object of self.
419
- However, if the query does not return an array of Active::Model-Objects, then the entries become self
420
- =end
421
-
422
- def query_database query, set_from: true
423
- query.from self if set_from && query.is_a?(OrientSupport::OrientQuery) && query.from.nil?
424
- sql_cmd = -> (command) {{ type: "cmd", language: "sql", command: command }}
425
- db.execute do
426
- sql_cmd[query.to_s]
427
- end
428
- end
429
-
430
- ########### DELETE ###############
431
-
432
- # Delete a property from the class
433
-
434
- def delete_property field
435
- orientdb.delete_property self, field
436
- end
437
-
438
- # Delete a record
439
-
440
- def delete_record *rid
441
- db.delete_record rid
442
- end
443
- alias delete_document delete_record
444
-
445
- # Delete a record from the class
446
-
447
- def delete_records where: {}
448
- orientdb.delete_records self, where: where
449
- end
450
- alias delete_documents delete_records
451
-
452
-
453
-
454
- ##################### EXPERIMENT #################
455
-
456
- =begin
457
- Suppose that you created a graph where vertexes month is connected with
458
- the vertexes day by the edge TIMEOF.
459
- Suppose we want to find all the days in the first month and in the third month..
460
-
461
- Usually we can do in the following way.
462
-
463
- ORD.create_class "Month"
464
- (.. put some records into Month ... )
465
- firstmonth = Month.first
466
- thirdmonth = month.all[2]
467
- days_firstmonth = firstmonth.out_TIMEOF.map{|x| x.in}
468
- days_thirdmonth = thirdmonth.out_TIMEOF.map{|x| x.in}
469
-
470
- However we can obtain the same result with the following command
471
-
472
- Month.add_edge_link name: "days", direction: "out", edge: TIME_OF
473
- firstmonth = month.first
474
- thirdmonth = month.all[2]
475
- days_firstmonth = firstmonth.days
476
- days_thirdmonth = thirdmonth.days
477
-
478
- To get their value you can do:
479
- thirdmonth.days.value
480
- =end
481
-
482
-
483
- def add_edge_link name:, direction: :out, edge:
484
- dir = direction.to_s == "out" ? :out : :in
485
- define_method(name.to_sym) do
486
- return self["#{dir}_#{edge.classname}"].map{|x| x["in"]}
487
- end
488
- end
489
-
490
- =begin
491
- See http://orientdb.com/docs/2.1/SQL-Alter-Property.html
492
- =end
493
-
494
- def alter_property property:, attribute: "DEFAULT", alteration:
495
- orientdb.alter_property self, property: property, attribute: attribute, alteration: alteration
496
- end
497
-
498
-
499
-
500
- end