microsoft_graph 0.1.1 → 0.1.2

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -11
  3. data/.rspec +2 -2
  4. data/.travis.yml +4 -4
  5. data/Gemfile +4 -4
  6. data/LICENSE +10 -10
  7. data/README.md +98 -98
  8. data/Rakefile +7 -7
  9. data/data/metadata_v1.0.xml +1686 -1686
  10. data/integration_spec/integration_spec_helper.rb +18 -18
  11. data/integration_spec/live_spec.rb +180 -180
  12. data/lib/microsoft_graph.rb +35 -35
  13. data/lib/microsoft_graph/base.rb +110 -110
  14. data/lib/microsoft_graph/base_entity.rb +152 -152
  15. data/lib/microsoft_graph/cached_metadata_directory.rb +3 -3
  16. data/lib/microsoft_graph/class_builder.rb +217 -217
  17. data/lib/microsoft_graph/collection.rb +95 -95
  18. data/lib/microsoft_graph/collection_association.rb +232 -230
  19. data/lib/microsoft_graph/errors.rb +6 -6
  20. data/lib/microsoft_graph/version.rb +3 -3
  21. data/lib/odata.rb +49 -49
  22. data/lib/odata/entity_set.rb +20 -20
  23. data/lib/odata/errors.rb +18 -18
  24. data/lib/odata/navigation_property.rb +30 -30
  25. data/lib/odata/operation.rb +17 -17
  26. data/lib/odata/property.rb +38 -38
  27. data/lib/odata/request.rb +49 -49
  28. data/lib/odata/service.rb +279 -279
  29. data/lib/odata/singleton.rb +20 -20
  30. data/lib/odata/type.rb +25 -25
  31. data/lib/odata/types/collection_type.rb +30 -30
  32. data/lib/odata/types/complex_type.rb +19 -19
  33. data/lib/odata/types/entity_type.rb +33 -33
  34. data/lib/odata/types/enum_type.rb +37 -37
  35. data/lib/odata/types/primitive_type.rb +12 -12
  36. data/lib/odata/types/primitive_types/binary_type.rb +15 -15
  37. data/lib/odata/types/primitive_types/boolean_type.rb +15 -15
  38. data/lib/odata/types/primitive_types/date_time_offset_type.rb +15 -15
  39. data/lib/odata/types/primitive_types/date_type.rb +23 -23
  40. data/lib/odata/types/primitive_types/double_type.rb +16 -16
  41. data/lib/odata/types/primitive_types/guid_type.rb +24 -24
  42. data/lib/odata/types/primitive_types/int_16_type.rb +19 -19
  43. data/lib/odata/types/primitive_types/int_32_type.rb +15 -15
  44. data/lib/odata/types/primitive_types/int_64_type.rb +15 -15
  45. data/lib/odata/types/primitive_types/stream_type.rb +15 -15
  46. data/lib/odata/types/primitive_types/string_type.rb +15 -15
  47. data/microsoft_graph.gemspec +31 -31
  48. data/tasks/update_metadata.rb +17 -17
  49. metadata +5 -5
