class OData4::Service

Encapsulates the basic details and functionality needed to interact with an OData4 service.

Constants

DEFAULT_TIMEOUT
METADATA_TIMEOUTS
MIME_TYPES

Attributes

connection[R]

The Faraday connection object used by the service to make requests

options[R]

Service options

service_url[R]

The OData4 Service's URL

Public Class Methods

new(service_url, options = {}, &block) click to toggle source

Opens the service based on the requested URL and adds the service to {OData4::Registry}

@param service_url [String|Faraday::Connection]

The URL to the desired OData4 service, or a Faraday connection object

@param options [Hash] options to pass to the service @return [OData4::Service] an instance of the service

# File lib/odata4/service.rb, line 33
def initialize(service_url, options = {}, &block)
  if service_url.is_a? Faraday::Connection
    @connection  = service_url
    @service_url = connection.url_prefix
  else
    @service_url = service_url
    @connection  = Faraday.new(service_url, options[:connection], &block)
  end
  @options     = default_options.merge(options)
  OData4::ServiceRegistry.add(self)
  register_custom_types
end
open(service_url, options = {}, &block) click to toggle source

Opens the service based on the requested URL and adds the service to {OData4::Registry} @deprecated Use {Service.new} instead.

@param service_url [String] the URL to the desired OData4 service @param options [Hash] options to pass to the service @return [OData4::Service] an instance of the service

# File lib/odata4/service.rb, line 53
def self.open(service_url, options = {}, &block)
  Service.new(service_url, options, &block)
end

Public Instance Methods

[](entity_set_name) click to toggle source

Retrieves the EntitySet associated with a specific EntityType by name

@param entity_set_name [to_s] the name of the EntitySet desired @return [OData4::EntitySet] an OData4::EntitySet to query

# File lib/odata4/service.rb, line 102
def [](entity_set_name)
  entity_container[entity_set_name]
end
complex_types() click to toggle source

Returns a list of `ComplexType`s used by the service. @return [Hash<String, OData4::Schema::ComplexType>]

# File lib/odata4/service.rb, line 125
def complex_types
  @complex_types ||= schemas.map do |namespace, schema|
    schema.complex_types.map do |name, complex_type|
      [ "#{namespace}.#{name}", complex_type ]
    end.to_h
  end.reduce({}, :merge)
end
entity_container() click to toggle source

Returns the service's EntityContainer (singleton) @return OData4::EntityContainer

# File lib/odata4/service.rb, line 88
def entity_container
  @entity_container ||= EntityContainer.new(self)
end
entity_sets() click to toggle source

Returns a hash of EntitySet names and their respective EntityType names @return Hash<String, String>

# File lib/odata4/service.rb, line 94
def entity_sets
  entity_container.entity_sets
end
entity_types() click to toggle source

Returns a list of `EntityType`s exposed by the service @return Array<String>

# File lib/odata4/service.rb, line 115
def entity_types
  @entity_types ||= schemas.map do |namespace, schema|
    schema.entity_types.map do |entity_type|
      "#{namespace}.#{entity_type}"
    end
  end.flatten
end
enum_types() click to toggle source

Returns a list of `EnumType`s used by the service @return [Hash<String, OData4::Schema::EnumType>]

# File lib/odata4/service.rb, line 135
def enum_types
  @enum_types ||= schemas.map do |namespace, schema|
    schema.enum_types.map do |name, enum_type|
      [ "#{namespace}.#{name}", enum_type ]
    end.to_h
  end.reduce({}, :merge)
end
execute(url_chunk, options = {}) click to toggle source

Execute a request against the service

@param url_chunk [to_s] string to append to service URL @param options [Hash] additional request options @return [OData4::Service::Response]

# File lib/odata4/service.rb, line 153
def execute(url_chunk, options = {})
  Request.new(self, url_chunk, options).execute
end
get_property_type(entity_name, property_name) click to toggle source

Get the property type for an entity from metadata.

@param entity_name [to_s] the fully qualified entity name @param property_name [to_s] the property name needed @return [String] the name of the property's type

# File lib/odata4/service.rb, line 162
def get_property_type(entity_name, property_name)
  namespace, _, entity_name = entity_name.rpartition('.')
  raise ArgumentError, 'Namespace missing' if namespace.nil? || namespace.empty?
  schemas[namespace].get_property_type(entity_name, property_name)
