active-orient 0.42 → 0.79
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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/Gemfile +13 -5
- data/Guardfile +12 -4
- data/README.md +67 -280
- data/VERSION +1 -1
- data/active-orient.gemspec +6 -5
- data/bin/active-orient-0.6.gem +0 -0
- data/bin/active-orient-console +85 -0
- data/config/boot.rb +72 -1
- data/config/config.yml +10 -0
- data/config/connect.yml +9 -4
- data/examples/books.rb +92 -40
- data/examples/streets.rb +89 -85
- data/examples/test_commands.rb +97 -0
- data/examples/test_commands_2.rb +59 -0
- data/examples/test_commands_3.rb +55 -0
- data/examples/test_commands_4.rb +33 -0
- data/examples/time_graph.md +162 -0
- data/lib/active-orient.rb +75 -9
- data/lib/base.rb +238 -169
- data/lib/base_properties.rb +68 -60
- data/lib/class_utils.rb +226 -0
- data/lib/database_utils.rb +98 -0
- data/lib/init.rb +79 -0
- data/lib/java-api.rb +442 -0
- data/lib/jdbc.rb +211 -0
- data/lib/model/custom.rb +26 -0
- data/lib/model/edge.rb +70 -0
- data/lib/model/model.rb +134 -0
- data/lib/model/the_class.rb +607 -0
- data/lib/model/the_record.rb +266 -0
- data/lib/model/vertex.rb +236 -0
- data/lib/orientdb_private.rb +48 -0
- data/lib/other.rb +371 -0
- data/lib/railtie.rb +68 -0
- data/lib/rest/change.rb +147 -0
- data/lib/rest/create.rb +279 -0
- data/lib/rest/delete.rb +134 -0
- data/lib/rest/operations.rb +211 -0
- data/lib/rest/read.rb +171 -0
- data/lib/rest/rest.rb +112 -0
- data/lib/rest_disabled.rb +24 -0
- data/lib/support/logging.rb +38 -0
- data/lib/support/orient.rb +196 -0
- data/lib/support/orientquery.rb +469 -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 +65 -24
- data/active-orient-0.4.gem +0 -0
- data/active-orient-0.41.gem +0 -0
- data/lib/model.rb +0 -468
- data/lib/orient.rb +0 -98
- data/lib/query.rb +0 -88
- data/lib/rest.rb +0 -1059
- data/lib/support.rb +0 -372
- data/test.rb +0 -4
- data/usecase.md +0 -91
@@ -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,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,196 @@
|
|
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
|
+
|
11
|
+
class Array < Array
|
12
|
+
include OrientSupport::Support
|
13
|
+
|
14
|
+
=begin
|
15
|
+
During initialisation the model-instance to work on is stored in @orient.
|
16
|
+
|
17
|
+
The keyword_parameter »work_on« holds the record to work on.
|
18
|
+
The second argument holds the array to work with
|
19
|
+
|
20
|
+
If instead of a model-instance the model-class is provided, a new model-instance is created and returned
|
21
|
+
Its up to the caller to save the new instance in the database
|
22
|
+
|
23
|
+
Further a list of array-elements is expected, which are forwarded (as Array) to Array
|
24
|
+
|
25
|
+
Its used to initialize Objects comming from the database (i.e. /lib/base.rb)
|
26
|
+
|
27
|
+
elsif iv.is_a? Array
|
28
|
+
OrientSupport::Array.new( work_on: self, work_with: iv.from_orient){ key.to_sym }
|
29
|
+
|
30
|
+
=end
|
31
|
+
|
32
|
+
def initialize( work_on:, work_with: )
|
33
|
+
@orient = work_on.class == Class ? work_on.new : work_on
|
34
|
+
super work_with
|
35
|
+
begin
|
36
|
+
@name = @orient.attributes.key(self)
|
37
|
+
rescue TypeError => e # not defined
|
38
|
+
ActiveOrient::Base.logger.debug{ "--------------------Type Error ----------------------------------" }
|
39
|
+
ActiveOrient::Base.logger.debug("OrientSupport::Array"){ "Attributes #{@orient.attributes.inspect}" }
|
40
|
+
ActiveOrient::Base.logger.debug("OrientSupport::Array"){ e.inspect
|
41
|
+
ActiveOrient::Base.logger.debug{ "indicates a try to access a non existing array element" }}
|
42
|
+
nil
|
43
|
+
rescue NameError =>e
|
44
|
+
ActiveOrient::Base.logger.debug{ "--------------------Name Error ------------" }
|
45
|
+
ActiveOrient::Base.logger.debug ("OrientSupport::Array"){ e.inspect }
|
46
|
+
#ActiveOrient::Base.logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
47
|
+
ActiveOrient::Base.logger.debug{ "due to a bug in ActiveSupport DateTime Calculations" }
|
48
|
+
# we just ignore the error
|
49
|
+
end
|
50
|
+
@name = yield if @name.nil? && block_given?
|
51
|
+
end
|
52
|
+
def as_json o=nil
|
53
|
+
map{|x| x.rid? ? x.rid : x }
|
54
|
+
end
|
55
|
+
|
56
|
+
def record
|
57
|
+
@orient
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_human
|
61
|
+
map &:to_human
|
62
|
+
end
|
63
|
+
# returns the modified array and is chainable
|
64
|
+
#
|
65
|
+
# i= V.get( '89:0')
|
66
|
+
# ii=i.zwoebelkuchen << 'z78' << 6 << [454, 787]
|
67
|
+
# => [7, 5, 6, "z78", 78, 45, "z78", 6, 454, 787]
|
68
|
+
=begin
|
69
|
+
Append the argument to the Array, changes the Array itself.
|
70
|
+
|
71
|
+
The change is immediately transmitted to the database.
|
72
|
+
|
73
|
+
|
74
|
+
=end
|
75
|
+
def append *arg
|
76
|
+
|
77
|
+
@orient.update { "#{@name.to_s} = #{@name} || #{arg.to_or} "}[@name]
|
78
|
+
end
|
79
|
+
|
80
|
+
alias << append
|
81
|
+
|
82
|
+
def remove *k
|
83
|
+
# todo combine queries in a transaction
|
84
|
+
puts "delete: #{@name} --< #{k.map(&:to_or).join( ' :: ' )}"
|
85
|
+
k.each{|item| @orient.remove( " #{@name} = #{item.to_or}")[@name] }
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
=begin
|
91
|
+
Updating of single items
|
92
|
+
=end
|
93
|
+
|
94
|
+
def []= key, value
|
95
|
+
super
|
96
|
+
@orient.update set: {@name => self} if @name.present?
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
###
|
101
|
+
## just works with Hashes as parameters
|
102
|
+
def where *item
|
103
|
+
where_string = item.map{|m| where_string = compose_where( m ) }.join(' and ')
|
104
|
+
subquery= OrientSupport::OrientQuery.new from: @orient, projection: "expand( #{@name})"
|
105
|
+
q= OrientSupport::OrientQuery.new from: subquery, where: item
|
106
|
+
@orient.query q.to_s
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
def method_missing *args
|
111
|
+
|
112
|
+
self.map{|x| x.send *args }
|
113
|
+
rescue NoMethodError => e
|
114
|
+
ActiveOrient::Base.logger.error("OrientSupport::Array"){ "MethodMissing -> Undefined method: #{args.first} -- Args: #{args[1..-1].inspect}"}
|
115
|
+
ActiveOrient::Base.logger.error {" The Message #{e.message}"}
|
116
|
+
ActiveOrient::Base.logger.error{ e.backtrace.map {|l| " #{l}\n"}.join }
|
117
|
+
end
|
118
|
+
|
119
|
+
end #Class
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
class Hash < Hash # WithIndifferentAccess
|
125
|
+
include OrientSupport::Support
|
126
|
+
def initialize modelinstance, args
|
127
|
+
super()
|
128
|
+
# puts "Hash.new args #{args}"
|
129
|
+
@orient = modelinstance
|
130
|
+
self.merge! args
|
131
|
+
@name = modelinstance.attributes.key(self)
|
132
|
+
@name = yield if @name.nil? && block_given?
|
133
|
+
# puts "@name #{@name}"
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def []= k, v
|
139
|
+
@orient.update { "#{@name.to_s}.#{k.to_s} = #{v.to_or}" }
|
140
|
+
end
|
141
|
+
|
142
|
+
# Inserts the provided Hash to the (possibly emty) list-property and returns a hash
|
143
|
+
def append arg
|
144
|
+
# the argument is simply provided as JSON-parameter to »update«
|
145
|
+
# generated query: update {rrid} set { @name } = { arg.to_json } return after @this
|
146
|
+
# todo : consider returning a OrientSuport::Hash
|
147
|
+
@orient.update { "#{@name.to_s} = "+ arg.to_json }[@name]
|
148
|
+
end
|
149
|
+
|
150
|
+
alias << append
|
151
|
+
|
152
|
+
# removes a key-value entry from the hash.
|
153
|
+
#
|
154
|
+
# parameter: list of key's (duplicate values are removed)
|
155
|
+
def remove *k
|
156
|
+
# todo combine queries in a transaction
|
157
|
+
k.map{ |key| @orient.update( remove: true ) { "#{@name.to_s}.#{key} " } }.last
|
158
|
+
end
|
159
|
+
# def delete *key
|
160
|
+
#
|
161
|
+
# key.each do | k |
|
162
|
+
# o = OrientSupport::OrientQuery.new from: @orient,
|
163
|
+
# kind: 'update',
|
164
|
+
# set: "#{@name}.#{k.to_s}",
|
165
|
+
# return: "$current.#{@name}"
|
166
|
+
# @orient.db.execute{ o.to_s.gsub( 'set ', 'remove ' ) }.first.send( @name ) # extracts the modified array (from DB) from the result
|
167
|
+
# end
|
168
|
+
# @orient.reload!
|
169
|
+
# @orient.send @name # return value
|
170
|
+
# end
|
171
|
+
|
172
|
+
def delete_if &b
|
173
|
+
super &b
|
174
|
+
@orient.update set:{ @name => self}
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
end
|
180
|
+
end #Module
|
181
|
+
|
182
|
+
class Hash
|
183
|
+
|
184
|
+
def to_human
|
185
|
+
"{ " + self.map{ |k,v| [k.to_s,": ", v.to_orient].join }.join(', ') + " }"
|
186
|
+
end
|
187
|
+
|
188
|
+
def coerce arg
|
189
|
+
if arg.is_a? DateTime
|
190
|
+
nil
|
191
|
+
else
|
192
|
+
super
|
193
|
+
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
@@ -0,0 +1,469 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
module OrientSupport
|
3
|
+
module Support
|
4
|
+
|
5
|
+
=begin
|
6
|
+
supports
|
7
|
+
where: 'string'
|
8
|
+
where: { property: 'value', property: value, ... }
|
9
|
+
where: ['string, { property: value, ... }, ... ]
|
10
|
+
|
11
|
+
Used by update and select
|
12
|
+
|
13
|
+
_Usecase:_
|
14
|
+
ORD.compose_where 'z=34', {u:6}
|
15
|
+
=> "where z=34 and u = 6"
|
16
|
+
=end
|
17
|
+
|
18
|
+
#
|
19
|
+
def compose_where *arg , &b
|
20
|
+
arg = arg.flatten
|
21
|
+
return "" if arg.blank? || arg.size == 1 && arg.first.blank?
|
22
|
+
"where " + generate_sql_list( arg , &b)
|
23
|
+
end
|
24
|
+
|
25
|
+
=begin
|
26
|
+
designs a list of "Key = Value" pairs combined by "and" or the binding provided by the block
|
27
|
+
ORD.generate_sql_list where: 25 , upper: '65'
|
28
|
+
=> "where = 25 and upper = '65'"
|
29
|
+
ORD.generate_sql_list( con_id: 25 , symbol: :G) { ',' }
|
30
|
+
=> "con_id = 25 , symbol = 'G'"
|
31
|
+
=end
|
32
|
+
def generate_sql_list attributes = {}, &b
|
33
|
+
fill = block_given? ? yield : 'and'
|
34
|
+
a= case attributes
|
35
|
+
when ::Hash
|
36
|
+
attributes.map do |key, value|
|
37
|
+
case value
|
38
|
+
when ActiveOrient::Model
|
39
|
+
"#{key} = #{value.rrid}"
|
40
|
+
when Numeric
|
41
|
+
"#{key} = #{value}"
|
42
|
+
when ::Array
|
43
|
+
"#{key} in [#{value.to_orient}]"
|
44
|
+
when Range
|
45
|
+
"#{key} between #{value.first} and #{value.last} "
|
46
|
+
when DateTime
|
47
|
+
"#{key} = date(\'#{value.strftime("%Y%m%d%H%M%S")}\',\'yyyyMMddHHmmss\')"
|
48
|
+
when Date
|
49
|
+
"#{key} = date(\'#{value.to_s}\',\'yyyy-MM-dd\')"
|
50
|
+
else # String, Symbol, Time, Trueclass, Falseclass ...
|
51
|
+
"#{key} = \'#{value.to_s}\'"
|
52
|
+
end
|
53
|
+
end.join(" #{fill} ")
|
54
|
+
when ::Array
|
55
|
+
attributes.map{|y| generate_sql_list y, &b }.join( " #{fill} " )
|
56
|
+
when String
|
57
|
+
attributes
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
class MatchConnection
|
64
|
+
attr_accessor :as
|
65
|
+
def initialize edge: nil, direction: :both, as: nil, count: 1
|
66
|
+
@edge = edge
|
67
|
+
@direction = direction # may be :both, :in, :out
|
68
|
+
@as = as
|
69
|
+
@count = count
|
70
|
+
end
|
71
|
+
|
72
|
+
def direction= dir
|
73
|
+
@direction = dir
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def direction
|
78
|
+
fillup = @edge.present? ? @edge : ''
|
79
|
+
case @direction
|
80
|
+
when :both
|
81
|
+
" -#{fillup}- "
|
82
|
+
when :in
|
83
|
+
" <-#{fillup}- "
|
84
|
+
when :out
|
85
|
+
" -#{fillup}-> "
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def compose
|
91
|
+
ministatement = @as.present? ? "{ as: #{@as} } " : ""
|
92
|
+
(1 .. @count).map{|x| direction }.join("{}") << ministatement
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class MatchStatement
|
99
|
+
include Support
|
100
|
+
attr_accessor :as
|
101
|
+
attr_accessor :where
|
102
|
+
def initialize match_class=nil, **args
|
103
|
+
@misc = []
|
104
|
+
@where = []
|
105
|
+
@while = []
|
106
|
+
@maxdepth = 0
|
107
|
+
@as = nil
|
108
|
+
|
109
|
+
|
110
|
+
@match_class = match_class
|
111
|
+
@as = match_class.pluralize if match_class.is_a? String
|
112
|
+
|
113
|
+
args.each do |k, v|
|
114
|
+
case k
|
115
|
+
when :as
|
116
|
+
@as = v
|
117
|
+
when :while
|
118
|
+
@while << v
|
119
|
+
when :where
|
120
|
+
@where << v
|
121
|
+
when :class
|
122
|
+
@match_class = v
|
123
|
+
@as = v.pluralize
|
124
|
+
else
|
125
|
+
self.send k, v
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def while_s
|
131
|
+
compose_where( @while ).gsub( /where/, 'while:(' )<< ")" unless @while.blank?
|
132
|
+
end
|
133
|
+
|
134
|
+
def match_alias
|
135
|
+
"as: #{@as }"
|
136
|
+
end
|
137
|
+
def where_s
|
138
|
+
compose_where( @where ).gsub( /where/, 'where:(' )<< ")" unless @where.blank?
|
139
|
+
end
|
140
|
+
|
141
|
+
def maxdepth=x
|
142
|
+
@maxdepth = x
|
143
|
+
end
|
144
|
+
|
145
|
+
def method_missing method, *arg, &b
|
146
|
+
@misc << method.to_s << generate_sql_list(arg)
|
147
|
+
end
|
148
|
+
|
149
|
+
def misc
|
150
|
+
@misc.join(' ') unless @misc.empty?
|
151
|
+
end
|
152
|
+
# used for the first compose-statement of a compose-query
|
153
|
+
def compose_simple
|
154
|
+
'{'+ [ "class: #{@match_class}",
|
155
|
+
"as: #{@as}" ,
|
156
|
+
where_s ].compact.join(', ') + '}'
|
157
|
+
end
|
158
|
+
|
159
|
+
def compose
|
160
|
+
|
161
|
+
'{'+ [ "class: #{@match_class}",
|
162
|
+
"as: #{@as}" ,
|
163
|
+
where_s,
|
164
|
+
while_s,
|
165
|
+
@maxdepth >0 ? "maxdepth: #{maxdepth}": nil ].compact.join(', ')+'}'
|
166
|
+
end
|
167
|
+
alias :to_s :compose
|
168
|
+
end
|
169
|
+
|
170
|
+
class OrientQuery
|
171
|
+
include Support
|
172
|
+
|
173
|
+
|
174
|
+
attr_accessor :where
|
175
|
+
attr_accessor :let
|
176
|
+
attr_accessor :projection
|
177
|
+
attr_accessor :order
|
178
|
+
attr_accessor :db
|
179
|
+
attr_accessor :match_statements
|
180
|
+
|
181
|
+
def initialize **args
|
182
|
+
@projection = []
|
183
|
+
@misc = []
|
184
|
+
@let = []
|
185
|
+
@where = []
|
186
|
+
@order = []
|
187
|
+
@aliases = []
|
188
|
+
@match_statements = []
|
189
|
+
@class = nil
|
190
|
+
@return = nil
|
191
|
+
@db = nil
|
192
|
+
@kind = 'select'
|
193
|
+
args.each do |k, v|
|
194
|
+
case k
|
195
|
+
when :projection
|
196
|
+
@projection << v
|
197
|
+
when :let
|
198
|
+
@let << v
|
199
|
+
when :order
|
200
|
+
@order << v
|
201
|
+
when :where
|
202
|
+
@where << v
|
203
|
+
when :kind
|
204
|
+
@kind = v
|
205
|
+
when :start
|
206
|
+
@match_statements[0] = MatchStatement.new **v
|
207
|
+
# @match_statements[1] = MatchConnection.new
|
208
|
+
when :connection
|
209
|
+
@match_statements[1] = MatchConnection.new **v
|
210
|
+
when :return
|
211
|
+
@aliases << v
|
212
|
+
else
|
213
|
+
self.send k, v
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
=begin
|
220
|
+
where: "r > 9" --> where r > 9
|
221
|
+
where: {a: 9, b: 's'} --> where a = 9 and b = 's'
|
222
|
+
where:[{ a: 2} , 'b > 3',{ c: 'ufz' }] --> where a = 2 and b > 3 and c = 'ufz'
|
223
|
+
=end
|
224
|
+
def method_missing method, *arg, &b # :nodoc:
|
225
|
+
@misc << method.to_s << generate_sql_list(arg)
|
226
|
+
self.to_s # return compiled result
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
def misc # :nodoc:
|
231
|
+
@misc.join(' ') unless @misc.empty?
|
232
|
+
# self.to_s # return compiled result
|
233
|
+
end
|
234
|
+
|
235
|
+
def subquery # :nodoc:
|
236
|
+
nil
|
237
|
+
end
|
238
|
+
|
239
|
+
|
240
|
+
|
241
|
+
=begin
|
242
|
+
(only if kind == :match): connect
|
243
|
+
|
244
|
+
Add a connection to the match-query
|
245
|
+
|
246
|
+
A Match-Query alwas has an Entry-Stratement and maybe other Statements.
|
247
|
+
They are connected via " -> " (outE), "<-" (inE) or "--" (both).
|
248
|
+
|
249
|
+
The connection method adds a connection to the statement-stack.
|
250
|
+
|
251
|
+
Parameters:
|
252
|
+
direction: :in, :out, :both
|
253
|
+
edge_class: to restrict the Query on a certain Edge-Class
|
254
|
+
count: To repeat the connection
|
255
|
+
as: Includes a micro-statement to finalize the Match-Query
|
256
|
+
as: defines a output-variablet, which is used later in the return-statement
|
257
|
+
|
258
|
+
The method returns the OrientSupport::MatchConnection object, which can be modified further.
|
259
|
+
It is compiled by calling compose
|
260
|
+
=end
|
261
|
+
|
262
|
+
def connect direction, edge_class: nil, count: 1, as: nil
|
263
|
+
direction= :both unless [ :in, :out].include? direction
|
264
|
+
match_statements << m = OrientSupport::MatchConnection.new( direction: direction, count: count, as: as)
|
265
|
+
m
|
266
|
+
end
|
267
|
+
|
268
|
+
=begin
|
269
|
+
(only if kind == :match): statement
|
270
|
+
|
271
|
+
A Match Query consists of a simple start-statement
|
272
|
+
( classname and where-condition ), a connection followd by other Statement-connection-pairs.
|
273
|
+
It performs a sub-query starting at the given entry-point.
|
274
|
+
|
275
|
+
Statement adds a statement to the statement-stack.
|
276
|
+
Statement returns the created OrientSupport::MatchStatement-record for further modifications.
|
277
|
+
It is compiled by calling »compose«.
|
278
|
+
|
279
|
+
OrientSupport::OrientQuery collects any "as"-directive for inclusion in the return-statement
|
280
|
+
|
281
|
+
Parameter (all optional)
|
282
|
+
Class: classname, :where: {}, while: {}, as: string, maxdepth: >0 ,
|
283
|
+
|
284
|
+
=end
|
285
|
+
def statement match_class= nil, **args
|
286
|
+
match_statements << s = OrientSupport::MatchStatement.new( mattch_class, args )
|
287
|
+
s
|
288
|
+
end
|
289
|
+
=begin
|
290
|
+
Output the compiled query
|
291
|
+
Parameter: destination (rest, batch )
|
292
|
+
If the query is submitted via the REST-Interface (as get-command), the limit parameter is extracted.
|
293
|
+
=end
|
294
|
+
|
295
|
+
def compose(destination: :batch)
|
296
|
+
if @kind == :match
|
297
|
+
unless @match_statements.empty?
|
298
|
+
match_query = @kind.to_s.upcase + " "+ @match_statements[0].compose_simple
|
299
|
+
match_query << @match_statements[1..-1].map( &:compose ).join
|
300
|
+
match_query << " RETURN "<< (@match_statements.map( &:as ).compact | @aliases).join(', ')
|
301
|
+
end
|
302
|
+
elsif @kind.to_sym == :update
|
303
|
+
return_statement = "return after " + ( @aliases.empty? ? "$this" : @aliases.first.to_s)
|
304
|
+
[ @kind, @database, misc, where_s, return_statement ].compact.join(' ')
|
305
|
+
elsif destination == :rest
|
306
|
+
[@kind, projection_s, from, let_s, where_s, subquery, misc, order_s, group_by, unwind, skip].compact.join(' ')
|
307
|
+
else
|
308
|
+
[@kind, projection_s, from, let_s, where_s, subquery, misc, order_s, group_by, limit, unwind, skip].compact.join(' ')
|
309
|
+
end
|
310
|
+
end
|
311
|
+
alias :to_s :compose
|
312
|
+
|
313
|
+
=begin
|
314
|
+
from can either be a Databaseclass to operate on or a Subquery providing data to query further
|
315
|
+
=end
|
316
|
+
|
317
|
+
|
318
|
+
def from arg = nil
|
319
|
+
if arg.present?
|
320
|
+
@database = case arg
|
321
|
+
when ActiveOrient::Model # a single record
|
322
|
+
arg.rrid
|
323
|
+
when OrientQuery # result of a query
|
324
|
+
' ( '+ arg.to_s + ' ) '
|
325
|
+
when Class
|
326
|
+
arg.ref_name
|
327
|
+
else
|
328
|
+
if arg.to_s.rid? # a string with "#ab:cd"
|
329
|
+
arg
|
330
|
+
else # a database-class-name
|
331
|
+
arg.to_s
|
332
|
+
end
|
333
|
+
end
|
334
|
+
compose # return the complete query
|
335
|
+
else # read from
|
336
|
+
"from #{@database}" unless @database.nil?
|
337
|
+
end
|
338
|
+
end
|
339
|
+
alias :from= :from
|
340
|
+
|
341
|
+
def database_class # :nodoc:
|
342
|
+
if @database.present?
|
343
|
+
@database
|
344
|
+
elsif @from.is_a? OrientQuery
|
345
|
+
@from.database_class
|
346
|
+
else
|
347
|
+
nil
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def database_class= arg # :nodoc:
|
352
|
+
@database = arg if @database.present?
|
353
|
+
if @from.is_a? OrientQuery
|
354
|
+
@from.database_class= arg
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
def where_s # :nodoc:
|
359
|
+
compose_where @where
|
360
|
+
end
|
361
|
+
|
362
|
+
def let_s # :nodoc:
|
363
|
+
unless @let.empty?
|
364
|
+
"let " << @let.map do |s|
|
365
|
+
case s
|
366
|
+
when String
|
367
|
+
s
|
368
|
+
when Array
|
369
|
+
s.join(', ')
|
370
|
+
# when Hash ### is not recognized in jruby
|
371
|
+
else
|
372
|
+
s.map{|x,y| "$#{x} = (#{y})"}.join(', ')
|
373
|
+
end
|
374
|
+
end.join(', ')
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def distinct d
|
379
|
+
@projection << case d
|
380
|
+
when String, Symbol
|
381
|
+
"distinct #{d.to_s} "
|
382
|
+
else
|
383
|
+
dd= d.to_a.flatten
|
384
|
+
"distinct #{dd.first.to_s} as #{dd.last}"
|
385
|
+
end
|
386
|
+
compose
|
387
|
+
end
|
388
|
+
alias :distinct= :distinct
|
389
|
+
|
390
|
+
def projection_s # :nodoc:
|
391
|
+
@projection.map do | s |
|
392
|
+
case s
|
393
|
+
when Array
|
394
|
+
s.join(', ')
|
395
|
+
when String, Symbol
|
396
|
+
s.to_s
|
397
|
+
else
|
398
|
+
s.map{ |x,y| "#{x} as #{y}"}.join( ', ')
|
399
|
+
end
|
400
|
+
end.join( ', ' )
|
401
|
+
end
|
402
|
+
|
403
|
+
def limit l=nil
|
404
|
+
@limit = "limit #{l.to_s}" if l.present?
|
405
|
+
# only a string is allowed
|
406
|
+
@limit
|
407
|
+
end
|
408
|
+
alias :limit= :limit
|
409
|
+
|
410
|
+
def get_limit # :nodoc:
|
411
|
+
@limit.nil? ? -1 : @limit.split(' ').last.to_i
|
412
|
+
end
|
413
|
+
|
414
|
+
def expand item
|
415
|
+
@projection =[ " expand ( #{item.to_s} )" ]
|
416
|
+
compose
|
417
|
+
end
|
418
|
+
|
419
|
+
|
420
|
+
def nodes in_or_out = :out, via: nil, where: nil, expand: true
|
421
|
+
condition = where.present? ? "[ #{generate_sql_list(where)} ]" : ""
|
422
|
+
start = in_or_out
|
423
|
+
the_end = in_or_out == :in ? :out : :in
|
424
|
+
argument = " #{start}E(#{via.to_or if via.present?}).#{the_end}#{condition} "
|
425
|
+
|
426
|
+
if expand.present?
|
427
|
+
send :expand, argument
|
428
|
+
else
|
429
|
+
@projection << argument
|
430
|
+
end
|
431
|
+
compose
|
432
|
+
end
|
433
|
+
|
434
|
+
def group_by g = nil
|
435
|
+
@group = "group by #{g.to_s}" if g.present?
|
436
|
+
# only a string is allowed
|
437
|
+
@group
|
438
|
+
end
|
439
|
+
|
440
|
+
def unwind u = nil
|
441
|
+
@unwind = "unwind #{u.to_s}" if u.present?
|
442
|
+
# only a string is allowed
|
443
|
+
@unwind
|
444
|
+
end
|
445
|
+
|
446
|
+
def skip n = nil
|
447
|
+
@skip = n if n.present?
|
448
|
+
"skip #{@skip}" if @skip.present?
|
449
|
+
end
|
450
|
+
|
451
|
+
def order_s # :nodoc:
|
452
|
+
unless @order.empty?
|
453
|
+
# the [@order] is nessesary to enable query.order= "..." oder query.order= { a: :b }
|
454
|
+
"order by " << [@order].flatten.map do |o|
|
455
|
+
case o
|
456
|
+
when String, Symbol, Array
|
457
|
+
o.to_s
|
458
|
+
else
|
459
|
+
o.map{|x,y| "#{x} #{y}"}.join(" ")
|
460
|
+
end # case
|
461
|
+
end.join(', ')
|
462
|
+
else
|
463
|
+
''
|
464
|
+
end # unless
|
465
|
+
end # def
|
466
|
+
end # class
|
467
|
+
|
468
|
+
|
469
|
+
end # module
|