odata4 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.autotest +2 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +75 -0
  8. data/CHANGELOG.md +120 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +23 -0
  11. data/README.md +287 -0
  12. data/Rakefile +7 -0
  13. data/TODO.md +55 -0
  14. data/lib/odata4.rb +37 -0
  15. data/lib/odata4/complex_type.rb +76 -0
  16. data/lib/odata4/complex_type/property.rb +114 -0
  17. data/lib/odata4/entity.rb +319 -0
  18. data/lib/odata4/entity_set.rb +162 -0
  19. data/lib/odata4/enum_type.rb +95 -0
  20. data/lib/odata4/enum_type/property.rb +62 -0
  21. data/lib/odata4/navigation_property.rb +29 -0
  22. data/lib/odata4/navigation_property/proxy.rb +76 -0
  23. data/lib/odata4/properties.rb +25 -0
  24. data/lib/odata4/properties/binary.rb +50 -0
  25. data/lib/odata4/properties/boolean.rb +37 -0
  26. data/lib/odata4/properties/date.rb +27 -0
  27. data/lib/odata4/properties/date_time.rb +83 -0
  28. data/lib/odata4/properties/date_time_offset.rb +17 -0
  29. data/lib/odata4/properties/decimal.rb +50 -0
  30. data/lib/odata4/properties/float.rb +67 -0
  31. data/lib/odata4/properties/geography.rb +13 -0
  32. data/lib/odata4/properties/geography/base.rb +162 -0
  33. data/lib/odata4/properties/geography/line_string.rb +33 -0
  34. data/lib/odata4/properties/geography/point.rb +31 -0
  35. data/lib/odata4/properties/geography/polygon.rb +38 -0
  36. data/lib/odata4/properties/guid.rb +17 -0
  37. data/lib/odata4/properties/integer.rb +107 -0
  38. data/lib/odata4/properties/number.rb +14 -0
  39. data/lib/odata4/properties/string.rb +72 -0
  40. data/lib/odata4/properties/time.rb +40 -0
  41. data/lib/odata4/properties/time_of_day.rb +27 -0
  42. data/lib/odata4/property.rb +118 -0
  43. data/lib/odata4/property_registry.rb +41 -0
  44. data/lib/odata4/query.rb +231 -0
  45. data/lib/odata4/query/criteria.rb +92 -0
  46. data/lib/odata4/query/criteria/comparison_operators.rb +49 -0
  47. data/lib/odata4/query/criteria/date_functions.rb +61 -0
  48. data/lib/odata4/query/criteria/geography_functions.rb +21 -0
  49. data/lib/odata4/query/criteria/lambda_operators.rb +27 -0
  50. data/lib/odata4/query/criteria/string_functions.rb +40 -0
  51. data/lib/odata4/query/in_batches.rb +58 -0
  52. data/lib/odata4/query/result.rb +84 -0
  53. data/lib/odata4/query/result/atom.rb +41 -0
  54. data/lib/odata4/query/result/json.rb +42 -0
  55. data/lib/odata4/railtie.rb +19 -0
  56. data/lib/odata4/service.rb +344 -0
  57. data/lib/odata4/service_registry.rb +52 -0
  58. data/lib/odata4/version.rb +3 -0
  59. data/odata4.gemspec +34 -0
  60. data/spec/fixtures/files/entity_to_xml.xml +17 -0
  61. data/spec/fixtures/files/metadata.xml +150 -0
  62. data/spec/fixtures/files/product_0.json +10 -0
  63. data/spec/fixtures/files/product_0.xml +28 -0
  64. data/spec/fixtures/files/products.json +106 -0
  65. data/spec/fixtures/files/products.xml +308 -0
  66. data/spec/fixtures/files/supplier_0.json +26 -0
  67. data/spec/fixtures/files/supplier_0.xml +32 -0
  68. data/spec/fixtures/vcr_cassettes/complex_type_specs.yml +127 -0
  69. data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1348 -0
  70. data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
  71. data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
  72. data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
  73. data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
  74. data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
  75. data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
  76. data/spec/fixtures/vcr_cassettes/query_specs.yml +663 -0
  77. data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
  78. data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
  79. data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +749 -0
  80. data/spec/odata4/complex_type_spec.rb +116 -0
  81. data/spec/odata4/entity/shared_examples.rb +82 -0
  82. data/spec/odata4/entity_set_spec.rb +168 -0
  83. data/spec/odata4/entity_spec.rb +151 -0
  84. data/spec/odata4/enum_type_spec.rb +134 -0
  85. data/spec/odata4/navigation_property/proxy_spec.rb +44 -0
  86. data/spec/odata4/navigation_property_spec.rb +55 -0
  87. data/spec/odata4/properties/binary_spec.rb +50 -0
  88. data/spec/odata4/properties/boolean_spec.rb +72 -0
  89. data/spec/odata4/properties/date_spec.rb +23 -0
  90. data/spec/odata4/properties/date_time_offset_spec.rb +30 -0
  91. data/spec/odata4/properties/date_time_spec.rb +23 -0
  92. data/spec/odata4/properties/decimal_spec.rb +24 -0
  93. data/spec/odata4/properties/float_spec.rb +45 -0
  94. data/spec/odata4/properties/geography/line_string_spec.rb +33 -0
  95. data/spec/odata4/properties/geography/point_spec.rb +29 -0
  96. data/spec/odata4/properties/geography/polygon_spec.rb +55 -0
  97. data/spec/odata4/properties/geography/shared_examples.rb +72 -0
  98. data/spec/odata4/properties/guid_spec.rb +17 -0
  99. data/spec/odata4/properties/integer_spec.rb +58 -0
  100. data/spec/odata4/properties/string_spec.rb +46 -0
  101. data/spec/odata4/properties/time_of_day_spec.rb +23 -0
  102. data/spec/odata4/properties/time_spec.rb +15 -0
  103. data/spec/odata4/property_registry_spec.rb +16 -0
  104. data/spec/odata4/property_spec.rb +32 -0
  105. data/spec/odata4/query/criteria_spec.rb +229 -0
  106. data/spec/odata4/query/result_spec.rb +53 -0
  107. data/spec/odata4/query_spec.rb +196 -0
  108. data/spec/odata4/service_registry_spec.rb +18 -0
  109. data/spec/odata4/service_spec.rb +80 -0
  110. data/spec/odata4/usage_example_spec.rb +176 -0
  111. data/spec/spec_helper.rb +32 -0
  112. data/spec/support/coverage.rb +2 -0
  113. data/spec/support/vcr.rb +9 -0
  114. metadata +380 -0
