Class: Orientdb4r::RestClient

Inherits:
Client
  • Object
show all
Includes:
Aop2
Defined in:
lib/orientdb4r/rest/client.rb

Constant Summary

Constants inherited from Client

Client::DEFAULT_SERVER_VERSION, Client::SERVER_VERSION_PATTERN

Instance Attribute Summary

Attributes inherited from Client

#connection_library, #database, #lb_strategy, #load_balancing, #nodes, #password, #proxy, #server_version, #user

Instance Method Summary collapse

Methods included from Aop2

#aop_context, #aop_context=, included

Methods inherited from Client

#class_exists?, #connected?, #create_class, #create_property, #database_exists?, #drop_class

Methods included from Utils

#blank?, #compare_versions, #random_string, #verify_and_sanitize_options, #verify_options

Constructor Details

#initialize(options) ⇒ RestClient

:nodoc:

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/orientdb4r/rest/client.rb', line 13

def initialize(options) #:nodoc:
  super()
  options_pattern = {
    :host => 'localhost', :port => 2480, :ssl => false,
    :nodes => :optional,
    :connection_library => :restclient,
#        :connection_library => :excon,
    :load_balancing => :sequence,
    :proxy => :optional,
    :user_agent => :optional,
    :lb_recover_time => :optional
  }
  verify_and_sanitize_options(options, options_pattern)

  # fake nodes for single server
  if options[:nodes].nil?
    options[:nodes] = [{:host => options[:host], :port => options[:port], :ssl => options[:ssl]}]
  end
  raise ArgumentError, 'nodes has to be array' unless options[:nodes].is_a? Array

  # instantiate nodes according to HTTP library
  @connection_library = options[:connection_library]
  node_clazz = case connection_library
    when :restclient then Orientdb4r::RestClientNode
    when :excon then Orientdb4r::ExconNode
    else raise ArgumentError, "unknown connection library: #{connection_library}"
  end

  # nodes
  options[:nodes].each do |node_options|
    verify_and_sanitize_options(node_options, options_pattern)
    @nodes << node_clazz.new(node_options[:host], node_options[:port], node_options[:ssl])
  end

  # load balancing
  @load_balancing = options[:load_balancing]
  @lb_strategy = case load_balancing
    when :sequence then Orientdb4r::Sequence.new nodes.size
    when :round_robin then Orientdb4r::RoundRobin.new nodes.size
    else raise ArgumentError, "unknow load balancing type: #{load_balancing}"
  end
  # recover time
  recover_time = options[:lb_recover_time]
  @lb_strategy.recover_time = recover_time.to_i unless recover_time.nil?


  # proxy
  @proxy = options[:proxy]
  unless proxy.nil?
    case connection_library
      when :restclient then ::RestClient.proxy = proxy
      when :excon then nodes.each { |node| node.proxy = proxy }
    end
  end

  # user-agent
  agent = options[:user_agent]
  unless agent.nil?
    nodes.each { |node| node.user_agent = agent }
  end

  Orientdb4r::logger.info "client initialized with #{@nodes.size} node(s) "
  Orientdb4r::logger.info "connection_library=#{options[:connection_library]}, load_balancing=#{load_balancing}"
end

Instance Method Details

#command(sql) ⇒ Object

:nodoc:

Raises:

  • (ArgumentError)


252
253
254
255
256
# File 'lib/orientdb4r/rest/client.rb', line 252

def command(sql) #:nodoc:
  raise ArgumentError, 'command is blank' if blank? sql
  response = call_server(:method => :post, :uri => "command/#{@database}/sql/#{CGI::escape(sql)}")
  process_response(response)
end

#connect(options) ⇒ Object

————————————————————— CONNECTION



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/orientdb4r/rest/client.rb', line 81

def connect(options) #:nodoc:
  options_pattern = { :database => :mandatory, :user => :mandatory, :password => :mandatory }
  verify_and_sanitize_options(options, options_pattern)

  @database = options[:database]
  @user = options[:user]
  @password = options[:password]

  @nodes.each { |node| node.cleanup } # destroy all used session <= problem in 1.3.0-SNAPSHOT
  begin
    response = call_server(:method => :get, :uri => "connect/#{@database}")
  rescue
    @connected = false
    @server_version = nil
    @user = nil
    @password = nil
    @database = nil
    @nodes.each { |node| node.cleanup }
    raise ConnectionError
  end
  rslt = process_response response
  decorate_classes_with_model(rslt['classes'])

  # try to read server version
  if rslt.include? 'server'
    @server_version = rslt['server']['version']
  else
    @server_version = DEFAULT_SERVER_VERSION
  end
  unless server_version =~ SERVER_VERSION_PATTERN
    Orientdb4r::logger.warn "bad version format, version=#{server_version}"
    @server_version = DEFAULT_SERVER_VERSION
  end

  Orientdb4r::logger.info "successfully connected to server, version=#{server_version}"
  @connected = true
  rslt
