frodata 0.9.1
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.
- checksums.yaml +7 -0
- data/.autotest +2 -0
- data/.gitignore +24 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +75 -0
- data/CHANGELOG.md +150 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +427 -0
- data/Rakefile +7 -0
- data/TODO.md +55 -0
- data/frodata.gemspec +34 -0
- data/lib/frodata.rb +36 -0
- data/lib/frodata/entity.rb +332 -0
- data/lib/frodata/entity_container.rb +75 -0
- data/lib/frodata/entity_set.rb +161 -0
- data/lib/frodata/errors.rb +68 -0
- data/lib/frodata/navigation_property.rb +29 -0
- data/lib/frodata/navigation_property/proxy.rb +80 -0
- data/lib/frodata/properties.rb +32 -0
- data/lib/frodata/properties/binary.rb +50 -0
- data/lib/frodata/properties/boolean.rb +37 -0
- data/lib/frodata/properties/collection.rb +50 -0
- data/lib/frodata/properties/complex.rb +114 -0
- data/lib/frodata/properties/date.rb +27 -0
- data/lib/frodata/properties/date_time.rb +83 -0
- data/lib/frodata/properties/date_time_offset.rb +17 -0
- data/lib/frodata/properties/decimal.rb +50 -0
- data/lib/frodata/properties/enum.rb +62 -0
- data/lib/frodata/properties/float.rb +67 -0
- data/lib/frodata/properties/geography.rb +13 -0
- data/lib/frodata/properties/geography/base.rb +162 -0
- data/lib/frodata/properties/geography/line_string.rb +33 -0
- data/lib/frodata/properties/geography/point.rb +31 -0
- data/lib/frodata/properties/geography/polygon.rb +38 -0
- data/lib/frodata/properties/guid.rb +17 -0
- data/lib/frodata/properties/integer.rb +107 -0
- data/lib/frodata/properties/number.rb +14 -0
- data/lib/frodata/properties/string.rb +72 -0
- data/lib/frodata/properties/time.rb +40 -0
- data/lib/frodata/properties/time_of_day.rb +27 -0
- data/lib/frodata/property.rb +139 -0
- data/lib/frodata/property_registry.rb +41 -0
- data/lib/frodata/query.rb +233 -0
- data/lib/frodata/query/criteria.rb +92 -0
- data/lib/frodata/query/criteria/comparison_operators.rb +49 -0
- data/lib/frodata/query/criteria/date_functions.rb +61 -0
- data/lib/frodata/query/criteria/geography_functions.rb +21 -0
- data/lib/frodata/query/criteria/lambda_operators.rb +27 -0
- data/lib/frodata/query/criteria/string_functions.rb +40 -0
- data/lib/frodata/query/in_batches.rb +58 -0
- data/lib/frodata/railtie.rb +19 -0
- data/lib/frodata/schema.rb +155 -0
- data/lib/frodata/schema/complex_type.rb +79 -0
- data/lib/frodata/schema/enum_type.rb +95 -0
- data/lib/frodata/service.rb +254 -0
- data/lib/frodata/service/request.rb +85 -0
- data/lib/frodata/service/response.rb +162 -0
- data/lib/frodata/service/response/atom.rb +40 -0
- data/lib/frodata/service/response/json.rb +41 -0
- data/lib/frodata/service/response/plain.rb +36 -0
- data/lib/frodata/service/response/xml.rb +40 -0
- data/lib/frodata/service_registry.rb +52 -0
- data/lib/frodata/version.rb +3 -0
- data/spec/fixtures/files/entity_to_xml.xml +17 -0
- data/spec/fixtures/files/error.xml +5 -0
- data/spec/fixtures/files/metadata.xml +150 -0
- data/spec/fixtures/files/product_0.json +10 -0
- data/spec/fixtures/files/product_0.xml +28 -0
- data/spec/fixtures/files/products.json +106 -0
- data/spec/fixtures/files/products.xml +308 -0
- data/spec/fixtures/files/supplier_0.json +26 -0
- data/spec/fixtures/files/supplier_0.xml +32 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs.yml +1635 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/bad_entry.yml +183 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/existing_entry.yml +256 -0
- data/spec/fixtures/vcr_cassettes/entity_set_specs/new_entry.yml +185 -0
- data/spec/fixtures/vcr_cassettes/entity_specs.yml +285 -0
- data/spec/fixtures/vcr_cassettes/navigation_property_proxy_specs.yml +346 -0
- data/spec/fixtures/vcr_cassettes/query/result_specs.yml +189 -0
- data/spec/fixtures/vcr_cassettes/query_specs.yml +1060 -0
- data/spec/fixtures/vcr_cassettes/schema/complex_type_specs.yml +127 -0
- data/spec/fixtures/vcr_cassettes/service/request_specs.yml +193 -0
- data/spec/fixtures/vcr_cassettes/service_registry_specs.yml +129 -0
- data/spec/fixtures/vcr_cassettes/service_specs.yml +127 -0
- data/spec/fixtures/vcr_cassettes/usage_example_specs.yml +1330 -0
- data/spec/frodata/entity/shared_examples.rb +82 -0
- data/spec/frodata/entity_container_spec.rb +38 -0
- data/spec/frodata/entity_set_spec.rb +168 -0
- data/spec/frodata/entity_spec.rb +151 -0
- data/spec/frodata/errors_spec.rb +48 -0
- data/spec/frodata/navigation_property/proxy_spec.rb +44 -0
- data/spec/frodata/navigation_property_spec.rb +55 -0
- data/spec/frodata/properties/binary_spec.rb +50 -0
- data/spec/frodata/properties/boolean_spec.rb +72 -0
- data/spec/frodata/properties/collection_spec.rb +44 -0
- data/spec/frodata/properties/date_spec.rb +23 -0
- data/spec/frodata/properties/date_time_offset_spec.rb +30 -0
- data/spec/frodata/properties/date_time_spec.rb +23 -0
- data/spec/frodata/properties/decimal_spec.rb +51 -0
- data/spec/frodata/properties/float_spec.rb +45 -0
- data/spec/frodata/properties/geography/line_string_spec.rb +33 -0
- data/spec/frodata/properties/geography/point_spec.rb +29 -0
- data/spec/frodata/properties/geography/polygon_spec.rb +55 -0
- data/spec/frodata/properties/geography/shared_examples.rb +72 -0
- data/spec/frodata/properties/guid_spec.rb +17 -0
- data/spec/frodata/properties/integer_spec.rb +58 -0
- data/spec/frodata/properties/string_spec.rb +46 -0
- data/spec/frodata/properties/time_of_day_spec.rb +23 -0
- data/spec/frodata/properties/time_spec.rb +15 -0
- data/spec/frodata/property_registry_spec.rb +16 -0
- data/spec/frodata/property_spec.rb +71 -0
- data/spec/frodata/query/criteria_spec.rb +229 -0
- data/spec/frodata/query_spec.rb +199 -0
- data/spec/frodata/schema/complex_type_spec.rb +96 -0
- data/spec/frodata/schema/enum_type_spec.rb +112 -0
- data/spec/frodata/schema_spec.rb +97 -0
- data/spec/frodata/service/request_spec.rb +49 -0
- data/spec/frodata/service/response_spec.rb +85 -0
- data/spec/frodata/service_registry_spec.rb +18 -0
- data/spec/frodata/service_spec.rb +191 -0
- data/spec/frodata/usage_example_spec.rb +188 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/coverage.rb +2 -0
- data/spec/support/vcr.rb +9 -0
- metadata +401 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
require 'frodata/query/criteria/comparison_operators'
|
|
2
|
+
require 'frodata/query/criteria/string_functions'
|
|
3
|
+
require 'frodata/query/criteria/date_functions'
|
|
4
|
+
require 'frodata/query/criteria/geography_functions'
|
|
5
|
+
require 'frodata/query/criteria/lambda_operators'
|
|
6
|
+
|
|
7
|
+
module FrOData
|
|
8
|
+
class Query
|
|
9
|
+
# Represents a discreet criteria within an FrOData::Query. Should not,
|
|
10
|
+
# normally, be instantiated directly.
|
|
11
|
+
class Criteria
|
|
12
|
+
# The property name that is the target of the criteria.
|
|
13
|
+
attr_reader :property
|
|
14
|
+
# The operator of the criteria.
|
|
15
|
+
attr_reader :operator
|
|
16
|
+
# The value of the criteria.
|
|
17
|
+
attr_reader :value
|
|
18
|
+
# A function to apply to the property.
|
|
19
|
+
attr_reader :function
|
|
20
|
+
# An optional argument to the function.
|
|
21
|
+
attr_reader :argument
|
|
22
|
+
|
|
23
|
+
# Initializes a new criteria with provided options.
|
|
24
|
+
# @param options [Hash]
|
|
25
|
+
def initialize(options = {})
|
|
26
|
+
@property = options[:property]
|
|
27
|
+
@operator = options[:operator]
|
|
28
|
+
@function = options[:function]
|
|
29
|
+
@argument = options[:argument]
|
|
30
|
+
@value = options[:value]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
include ComparisonOperators
|
|
34
|
+
include StringFunctions
|
|
35
|
+
include DateFunctions
|
|
36
|
+
include GeographyFunctions
|
|
37
|
+
include LambdaOperators
|
|
38
|
+
|
|
39
|
+
# Returns criteria as query-ready string.
|
|
40
|
+
def to_s
|
|
41
|
+
query = function ? function_expression : property_name
|
|
42
|
+
|
|
43
|
+
if operator && !lambda_operator?
|
|
44
|
+
"#{query} #{operator} #{url_value(value)}"
|
|
45
|
+
else
|
|
46
|
+
query
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def property_name
|
|
53
|
+
property.name
|
|
54
|
+
rescue NoMethodError
|
|
55
|
+
property.to_s
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def function_expression
|
|
59
|
+
return lambda_expression if lambda_operator?
|
|
60
|
+
|
|
61
|
+
if argument
|
|
62
|
+
"#{function}(#{property_name},#{url_value(argument)})"
|
|
63
|
+
else
|
|
64
|
+
"#{function}(#{property_name})"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def lambda_expression
|
|
69
|
+
"#{property_name}/#{function}(d:d/#{argument} #{operator} #{url_value(value)})"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def url_value(value)
|
|
73
|
+
property.value = value
|
|
74
|
+
property.url_value
|
|
75
|
+
rescue
|
|
76
|
+
value
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def set_operator_and_value(operator, value)
|
|
80
|
+
@operator = operator
|
|
81
|
+
@value = value
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def set_function_and_argument(function, argument)
|
|
86
|
+
@function = function
|
|
87
|
+
@argument = argument
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
class Criteria
|
|
4
|
+
module ComparisonOperators
|
|
5
|
+
# Sets up equality operator.
|
|
6
|
+
# @param value [to_s]
|
|
7
|
+
# @return [self]
|
|
8
|
+
def eq(value)
|
|
9
|
+
set_operator_and_value(:eq, value)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Sets up non-equality operator.
|
|
13
|
+
# @param value [to_s]
|
|
14
|
+
# @return [self]
|
|
15
|
+
def ne(value)
|
|
16
|
+
set_operator_and_value(:ne, value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Sets up greater-than operator.
|
|
20
|
+
# @param value [to_s]
|
|
21
|
+
# @return [self]
|
|
22
|
+
def gt(value)
|
|
23
|
+
set_operator_and_value(:gt, value)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Sets up greater-than-or-equal operator.
|
|
27
|
+
# @param value [to_s]
|
|
28
|
+
# @return [self]
|
|
29
|
+
def ge(value)
|
|
30
|
+
set_operator_and_value(:ge, value)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Sets up less-than operator.
|
|
34
|
+
# @param value [to_s]
|
|
35
|
+
# @return [self]
|
|
36
|
+
def lt(value)
|
|
37
|
+
set_operator_and_value(:lt, value)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Sets up less-than-or-equal operator.
|
|
41
|
+
# @param value [to_s]
|
|
42
|
+
# @return [self]
|
|
43
|
+
def le(value)
|
|
44
|
+
set_operator_and_value(:le, value)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
class Criteria
|
|
4
|
+
module DateFunctions
|
|
5
|
+
# Applies the `year` function.
|
|
6
|
+
# @return [self]
|
|
7
|
+
def year
|
|
8
|
+
set_function_and_argument(:year, nil)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Applies the `month` function.
|
|
12
|
+
# @return [self]
|
|
13
|
+
def month
|
|
14
|
+
set_function_and_argument(:month, nil)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Applies the `day` function.
|
|
18
|
+
# @return [self]
|
|
19
|
+
def day
|
|
20
|
+
set_function_and_argument(:day, nil)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Applies the `hour` function.
|
|
24
|
+
# @return [self]
|
|
25
|
+
def hour
|
|
26
|
+
set_function_and_argument(:hour, nil)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Applies the `minute` function.
|
|
30
|
+
# @return [self]
|
|
31
|
+
def minute
|
|
32
|
+
set_function_and_argument(:minute, nil)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Applies the `second` function.
|
|
36
|
+
# @return [self]
|
|
37
|
+
def second
|
|
38
|
+
set_function_and_argument(:second, nil)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Applies the `fractionalseconds` function.
|
|
42
|
+
# @return [self]
|
|
43
|
+
def fractionalseconds
|
|
44
|
+
set_function_and_argument(:fractionalseconds, nil)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Applies the `date` function.
|
|
48
|
+
# @return [self]
|
|
49
|
+
def date
|
|
50
|
+
set_function_and_argument(:date, nil)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Applies the `time` function.
|
|
54
|
+
# @return [self]
|
|
55
|
+
def time
|
|
56
|
+
set_function_and_argument(:time, nil)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
class Criteria
|
|
4
|
+
module GeographyFunctions
|
|
5
|
+
# Applies the `geo.distance` function.
|
|
6
|
+
# @param to [to_s]
|
|
7
|
+
# @return [self]
|
|
8
|
+
def distance(to)
|
|
9
|
+
set_function_and_argument(:'geo.distance', to)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Applies the `geo.intersects` function.
|
|
13
|
+
# @param what [to_s]
|
|
14
|
+
# @return [self]
|
|
15
|
+
def intersects(what)
|
|
16
|
+
set_function_and_argument(:'geo.intersects', what)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
class Criteria
|
|
4
|
+
module LambdaOperators
|
|
5
|
+
# Applies the `any` lambda operator to the given property
|
|
6
|
+
# @param property [to_s]
|
|
7
|
+
# @return [self]
|
|
8
|
+
def any(property)
|
|
9
|
+
set_function_and_argument(:any, property)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Applies the `any` lambda operator to the given property
|
|
13
|
+
# @param property [to_s]
|
|
14
|
+
# @return [self]
|
|
15
|
+
def all(property)
|
|
16
|
+
set_function_and_argument(:all, property)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def lambda_operator?
|
|
22
|
+
[:any, :all].include?(function)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
class Criteria
|
|
4
|
+
module StringFunctions
|
|
5
|
+
# Sets up a `contains` function criterium.
|
|
6
|
+
# @param str [to_s]
|
|
7
|
+
# @return [self]
|
|
8
|
+
def contains(str)
|
|
9
|
+
set_function_and_argument(:contains, str)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Sets up a `startswith` function criterium.
|
|
13
|
+
# @param str [to_s]
|
|
14
|
+
# @return [self]
|
|
15
|
+
def startswith(str)
|
|
16
|
+
set_function_and_argument(:startswith, str)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Sets up a `endswith` function criterium.
|
|
20
|
+
# @param str [to_s]
|
|
21
|
+
# @return [self]
|
|
22
|
+
def endswith(str)
|
|
23
|
+
set_function_and_argument(:endswith, str)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Applies the `tolower` function to the property.
|
|
27
|
+
# @return [self]
|
|
28
|
+
def tolower
|
|
29
|
+
set_function_and_argument(:tolower, nil)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Applies the `toupper` function to the property.
|
|
33
|
+
# @return [self]
|
|
34
|
+
def toupper
|
|
35
|
+
set_function_and_argument(:toupper, nil)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Query
|
|
3
|
+
module InBatches
|
|
4
|
+
DEFAULT_BATCH_SIZE = 10
|
|
5
|
+
|
|
6
|
+
# Process results in batches.
|
|
7
|
+
#
|
|
8
|
+
# When a block is given, yields `FrOData::Query::Result`
|
|
9
|
+
# objects of specified batch size to the block.
|
|
10
|
+
#
|
|
11
|
+
# service['Products'].query.in_batches(of: 10) do |batch|
|
|
12
|
+
# batch.count # batch size (10 except for last batch)
|
|
13
|
+
# batch.is_a? FrOData::Query::Result # true
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Returns an Enumerator to process results individually.
|
|
17
|
+
#
|
|
18
|
+
# service['Products'].query.in_batches.each do |entity|
|
|
19
|
+
# entity.is_a? FrOData::Entity # true
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# @param of: [int] batch size
|
|
23
|
+
# @return [Enumerator]
|
|
24
|
+
def in_batches(of: DEFAULT_BATCH_SIZE, &block)
|
|
25
|
+
per_page = of
|
|
26
|
+
|
|
27
|
+
if block_given?
|
|
28
|
+
each_batch(of, &block)
|
|
29
|
+
else
|
|
30
|
+
Enumerator.new do |result|
|
|
31
|
+
each_batch(of) do |batch|
|
|
32
|
+
batch.each { |entity| result << entity }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def each_batch(per_page, &block)
|
|
41
|
+
page = 0
|
|
42
|
+
|
|
43
|
+
loop do
|
|
44
|
+
batch = get_paginated_entities(per_page, page)
|
|
45
|
+
break if batch.empty?
|
|
46
|
+
|
|
47
|
+
yield batch
|
|
48
|
+
|
|
49
|
+
page += 1
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def get_paginated_entities(per_page, page)
|
|
54
|
+
skip(per_page * page).limit(per_page).execute
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module FrOData
|
|
2
|
+
class Railtie < Rails::Railtie
|
|
3
|
+
config.before_initialize do
|
|
4
|
+
::FrOData::Railtie.load_configuration!
|
|
5
|
+
::FrOData::Railtie.setup_service_registry!
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
# Looks for config/odata.yml and loads the configuration.
|
|
9
|
+
def self.load_configuration!
|
|
10
|
+
# TODO Implement Rails configuration loading
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Examines the loaded configuration and populates the
|
|
14
|
+
# FrOData::ServiceRegistry accordingly.
|
|
15
|
+
def self.setup_service_registry!
|
|
16
|
+
# TODO Populate FrOData::ServiceRegistry based on configuration
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
require 'frodata/schema/complex_type'
|
|
2
|
+
require 'frodata/schema/enum_type'
|
|
3
|
+
|
|
4
|
+
module FrOData
|
|
5
|
+
class Schema
|
|
6
|
+
# The schema's parent service
|
|
7
|
+
attr_reader :service
|
|
8
|
+
# The schema's metadata (i.e its XML definition)
|
|
9
|
+
attr_reader :metadata
|
|
10
|
+
|
|
11
|
+
# Creates a new schema.
|
|
12
|
+
#
|
|
13
|
+
# @param schema_definition [Nokogiri::XML] The schema's XML definition
|
|
14
|
+
# @param service [FrOData::Service] The schema's parent service
|
|
15
|
+
def initialize(schema_definition, service)
|
|
16
|
+
@metadata = schema_definition
|
|
17
|
+
@service = service
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Returns the schema's `Namespace` attribute (mandatory).
|
|
21
|
+
# @return [String]
|
|
22
|
+
def namespace
|
|
23
|
+
@namespace ||= metadata.attributes['Namespace'].value
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns a list of actions defined by the schema.
|
|
27
|
+
# @return [Array<String>]
|
|
28
|
+
def actions
|
|
29
|
+
@actions ||= metadata.xpath('//Action').map do |action|
|
|
30
|
+
action.attributes['Name'].value
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Returns a list of entities defined by the schema.
|
|
35
|
+
# @return [Array<String>]
|
|
36
|
+
def entity_types
|
|
37
|
+
@entity_types ||= metadata.xpath('//EntityType').map do |entity|
|
|
38
|
+
entity.attributes['Name'].value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns a list of `ComplexType`s defined by the schema.
|
|
43
|
+
# @return [Hash<String, FrOData::Schema::ComplexType>]
|
|
44
|
+
def complex_types
|
|
45
|
+
@complex_types ||= metadata.xpath('//ComplexType').map do |entity|
|
|
46
|
+
[
|
|
47
|
+
entity.attributes['Name'].value,
|
|
48
|
+
ComplexType.new(entity, self)
|
|
49
|
+
]
|
|
50
|
+
end.to_h
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns a list of EnumTypes defined by the schema.
|
|
54
|
+
# @return [Hash<String, FrOData::Schema::EnumType>]
|
|
55
|
+
def enum_types
|
|
56
|
+
@enum_types ||= metadata.xpath('//EnumType').map do |entity|
|
|
57
|
+
[
|
|
58
|
+
entity.attributes['Name'].value,
|
|
59
|
+
EnumType.new(entity, self)
|
|
60
|
+
]
|
|
61
|
+
end.to_h
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns a list of functions defined by the schema.
|
|
65
|
+
# @return [Array<String>]
|
|
66
|
+
def functions
|
|
67
|
+
@functions ||= metadata.xpath('//Function').map do |function|
|
|
68
|
+
function.attributes['Name'].value
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns a list of type definitions defined by the schema.
|
|
73
|
+
# @return [Array<String>]
|
|
74
|
+
def type_definitions
|
|
75
|
+
@typedefs ||= metadata.xpath('//TypeDefinition').map do |typedef|
|
|
76
|
+
typedef.attributes['Name'].value
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns a hash for finding an association through an entity type's defined
|
|
81
|
+
# NavigationProperty elements.
|
|
82
|
+
# @return [Hash<Hash<FrOData::NavigationProperty>>]
|
|
83
|
+
def navigation_properties
|
|
84
|
+
@navigation_properties ||= metadata.xpath('//EntityType').map do |entity_type_def|
|
|
85
|
+
[
|
|
86
|
+
entity_type_def.attributes['Name'].value,
|
|
87
|
+
entity_type_def.xpath('./NavigationProperty').map do |nav_property_def|
|
|
88
|
+
[
|
|
89
|
+
nav_property_def.attributes['Name'].value,
|
|
90
|
+
::FrOData::NavigationProperty.build(nav_property_def)
|
|
91
|
+
]
|
|
92
|
+
end.to_h
|
|
93
|
+
]
|
|
94
|
+
end.to_h
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Get the property type for an entity from metadata.
|
|
98
|
+
#
|
|
99
|
+
# @param entity_name [to_s] the name of the relevant entity
|
|
100
|
+
# @param property_name [to_s] the property name needed
|
|
101
|
+
# @return [String] the name of the property's type
|
|
102
|
+
def get_property_type(entity_name, property_name)
|
|
103
|
+
metadata.xpath("//EntityType[@Name='#{entity_name}']/Property[@Name='#{property_name}']").first.attributes['Type'].value
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Get the primary key for the supplied Entity.
|
|
107
|
+
#
|
|
108
|
+
# @param entity_name [to_s]
|
|
109
|
+
# @return [String]
|
|
110
|
+
def primary_key_for(entity_name)
|
|
111
|
+
metadata.xpath("//EntityType[@Name='#{entity_name}']/Key/PropertyRef").first.attributes['Name'].value
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Get the list of properties and their various options for the supplied
|
|
115
|
+
# Entity name.
|
|
116
|
+
# @param entity_name [to_s]
|
|
117
|
+
# @return [Hash]
|
|
118
|
+
# @api private
|
|
119
|
+
def properties_for_entity(entity_name)
|
|
120
|
+
type_definition = metadata.xpath("//EntityType[@Name='#{entity_name}']").first
|
|
121
|
+
raise ArgumentError, "Unknown EntityType: #{entity_name}" if type_definition.nil?
|
|
122
|
+
properties_to_return = {}
|
|
123
|
+
type_definition.xpath('./Property').each do |property_xml|
|
|
124
|
+
property_name, property = process_property_from_xml(property_xml)
|
|
125
|
+
properties_to_return[property_name] = property
|
|
126
|
+
end
|
|
127
|
+
properties_to_return
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def process_property_from_xml(property_xml)
|
|
133
|
+
property_name = property_xml.attributes['Name'].value
|
|
134
|
+
property_type = property_xml.attributes['Type'].value
|
|
135
|
+
property_options = { service: service }
|
|
136
|
+
|
|
137
|
+
property_type, value_type = property_type.split(/\(|\)/)
|
|
138
|
+
if property_type == 'Collection'
|
|
139
|
+
klass = ::FrOData::Properties::Collection
|
|
140
|
+
property_options.merge(value_type: value_type)
|
|
141
|
+
else
|
|
142
|
+
klass = ::FrOData::PropertyRegistry[property_type]
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
if klass.nil?
|
|
146
|
+
raise RuntimeError, "Unknown property type: #{value_type}"
|
|
147
|
+
else
|
|
148
|
+
property_options[:allows_nil] = false if property_xml.attributes['Nullable'] == 'false'
|
|
149
|
+
property = klass.new(property_name, nil, property_options)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
return [property_name, property]
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|