end
inspect() click to toggle source

Returns a more compact inspection of the service object

# File lib/odata4/service.rb, line 144
def inspect
  "#<#{self.class.name}:#{self.object_id} name='#{name}' service_url='#{self.service_url}'>"
end
logger() click to toggle source

Returns the logger instance used by the service. When Ruby on Rails has been detected, the service will use `Rails.logger`. The log level will NOT be changed.

When no Rails has been detected, a default logger will be used that logs to STDOUT with the log level supplied via options, or the default log level if none was given. @return [Logger]

# File lib/odata4/service.rb, line 197
def logger
  @logger ||= options[:logger] || if defined?(Rails)
    Rails.logger
  else
    default_logger
  end
end
logger=(custom_logger) click to toggle source

Allows the logger to be set to a custom `Logger` instance. @param custom_logger [Logger]

# File lib/odata4/service.rb, line 207
def logger=(custom_logger)
  @logger = custom_logger
end
metadata() click to toggle source

Returns the service's metadata definition. @return [Nokogiri::XML]

# File lib/odata4/service.rb, line 71
def metadata
  @metadata ||= lambda { read_metadata }.call
end
metadata_url() click to toggle source

Returns the service's metadata URL. @return [String]

# File lib/odata4/service.rb, line 65
def metadata_url
  "#{service_url}/$metadata"
end
name() click to toggle source

Returns user supplied name for service, or its URL @return [String]

# File lib/odata4/service.rb, line 59
def name
  @name ||= options[:name] || service_url
end
namespace() click to toggle source

Returns the default namespace, that is, the namespace of the schema that contains the service's EntityContainer. @return [String]

# File lib/odata4/service.rb, line 109
def namespace
  entity_container.namespace
end
primary_key_for(entity_name) click to toggle source

Get the primary key for the supplied Entity.

@param entity_name [to_s] The fully qualified entity name @return [String]

# File lib/odata4/service.rb, line 172
def primary_key_for(entity_name)
  namespace, _, entity_name = entity_name.rpartition('.')
  raise ArgumentError, 'Namespace missing' if namespace.nil? || namespace.empty?
  schemas[namespace].primary_key_for(entity_name)
end
properties_for_entity(entity_name) click to toggle source

Get the list of properties and their various options for the supplied Entity name. @param entity_name [to_s] @return [Hash] @api private

# File lib/odata4/service.rb, line 183
def properties_for_entity(entity_name)
  namespace, _, entity_name = entity_name.rpartition('.')
  raise ArgumentError, 'Namespace missing' if namespace.nil? || namespace.empty?
  schemas[namespace].properties_for_entity(entity_name)
end
schemas() click to toggle source

Returns all of the service's schemas. @return Hash<String, OData4::Schema>

# File lib/odata4/service.rb, line 77
def schemas
  @schemas ||= metadata.xpath('//Schema').map do |schema_xml|
    [
      schema_xml.attributes['Namespace'].value,
      Schema.new(schema_xml, self)
    ]
  end.to_h
end

Private Instance Methods

default_logger() click to toggle source
# File lib/odata4/service.rb, line 222
def default_logger
  Logger.new(STDOUT).tap do |logger|
    logger.level = options[:log_level] || Logger::WARN
  end
end
default_options() click to toggle source
# File lib/odata4/service.rb, line 213
def default_options
  {
    request: {
      timeout: DEFAULT_TIMEOUT
    },
    strict: true # strict property validation
  }
end
read_metadata() click to toggle source
# File lib/odata4/service.rb, line 228
def read_metadata
  # From file, good for debugging
  if options[:metadata_file]
    data = File.read(options[:metadata_file])
    ::Nokogiri::XML(data).remove_namespaces!
  else # From a URL
    response = nil
    METADATA_TIMEOUTS.each do |timeout|
      response = execute(metadata_url, timeout: timeout)
      break unless response.timed_out?
    end
    raise "Metadata Timeout" if response.timed_out?
    ::Nokogiri::XML(response.body).remove_namespaces!
  end
end
register_custom_types() click to toggle source
# File lib/odata4/service.rb, line 244
def register_custom_types
  complex_types.each do |name, type|
    ::OData4::PropertyRegistry.add(name, type.property_class)
  end

  enum_types.each do |name, type|
    ::OData4::PropertyRegistry.add(name, type.property_class)
  end
end