@@ -0,0 +1,33 @@
1
+ module OData4
2
+ module Properties
3
+ module Geography
4
+ class LineString < Base
5
+ def type
6
+ 'Edm.GeographyLineString'
7
+ end
8
+
9
+ def coords_to_s
10
+ value.map { |pos| pos.join(' ') }.join(',')
11
+ end
12
+
13
+ def coords_from_s(str)
14
+ str.split(',').map { |pos| pos.split(' ').map(&:to_f) }
15
+ end
16
+
17
+ def xml_value
18
+ value.map do |coords|
19
+ { pos: coords.join(' ') }
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def self.parse_xml(property_xml)
26
+ property_xml.xpath('//pos').map do |el|
27
+ el.content.split(' ').map(&:to_f)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ module OData4
2
+ module Properties
3
+ module Geography
4
+ class Point < Base
5
+ def type
6
+ 'Edm.GeographyPoint'
7
+ end
8
+
9
+ def coords_to_s
10
+ value.join(' ')
11
+ end
12
+
13
+ def coords_from_s(str)
14
+ str.split(' ').map(&:to_f)
15
+ end
16
+
17
+ def xml_value
18
+ { pos: coords_to_s }
19
+ end
20
+
21
+ private
22
+
23
+ def self.parse_xml(property_xml)
24
+ property_xml.xpath('//pos').map do |el|
25
+ el.content.split(' ').map(&:to_f)
26
+ end.flatten
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ module OData4
2
+ module Properties
3
+ module Geography
4
+ class Polygon < Base
5
+ def type
6
+ 'Edm.GeographyPolygon'
7
+ end
8
+
9
+ def coords_to_s
10
+ '(' + value.map { |pos| pos.join(' ') }.join(',') + ')'
11
+ end
12
+
13
+ def coords_from_s(str)
14
+ str.gsub(/[()]/, '')
15
+ .split(',').map { |pos| pos.split(' ').map(&:to_f) }
16
+ end
17
+
18
+ def xml_value
19
+ {
20
+ exterior: {
21
+ LinearRing: value.map do |coords|
22
+ { pos: coords.join(' ') }
23
+ end
24
+ }
25
+ }
26
+ end
27
+
28
+ private
29
+
30
+ def self.parse_xml(property_xml)
31
+ property_xml.xpath('//pos').map do |el|
32
+ el.content.split(' ').map(&:to_f)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ module OData4
2
+ module Properties
3
+ # Defines the GUID OData4 type.
4
+ class Guid < OData4::Property
5
+ # The OData4 type name
6
+ def type
7
+ 'Edm.Guid'
8
+ end
9
+
10
+ # Value to be used in URLs.
11
+ # @return [String]
12
+ def url_value
13
+ "guid'#{value}'"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,107 @@
1
+ module OData4
2
+ module Properties
3
+ # Defines the Integer OData4 type.
4
+ class Integer < OData4::Property
5
+ include OData4::Properties::Number
6
+
7
+ # Returns the property value, properly typecast
8
+ # @return [Integer,nil]
9
+ def value
10
+ if (@value.nil? || @value.empty?) && allows_nil?
11
+ nil
12
+ else
13
+ @value.to_i
14
+ end
15
+ end
16
+
17
+ # Sets the property value
18
+ # @params new_value [to_i]
19
+ def value=(new_value)
20
+ validate(new_value.to_i)
21
+ @value = new_value.to_i.to_s
22
+ end
23
+
24
+ # The OData4 type name
25
+ def type
26
+ 'Edm.Int64'
27
+ end
28
+
29
+ private
30
+
31
+ def exponent_size
32
+ 63
33
+ end
34
+
35
+ def min_value
36
+ @min ||= -(2**exponent_size)
37
+ end
38
+
39
+ def max_value
40
+ @max ||= (2**exponent_size)-1
41
+ end
42
+ end
43
+
44
+ # Defines the Integer (16 bit) OData4 type.
45
+ class Int16 < Integer
46
+ # The OData4 type name
47
+ def type
48
+ 'Edm.Int16'
49
+ end
50
+
51
+ private
52
+
53
+ def exponent_size
54
+ 15
55
+ end
56
+ end
57
+
58
+ # Defines the Integer (32 bit) OData4 type.
59
+ class Int32 < Integer
60
+ # The OData4 type name
61
+ def type
62
+ 'Edm.Int32'
63
+ end
64
+
65
+ private
66
+
67
+ def exponent_size
68
+ 31
69
+ end
70
+ end
71
+
72
+ # Defines the Integer (64 bit) OData4 type.
73
+ class Int64 < Integer; end
74
+
75
+ # Defines the Byte OData4 type.
76
+ class Byte < Integer
77
+ # The OData4 type name
78
+ def type
79
+ 'Edm.Byte'
80
+ end
81
+
82
+ private
83
+
84
+ def exponent_size
85
+ 8
86
+ end
87
+
88
+ def min_value
89
+ 0
90
+ end
91
+ end
92
+
93
+ # Defines the Signed Byte OData4 type.
94
+ class SByte < Integer
95
+ # The OData4 type name
96
+ def type
97
+ 'Edm.SByte'
98
+ end
99
+
100
+ private
101
+
102
+ def exponent_size
103
+ 7
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,14 @@
1
+ module OData4
2
+ module Properties
3
+ # Defines common behavior for OData4 numeric types.
4
+ module Number
5
+ private
6
+
7
+ def validate(value)
8
+ if value > max_value || value < min_value
9
+ raise ::ArgumentError, "Value is outside accepted range: #{min_value} to #{max_value}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,72 @@
1
+ module OData4
2
+ module Properties
3
+ # Defines the String OData4 type.
4
+ class String < OData4::Property
5
+ # Returns the property value, properly typecast
6
+ # @return [String,nil]
7
+ def value
8
+ if (@value.nil? || @value.empty?) && allows_nil?
9
+ nil
10
+ else
11
+ encode_value(@value)
12
+ end
13
+ end
14
+
15
+ # Sets the property value
16
+ # @params new_value [to_s,nil]
17
+ def value=(new_value)
18
+ validate(new_value)
19
+ @value = new_value.nil? ? nil : encode_value(new_value.to_s)
20
+ end
21
+
22
+ # Value to be used in URLs.
23
+ # @return [String]
24
+ def url_value
25
+ "'#{value}'"
26
+ end
27
+
28
+ # The OData4 type name
29
+ def type
30
+ 'Edm.String'
31
+ end
32
+
33
+ # Is the property value Unicode encoded
34
+ def is_unicode?
35
+ options[:unicode]
36
+ end
37
+
38
+ # Does the property have a default value
39
+ def has_default_value?
40
+ not(options[:default_value].nil?)
41
+ end
42
+
43
+ # The default value for the property
44
+ def default_value
45
+ options[:default_value]
46
+ end
47
+
48
+ private
49
+
50
+ def default_options
51
+ super.merge({
52
+ unicode: true,
53
+ default_value: nil
54
+ })
55
+ end
56
+
57
+ def validate(new_value)
58
+ if new_value.nil? && !allows_nil?
59
+ raise ArgumentError, 'This property does not allow for nil values to be set'
60
+ end
61
+ end
62
+
63
+ def encode_value(new_value)
64
+ if options[:unicode]
65
+ new_value.encode(Encoding::UTF_8)
66
+ else
67
+ new_value.encode(Encoding::ASCII)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,40 @@
1
+ module OData4
2
+ module Properties
3
+ # Defines the Time OData4 type.
4
+ class Time < OData4::Property
5
+ # Returns the property value, properly typecast
6
+ # @return [Time,nil]
7
+ def value
8
+ if (@value.nil? || @value.empty?) && allows_nil?
9
+ nil
10
+ else
11
+ ::Time.strptime(@value, '%H:%M:%S%:z')
12
+ end
13
+ end
14
+
15
+ # Sets the property value
16
+ # @params new_value [Time]
17
+ def value=(new_value)
18
+ validate(new_value)
19
+ @value = parse_value(new_value)
20
+ end
21
+
22
+ # The OData4 type name
23
+ def type
24
+ 'Edm.Time'
25
+ end
26
+
27
+ private
28
+
29
+ def validate(value)
30
+ unless value.is_a?(::Time)
31
+ raise ArgumentError, 'Value is not a time object'
32
+ end
33
+ end
34
+
35
+ def parse_value(value)
36
+ value.strftime('%H:%M:%S%:z')
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ require 'odata4/properties/date_time'
2
+
3
+ module OData4
4
+ module Properties
5
+ # Defines the Date OData4 type.
6
+ class TimeOfDay < OData4::Properties::DateTime
7
+ # The OData4 type name
8
+ def type
9
+ 'Edm.TimeOfDay'
10
+ end
11
+
12
+ def url_value
13
+ @value
14
+ end
15
+
16
+ protected
17
+
18
+ def date_class
19
+ ::Time
20
+ end
21
+
22
+ def strptime_format
23
+ '%H:%M:%S.%L'
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,118 @@
1
+ module OData4
2
+ # OData4::Property represents an abstract property, defining the basic
3
+ # interface and required methods, with some default implementations. All
4
+ # supported property types should be implemented under the OData4::Properties
5
+ # namespace.
6
+ class Property
7
+ # The property's name
8
+ attr_reader :name
9
+ # The property's value
10
+ attr_accessor :value
11
+
12
+ # Default intialization for a property with a name, value and options.
13
+ # @param name [to_s]
14
+ # @param value [to_s,nil]
15
+ # @param options [Hash]
16
+ def initialize(name, value, options = {})
17
+ @name = name.to_s
18
+ @value = value.nil? ? nil : value.to_s
19
+ @options = default_options.merge(options)
20
+ end
21
+
22
+ # Abstract implementation, should return property type, based on
23
+ # OData4::Service metadata in proper implementation.
24
+ # @raise NotImplementedError
25
+ def type
26
+ raise NotImplementedError
27
+ end
28
+
29
+ # Provides for value-based equality checking.
30
+ # @param other [value] object for comparison
31
+ # @return [Boolean]
32
+ def ==(other)
33
+ self.value == other.value
34
+ end
35
+
36
+ # Whether the property permits a nil value.
37
+ # (Default=true)
38
+ # @return [Boolean]
39
+ def allows_nil?
40
+ options[:allows_nil]
41
+ end
42
+
43
+ # Whether the property uses strict validation.
44
+ # (Default=false)
45
+ # @return [Boolean]
46
+ def strict?
47
+ options[:strict]
48
+ end
49
+
50
+ # The configured concurrency mode for the property.
51
+ # @return [String]
52
+ def concurrency_mode
53
+ @concurrecy_mode ||= options[:concurrency_mode]
54
+ end
55
+
56
+ # Value to be used in XML.
57
+ # @return [String]
58
+ def xml_value
59
+ @value
60
+ end
61
+
62
+ # Value to be used in JSON.
63
+ # @return [*]
64
+ def json_value
65
+ value
66
+ end
67
+
68
+ # Value to be used in URLs.
69
+ # @return [String]
70
+ def url_value
71
+ @value
72
+ end
73
+
74
+ # Returns the XML representation of the property to the supplied XML
75
+ # builder.
76
+ # @param xml_builder [Nokogiri::XML::Builder]
77
+ def to_xml(xml_builder)
78
+ attributes = {
79
+ 'metadata:type' => type,
80
+ }
81
+
82
+ if value.nil?
83
+ attributes['metadata:null'] = 'true'
84
+ xml_builder['data'].send(name.to_sym, attributes)
85
+ else
86
+ xml_builder['data'].send(name.to_sym, attributes, xml_value)
87
+ end
88
+ end
89
+
90
+ # Creates a new property instance from an XML element
91
+ # @param property_xml [Nokogiri::XML::Element]
92
+ # @param options [Hash]
93
+ # @return [OData4::Property]
94
+ def self.from_xml(property_xml, options = {})
95
+ if property_xml.attributes['null'].andand.value == 'true'
96
+ content = nil
97
+ else
98
+ content = property_xml.content
99
+ end
100
+
101
+ new(property_xml.name, content, options)
102
+ end
103
+
104
+ private
105
+
106
+ def default_options
107
+ {
108
+ allows_nil: true,
109
+ concurrency_mode: :none,
110
+ strict: false
111
+ }
112
+ end
113
+
114
+ def options
115
+ @options
116
+ end
117
+ end
118
+ end