active-orient 0.4 → 0.80
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.graphs.txt.swp +0 -0
- data/Gemfile +9 -5
- data/Guardfile +12 -4
- data/README.md +70 -281
- data/VERSION +1 -1
- data/active-orient.gemspec +9 -7
- data/bin/active-orient-0.6.gem +0 -0
- data/bin/active-orient-console +97 -0
- data/changelog.md +60 -0
- data/config/boot.rb +70 -17
- data/config/config.yml +10 -0
- data/config/connect.yml +11 -6
- data/examples/books.rb +154 -65
- data/examples/streets.rb +89 -85
- data/graphs.txt +70 -0
- data/lib/active-orient.rb +78 -6
- data/lib/base.rb +266 -168
- data/lib/base_properties.rb +76 -65
- data/lib/class_utils.rb +187 -0
- data/lib/database_utils.rb +99 -0
- data/lib/init.rb +80 -0
- data/lib/java-api.rb +442 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/custom.rb +29 -0
- data/lib/model/e.rb +6 -0
- data/lib/model/edge.rb +114 -0
- data/lib/model/model.rb +134 -0
- data/lib/model/the_class.rb +657 -0
- data/lib/model/the_record.rb +313 -0
- data/lib/model/vertex.rb +371 -0
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +423 -0
- data/lib/railtie.rb +68 -0
- data/lib/rest/change.rb +150 -0
- data/lib/rest/create.rb +287 -0
- data/lib/rest/delete.rb +150 -0
- data/lib/rest/operations.rb +222 -0
- data/lib/rest/read.rb +189 -0
- data/lib/rest/rest.rb +120 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support/conversions.rb +42 -0
- data/lib/support/default_formatter.rb +7 -0
- data/lib/support/errors.rb +41 -0
- data/lib/support/logging.rb +38 -0
- data/lib/support/orient.rb +305 -0
- data/lib/support/orientquery.rb +647 -0
- data/lib/support/query.rb +92 -0
- data/rails.md +154 -0
- data/rails/activeorient.rb +32 -0
- data/rails/config.yml +10 -0
- data/rails/connect.yml +17 -0
- metadata +89 -30
- data/lib/model.rb +0 -461
- data/lib/orient.rb +0 -98
- data/lib/query.rb +0 -88
- data/lib/rest.rb +0 -1036
- data/lib/support.rb +0 -347
- data/test.rb +0 -4
- data/usecase.md +0 -91
data/lib/rest/rest.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require_relative "read.rb" # manage get
|
2
|
+
require_relative "create.rb" # manage create
|
3
|
+
require_relative "change.rb" # manage update
|
4
|
+
require_relative "operations.rb" # manage count, functions and execute
|
5
|
+
require_relative "delete.rb" # manage delete
|
6
|
+
require_relative "../support/logging"
|
7
|
+
#require 'cgi'
|
8
|
+
require 'rest-client'
|
9
|
+
require 'pond'
|
10
|
+
|
11
|
+
module ActiveOrient
|
12
|
+
|
13
|
+
=begin
|
14
|
+
OrientDB points to an OrientDB-Database.
|
15
|
+
The communication is based on the OrientDB-REST-API.
|
16
|
+
|
17
|
+
Its usually initialised through ActiveOrient::Init.connect
|
18
|
+
|
19
|
+
=end
|
20
|
+
|
21
|
+
class OrientDB
|
22
|
+
include OrientSupport::Support
|
23
|
+
include OrientSupport::Logging
|
24
|
+
include OrientDbPrivate
|
25
|
+
include DatabaseUtils
|
26
|
+
include ClassUtils
|
27
|
+
include RestRead
|
28
|
+
include RestCreate
|
29
|
+
include RestChange
|
30
|
+
include RestOperations
|
31
|
+
include RestDelete
|
32
|
+
|
33
|
+
|
34
|
+
#### INITIALIZATION ####
|
35
|
+
|
36
|
+
=begin
|
37
|
+
OrientDB is conventionally initialized.
|
38
|
+
|
39
|
+
|
40
|
+
The first call initialises database-name and -classes, server-adress and user-credentials.
|
41
|
+
|
42
|
+
Subsequent initialisations are made to initialise namespaced database classes, ie.
|
43
|
+
|
44
|
+
ORD = ActiveOrient.init.connect database: 'temp'
|
45
|
+
server: 'localhost',
|
46
|
+
port: 2480,
|
47
|
+
user: root,
|
48
|
+
password: root
|
49
|
+
module HC; end
|
50
|
+
ActiveOrient::Init.define_namespace { HC }
|
51
|
+
ActiveOrient::OrientDB.new preallocate: true
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
=end
|
58
|
+
|
59
|
+
def initialize database: nil, preallocate: true, model_dir: nil, **defaults
|
60
|
+
ActiveOrient.database ||= database || 'temp'
|
61
|
+
ActiveOrient.database_classes ||= Hash.new
|
62
|
+
|
63
|
+
ActiveOrient.default_server ||= { :server => defaults[:server] || 'localhost' ,
|
64
|
+
:port => defaults[:port] ||= 2480,
|
65
|
+
:user => defaults[:user].to_s ,
|
66
|
+
:password => defaults[:password].to_s }
|
67
|
+
# setup connection pool
|
68
|
+
# database-settings: client.channel.maxPool = 100
|
69
|
+
ActiveOrient.db_pool ||= Pond.new( :maximum_size => 25, :timeout => 50) { get_resource }
|
70
|
+
# ActiveOrient.db_pool.collection = :stack
|
71
|
+
connect()
|
72
|
+
database_classes # initialize @classes-array and ActiveOrient.database_classes
|
73
|
+
ActiveOrient::Base.logger = logger
|
74
|
+
ActiveOrient::Model.orientdb = self
|
75
|
+
ActiveOrient::Model.db = self
|
76
|
+
ActiveOrient::Model.keep_models_without_file ||= nil
|
77
|
+
preallocate_classes( model_dir ) if preallocate
|
78
|
+
Thread.abort_on_exception = true
|
79
|
+
end
|
80
|
+
|
81
|
+
# thread safe method to allocate a resource
|
82
|
+
def get_resource
|
83
|
+
logger.debug {"ALLOCATING NEW RESOURCE --> #{ ActiveOrient.db_pool.size }" }
|
84
|
+
login = [ActiveOrient.default_server[:user] , ActiveOrient.default_server[:password]]
|
85
|
+
server_adress = "http://#{ActiveOrient.default_server[:server]}:#{ActiveOrient.default_server[:port]}"
|
86
|
+
RestClient::Resource.new(server_adress, *login)
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
# Used to connect to the database
|
92
|
+
|
93
|
+
def connect
|
94
|
+
first_tentative = true
|
95
|
+
begin
|
96
|
+
database = ActiveOrient.database
|
97
|
+
logger.progname = 'OrientDB#Connect'
|
98
|
+
r = ActiveOrient.db_pool.checkout do | conn |
|
99
|
+
r = conn["/connect/#{database}"].get
|
100
|
+
end
|
101
|
+
if r.code == 204
|
102
|
+
logger.info{"Connected to database #{database}"}
|
103
|
+
true
|
104
|
+
else
|
105
|
+
logger.error{"Connection to database #{database} could NOT be established"}
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
rescue RestClient::Unauthorized => e
|
109
|
+
if first_tentative
|
110
|
+
logger.info{"Database #{database} NOT present --> creating"}
|
111
|
+
first_tentative = false
|
112
|
+
create_database database: database
|
113
|
+
retry
|
114
|
+
else
|
115
|
+
Kernel.exit
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
=begin #nodoc#
|
2
|
+
If properties are allocated on class-level, they can be preinitialized using
|
3
|
+
this method.
|
4
|
+
This is disabled for now, because it does not seem nessesary
|
5
|
+
=end
|
6
|
+
|
7
|
+
def preallocate_class_properties o_class # :nodoc:
|
8
|
+
p= get_class_properties( o_class )['properties']
|
9
|
+
unless p.nil? || p.blank?
|
10
|
+
predefined_attributes = p.map do | property |
|
11
|
+
[ property['name'] ,
|
12
|
+
case property['type']
|
13
|
+
when 'LINKMAP'
|
14
|
+
Array.new
|
15
|
+
when 'STRING'
|
16
|
+
''
|
17
|
+
else
|
18
|
+
nil
|
19
|
+
end ]
|
20
|
+
end.to_h
|
21
|
+
else
|
22
|
+
{}
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
=begin
|
2
|
+
Rails-specific stuff
|
3
|
+
|
4
|
+
Mimics ActiveModell::conversions
|
5
|
+
=end
|
6
|
+
module Conversions
|
7
|
+
|
8
|
+
|
9
|
+
=begin
|
10
|
+
Returns an Array of all key attributes if any is set, regardless if the object is persisted or not. Returns nil if there are no key attributes.
|
11
|
+
=end
|
12
|
+
def to_key
|
13
|
+
key = respond_to?(:rid) && rid
|
14
|
+
key ? [key] : nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns a +string+ representing the object's key suitable for use in URLs,
|
18
|
+
# # or +nil+ if <tt>persisted?</tt> is +false+.
|
19
|
+
def to_param
|
20
|
+
(persisted? && key = to_key) ? key.join('-') : nil
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Returns a +string+ identifying the path associated with the object.
|
25
|
+
# # ActionPack uses this to find a suitable partial to represent the object.
|
26
|
+
def to_partial_path
|
27
|
+
self.class._to_partial_path
|
28
|
+
end
|
29
|
+
|
30
|
+
# module ClassMethods #:nodoc:
|
31
|
+
# Provide a class level cache for #to_partial_path. This is an
|
32
|
+
# internal method and should not be accessed directly.
|
33
|
+
|
34
|
+
# def self._to_partial_path #:nodoc:
|
35
|
+
# @_to_partial_path ||= begin
|
36
|
+
# element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
|
37
|
+
# collection = ActiveSupport::Inflector.tableize(name)
|
38
|
+
# "#{collection}/#{element}".freeze
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#end
|
42
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveOrient
|
2
|
+
module Error
|
3
|
+
# Error handling
|
4
|
+
class Error < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class ArgumentError < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
class SymbolError < ArgumentError
|
11
|
+
end
|
12
|
+
|
13
|
+
class LoadError < LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
class ServerError < RuntimeError
|
17
|
+
end
|
18
|
+
end # module IB
|
19
|
+
end
|
20
|
+
# Patching Object with universally accessible top level error method.
|
21
|
+
# The method is used throughout the lib instead of plainly raising exceptions.
|
22
|
+
# This allows lib user to easily inject user-specific error handling into the lib
|
23
|
+
# by just replacing Object#error method.
|
24
|
+
def error message, type=:standard, backtrace=nil
|
25
|
+
e = case type
|
26
|
+
when :standard
|
27
|
+
ActiveOrientOrient::Error.new message
|
28
|
+
when :args
|
29
|
+
ActiveOrient::ArgumentError.new message
|
30
|
+
when :symbol
|
31
|
+
ActiveOrient::SymbolError.new message
|
32
|
+
when :load
|
33
|
+
AcitveOrient::LoadError.new message
|
34
|
+
when :server
|
35
|
+
ActiveOrient::Error::ServerError.new message
|
36
|
+
end
|
37
|
+
e.set_backtrace(backtrace) if backtrace
|
38
|
+
raise e
|
39
|
+
end
|
40
|
+
|
41
|
+
# resued from https://github.com/ib-ruby/ib-ruby
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#require_relative 'default_formatter'
|
2
|
+
module OrientSupport
|
3
|
+
module Logging
|
4
|
+
def self.included(base)
|
5
|
+
base.extend ClassMethods
|
6
|
+
base.send :define_method, :logger do
|
7
|
+
base.logger
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def logger
|
13
|
+
@logger
|
14
|
+
end
|
15
|
+
|
16
|
+
def logger=(logger)
|
17
|
+
@logger = logger
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure_logger(log= nil)
|
21
|
+
if log
|
22
|
+
@logger = log
|
23
|
+
else
|
24
|
+
@logger = Logger.new(STDOUT)
|
25
|
+
@logger.level = Logger::INFO
|
26
|
+
@logger.formatter = DefaultFormatter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class DefaultFormatter < Logger::Formatter
|
33
|
+
def self.call(severity, time, program_name, msg)
|
34
|
+
"#{time.strftime("%d.%m.(%X)")}#{"%5s" % severity}->#{msg}\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
# source: https://github.com/jondot/sneakers/blob/master/lib/sneakers/concerns/logging.rb
|
@@ -0,0 +1,305 @@
|
|
1
|
+
module OrientSupport
|
2
|
+
|
3
|
+
# This Module fences specialized Ruby objects
|
4
|
+
|
5
|
+
# The Array _knows_ its database-class. This enables database-transactions outside the scope
|
6
|
+
# of ActiveOrient
|
7
|
+
#
|
8
|
+
# The Database-Class is available through Array#record
|
9
|
+
#
|
10
|
+
# *caution:*
|
11
|
+
# Don't mix ActiveOrient::Array's with conventional ones
|
12
|
+
# > t= G21.first
|
13
|
+
# > t.ll
|
14
|
+
# => ["test", "test_2", 5, 8, 7988, "uzg"]
|
15
|
+
# > t.ll = [9,6,7] # This is an assignment of an Array to the variable »ll»
|
16
|
+
# # It does NOT call ActiveOrient::Array#=[].
|
17
|
+
# => [9, 6, 7] # Instead an Array is assigned to the variable »ll»
|
18
|
+
#
|
19
|
+
# it is only updated localy, as shown if we reload the document
|
20
|
+
# > t= G21.first.attributes
|
21
|
+
# => {:ll=>["test", "test_2", 5, 8, 7988, "uzg"]}
|
22
|
+
#
|
23
|
+
# Thus its imperativ to safe the changes made.
|
24
|
+
|
25
|
+
|
26
|
+
class Array < Array
|
27
|
+
include OrientSupport::Support
|
28
|
+
|
29
|
+
=begin
|
30
|
+
During initialisation the model-instance to work on is stored in @orient.
|
31
|
+
|
32
|
+
The keyword_parameter »work_on« holds the record to work on.
|
33
|
+
The second argument holds the array to work with
|
34
|
+
|
35
|
+
If instead of a model-instance the model-class is provided, a new model-instance is created and returned
|
36
|
+
Its up to the caller to save the new instance in the database
|
37
|
+
|
38
|
+
Further a list of array-elements is expected, which are forwarded (as Array) to Array
|
39
|
+
|
40
|
+
Its used to initialize Objects comming from the database (i.e. /lib/base.rb)
|
41
|
+
|
42
|
+
elsif iv.is_a? Array
|
43
|
+
OrientSupport::Array.new( work_on: self, work_with: iv.from_orient){ key.to_sym }
|
44
|
+
|
45
|
+
=end
|
46
|
+
|
47
|
+
def initialize( work_on:, work_with: )
|
48
|
+
@orient = work_on.class == Class ? work_on.new : work_on
|
49
|
+
super work_with
|
50
|
+
begin
|
51
|
+
@name = block_given? ? yield : @orient.attributes.key(self)
|
52
|
+
rescue TypeError => e # not defined
|
53
|
+
ActiveOrient::Base.logger.debug{ "--------------------Type Error ----------------------------------" }
|
54
|
+
ActiveOrient::Base.logger.debug("OrientSupport::Array"){ "Attributes #{@orient.attributes.inspect}" }
|
55
|
+
ActiveOrient::Base.logger.debug("OrientSupport::Array"){ e.inspect
|
56
|
+
ActiveOrient::Base.logger.debug{ "indicates a try to access a non existing array element" }}
|
57
|
+
nil
|
58
|
+
rescue NameError =>e
|
59
|
+
ActiveOrient::Base.logger.debug{ "--------------------Name Error ------------" }
|
60
|
+
ActiveOrient::Base.logger.debug ("OrientSupport::Array"){ e.inspect }
|
61
|
+
#ActiveOrient::Base.logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
62
|
+
ActiveOrient::Base.logger.debug{ "due to a bug in ActiveSupport DateTime Calculations" }
|
63
|
+
# we just ignore the error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
def as_json o=nil
|
67
|
+
map{|x| x.rid? ? x.rid : x }
|
68
|
+
end
|
69
|
+
|
70
|
+
def record
|
71
|
+
@orient
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_human
|
75
|
+
map &:to_human
|
76
|
+
end
|
77
|
+
=begin
|
78
|
+
|
79
|
+
Appends the arguments to the Array.
|
80
|
+
|
81
|
+
Returns the modified database-document (not the array !!)
|
82
|
+
=end
|
83
|
+
def append *arg
|
84
|
+
|
85
|
+
@orient.update { "set #{@name.to_s} = #{@name} || #{arg.to_or} "}[@name] if check_if_complete
|
86
|
+
@orient.reload!
|
87
|
+
end
|
88
|
+
=begin
|
89
|
+
Append the argument to the Array, changes the Array itself.
|
90
|
+
|
91
|
+
Returns the modified Array ( and is chainable )
|
92
|
+
#
|
93
|
+
# i= V.get( '89:0')
|
94
|
+
# ii=i.zwoebelkuchen << 'z78' << 6 << [454, 787]
|
95
|
+
# => [7, 5, 6, "z78", 78, 45, "z78", 6, 454, 787]
|
96
|
+
|
97
|
+
The change is immediately transmitted to the database.
|
98
|
+
|
99
|
+
The difference to `append`: that method accepts a komma separated list of arguments
|
100
|
+
and returns the modified database-document. `<<` accepts only one argument. An
|
101
|
+
Array is translated into multi-arguments of `append`
|
102
|
+
|
103
|
+
> t = G21.create ll: ['test','test_2', 5, 8 , 7988, "uzg"]
|
104
|
+
INFO->CREATE VERTEX ml_g21 CONTENT {"ll":["test","test_2",5,8,7988,"uzg"]}
|
105
|
+
=> #<ML::G21:0x0000000002622cb0 @metadata={:type=>"d", :class=>"ml_g21", :version=>1,
|
106
|
+
:fieldTypes=>nil, :cluster=>271, :record=>0},
|
107
|
+
@attributes={:ll=>["test", "test_2", 5, 8, 7988, "uzg"]}>
|
108
|
+
> t.ll << [9,10]
|
109
|
+
INFO->update #271:0 set ll = ll || [9, 10] return after @this
|
110
|
+
=> ["test", "test_2", 5, 8, 7988, "uzg"]
|
111
|
+
> t.ll << [9,10] << 'u'
|
112
|
+
INFO->update #271:0 set ll = ll || [9, 10] return after @this
|
113
|
+
INFO->update #271:0 set ll = ll || ['u'] return after @this
|
114
|
+
=> ["test", "test_2", 5, 8, 7988, "uzg", 9, 10]
|
115
|
+
|
116
|
+
|
117
|
+
The Array can be treated separately
|
118
|
+
|
119
|
+
> z = t.ll
|
120
|
+
=> ["test", "test_2", 5, 8, 7988, "uzg"]
|
121
|
+
> z << 78
|
122
|
+
INFO->update #272:0 set ll = ll || [78] return after @this
|
123
|
+
=> ["test", "test_2", 5, 8, 7988, "uzg", 78]
|
124
|
+
|
125
|
+
=end
|
126
|
+
def << arg
|
127
|
+
append( *arg).send @name
|
128
|
+
end
|
129
|
+
|
130
|
+
=begin
|
131
|
+
|
132
|
+
Removes the specified list entries from the Array
|
133
|
+
|
134
|
+
Returns the modified Array (and is chainable).
|
135
|
+
|
136
|
+
> t= G21.first
|
137
|
+
> t.ll
|
138
|
+
=> ["test", "test_2", 7988, "uzg", 6789, "xvy"]
|
139
|
+
> u= t.ll << 'xvz'
|
140
|
+
# INFO->update #272:0 set ll = ll || ['xvz'] return after @this
|
141
|
+
=> ["test", "test_2", 7988, "uzg", 6789, "xvy", "xvz"]
|
142
|
+
> z= u.remove 'xvy'
|
143
|
+
# INFO->update #272:0 remove ll = 'xvy' return after @this
|
144
|
+
=> ["test", "test_2", 7988, "uzg", 6789, "xvz"]
|
145
|
+
|
146
|
+
The ModelInstance is updated, too, as shown by calling
|
147
|
+
|
148
|
+
> t.ll
|
149
|
+
=> ["test", "test_2", 7988, "uzg", 6789, "xvz"]
|
150
|
+
|
151
|
+
|
152
|
+
Thus
|
153
|
+
|
154
|
+
> t.ll.remove 7988
|
155
|
+
# INFO->update #272:0 remove ll = 7988 return after @this
|
156
|
+
=> ["test", "test_2", "uzg", 6789, "xvz"]
|
157
|
+
|
158
|
+
returns thea modified Array
|
159
|
+
=end
|
160
|
+
def remove *k
|
161
|
+
# todo combine queries in a transaction
|
162
|
+
ActiveOrient::Base.logger.debug { "delete: #{@name} --< #{k.map(&:to_or).join( ' :: ' )}"}
|
163
|
+
k.map{|l| @orient.update( {remove: { @name => l} } ) }
|
164
|
+
# @orient.reload!
|
165
|
+
# @orient.send @name
|
166
|
+
end
|
167
|
+
|
168
|
+
def remove_by_index index
|
169
|
+
@orient.update( { remove: { @name => "#{@name[index]}" } } )
|
170
|
+
end
|
171
|
+
|
172
|
+
def check_if_complete
|
173
|
+
if @name.blank?
|
174
|
+
@orient.logger.warn{ "Database is uneffected. Operation is incomplete/ not allowed" }
|
175
|
+
false
|
176
|
+
else
|
177
|
+
true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
=begin
|
181
|
+
Updating of single items
|
182
|
+
=end
|
183
|
+
def []= key, value
|
184
|
+
super
|
185
|
+
@orient.update set: {@name => self} if @name.present? if check_if_complete
|
186
|
+
end
|
187
|
+
|
188
|
+
|
189
|
+
###
|
190
|
+
## just works with Hashes as parameters
|
191
|
+
def where *item
|
192
|
+
where_string = item.map{|m| where_string = compose_where( m ) }.join(' and ')
|
193
|
+
subquery= OrientSupport::OrientQuery.new from: @orient, projection: "expand( #{@name})"
|
194
|
+
q= OrientSupport::OrientQuery.new from: subquery, where: item
|
195
|
+
@orient.db.execute{ q.to_s } if check_if_complete
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
def method_missing method, *args
|
200
|
+
return if empty?
|
201
|
+
if @orient.is_a? ActiveOrient::Model # IB::Model
|
202
|
+
# delegate to public methods
|
203
|
+
self.map{|x| x.public_send(method, *args)}
|
204
|
+
else
|
205
|
+
self.map{|x| x.send method, *args }
|
206
|
+
end
|
207
|
+
rescue NoMethodError => e
|
208
|
+
ActiveOrient::Base.logger.error("OrientSupport::Array"){ "#{self.inspect} MethodMissing -> Undefined method: #{args.first} -- Args: #{args[1..-1].inspect}"}
|
209
|
+
ActiveOrient::Base.logger.error {" The Message #{e.message}"}
|
210
|
+
ActiveOrient::Base.logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
211
|
+
raise
|
212
|
+
end
|
213
|
+
|
214
|
+
end #Class
|
215
|
+
|
216
|
+
|
217
|
+
|
218
|
+
|
219
|
+
class Hash < Hash # WithIndifferentAccess
|
220
|
+
include OrientSupport::Support
|
221
|
+
def initialize modelinstance, args
|
222
|
+
super()
|
223
|
+
@orient = modelinstance
|
224
|
+
self.merge! args
|
225
|
+
@name = block_given? ? yield : modelinstance.attributes.key(self)
|
226
|
+
self
|
227
|
+
end
|
228
|
+
|
229
|
+
def store k, v
|
230
|
+
@orient.update { "set #{@name}[#{k.to_s.to_or}] = #{v.to_or} "}[@name] #if check_if_complete
|
231
|
+
@orient.reload!
|
232
|
+
end
|
233
|
+
|
234
|
+
alias []= store
|
235
|
+
|
236
|
+
|
237
|
+
# Inserts the provided Hash to the (possibly empty) list-property and updates the dataset
|
238
|
+
#
|
239
|
+
# Keys are translated to symbols
|
240
|
+
#
|
241
|
+
def merge **arg
|
242
|
+
@orient.update @name => super(**arg)
|
243
|
+
@orient.reload!
|
244
|
+
end
|
245
|
+
|
246
|
+
alias << merge
|
247
|
+
|
248
|
+
# removes a key-value entry from the hash.
|
249
|
+
#
|
250
|
+
# parameter: list of key's
|
251
|
+
#
|
252
|
+
# returns the modified OrientSupport::Hash
|
253
|
+
#
|
254
|
+
# ie, given
|
255
|
+
# b => <Base[51:0]: < Base: 51:0 >, a_set : {:warrant_value=>["8789", "HKD"], :what_if_pm_enabled=>["true", ""], :t_bill_value=>["0", "HKD"]}>
|
256
|
+
# c= b.a_set.remove :warrant_value
|
257
|
+
# INFO->update #51:0 remove a_set = 'warrant_value' return after $current
|
258
|
+
# c => {:what_if_pm_enabled=>["true", ""], :t_bill_value=>["0", "HKD"]}
|
259
|
+
|
260
|
+
|
261
|
+
def remove *k
|
262
|
+
# todo combine queries in a transaction
|
263
|
+
|
264
|
+
r= k.map{|key| @orient.update{ "remove #{@name} = #{key.to_s.to_or} " } }
|
265
|
+
@orient.reload!.send @name
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
def delete_if &b
|
270
|
+
super &b
|
271
|
+
@orient.update set:{ @name => self}
|
272
|
+
|
273
|
+
end
|
274
|
+
|
275
|
+
# slice returns a subset of the hash
|
276
|
+
#
|
277
|
+
# excepts a regular expression as well
|
278
|
+
def slice arg
|
279
|
+
if arg.is_a? Regexp
|
280
|
+
find_all{ |key| key.to_s.match(arg) }.to_h
|
281
|
+
else
|
282
|
+
super arg.to_sym
|
283
|
+
end
|
284
|
+
end
|
285
|
+
def [] arg
|
286
|
+
super
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end #Module
|
290
|
+
|
291
|
+
class Hash
|
292
|
+
|
293
|
+
def to_human
|
294
|
+
"{ " + self.map{ |k,v| [k.to_s,": ", v.to_orient].join }.join(', ') + " }"
|
295
|
+
end
|
296
|
+
|
297
|
+
# def coerce arg
|
298
|
+
# if arg.is_a? DateTime
|
299
|
+
# nil
|
300
|
+
# else
|
301
|
+
# super
|
302
|
+
#
|
303
|
+
# end
|
304
|
+
# end
|
305
|
+
end
|