data/lib/odata/service.rb CHANGED
@@ -1,279 +1,279 @@
1
- module OData
2
- class Service
3
- attr_reader :base_url
4
- attr_reader :metadata
5
-
6
- def initialize(options = {}, &block)
7
- @auth_callback = options[:auth_callback] || block
8
- @base_url = options[:base_url]
9
- @metadata_file = options[:metadata_file]
10
- @type_name_map = {}
11
- @metadata = fetch_metadata
12
- populate_types_from_metadata
13
- end
14
-
15
- def namespace
16
- schema_defintion = metadata.xpath("//Schema") && metadata.xpath("//Schema").first
17
- schema_defintion["Namespace"] if schema_defintion
18
- end
19
-
20
- def inspect
21
- "#<#{self.class} #{base_url}>"
22
- end
23
-
24
- def get(path, *select_properties)
25
- camel_case_select_properties = select_properties.map do |prop|
26
- OData.convert_to_camel_case(prop)
27
- end
28
-
29
- if ! camel_case_select_properties.empty?
30
- encoded_select_properties = URI.encode_www_form(
31
- '$select' => camel_case_select_properties.join(',')
32
- )
33
- path = "#{path}?#{encoded_select_properties}"
34
- end
35
-
36
- response = request(
37
- method: :get,
38
- uri: "#{base_url}#{path}"
39
- )
40
- {type: get_type_for_odata_response(response), attributes: response}
41
- end
42
-
43
- def delete(path)
44
- request(
45
- method: :delete,
46
- uri: "#{base_url}#{path}"
47
- )
48
- end
49
-
50
- def post(path, data)
51
- request(
52
- method: :post,
53
- uri: "#{base_url}#{path}",
54
- data: data
55
- )
56
- end
57
-
58
- def patch(path, data)
59
- request(
60
- method: :patch,
61
- uri: "#{base_url}#{path}",
62
- data: data
63
- )
64
- end
65
-
66
- def request(options = {})
67
- req = Request.new(options[:method], options[:uri], options[:data])
68
- @auth_callback.call(req) if @auth_callback
69
- req.perform
70
- end
71
-
72
- def complex_types
73
- @complex_types ||= metadata.xpath("//ComplexType").map do |complex_type|
74
- @type_name_map["#{namespace}.#{complex_type["Name"]}"] = ComplexType.new(
75
- name: "#{namespace}.#{complex_type["Name"]}",
76
- base_type: complex_type["BaseType"],
77
- service: self,
78
- )
79
- end
80
- end
81
-
82
- def entity_types
83
- @entity_types ||= metadata.xpath("//EntityType").map do |entity|
84
- options = {
85
- name: "#{namespace}.#{entity["Name"]}",
86
- abstract: entity["Abstract"] == "true",
87
- base_type: entity["BaseType"],
88
- open_type: entity["OpenType"] == "true",
89
- has_stream: entity["HasStream"] == "true",
90
- service: self,
91
- }
92
- @type_name_map["#{namespace}.#{entity["Name"]}"] = EntityType.new(options)
93
- end
94
- end
95
-
96
- def enum_types
97
- @enum_types ||= metadata.xpath("//EnumType").map do |type|
98
- members = type.xpath("./Member").map do |m, i|
99
- value = m['Value'] && m['Value'].to_i || i
100
- {
101
- name: m["Name"],
102
- value: value,
103
- }
104
- end
105
- @type_name_map["#{namespace}.#{type["Name"]}"] = EnumType.new({name: "#{namespace}.#{type["Name"]}", members: members})
106
- end
107
- end
108
-
109
- def actions
110
- metadata.xpath("//Action").map do |action|
111
- build_operation(action)
112
- end
113
- end
114
-
115
- def functions
116
- metadata.xpath("//Function").map do |function|
117
- build_operation(function)
118
- end
119
- end
120
-
121
- def populate_primitive_types
122
- @type_name_map.merge!(
123
- "Edm.Binary" => OData::BinaryType.new,
124
- "Edm.Date" => OData::DateType.new,
125
- "Edm.Double" => OData::DoubleType.new,
126
- "Edm.Guid" => OData::GuidType.new,
127
- "Edm.Int16" => OData::Int16Type.new,
128
- "Edm.Int32" => OData::Int32Type.new,
129
- "Edm.Int64" => OData::Int64Type.new,
130
- "Edm.Stream" => OData::StreamType.new,
131
- "Edm.String" => OData::StringType.new,
132
- "Edm.Boolean" => OData::BooleanType.new,
133
- "Edm.DateTimeOffset" => OData::DateTimeOffsetType.new
134
- )
135
- end
136
-
137
- def singletons
138
- metadata.xpath("//Singleton").map do |singleton|
139
- Singleton.new(
140
- name: singleton["Name"],
141
- type: singleton["Type"],
142
- service: self
143
- )
144
- end
145
- end
146
-
147
- def entity_sets
148
- @entity_sets ||= metadata.xpath("//EntitySet").map do |entity_set|
149
- EntitySet.new(
150
- name: entity_set["Name"],
151
- member_type: entity_set["EntityType"],
152
- service: self
153
- )
154
- end
155
- end
156
-
157
- def get_type_for_odata_response(parsed_response)
158
- if odata_type_string = parsed_response["@odata.type"]
159
- get_type_by_name(type_name_from_odata_type_field(odata_type_string))
160
- elsif context = parsed_response["@odata.context"]
161
- singular, segments = segments_from_odata_context_field(context)
162
- first_entity_type = get_type_by_name("Collection(#{entity_set_by_name(segments.shift).member_type})")
163
- entity_type = segments.reduce(first_entity_type) do |last_entity_type, segment|
164
- last_entity_type.member_type.navigation_property_by_name(segment).type
165
- end
166
- singular && entity_type.respond_to?(:member_type) ? entity_type.member_type : entity_type
167
- end
168
- end
169
-
170
- def get_type_by_name(type_name)
171
- @type_name_map[type_name] || build_collection(type_name)
172
- end
173
-
174
- def entity_set_by_name(name)
175
- entity_sets.find { |entity_set| entity_set.name == name }
176
- end
177
-
178
- def properties_for_type(type_name)
179
- raw_type_name = remove_namespace(type_name)
180
- type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
181
- type_definition.xpath("./Property").map do |property|
182
- options = {
183
- name: property["Name"],
184
- nullable: property["Nullable"] != "false",
185
- type: get_type_by_name(property["Type"]),
186
- }
187
- OData::Property.new(options)
188
- end
189
- end
190
-
191
- def navigation_properties_for_type(type_name)
192
- raw_type_name = remove_namespace(type_name)
193
- type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
194
- type_definition.xpath("./NavigationProperty").map do |property|
195
- options = {
196
- name: property["Name"],
197
- nullable: property["Nullable"] != "false",
198
- type: get_type_by_name(property["Type"]),
199
- contains_target: property["ContainsTarget"],
200
- partner: property["Partner"],
201
- }
202
- OData::NavigationProperty.new(options)
203
- end
204
- end
205
-
206
- private
207
-
208
- def type_name_from_odata_type_field(odata_type_field)
209
- odata_type_field.sub("#", '')
210
- end
211
-
212
- def segments_from_odata_context_field(odata_context_field)
213
- segments = odata_context_field.split("$metadata#").last.split("/").map { |s| s.split("(").first }
214
- segments.pop if singular = segments.last == "$entity"
215
- [singular, segments]
216
- end
217
-
218
- def populate_types_from_metadata
219
- enum_types
220
- populate_primitive_types
221
- complex_types
222
- entity_types
223
- end
224
-
225
- def fetch_metadata
226
- response = if @metadata_file
227
- File.read(@metadata_file)
228
- else # From a URL
229
- uri = URI("#{base_url}$metadata?detailed=true")
230
- Net::HTTP
231
- .new(uri.hostname, uri.port)
232
- .tap { |h| h.use_ssl = uri.scheme == "https" }
233
- .get(uri).body
234
- end
235
- ::Nokogiri::XML(response).remove_namespaces!
236
- end
237
-
238
- def build_collection(collection_name)
239
- member_type_name = collection_name.gsub(/Collection\(([^)]+)\)/, "\\1")
240
- CollectionType.new(name: collection_name, member_type: @type_name_map[member_type_name])
241
- end
242
-
243
- def build_operation(operation_xml)
244
- binding_type = if operation_xml["IsBound"] == "true"
245
- type_name = operation_xml.xpath("./Parameter[@Name='bindingParameter']|./Parameter[@Name='bindingparameter']").first["Type"]
246
- get_type_by_name(type_name)
247
- end
248
- entity_set_type = if operation_xml["EntitySetType"]
249
- entity_set_by_name(operation_xml["EntitySetType"])
250
- end
251
- parameters = operation_xml.xpath("./Parameter").inject([]) do |result, parameter|
252
- unless parameter["Name"] == 'bindingParameter'
253
- result.push({
254
- name: parameter["Name"],
255
- type: get_type_by_name(parameter["Type"]),
256
- nullable: parameter["Nullable"],
257
- })
258
- end
259
- result
260
- end
261
- return_type = if return_type_node = operation_xml.xpath("./ReturnType").first
262
- get_type_by_name(return_type_node["Type"])
263
- end
264
-
265
- options = {
266
- name: operation_xml["Name"],
267
- entity_set_type: entity_set_type,
268
- binding_type: binding_type,
269
- parameters: parameters,
270
- return_type: return_type
271
- }
272
- Operation.new(options)
273
- end
274
-
275
- def remove_namespace(name)
276
- name.gsub("#{namespace}.", "")
277
- end
278
- end
279
- end
1
+ module OData
2
+ class Service
3
+ attr_reader :base_url
4
+ attr_reader :metadata
5
+
6
+ def initialize(options = {}, &block)
7
+ @auth_callback = options[:auth_callback] || block
8
+ @base_url = options[:base_url]
9
+ @metadata_file = options[:metadata_file]
10
+ @type_name_map = {}
11
+ @metadata = fetch_metadata
12
+ populate_types_from_metadata
13
+ end
14
+
15
+ def namespace
16
+ schema_defintion = metadata.xpath("//Schema") && metadata.xpath("//Schema").first
17
+ schema_defintion["Namespace"] if schema_defintion
18
+ end
19
+
20
+ def inspect
21
+ "#<#{self.class} #{base_url}>"
22
+ end
23
+
24
+ def get(path, *select_properties)
25
+ camel_case_select_properties = select_properties.map do |prop|
26
+ OData.convert_to_camel_case(prop)
27
+ end
28
+
29
+ if ! camel_case_select_properties.empty?
30
+ encoded_select_properties = URI.encode_www_form(
31
+ '$select' => camel_case_select_properties.join(',')
32
+ )
33
+ path = "#{path}?#{encoded_select_properties}"
34
+ end
35
+
36
+ response = request(
37
+ method: :get,
38
+ uri: "#{base_url}#{path}"
39
+ )
40
+ {type: get_type_for_odata_response(response), attributes: response}
41
+ end
42
+
43
+ def delete(path)
44
+ request(
45
+ method: :delete,
46
+ uri: "#{base_url}#{path}"
47
+ )
48
+ end
49
+
50
+ def post(path, data)
51
+ request(
52
+ method: :post,
53
+ uri: "#{base_url}#{path}",
54
+ data: data
55
+ )
56
+ end
57
+
58
+ def patch(path, data)
59
+ request(
60
+ method: :patch,
61
+ uri: "#{base_url}#{path}",
62
+ data: data
63
+ )
64
+ end
65
+
66
+ def request(options = {})
67
+ req = Request.new(options[:method], options[:uri], options[:data])
68
+ @auth_callback.call(req) if @auth_callback
69
+ req.perform
70
+ end
71
+
72
+ def complex_types
73
+ @complex_types ||= metadata.xpath("//ComplexType").map do |complex_type|
74
+ @type_name_map["#{namespace}.#{complex_type["Name"]}"] = ComplexType.new(
75
+ name: "#{namespace}.#{complex_type["Name"]}",
76
+ base_type: complex_type["BaseType"],
77
+ service: self,
78
+ )
79
+ end
80
+ end
81
+
82
+ def entity_types
83
+ @entity_types ||= metadata.xpath("//EntityType").map do |entity|
84
+ options = {
85
+ name: "#{namespace}.#{entity["Name"]}",
86
+ abstract: entity["Abstract"] == "true",
87
+ base_type: entity["BaseType"],
88
+ open_type: entity["OpenType"] == "true",
89
+ has_stream: entity["HasStream"] == "true",
90
+ service: self,
91
+ }
92
+ @type_name_map["#{namespace}.#{entity["Name"]}"] = EntityType.new(options)
93
+ end
94
+ end
95
+
96
+ def enum_types
97
+ @enum_types ||= metadata.xpath("//EnumType").map do |type|
98
+ members = type.xpath("./Member").map do |m, i|
99
+ value = m['Value'] && m['Value'].to_i || i
100
+ {
101
+ name: m["Name"],
102
+ value: value,
103
+ }
104
+ end
105
+ @type_name_map["#{namespace}.#{type["Name"]}"] = EnumType.new({name: "#{namespace}.#{type["Name"]}", members: members})
106
+ end
107
+ end
108
+
109
+ def actions
110
+ metadata.xpath("//Action").map do |action|
111
+ build_operation(action)
112
+ end
113
+ end
114
+
115
+ def functions
116
+ metadata.xpath("//Function").map do |function|
117
+ build_operation(function)
118
+ end
119
+ end
120
+
121
+ def populate_primitive_types
122
+ @type_name_map.merge!(
123
+ "Edm.Binary" => OData::BinaryType.new,
124
+ "Edm.Date" => OData::DateType.new,
125
+ "Edm.Double" => OData::DoubleType.new,
126
+ "Edm.Guid" => OData::GuidType.new,
127
+ "Edm.Int16" => OData::Int16Type.new,
128
+ "Edm.Int32" => OData::Int32Type.new,
129
+ "Edm.Int64" => OData::Int64Type.new,
130
+ "Edm.Stream" => OData::StreamType.new,
131
+ "Edm.String" => OData::StringType.new,
132
+ "Edm.Boolean" => OData::BooleanType.new,
133
+ "Edm.DateTimeOffset" => OData::DateTimeOffsetType.new
134
+ )
135
+ end
136
+
137
+ def singletons
138
+ metadata.xpath("//Singleton").map do |singleton|
139
+ Singleton.new(
140
+ name: singleton["Name"],
141
+ type: singleton["Type"],
142
+ service: self
143
+ )
144
+ end
145
+ end
146
+
147
+ def entity_sets
148
+ @entity_sets ||= metadata.xpath("//EntitySet").map do |entity_set|
149
+ EntitySet.new(
150
+ name: entity_set["Name"],
151
+ member_type: entity_set["EntityType"],
152
+ service: self
153
+ )
154
+ end
155
+ end
156
+
157
+ def get_type_for_odata_response(parsed_response)
158
+ if odata_type_string = parsed_response["@odata.type"]
159
+ get_type_by_name(type_name_from_odata_type_field(odata_type_string))
160
+ elsif context = parsed_response["@odata.context"]
161
+ singular, segments = segments_from_odata_context_field(context)
162
+ first_entity_type = get_type_by_name("Collection(#{entity_set_by_name(segments.shift).member_type})")
163
+ entity_type = segments.reduce(first_entity_type) do |last_entity_type, segment|
164
+ last_entity_type.member_type.navigation_property_by_name(segment).type
165
+ end
166
+ singular && entity_type.respond_to?(:member_type) ? entity_type.member_type : entity_type
167
+ end
168
+ end
169
+
170
+ def get_type_by_name(type_name)
171
+ @type_name_map[type_name] || build_collection(type_name)
172
+ end
173
+
174
+ def entity_set_by_name(name)
175
+ entity_sets.find { |entity_set| entity_set.name == name }
176
+ end
177
+
178
+ def properties_for_type(type_name)
179
+ raw_type_name = remove_namespace(type_name)
180
+ type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
181
+ type_definition.xpath("./Property").map do |property|
182
+ options = {
183
+ name: property["Name"],
184
+ nullable: property["Nullable"] != "false",
185
+ type: get_type_by_name(property["Type"]),
186
+ }
187
+ OData::Property.new(options)
188
+ end
189
+ end
190
+
191
+ def navigation_properties_for_type(type_name)
192
+ raw_type_name = remove_namespace(type_name)
193
+ type_definition = metadata.xpath("//EntityType[@Name='#{raw_type_name}']|//ComplexType[@Name='#{raw_type_name}']")
194
+ type_definition.xpath("./NavigationProperty").map do |property|
195
+ options = {
196
+ name: property["Name"],
197
+ nullable: property["Nullable"] != "false",
198
+ type: get_type_by_name(property["Type"]),
199
+ contains_target: property["ContainsTarget"],
200
+ partner: property["Partner"],
201
+ }
202
+ OData::NavigationProperty.new(options)
203
+ end
204
+ end
205
+
206
+ private
207
+
208
+ def type_name_from_odata_type_field(odata_type_field)
209
+ odata_type_field.sub("#", '')
210
+ end
211
+
212
+ def segments_from_odata_context_field(odata_context_field)
213
+ segments = odata_context_field.split("$metadata#").last.split("/").map { |s| s.split("(").first }
214
+ segments.pop if singular = segments.last == "$entity"
215
+ [singular, segments]
216
+ end
217
+
218
+ def populate_types_from_metadata
219
+ enum_types
220
+ populate_primitive_types
221
+ complex_types
222
+ entity_types
223
+ end
224
+
225
+ def fetch_metadata
226
+ response = if @metadata_file
227
+ File.read(@metadata_file)
228
+ else # From a URL
229
+ uri = URI("#{base_url}$metadata?detailed=true")
230
+ Net::HTTP
231
+ .new(uri.hostname, uri.port)
232
+ .tap { |h| h.use_ssl = uri.scheme == "https" }
233
+ .get(uri).body
234
+ end
235
+ ::Nokogiri::XML(response).remove_namespaces!
236
+ end
237
+
238
+ def build_collection(collection_name)
239
+ member_type_name = collection_name.gsub(/Collection\(([^)]+)\)/, "\\1")
240
+ CollectionType.new(name: collection_name, member_type: @type_name_map[member_type_name])
241
+ end
242
+
243
+ def build_operation(operation_xml)
244
+ binding_type = if operation_xml["IsBound"] == "true"
245
+ type_name = operation_xml.xpath("./Parameter[@Name='bindingParameter']|./Parameter[@Name='bindingparameter']").first["Type"]
246
+ get_type_by_name(type_name)
247
+ end
248
+ entity_set_type = if operation_xml["EntitySetType"]
249
+ entity_set_by_name(operation_xml["EntitySetType"])
250
+ end
251
+ parameters = operation_xml.xpath("./Parameter").inject([]) do |result, parameter|
252
+ unless parameter["Name"] == 'bindingParameter'
253
+ result.push({
254
+ name: parameter["Name"],
255
+ type: get_type_by_name(parameter["Type"]),
256
+ nullable: parameter["Nullable"],
257
+ })
258
+ end
259
+ result
260
+ end
261
+ return_type = if return_type_node = operation_xml.xpath("./ReturnType").first
262
+ get_type_by_name(return_type_node["Type"])
263
+ end
264
+
265
+ options = {
266
+ name: operation_xml["Name"],
267
+ entity_set_type: entity_set_type,
268
+ binding_type: binding_type,
269
+ parameters: parameters,
270
+ return_type: return_type
271
+ }
272
+ Operation.new(options)
273
+ end
274
+
275
+ def remove_namespace(name)
276
+ name.gsub("#{namespace}.", "")
277
+ end
278
+ end
279
+ end