Class: OData4::Entity

Inherits:
Object
  • Object
show all
Defined in:
lib/odata4/entity.rb

Overview

An OData4::Entity represents a single record returned by the service. All Entities have a type and belong to a specific namespace. They are written back to the service via the EntitySet they came from. OData4::Entity instances should not be instantiated directly; instead, they should either be read or instantiated from their respective OData4::EntitySet.

Constant Summary collapse

PROPERTY_NOT_LOADED =
:not_loaded
XML_NAMESPACES =
{
  'xmlns'           => 'http://www.w3.org/2005/Atom',
  'xmlns:data'      => 'http://docs.oasis-open.org/odata/ns/data',
  'xmlns:metadata'  => 'http://docs.oasis-open.org/odata/ns/metadata',
  'xmlns:georss'    => 'http://www.georss.org/georss',
  'xmlns:gml'       => 'http://www.opengis.net/gml',
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Entity

Initializes a bare Entity

Parameters:

  • options (Hash) (defaults to: {})


29
30
31
32
33
34
35
36
37
# File 'lib/odata4/entity.rb', line 29

def initialize(options = {})
  @id = options[:id]
  @type = options[:type]
  @service_name = options[:service_name]
  @entity_set = options[:entity_set]
  @context = options[:context]
  @links = options[:links]
  @errors = []
end

Instance Attribute Details

#entity_setObject (readonly)

The entity set this entity belongs to



13
14
15
# File 'lib/odata4/entity.rb', line 13

def entity_set
  @entity_set
end

#errorsObject (readonly)

List of errors on entity



15
16
17
# File 'lib/odata4/entity.rb', line 15

def errors
  @errors
end

#service_nameObject (readonly)

The OData4::Service’s identifying name



11
12
13
# File 'lib/odata4/entity.rb', line 11

def service_name
  @service_name
end

#typeObject (readonly)

The Entity type name



9
10
11
# File 'lib/odata4/entity.rb', line 9

def type
  @type
end

Class Method Details

.from_json(json, options = {}) ⇒ OData4::Entity

Create Entity from JSON document with provided options.

Parameters:

  • json (Hash|to_s)
  • options (Hash) (defaults to: {})

Returns:



144
145
146
147
148
149
150
151
152
# File 'lib/odata4/entity.rb', line 144

def self.from_json(json, options = {})
  return nil if json.nil?
  json = JSON.parse(json.to_s) unless json.is_a?(Hash)
   = (json)
  options.merge!(context: ['@odata.context'])
  entity = with_properties(json, options)
  (entity, )
  entity
end

.from_xml(xml_doc, options = {}) ⇒ OData4::Entity

Create Entity from XML document with provided options.

Parameters:

  • xml_doc (Nokogiri::XML)
  • options (Hash) (defaults to: {})

Returns:



158
159
160
161
162
163
164
# File 'lib/odata4/entity.rb', line 158

def self.from_xml(xml_doc, options = {})
  return nil if xml_doc.nil?
  entity = OData4::Entity.new(options)
  process_properties(entity, xml_doc)
  process_links(entity, xml_doc)
  entity
end

.with_properties(new_properties = {}, options = {}) ⇒ Object

Create Entity with provided properties and options.

Parameters:

  • new_properties (Hash) (defaults to: {})
  • options (Hash) (defaults to: {})
  • (OData4::Entity)


126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/odata4/entity.rb', line 126

def self.with_properties(new_properties = {}, options = {})
  entity = OData4::Entity.new(options)
  entity.instance_eval do
    service.properties_for_entity(type).each do |property_name, instance|
      set_property(property_name, instance)
    end

    new_properties.each do |property_name, property_value|
      self[property_name] = property_value
    end
  end
  entity
end

Instance Method Details

#[](property_name) ⇒ *

Get property value

Parameters:

  • property_name (to_s)

Returns:

  • (*)


58
59
60
61
62
63
64
# File 'lib/odata4/entity.rb', line 58

def [](property_name)
  if get_property(property_name).is_a?(::OData4::Properties::Complex)
    get_property(property_name)
  else
    get_property(property_name).value
  end
end

#[]=(property_name, value) ⇒ Object

Set property value

Parameters:

  • property_name (to_s)
  • value (*)


69
70
71
# File 'lib/odata4/entity.rb', line 69

def []=(property_name, value)
  get_property(property_name).value = value
end

#any_errors?Boolean

Returns:

  • (Boolean)


224
225
226
# File 'lib/odata4/entity.rb', line 224

def any_errors?
  !errors.empty?
end

#contextString

Returns context URL for this entity

Returns:

  • (String)


51
52
53
# File 'lib/odata4/entity.rb', line 51

def context
  @context ||= context_url
end

#get_property(property_name) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/odata4/entity.rb', line 73

def get_property(property_name)
  prop_name = property_name.to_s
  # Property is lazy loaded
  if properties_xml_value.has_key?(prop_name)
    property = instantiate_property(prop_name, properties_xml_value[prop_name])
    set_property(prop_name, property.dup)
    properties_xml_value.delete(prop_name)
  end

  if properties.has_key? prop_name
    properties[prop_name]
  elsif navigation_properties.has_key? prop_name
    navigation_properties[prop_name]
  else
    raise ArgumentError, "Unknown property: #{property_name}"
  end
end

#idString

Returns the canonical URL for this entity

Returns:

  • (String)


206
207
208
209
210
211
212
# File 'lib/odata4/entity.rb', line 206

def id
  @id ||= lambda {
    entity_set = self.entity_set.andand.name
    entity_set ||= context.split('#').last.split('/').first
    "#{entity_set}(#{self[primary_key]})"
  }.call
end

#is_new?Boolean

Returns:

  • (Boolean)


220
221
222
# File 'lib/odata4/entity.rb', line 220

def is_new?
  self[primary_key].nil?
end

Links to other OData4 entitites

Returns:

  • (Hash)


113
114
115
116
117
118
119
120
# File 'lib/odata4/entity.rb', line 113

def links
  @links ||= schema.navigation_properties[name].map do |nav_name, details|
    [
      nav_name,
      { type: details.nav_type, href: "#{id}/#{nav_name}" }
    ]
  end.to_h
end

#nameString

Returns name of Entity from Service specified type.

Returns:

  • (String)


45
46
47
# File 'lib/odata4/entity.rb', line 45

def name
  @name ||= type.split('.').last
end

#namespaceObject



39
40
41
# File 'lib/odata4/entity.rb', line 39

def namespace
  @namespace ||= type.rpartition('.').first
end


102
103
104
105
106
107
108
109
# File 'lib/odata4/entity.rb', line 102

def navigation_properties
  @navigation_properties ||= links.keys.map do |nav_name|
    [
      nav_name,
      OData4::NavigationProperty::Proxy.new(self, nav_name)
    ]
  end.to_h
end


98
99
100
# File 'lib/odata4/entity.rb', line 98

def navigation_property_names
  navigation_properties.keys
end

#primary_keyString

Returns the primary key for the Entity.

Returns:

  • (String)


216
217
218
# File 'lib/odata4/entity.rb', line 216

def primary_key
  schema.primary_key_for(name)
end

#property_namesObject



91
92
93
94
95
96
# File 'lib/odata4/entity.rb', line 91

def property_names
  [
    @properties_xml_value.andand.keys,
    @properties.andand.keys
  ].compact.flatten
end

#schemaObject



232
233
234
# File 'lib/odata4/entity.rb', line 232

def schema
  @schema ||= service.schemas[namespace]
end

#serviceObject



228
229
230
# File 'lib/odata4/entity.rb', line 228

def service
  @service ||= OData4::ServiceRegistry[service_name]
end

#to_hashHash

Converts Entity to a hash.

Returns:

  • (Hash)


198
199
200
201
202
# File 'lib/odata4/entity.rb', line 198

def to_hash
  property_names.map do |name|
    [name, get_property(name).json_value]
  end.to_h
end

#to_jsonString

Converts Entity to its JSON representation.

Returns:

  • (String)


191
192
193
194
# File 'lib/odata4/entity.rb', line 191

def to_json
  # TODO: add @odata.context
  to_hash.to_json
end

#to_xmlString

Converts Entity to its XML representation.

Returns:

  • (String)


168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/odata4/entity.rb', line 168

def to_xml
  namespaces = XML_NAMESPACES.merge('xml:base' => service.service_url)
  builder = Nokogiri::XML::Builder.new do |xml|
    xml.entry(namespaces) do
      xml.category(term: type,
                   scheme: 'http://docs.oasis-open.org/odata/ns/scheme')
      xml.author { xml.name }

      xml.content(type: 'application/xml') do
        xml['metadata'].properties do
          property_names.each do |name|
            next if name == primary_key
            get_property(name).to_xml(xml)
          end
        end
      end
    end
  end
  builder.to_xml
end