end

#create_database(options) ⇒ Object

—————————————————————– DATABASE



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/orientdb4r/rest/client.rb', line 159

def create_database(options) #:nodoc:
  options_pattern = {
    :database => :mandatory, :type => 'memory',
    :user => :optional, :password => :optional
  }
  verify_and_sanitize_options(options, options_pattern)

  params = { :method => :post, :uri => "database/#{options[:database]}/#{options[:type]}" }
  params[:no_session] = true # out of existing session which represents an already done authentication

  # additional authentication allowed, overriden in 'call_server' if not defined
  params[:user] = options[:user] if options.include? :user
  params[:password] = options[:password] if options.include? :password

  response = call_server params
  process_response(response)
end

#create_document(doc) ⇒ Object

—————————————————————– DOCUMENT



300
301
302
303
304
305
306
307
308
# File 'lib/orientdb4r/rest/client.rb', line 300

def create_document(doc) #:nodoc:
  response = call_server(:method => :post, :uri => "document/#{@database}", \
      :content_type => 'application/json', :data => doc.to_json)
  srid = process_response(response)  do
    raise DataError, 'validation problem' if response.body =~ /OValidationException/
  end

  Rid.new srid
end

#delete_database(options) ⇒ Object

:nodoc:



205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/orientdb4r/rest/client.rb', line 205

def delete_database(options) #:nodoc:
  options_pattern = {
    :database => :mandatory, :user => :optional, :password => :optional
  }
  verify_and_sanitize_options(options, options_pattern)

  params = { :method => :delete, :uri => "database/#{options[:database]}" }
  params[:no_session] = true # out of existing session which represents an already done authentication

  # additional authentication allowed, overriden in 'call_server' if not defined
  params[:user] = options[:user] if options.include? :user
  params[:password] = options[:password] if options.include? :password

  response = call_server params
  process_response(response)
end

#delete_document(rid) ⇒ Object

:nodoc:



342
343
344
345
346
347
348
349
350
# File 'lib/orientdb4r/rest/client.rb', line 342

def delete_document(rid) #:nodoc:
  rid = Rid.new(rid) unless rid.is_a? Rid

  response = call_server(:method => :delete, :uri => "document/#{@database}/#{rid.unprefixed}")
  process_response(response) do
    raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
  end
  # empty http response
end

#disconnectObject

:nodoc:



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/orientdb4r/rest/client.rb', line 121

def disconnect #:nodoc:
  return unless @connected

  begin
    call_server(:method => :get, :uri => 'disconnect')
    # https://groups.google.com/forum/?fromgroups#!topic/orient-database/5MAMCvFavTc
    # Disconnect doesn't require you're authenticated.
    # It always returns 401 because some browsers intercept this and avoid to reuse the same session again.
  ensure
    @connected = false
    @server_version = nil
    @user = nil
    @password = nil
    @database = nil
    @nodes.each { |node| node.cleanup }
    Orientdb4r::logger.debug 'disconnected from server'
  end
end

#get_class(name) ⇒ Object

——————————————————————– CLASS

Raises:

  • (ArgumentError)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/orientdb4r/rest/client.rb', line 261

def get_class(name) #:nodoc:
  raise ArgumentError, "class name is blank" if blank?(name)

  if compare_versions(server_version, '1.1.0') >= 0
    response = call_server(:method => :get, :uri => "class/#{@database}/#{name}")
    rslt = process_response(response) do
      raise NotFoundError, 'class not found' if response.body =~ /Invalid class/
    end

    classes = [rslt]
  else
    # there is bug in REST API [v1.0.0, fixed in r5902], only data are returned
    # workaround - use metadate delivered by 'connect'
    response = call_server(:method => :get, :uri => "connect/#{@database}")
    connect_info = process_response(response) do
      raise NotFoundError, 'class not found' if response.body =~ /Invalid class/
    end

    classes = connect_info['classes'].select { |i| i['name'] == name }
    raise NotFoundError, "class not found, name=#{name}" unless 1 == classes.size
  end

  decorate_classes_with_model(classes)
  clazz = classes[0]
  clazz.extend Orientdb4r::HashExtension
  clazz.extend Orientdb4r::OClass
  unless clazz['properties'].nil? # there can be a class without properties
    clazz.properties.each do |prop|
      prop.extend Orientdb4r::HashExtension
      prop.extend Orientdb4r::Property
    end
  end

  clazz
