active-orient 0.6 → 0.42

Sign up to get free protection for your applications and to get access to all the features.
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