end

#get_database(options = nil) ⇒ Object

> curl –user admin:admin localhost:2480/database/temp

Raises:

  • (ArgumentError)


179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/orientdb4r/rest/client.rb', line 179

def get_database(options=nil) #:nodoc:
  raise ArgumentError, 'options have to be a Hash' if !options.nil? and !options.kind_of? Hash

  if options.nil?
    # use database from connect
    raise ConnectionError, 'client has to be connected if no params' unless connected?
    options = { :database => database }
  end

  options_pattern = { :database => :mandatory, :user => :optional, :password => :optional }
  verify_options(options, options_pattern)

  params = {:method => :get, :uri => "database/#{options[:database]}"}
  params[:no_session] = true # out of existing session which represents an already done authentication

  # additional authentication allowed, overriden in 'call_server' if not defined
  params[:user] = options[:user] if options.include? :user
  params[:password] = options[:password] if options.include? :password

  response = call_server params

  # NotFoundError cannot be raised - no way how to recognize from 401 bad auth
  process_response(response)
end

#get_document(rid) ⇒ Object

:nodoc:



311
312
313
314
315
316
317
318
319
320
321
# File 'lib/orientdb4r/rest/client.rb', line 311

def get_document(rid) #:nodoc:
  rid = Rid.new(rid) unless rid.is_a? Rid
  response = call_server(:method => :get, :uri => "document/#{@database}/#{rid.unprefixed}")
  rslt = process_response(response) do
    raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
    raise NotFoundError, 'record not found' if response.body =~ /Record with id .* was not found/ # why after delete?
  end

  rslt.extend Orientdb4r::DocumentMetadata
  rslt
end

#list_databasesObject

:nodoc:



223
224
225
226
227
# File 'lib/orientdb4r/rest/client.rb', line 223

def list_databases() #:nodoc:
  response = call_server :method => :get, :uri => 'listDatabases', :no_session => true
  rslt = process_response(response)
  rslt['databases']
end

#query(sql, options = nil) ⇒ Object

———————————————————————- SQL

Raises:

  • (ArgumentError)


231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/orientdb4r/rest/client.rb', line 231

def query(sql, options=nil) #:nodoc:
  raise ArgumentError, 'query is blank' if blank? sql

  options_pattern = { :limit => :optional }
  verify_options(options, options_pattern) unless options.nil?

  limit = ''
  limit = "/#{options[:limit]}" if !options.nil? and options.include?(:limit)

  response = call_server(:method => :get, :uri => "query/#{@database}/sql/#{CGI::escape(sql)}#{limit}")
  entries = process_response(response) do
    raise NotFoundError, 'record not found' if response.body =~ /ORecordNotFoundException/
  end

  rslt = entries['result']
  # mixin all document entries (they have '@class' attribute)
  rslt.each { |doc| doc.extend Orientdb4r::DocumentMetadata unless doc['@class'].nil? }
  rslt
end

#server(options = {}) ⇒ Object

:nodoc:



141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/orientdb4r/rest/client.rb', line 141

def server(options={}) #:nodoc:
  options_pattern = { :user => :optional, :password => :optional }
  verify_options(options, options_pattern)

  params = { :method => :get, :uri => 'server' }
  params[:no_session] = true # out of existing session which represents an already done authentication

  # additional authentication allowed, overriden in 'call_server' if not defined
  params[:user] = options[:user] if options.include? :user
  params[:password] = options[:password] if options.include? :password

  response = call_server params
  process_response(response)
end

#update_document(doc) ⇒ Object

:nodoc:

Raises:

  • (ArgumentError)


324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/orientdb4r/rest/client.rb', line 324

def update_document(doc) #:nodoc:
  raise ArgumentError, 'document is nil' if doc.nil?
  raise ArgumentError, 'document has no RID' if doc.doc_rid.nil?
  raise ArgumentError, 'document has no version' if doc.doc_version.nil?

  rid = doc.doc_rid
  doc.delete '@rid' # will be not updated

  response = call_server(:method => :put, :uri => "document/#{@database}/#{rid.unprefixed}", \
      :content_type => 'application/json', :data => doc.to_json)
  process_response(response) do
    raise DataError, 'concurrent modification' if response.body =~ /OConcurrentModificationException/
    raise DataError, 'validation problem' if response.body =~ /OValidationException/
  end
  # empty http response
end