diff --git a/docs/odata-url-conventions/odata-url-conventions.html b/docs/odata-url-conventions/odata-url-conventions.html index 7573b439..20c8dd81 100644 --- a/docs/odata-url-conventions/odata-url-conventions.html +++ b/docs/odata-url-conventions/odata-url-conventions.html @@ -1047,33 +1047,41 @@

OData-ABNF commonExpr syntax rule defines the formal grammar of common expressions.

+

The following subsections specify situations in which expressions evaluate to null if operands or parameters do not have the types expected by an operator or function. Notwithstanding these rules, if a service can infer such a type discrepancy for an expression that appears in a request independently of the underlying data, it MUST reject the request with an error message explaining the discrepancy. The inferral can be based on, for example, the declared type of a property or the type of a literal value that occurs in the expression.

+
+

Example 52: In a search for people above a certain age

+
http://host/service/People?$filter=Age gt '50'
+

the expression would always evaluate to null because the age 50 is erroneously given as a string and the $filter would return an empty result, although this is really the result of a typing error. That’s why a “type mismatch” error must instead be returned in such a case.

+

5.1.1.1 Logical Operators

-

OData defines a set of logical operators that evaluate to true or false (i.e. a boolCommonExpr as defined in OData-ABNF). Logical operators are typically used to filter a collection of resources.

+

OData defines a set of logical operators that evaluate to true or false (i.e. a boolCommonExpr as defined in OData-ABNF). Logical operators are typically used to filter a collection of resources.

The syntax rules for the logical operators are defined in OData-ABNF. 4.01 Services MUST support case-insensitive operator names. Clients that want to work with 4.0 services MUST use lower case operator names.

The six comparison operators can be used with all primitive values except Edm.Binary, Edm.Stream, and the Edm.Geo types. Edm.Binary, Edm.Stream, and the Edm.Geo types can only be compared to the null value using the eq and ne operators.

When applied to operands of numeric types, numeric promotion rules are applied.

The eq, ne, and in operators can be used with collection-valued operands, and the eq and ne operators can be used with operands of a structured type.

+

If at least one operand of an eq, ne, lt, le, gt, or ge operator is non-numeric and the operands have different types, the operator returns null.

+

The rules for the Boolean operators and, or, and not assume Boolean operands. If an operand of a Boolean operator is not Boolean, the operator returns null.

5.1.1.1.1 Equals
-

The eq operator returns true if the left operand is equal to the right operand, otherwise it returns false.

-

When applied to operands of entity types, the eq operator returns true if both operands represent the same entity, or both operands represent null.

-

When applied to operands of complex types, the eq operator returns true if both operands have the same structure and same values, or both operands represent null.

-

When applied to ordered collections, the eq operator returns true if both operands have the same cardinality and each member of the left operand is equal to the corresponding member of the right operand.

-

For services that support comparing unordered collections, the eq operator returns true if both operands are equal after applying the same ordering on both collections.

+

The eq operator returns true if the left operand is equal to the right operand, otherwise it returns false.

+

When applied to operands of entity types, the eq operator returns true if both operands represent the same entity, or both operands represent null.

+

When applied to operands of complex types, the eq operator returns true if both operands have the same structure and same values, or both operands represent null.

+

When applied to ordered collections, the eq operator returns true if both operands have the same cardinality and each member of the left operand is equal to the corresponding member of the right operand.

+

For services that support comparing unordered collections, the eq operator returns true if both operands are equal after applying the same ordering on both collections.

Each of the special values null, -INF, and INF is equal to itself, and only to itself.

The special value NaN is not equal to anything, even to itself.

5.1.1.1.2 Not Equals
-

The ne operator returns true if the left operand is not equal to the right operand, otherwise it returns false.

-

When applied to operands of entity types, the ne operator returns true if the two operands do not represent the same entity.

-

When applied to operands of complex types, the ne operator returns true if the operands do not have the same structure and same values.

-

When applied to ordered collections, the ne operator returns true if both operands do not have the same cardinality or any member of the left operand is not equal to the corresponding member of the right operand.

-

For services that support comparing unordered collections, the ne operator returns true if both operands do not have the same cardinality or do not contain the same members, in any order.

+

The ne operator returns true if the left operand is not equal to the right operand, otherwise it returns false.

+

When applied to operands of entity types, the ne operator returns true if the two operands do not represent the same entity.

+

When applied to operands of complex types, the ne operator returns true if the operands do not have the same structure and same values.

+

When applied to ordered collections, the ne operator returns true if both operands do not have the same cardinality or any member of the left operand is not equal to the corresponding member of the right operand.

+

For services that support comparing unordered collections, the ne operator returns true if both operands do not have the same cardinality or do not contain the same members, in any order.

Each of the special values null, -INF, and INF is not equal to any value but itself.

The special value NaN is not equal to anything, even to itself.

The null value is not equal to any value but itself.

@@ -1081,108 +1089,108 @@
5.1.1.1.2 Not Eq
5.1.1.1.3 Greater Than
-

The gt operator returns true if the left operand is greater than the right operand, otherwise it returns false.

+

The gt operator returns true if the left operand is greater than the right operand, otherwise it returns false.

The special value INF is greater than any number, and any number is greater than -INF.

The Boolean value true is greater than false.

Services SHOULD order language-dependent strings according to the Content-Language of the response, and SHOULD annotate string properties with language-dependent order with the term Core.IsLanguageDependent, see OData-VocCore.

-

If any operand is null, the operator returns false.

+

If any operand is null, the operator returns false.

5.1.1.1.4 Greater Than or Equal
-

The ge operator returns true if the left operand is greater than or equal to the right operand, otherwise it returns false.

+

The ge operator returns true if the left operand is greater than or equal to the right operand, otherwise it returns false.

See rules for gt and eq for details.

5.1.1.1.5 Less Than
-

The lt operator returns true if the left operand is less than the right operand, otherwise it returns false.

+

The lt operator returns true if the left operand is less than the right operand, otherwise it returns false.

The special value -INF is less than any number, and any number is less than INF.

The Boolean value false is less than true.

Services SHOULD order language-dependent strings according to the Content-Language of the response, and SHOULD annotate string properties with language-dependent order with the term Core.IsLanguageDependent, see OData-VocCore.

-

If any operand is null, the operator returns false.

+

If any operand is null, the operator returns false.

5.1.1.1.6 Less Than or Equal
-

The le operator returns true if the left operand is less than or equal to the right operand, otherwise it returns false.

+

The le operator returns true if the left operand is less than or equal to the right operand, otherwise it returns false.

See rules for lt and eq for details.

5.1.1.1.7 And
-

The and operator returns true if both the left and right operands evaluate to true, otherwise it returns false.

-

The null value is treated as unknown, so if one operand evaluates to null and the other operand to false, the and operator returns false. All other combinations with null return null.

+

The and operator returns true if both the left and right operands evaluate to true, otherwise it returns false.

+

The null value is treated as unknown, so if one operand evaluates to null and the other operand to false, the and operator returns false. All other combinations with null return null.

5.1.1.1.8 Or
-

The or operator returns false if both the left and right operands both evaluate to false, otherwise it returns true.

-

The null value is treated as unknown, so if one operand evaluates to null and the other operand to true, the or operator returns true. All other combinations with null return null.

+

The or operator returns false if both the left and right operands both evaluate to false, otherwise it returns true.

+

The null value is treated as unknown, so if one operand evaluates to null and the other operand to true, the or operator returns true. All other combinations with null return null.

5.1.1.1.9 Not
-

The not operator returns true if the operand returns false, otherwise it returns false.

+

The not operator returns true if the operand returns false, otherwise it returns false.

The null value is treated as unknown, so not null returns null.

5.1.1.1.10 Has
-

The has operator returns true if the right operand is an enumeration value whose flag(s) are set on the left operand.

+

The has operator returns true if the right operand is an enumeration value whose flag(s) are set on the left operand.

The null value is treated as unknown, so if one operand evaluates to null, the has operator returns null.

5.1.1.1.11 In
-

The in operator returns true if the left operand is a member of the right operand. The right operand MUST be either a comma-separated list of zero or more primitive values, enclosed in parentheses, or a single expression that resolves to a collection. If the right operand is an empty collection or list of values, the expression returns false.

+

The in operator returns true if the equality comparison of the left operand with at least one member of the right operand returns true. The right operand MUST be either a comma-separated list of zero or more primitive values, enclosed in parentheses, or a single expression that resolves to a collection. If the right operand is an empty collection or list of values, the in operator returns false.

5.1.1.1.12 Logical Operator Examples

The following examples illustrate the use and semantics of each of the logical operators.

-

Example 52: all products with a Name equal to Milk

+

Example 53: all products with a Name equal to Milk

http://host/service/Products?$filter=Name eq 'Milk'
-

Example 53: all products with a Name not equal to Milk

+

Example 54: all products with a Name not equal to Milk

http://host/service/Products?$filter=Name ne 'Milk'
-

Example 54: all products with a Name greater than Milk:

+

Example 55: all products with a Name greater than Milk:

http://host/service/Products?$filter=Name gt 'Milk'
-

Example 55: all products with a Name greater than or equal to Milk:

+

Example 56: all products with a Name greater than or equal to Milk:

http://host/service/Products?$filter=Name ge 'Milk'
-

Example 56: all products with a Name less than Milk:

+

Example 57: all products with a Name less than Milk:

http://host/service/Products?$filter=Name lt 'Milk'
-

Example 57: all products with a Name less than or equal to Milk:

+

Example 58: all products with a Name less than or equal to Milk:

http://host/service/Products?$filter=Name le 'Milk'
-

Example 58: all products with a Name equal to Milk that also have a Price less than 2.55:

+

Example 59: all products with a Name equal to Milk that also have a Price less than 2.55:

http://host/service/Products?$filter=Name eq 'Milk' and Price lt 2.55
-

Example 59: all products that either have a Name equal to Milk or have a Price less than 2.55:

+

Example 60: all products that either have a Name equal to Milk or have a Price less than 2.55:

http://host/service/Products?$filter=Name eq 'Milk' or Price lt 2.55
-

Example 60: all products that do not have a Name that ends with ilk:

+

Example 61: all products that do not have a Name that ends with ilk:

http://host/service/Products?$filter=not endswith(Name,'ilk')
-

Example 61: all products whose style value includes Yellow:

+

Example 62: all products whose style value includes Yellow:

http://host/service/Products?$filter=style has Sales.Pattern'Yellow'
-

Example 62: all products whose Name is Milk or Cheese:

+

Example 63: all products whose Name is Milk or Cheese:

http://host/service/Products?$filter=Name in ('Milk', 'Cheese')
@@ -1191,7 +1199,7 @@
5.1.1.2 Arithmetic Operators

OData defines a set of arithmetic operators that require operands that evaluate to numeric types. Arithmetic operators are typically used to filter a collection of resources. However, services MAY allow using arithmetic operators with the $orderby system query option.

-

If an operand of an arithmetic operator is null, the result is null.

+

If an operand of an arithmetic operator is null or has a non-allowed type, the result is null.

The syntax rules for the arithmetic operators are defined in OData-ABNF. 4.01 Services MUST support case-insensitive operator names. Clients that want to work with 4.0 services MUST use lower case operator names.

5.1.1.2.1 Addition
@@ -1257,31 +1265,31 @@

The following examples illustrate the use and semantics of each of the Arithmetic operators.

-

Example 63: all products with a Price of 2.55:

+

Example 64: all products with a Price of 2.55:

http://host/service/Products?$filter=Price add 2.45 eq 5.00
-

Example 64: all products with a Price of 2.55:

+

Example 65: all products with a Price of 2.55:

http://host/service/Products?$filter=Price sub 0.55 eq 2.00
-

Example 65: all products with a Price of 2.55:

+

Example 66: all products with a Price of 2.55:

http://host/service/Products?$filter=Price mul 2.0 eq 5.10
-

Example 66: all products with a Price of 2.55:

+

Example 67: all products with a Price of 2.55:

http://host/service/Products?$filter=Price div 2.55 eq 1
-

Example 67: all products with an integer Rating value of 4 or 5:

+

Example 68: all products with an integer Rating value of 4 or 5:

http://host/service/Products?$filter=Rating div 2 eq 2
-

Example 68: all products with an integer Rating value of 5:

+

Example 69: all products with an integer Rating value of 5:

http://host/service/Products?$filter=Rating divby 2 eq 2.5
-

Example 69: all products with a Rating exactly divisible by 5:

+

Example 70: all products with a Rating exactly divisible by 5:

http://host/service/Products?$filter=Rating mod 5 eq 0
@@ -1291,7 +1299,7 @@

5.1.1.3 Grouping<

The Grouping operator (open and close parenthesis “( )”) controls the evaluation order of an expression. The Grouping operator returns the expression grouped inside the parenthesis.

-

Example 70: all products because 9 mod 3 is 0

+

Example 71: all products because 9 mod 3 is 0

http://host/service/Products?$filter=(4 add 5) mod (4 sub 1) eq 0

@@ -1300,7 +1308,7 @@

$compute, $filter or $orderby system query options, or in parameter alias values. The following sections describe the available functions.

Note: ISNULL or COALESCE operators are not defined. Instead, OData defines a null literal that can be used in comparisons.

-

If a parameter of a canonical function is null, the function returns null.

+

If a parameter of a canonical function is null, the function returns null. If the types of parameters do not match the function signature, the function also returns null.

The syntax rules for all functions are defined in OData-ABNF. 4.01 Services MUST support case-insensitive canonical function names. Clients that want to work with 4.0 services MUST use lower case canonical function names.

@@ -1317,7 +1325,7 @@
5.1.1.5.1 concatThe concat function with collection parameter values returns a collection that appends all items of the second collection to the first. If both collections are ordered, the result is also ordered.

The concatMethodCallExpr syntax rule defines how the concat function is invoked.

-

Example 71: all customers from Berlin, Germany

+

Example 72: all customers from Berlin, Germany

http://host/service/Customers?$filter=concat(concat(City,', '),Country) eq 'Berlin, Germany'
@@ -1327,11 +1335,11 @@
5.1.1.5.2 cont

The contains function has two overloads, with the following signatures:

Edm.Boolean contains(Edm.String,Edm.String)
 Edm.Boolean contains(OrderedCollection,OrderedCollection)
-

The contains function with string parameter values returns true if the second string is a substring of the first string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

-

The contains function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the beginning or the end of the first collection.

+

The contains function with string parameter values returns true if the second string is a substring of the first string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

+

The contains function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the beginning or the end of the first collection.

The containsMethodCallExpr syntax rule defines how the contains function is invoked.

-

Example 72: all customers with a CompanyName that contains Alfreds

+

Example 73: all customers with a CompanyName that contains Alfreds

http://host/service/Customers?$filter=contains(CompanyName,'Alfreds')
@@ -1341,11 +1349,11 @@
5.1.1.5.3 ends

The endswith function has two overloads, with the following signatures:

Edm.Boolean endswith(Edm.String,Edm.String)
 Edm.Boolean endswith(OrderedCollection,OrderedCollection)
-

The endswith function with string parameter values returns true if the first string ends with the second string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

-

The endswith function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the beginning of the first collection.

+

The endswith function with string parameter values returns true if the first string ends with the second string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

+

The endswith function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the beginning of the first collection.

The endsWithMethodCallExpr syntax rule defines how the endswith function is invoked.

-

Example 73: all customers with a CompanyName that ends with Futterkiste

+

Example 74: all customers with a CompanyName that ends with Futterkiste

http://host/service/Customers?$filter=endswith(CompanyName,'Futterkiste')
@@ -1359,7 +1367,7 @@
5.1.1.5.4 indexof

The indexof function with ordered collection parameter values returns the zero-based index of the first occurrence of the second collection in the first collection, or -1 if the first collection does not contain the second collection.

The indexOfMethodCallExpr syntax rule defines how the indexof function is invoked.

-

Example 74: all customers with a CompanyName containing lfreds starting at the second character

+

Example 75: all customers with a CompanyName containing lfreds starting at the second character

http://host/service/Customers?$filter=indexof(CompanyName,'lfreds') eq 1
@@ -1373,7 +1381,7 @@
5.1.1.5.5 lengthThe length function with a collection parameter value returns the number of itens in the collection.

The lengthMethodCallExpr syntax rule defines how the length function is invoked.

-

Example 75: all customers with a CompanyName that is 19 characters long

+

Example 76: all customers with a CompanyName that is 19 characters long

http://host/service/Customers?$filter=length(CompanyName) eq 19
@@ -1383,11 +1391,11 @@
5.1.1.5.6 The startswith function has two overloads, with the following signatures:

Edm.Boolean startswith(Edm.String,Edm.String)
 Edm.Boolean startswith(Collection,Collection)
-

The startswith function with string parameter values returns true if the first string starts with the second string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

-

The startswith function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the end of the first collection.

+

The startswith function with string parameter values returns true if the first string starts with the second string, otherwise it returns false. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with tolower or toupper.

+

The startswith function with ordered collection parameter values returns true if the first collection can be transformed into the second collection by removing zero or more items from the end of the first collection.

The startsWithMethodCallExpr syntax rule defines how the startswith function is invoked.

-

Example 76: all customers with a CompanyName that starts with Alfr

+

Example 77: all customers with a CompanyName that starts with Alfr

http://host/service/Customers?$filter=startswith(CompanyName,'Alfr')
@@ -1408,11 +1416,11 @@
5.1.1.5.7 s

A negative start index N, if supported, returns a string/collection starting N characters/items before the end of the string/collection.

The substringMethodCallExpr syntax rule defines how the substring function is invoked.

-

Example 77: all customers with a CompanyName of lfreds Futterkiste once the first character has been removed

+

Example 78: all customers with a CompanyName of lfreds Futterkiste once the first character has been removed

http://host/service/Customers?$filter=substring(CompanyName,1) eq 'lfreds Futterkiste'
-

Example 78: all customers with a CompanyName that has lf as the second and third characters, e.g, Alfreds Futterkiste

+

Example 79: all customers with a CompanyName that has lf as the second and third characters, e.g, Alfreds Futterkiste

http://host/service/Customers?$filter=substring(CompanyName,1,2) eq 'lf'
@@ -1425,9 +1433,9 @@
5.1.1.6.1 h

The hassubset function has the following signature:

Edm.Boolean hassubset(Collection, Collection)
-

The hassubset function returns true if the first collection can be transformed into the second collection by reordering and/or removing zero or more items. The hasSubsetMethodCallExpr syntax rule defines how the hassubset function is invoked.

+

The hassubset function returns true if the first collection can be transformed into the second collection by reordering and/or removing zero or more items. The hasSubsetMethodCallExpr syntax rule defines how the hassubset function is invoked.

-

Example 80: hassubset expression that returns false: 1 appears only once in the left operand

+

Example 81: hassubset expression that returns false: 1 appears only once in the left operand

hassubset([1,2],[1,1,2])
@@ -1444,16 +1452,16 @@
5.

The hassubsequence function has the following signature:

Edm.Boolean hassubsequence(OrderedCollection,OrderedCollection)
-

The hassubsequence function returns true if the first collection can be transformed into the second collection by removing zero or more items. The hasSubsequenceMethodCallExpr syntax rule defines how the hassubsequence function is invoked.

+

The hassubsequence function returns true if the first collection can be transformed into the second collection by removing zero or more items. The hasSubsequenceMethodCallExpr syntax rule defines how the hassubsequence function is invoked.

-

Example 81: hassubsequence expressions that return true

+

Example 82: hassubsequence expressions that return true

hassubsequence([4,1,3],[4,1,3])
hassubsequence([4,1,3],[4,1])
hassubsequence([4,1,3],[4,3])
hassubsequence([4,1,3,1],[1,1])
-

Example 82: hassubsequence expressions that return false

+

Example 83: hassubsequence expressions that return false

hassubsequence([4,1,3],[1,3,4])
hassubsequence([4,1,3],[3,1])
hassubsequence([1,2],[1,1,2])
@@ -1469,13 +1477,13 @@
5.

The matchespattern function has the following signatures:

Edm.Boolean matchespattern(Edm.String,Edm.String)
 Edm.Boolean matchespattern(Edm.String,Edm.String,Edm.String)
-

The second parameter MUST evaluate to a string containing an ECMAScript (JavaScript) regular expression. The matchespattern function returns true if the first parameter evaluates to a string matching that regular expression, using syntax and semantics of ECMAScript regular expressions, otherwise it returns false. If the optional third parameter is provided, it MUST evaluate to a string consisting of ECMAScript regular expression flags to modify the match.

+

The second parameter MUST evaluate to a string containing an ECMAScript (JavaScript) regular expression, otherwise the function returns null. The matchespattern function returns true if the first parameter evaluates to a string matching that regular expression, using syntax and semantics of ECMAScript regular expressions, otherwise it returns false. If the optional third parameter is provided, it MUST evaluate to a string consisting of ECMAScript regular expression flags to modify the match, otherwise the function returns null.

-

Example 83: all customers with a CompanyName that match the (percent-encoded) regular expression ^A.*e$

+

Example 84: all customers with a CompanyName that match the (percent-encoded) regular expression ^A.*e$

http://host/service/Customers?$filter=matchespattern(CompanyName,'%5EA.*e$')
-

Example 84: all customers with a FormattedAddress that contains a line ending with berg or ends with berg

+

Example 85: all customers with a FormattedAddress that contains a line ending with berg or ends with berg

http://host/service/Customers?$filter=matchespattern(FormattedAddress,'berg$','m')
@@ -1486,7 +1494,7 @@
5.1.1.7.2 tolower
Edm.String tolower(Edm.String)

The tolower function returns the input parameter string value with all uppercase characters converted to lowercase according to Unicode rules. The toLowerMethodCallExpr syntax rule defines how the tolower function is invoked.

-

Example 85: all customers with a CompanyName that equals alfreds futterkiste once any uppercase characters have been converted to lowercase

+

Example 86: all customers with a CompanyName that equals alfreds futterkiste once any uppercase characters have been converted to lowercase

http://host/service/Customers?$filter=tolower(CompanyName) eq 'alfreds futterkiste'
@@ -1497,7 +1505,7 @@
5.1.1.7.3 toupper
Edm.String toupper(Edm.String)

The toupper function returns the input parameter string value with all lowercase characters converted to uppercase according to Unicode rules. The toUpperMethodCallExpr syntax rule defines how the toupper function is invoked.

-

Example 86: all customers with a CompanyName that equals ALFREDS FUTTERKISTE once any lowercase characters have been converted to uppercase

+

Example 87: all customers with a CompanyName that equals ALFREDS FUTTERKISTE once any lowercase characters have been converted to uppercase

http://host/service/Customers?$filter=toupper(CompanyName) eq 'ALFREDS FUTTERKISTE'
@@ -1508,7 +1516,7 @@
5.1.1.7.4 trim<
Edm.String trim(Edm.String)

The trim function returns the input parameter string value with all leading and trailing whitespace characters, according to Unicode rules, removed. The trimMethodCallExpr syntax rule defines how the trim function is invoked.

-

Example 87: all customers with a CompanyName without leading or trailing whitespace characters

+

Example 88: all customers with a CompanyName without leading or trailing whitespace characters

http://host/service/Customers?$filter=trim(CompanyName) eq CompanyName
@@ -1532,7 +1540,7 @@
5.1.1.8.2 day

The day function returns the day component Date or DateTimeOffset parameter value, evaluated in the time zone of the DateTimeOffset parameter value. The dayMethodCallExpr syntax rule defines how the day function is invoked.

Services that are unable to preserve the offset of Edm.DateTimeOffset values and instead normalize the values to some common time zone (for example UTC) MUST fail evaluation of the day function for literal Edm.DateTimeOffset values that are not stated in the time zone of the normalized values.

-

Example 88: all employees born on the 8th day of a month

+

Example 89: all employees born on the 8th day of a month

http://host/service/Employees?$filter=day(BirthDate) eq 8
@@ -1544,7 +1552,7 @@
-

Example 89: all employees born less than 100 milliseconds after a full second of any minute of any hour on any day

+

Example 90: all employees born less than 100 milliseconds after a full second of any minute of any hour on any day

http://host/service/Employees?$filter=[fractionalseconds(BirthDate) lt 0.1
@@ -1557,7 +1565,7 @@
5.1.1.8.4 hour<

The hour function returns the hour component (0 to 23) of the DateTimeOffset or TimeOfDay parameter value, evaluated in the time zone of the DateTimeOffset parameter value. The hourMethodCallExpr syntax rule defines how the hour function is invoked.

Services that are unable to preserve the offset of Edm.DateTimeOffset values and instead normalize the values to some common time zone (for example UTC) MUST fail evaluation of the hour function for literal Edm.DateTimeOffset values that are not stated in the time zone of the normalized values.

-

Example 90: all employees born in hour 4, between 04:00 (inclusive) and 05:00 (exclusive)

+

Example 91: all employees born in hour 4, between 04:00 (inclusive) and 05:00 (exclusive)

http://host/service/Employees?$filter=hour(BirthDate) eq 4
@@ -1583,7 +1591,7 @@
5.1.1.8.7 minute

The minute function returns the minute component (0 to 59) of the DateTimeOffset or TimeOfDay parameter value, evaluated in the time zone of the DateTimeOffset parameter value. The minuteMethodCallExpr syntax rule defines how the minute function is invoked.

-

Example 91: all employees born in minute 40 of any hour on any day

+

Example 92: all employees born in minute 40 of any hour on any day

http://host/service/Employees?$filter=minute(BirthDate) eq 40
@@ -1596,7 +1604,7 @@
5.1.1.8.8 month<

The month function returns the month component of the Date or DateTimeOffset parameter value, evaluated in the time zone of the DateTimeOffset parameter value. The monthMethodCallExpr syntax rule defines how the month function is invoked.

Services that are unable to preserve the offset of Edm.DateTimeOffset values and instead normalize the values to some common time zone (for example UTC) MUST fail evaluation of the month function for literal Edm.DateTimeOffset values that are not stated in the time zone of the normalized values.

-

Example 92: all employees born in May

+

Example 93: all employees born in May

http://host/service/Employees?$filter=month(BirthDate) eq 5
@@ -1616,7 +1624,7 @@
5.1.1.8.10 second

The second function returns the second component (0 to 59 for regular seconds, and 60 for leap seconds, without the fractional part) of the DateTimeOffset or TimeOfDay parameter value. The secondMethodCallExpr syntax rule defines how the second function is invoked.

-

Example 93: all employees born in second 40 of any minute of any hour on any day

+

Example 94: all employees born in second 40 of any minute of any hour on any day

http://host/service/Employees?$filter=second(BirthDate) eq 40
@@ -1651,7 +1659,7 @@
5.1.1.8.14 yearThe year function returns the year component of the Date or DateTimeOffset parameter value, evaluated in the time zone of the DateTimeOffset parameter value. The yearMethodCallExpr syntax rule defines how the year function is invoked.

Services that are unable to preserve the offset of Edm.DateTimeOffset values and instead normalize the values to some common time zone (for example UTC) MUST fail evaluation of the year function for literal Edm.DateTimeOffset values that are not stated in the time zone of the normalized values.

-

Example 94: all employees born in 1971

+

Example 95: all employees born in 1971

http://host/service/Employees?$filter=year(BirthDate) eq 1971
@@ -1667,7 +1675,7 @@
5.1.1.9.1 ceiling Edm.Decimal ceiling(Edm.Decimal)

The ceiling function rounds the input numeric parameter up to the nearest numeric value with no decimal component. The ceilingMethodCallExpr syntax rule defines how the ceiling function is invoked.

-

Example 95: all orders with freight costs that round up to 32

+

Example 96: all orders with freight costs that round up to 32

http://host/service/Orders?$filter=ceiling(Freight) eq 32
@@ -1679,7 +1687,7 @@
5.1.1.9.2 floor< Edm.Decimal floor(Edm.Decimal)

The floor function rounds the input numeric parameter down to the nearest numeric value with no decimal component. The floorMethodCallExpr syntax rule defines how the floor function is invoked.

-

Example 96: all orders with freight costs that round down to 32

+

Example 97: all orders with freight costs that round down to 32

http://host/service/Orders?$filter=floor(Freight) eq 32
@@ -1691,7 +1699,7 @@
5.1.1.9.3 round< Edm.Decimal round(Edm.Decimal)

The round function rounds the input numeric parameter to the nearest numeric value with no decimal component. The mid-point between two integers is rounded away from zero, i.e. 0.5 is rounded to 1 and -0.5 is rounded to -1. The roundMethodCallExpr syntax rule defines how the round function is invoked.

-

Example 97: all orders with freight costs that round to 32

+

Example 98: all orders with freight costs that round to 32

http://host/service/Orders?$filter=round(Freight) eq 32
@@ -1720,7 +1728,6 @@
5.1.1.10.1 castInteger types are cast to enumeration types based on the numeric value of the enumeration members of the target type. For non-flag enumeration types the cast fails if there is no enumeration member with the same numeric value as the integer value. For flag enumeration types the cast fails if the integer value is not in the value range of the underlying integer type of the enumeration type.
  • String values containing a representation of a date-time value according to XML-Schema-2, section 3.3.7 dateTime, can be cast to Edm.DateTimeOffset. If the string value does not contain a time-zone offset, it is treated as UTC.
  • -

    The cast function is optional for primitive values (first five rules) and up-casts (seventh rule).

    If the cast fails, the cast function returns null.

    @@ -1729,16 +1736,16 @@
    5.1.1.10.2 isofThe isof function has the following signatures

    Edm.Boolean isof(type)
     Edm.Boolean isof(expression,type)
    -

    The single parameter isof function returns true if the current instance is assignable to the type specified, according to the assignment rules for the cast function, otherwise it returns false.

    -

    The two parameter isof function returns true if the object referred to by the expression is assignable to the type specified, according to the same rules, otherwise it returns false.

    +

    The single parameter isof function returns true if the current instance is assignable to the type specified, according to the assignment rules for the cast function, otherwise it returns false.

    +

    The two parameter isof function returns true if the object referred to by the expression is assignable to the type specified, according to the same rules, otherwise it returns false.

    The isofExpr syntax rule defines how the isof function is invoked.

    -

    Example 98: orders that are also BigOrders

    +

    Example 99: orders that are also BigOrders

    http://host/service/Orders?$filter=isof(NorthwindModel.BigOrder)
    http://host/service/Orders?$filter=isof($it,NorthwindModel.BigOrder)
    -

    Example 99: orders of a customer that is a VIPCustomer

    +

    Example 100: orders of a customer that is a VIPCustomer

    http://host/service/Orders?$filter=isof(Customer,NorthwindModel.VIPCustomer)
    @@ -1760,7 +1767,7 @@
    5.1.

    The geo.intersects function has the following signatures:

    Edm.Boolean geo.intersects(Edm.GeographyPoint,Edm.GeographyPolygon)
     Edm.Boolean geo.intersects(Edm.GeometryPoint,Edm.GeometryPolygon)
    -

    The geo.intersects function returns true if the specified point lies within the interior or on the boundary of the specified polygon, otherwise it returns false.

    +

    The geo.intersects function returns true if the specified point lies within the interior or on the boundary of the specified polygon, otherwise it returns false.

    5.1.1.11.3 geo.length
    @@ -1780,12 +1787,12 @@
    5.1.1.12.1 caseThe case function has the following signature:

    expression case(Edm.Boolean:expression, …, Edm.Boolean:expression)

    Each parameter is a pair of expressions separated by a colon (:), where the first expression — the condition — MUST be a Boolean expression, and the second expression — the result — may evaluate to any type.

    -

    The case function evaluates the condition in each pair, starting with the leftmost pair, and stops as soon as a condition evaluates to true. It then returns the value of the result of this pair. It returns null if none of the conditions in any pair evaluates to true. Clients can specify a last pair whose condition is true to get a non-null “default/else/otherwise” result.

    +

    The case function evaluates the condition in each pair, starting with the leftmost pair, and stops as soon as a condition evaluates to true. It then returns the value of the result of this pair. It returns null if none of the conditions in any pair evaluates to true. Clients can specify a last pair whose condition is true to get a non-null “default/else/otherwise” result.

    Boolean expressions containing DateTimeOffset or TimeOfDay literals without the optional seconds part will introduce ambiguity for parsers. Clients SHOULD use whitespace or parentheses to avoid ambiguity.

    Clients SHOULD ensure that the results in all pairs are compatible. If all results are of the same type, the type of the case expression is of that type. If all results are of numeric type, then the type of the case expression is a numeric type capable of representing any of these expressions according to standard type promotion rules.

    Services MAY support case expressions containing parameters of incompatible types, in which case the case expression is treated as Edm.Untyped and its value has the type of the parameter expression selected by the case statement.

    -

    Example 100: compute signum(X)

    +

    Example 101: compute signum(X)

    $compute=case(X gt 0:1,X lt 0:-1,true:0) as SignumX
    @@ -1801,18 +1808,18 @@

    5.1.1.13.1 any

    -

    The any operator applies a Boolean expression to each member of a collection and returns true if and only if the expression is true for any member of the collection, otherwise it returns false. This implies that the any operator always returns false for an empty collection.

    -

    The any operator can be used without an argument expression. This short form returns false if and only if the collection is empty.

    +

    The any operator applies a Boolean expression to each member of a collection and returns true if and only if the expression is true for any member of the collection, otherwise it returns false. This implies that the any operator always returns false for an empty collection.

    +

    The any operator can be used without an argument expression. This short form returns false if and only if the collection is empty.

    -

    Example 101: all Orders that have any Items with a Quantity greater than 100

    +

    Example 102: all Orders that have any Items with a Quantity greater than 100

    http://host/service/Orders?$filter=Items/any(d:d/Quantity gt 100)
    -

    Example 102: all customers having an order with a deviating shipping address. The Address in the argument expression is evaluated in the scope of the Customers collection.

    +

    Example 103: all customers having an order with a deviating shipping address. The Address in the argument expression is evaluated in the scope of the Customers collection.

    http://host/service/Customers?$filter=Orders/any(o:o/ShippingAddress ne Address)
    -

    Example 103: all categories along with their products used in some order with a deviating unit price. The unprefixed UnitPrice in the argument expression is evaluated in the scope of the expanded Products.

    +

    Example 104: all categories along with their products used in some order with a deviating unit price. The unprefixed UnitPrice in the argument expression is evaluated in the scope of the expanded Products.

    http://host/service/Categories?$expand=Products(
       $filter=OrderItems/any(oi:oi/UnitPrice ne UnitPrice))
    @@ -1820,10 +1827,10 @@
    5.1.1.13.1 any
    5.1.1.13.2 all
    -

    The all operator applies a Boolean expression to each member of a collection and returns true if the expression is true for all members of the collection, otherwise it returns false. This implies that the all operator always returns true for an empty collection.

    +

    The all operator applies a Boolean expression to each member of a collection and returns true if the expression is true for all members of the collection, otherwise it returns false. This implies that the all operator always returns true for an empty collection.

    The all operator cannot be used without an argument expression.

    -

    Example 104: all Orders that have only Items with a Quantity greater than 100

    +

    Example 105: all Orders that have only Items with a Quantity greater than 100

    http://host/service/Orders?$filter=Items/all(d:d/Quantity gt 100)
    @@ -1836,7 +1843,7 @@
    $filter expressions. They are represented according to the primitiveLiteral rule in OData-ABNF.

    -

    Example 105: expressions using primitive literals

    +

    Example 106: expressions using primitive literals

    NullValue eq null
    TrueValue eq true
    FalseValue eq false
    @@ -1867,11 +1874,11 @@
    MUST be percent-encoded in URLs although some browsers will accept and pass them on unencoded.

    -

    Example 106: collection of string literals

    +

    Example 107: collection of string literals

    http://host/service/ProductsByColors(colors=@c)?@c=["red","green"]
    -

    Example 107: check whether a pair of properties has one of several possible pair values

    +

    Example 108: check whether a pair of properties has one of several possible pair values

    $filter=[FirstName,LastName] in [["John","Doe"],["Jane","Smith"]]
    @@ -1889,15 +1896,15 @@
    5.1.1.14.4 $it

    Note: property names and property paths in $filter expressions nested within $expand are evaluated in the context of the declared type of the expanded navigation property, so property names and property paths for the current instance of the collection identified by the resource path MUST be prefixed with $it/.

    The $it literal can also be used as a path prefix to invoke a bound function overload on the current instance within an expression. Function names without a path prefix refer to an unbound function overload.

    -

    Example 108: email addresses ending with .com assuming EmailAddresses is a collection of strings

    +

    Example 109: email addresses ending with .com assuming EmailAddresses is a collection of strings

    http://host/service/Customers(1)/EmailAddresses?$filter=endswith($it,'.com')
    -

    Example 109: customers along with their orders that shipped to the same city as the customer’s address. The nested filter expression is evaluated in the context of Orders; $it allows referring to values in the outer context of Customers. Note: the nested filter condition could equivalently be expressed as $it/Address/City eq $this/ShipTo/City.

    +

    Example 110: customers along with their orders that shipped to the same city as the customer’s address. The nested filter expression is evaluated in the context of Orders; $it allows referring to values in the outer context of Customers. Note: the nested filter condition could equivalently be expressed as $it/Address/City eq $this/ShipTo/City.

    http://host/service/Customers?$expand=Orders($filter=$it/Address/City eq ShipTo/City)
    -

    Example 110: products with at least 10 positive reviews. Model.PositiveReviews is a function bound to Model.Product returning a collection of reviews.

    +

    Example 111: products with at least 10 positive reviews. Model.PositiveReviews is a function bound to Model.Product returning a collection of reviews.

    http://host/service/Products?$filter=$it/Model.PositiveReviews()/$count ge 10
    @@ -1906,16 +1913,16 @@
    5.1.1.14.5 $root

    The $root literal can be used in expressions to refer to resources of the same service.

    -

    Example 111: all employees with the same last name as employee A1235

    +

    Example 112: all employees with the same last name as employee A1235

    http://host/service/Employees?$filter=LastName eq $root/Employees('A1245')/LastName
    -

    Example 112: products ordered by a set of customers, where the set of customers is passed as a JSON array containing the resource paths from $root to each customer

    +

    Example 113: products ordered by a set of customers, where the set of customers is passed as a JSON array containing the resource paths from $root to each customer

    http://host/service/ProductsOrderedBy(Customers=@c)
       ?@c=[$root/Customers('ALFKI'),$root/Customers('BLAUS')]
    -

    Example 113: function call returning the average rating of a given employee by their peers (employees in department D1)

    +

    Example 114: function call returning the average rating of a given employee by their peers (employees in department D1)

    http://host/service/Employees('A1245')/self.AvgRating(RatedBy=@peers)
       ?@peers=$root/Employees/$filter(Department eq 'D1')
    @@ -1925,7 +1932,7 @@
    5.1.1.14.6 $this

    The $this literal can be used in $filter and $orderby expressions nested within $expand and $select for collection-valued properties and navigation properties. It refers to the current instance of the collection.

    -

    Example 114: select only email addresses ending with .com

    +

    Example 115: select only email addresses ending with .com

    http://host/service/Customers?$select=EmailAddresses($filter=endswith($this,'.com'))
    @@ -1938,11 +1945,11 @@

    -

    Example 115: similar behavior whether HeadquarterAddress is a nullable complex type or a nullable navigation property

    +

    Example 116: similar behavior whether HeadquarterAddress is a nullable complex type or a nullable navigation property

    Companies(1)/HeadquarterAddress/Street

    To access properties of derived types, the property name MUST be prefixed with the qualified name of the derived type on which the property is defined, followed by a forward slash (/), see addressing derived types. If the current instance is not of the specified derived type, the path expression returns null.

    -

    If the property or navigation property is not defined for the type of the resource and that type supports dynamic properties or navigation properties, then the property or navigation property is treated as null for all instances on which it has no value.

    +

    If the property or navigation property is not defined for the type of the resource and that type supports dynamic properties or navigation properties, then the property or navigation property is treated as null for all instances on which it has no value.

    If the property or navigation property is not defined for the type of the resource and that type does not support dynamic properties or navigation properties, then the request may be considered malformed.

    @@ -1952,11 +1959,11 @@

    path expression leading to the annotated resource or property.

    If an annotation is not applied to the resource or property, then its value, and the values of its components, are treated as null.

    -

    Example 116: Return Products that have prices in Euro

    +

    Example 117: Return Products that have prices in Euro

    http://host/service/Products?$filter=Price/@Measures.Currency eq 'EUR'
    -

    Example 117: Return Employees that have any error messages in the Core.Messages annotation

    +

    Example 118: Return Employees that have any error messages in the Core.Messages annotation

    http://host/service/Employees?$filter=@Core.Messages/any(m:m/severity eq 'error')

    Services MAY additionally support the use of the unqualified term name by defining one or more default namespaces through the Core.DefaultNamespace annotation term defined in OData-VocCore. For more information on default namespaces, see Default Namespaces in OData-Protocol. This short notation however uses the same name pattern as parameter aliases. If a query option is specified as a parameter alias, then any occurrence of the parameter alias name in an expression MUST evaluate to the parameter alias value and MUST NOT evaluate to the annotation value of an identical unqualified term name.

    @@ -2136,7 +2143,7 @@

    5.1.2 System Query Option $filter

    -

    The $filter system query option allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with $filter is evaluated for each resource in the collection, and only items where the expression evaluates to true are included in the response. Resources for which the expression evaluates to false or to null, or which reference properties that are unavailable due to permissions, are omitted from the response.

    +

    The $filter system query option allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with $filter is evaluated for each resource in the collection, and only items where the expression evaluates to true are included in the response. Resources for which the expression evaluates to false or to null, or which reference properties that are unavailable due to permissions, are omitted from the response.

    The OData-ABNF filter syntax rule defines the formal grammar of the $filter query option.

    @@ -2155,65 +2162,65 @@

    -

    Example 118: expand a navigation property of an entity type

    +

    Example 119: expand a navigation property of an entity type

    http://host/service/Products?$expand=Category
    -

    Example 119: expand a navigation property of a complex type

    +

    Example 120: expand a navigation property of a complex type

    http://host/service/Customers?$expand=Addresses/Country

    A path MUST NOT appear in more than one expand item.

    Query options can be applied to an expanded navigation property by appending a semicolon-separated list of query options, enclosed in parentheses, to the navigation property name. Allowed system query options are $compute, $select, $expand, and $levels for all navigation properties, plus $filter, $orderby, $skip, $top, $count, and $search for collection-valued navigation properties.

    -

    Example 120: all categories and for each category all related products with a discontinued date equal to null

    +

    Example 121: all categories and for each category all related products with a discontinued date equal to null

    http://host/service/Categories?$expand=Products($filter=DiscontinuedDate eq null)

    The $count segment can be appended to a navigation property name or type-cast segment following a navigation property name to return just the count of the related entities. The $filter and $search system query options can be used to limit the number of related entities included in the count.

    -

    Example 121: all categories and for each category the number of all related products

    +

    Example 122: all categories and for each category the number of all related products

    http://host/service/Categories?$expand=Products/$count
    -

    Example 122: all categories and for each category the number of all related blue products

    +

    Example 123: all categories and for each category the number of all related blue products

    http://host/service/Categories?$expand=Products/$count($search=blue)

    To retrieve entity references instead of the related entities, append /$ref to the navigation property name or type-cast segment following a navigation property name. The system query options $filter, $search, $skip, $top, and $count can be used to limit the number of expanded entity references.

    -

    Example 123: all categories and for each category the references of all related products

    +

    Example 124: all categories and for each category the references of all related products

    http://host/service/Categories?$expand=Products/$ref
    -

    Example 124: all categories and for each category the references of all related products of the derived type Sales.PremierProduct

    +

    Example 125: all categories and for each category the references of all related products of the derived type Sales.PremierProduct

    http://host/service/Categories?$expand=Products/Sales.PremierProduct/$ref
    -

    Example 125: all categories and for each category the references of all related premier products with a current promotion equal to null

    +

    Example 126: all categories and for each category the references of all related premier products with a current promotion equal to null

    http://host/service/Categories
       ?$expand=Products/Sales.PremierProduct/$ref($filter=CurrentPromotion eq null)

    Cyclic navigation properties (whose target type is identical or can be cast to its source type) can be recursively expanded using the special $levels option. The value of the $levels option is either a positive integer to specify the number of levels to expand, or the literal string max to specify the maximum expansion level supported by that service. A $levels option with a value of 1 specifies a single expand with no recursion.

    -

    Example 126: all employees with their manager, manager’s manager, and manager’s manager’s manager

    +

    Example 127: all employees with their manager, manager’s manager, and manager’s manager’s manager

    http://host/service/Employees?$expand=ReportsTo($levels=3)

    It is also possible to expand all declared and dynamic navigation properties using a star (*). To retrieve references to all related entities use */$ref, and to expand all related entities with a certain distance use the star operator with the $levels option. The star operator can be combined with explicitly named navigation properties, which take precedence over the star operator.

    The star operator does not implicitly include stream properties.

    -

    Example 127: expand Supplier and include references for all other related entities

    +

    Example 128: expand Supplier and include references for all other related entities

    http://host/service/Categories?$expand=*/$ref,Supplier
    -

    Example 128: expand all related entities and their related entities

    +

    Example 129: expand all related entities and their related entities

    http://host/service/Categories?$expand=*($levels=2)

    Specifying a stream property includes the media stream inline according to the specified format.

    -

    Example 129: include Employee’s Photo stream property along with other properties of the customer

    +

    Example 130: include Employee’s Photo stream property along with other properties of the customer

    http://host/service/Employees?$expand=Photo

    Specifying $value for a media entity includes the media entity’s stream value inline according to the specified format.

    -

    Example 130: Include the Product’s media stream along with other properties of the product

    +

    Example 131: Include the Product’s media stream along with other properties of the product

    http://host/service/Products?$expand=$value

    @@ -2239,34 +2246,34 @@

    -

    Example 131: rating and release date of all products

    +

    Example 132: rating and release date of all products

    http://host/service/Products?$select=Rating,ReleaseDate

    It is also possible to request all declared and dynamic structural properties using a star (*).

    -

    Example 132: all structural properties of all products

    +

    Example 133: all structural properties of all products

    http://host/service/Products?$select=*
    -

    If the select item is not defined for the type of the resource, and that type supports dynamic properties or instance annotations, then the property is treated as null for all instances on which it is not defined.

    +

    If the select item is not defined for the type of the resource, and that type supports dynamic properties or instance annotations, then the property is treated as null for all instances on which it is not defined.

    If the select item is not defined for the type of the resource, and that type does not support dynamic properties or instance annotations, then the request is considered malformed.

    If the select item is an instance annotation of type entity or collection of entities, then the request is considered malformed. Entity-valued annotations can be included using $expand.

    If the select item is a navigation property, then the corresponding navigation link is represented in the response. If the navigation property also appears in an $expand query option, then it is additionally represented as inline content. This inline content can itself be restricted with a nested $select query option, see section 5.1.2.

    -

    Example 133: name and description of all products, plus name of expanded category

    +

    Example 134: name and description of all products, plus name of expanded category

    http://host/service/Products?$select=Name,Description
       &$expand=Category($select=Name)

    The select item MUST be prefixed with a qualified structured type name in order to select a property defined on a type derived from the type of the resource segment.

    A select item that is a complex type or collection of complex type can be followed by a forward slash, an optional type-cast segment, and the name of a property of the complex type (and so on for nested complex types).

    -

    Example 134: the AccountRepresentative property of any supplier that is of the derived type Namespace.PreferredSupplier, together with the Street property of the complex property Address, and the Location property of the derived complex type Namespace.AddressWithLocation

    +

    Example 135: the AccountRepresentative property of any supplier that is of the derived type Namespace.PreferredSupplier, together with the Street property of the complex property Address, and the Location property of the derived complex type Namespace.AddressWithLocation

    http://host/service/Suppliers
       ?$select=Namespace.PreferredSupplier/AccountRepresentative,
                Address/Street,Address/Namespace.AddressWithLocation/Location

    Query options can be applied to a select item that is a path to a single complex value or a collection of primitive or complex values by appending a semicolon-separated list of query options, enclosed in parentheses, to the select item. The allowed system query options depend on the type of the resource identified by the select item, see section System Query Options, with the exception of $expand. The same property MUST NOT have select options specified in more than one place in a request and MUST NOT be specified in more than one expand.

    -

    Example 135: select up to five addresses whose City starts with an H, sorted, and with the Country expanded

    +

    Example 136: select up to five addresses whose City starts with an H, sorted, and with the Country expanded

    http://host/service/Customers
       ?$select=Addresses($filter=startswith(City,'H');$top=5;
                          $orderby=Country/Name,City,Street)
    @@ -2278,7 +2285,7 @@ 

    -

    Example 136: the ID property, the ActionName action defined in Model and all actions and functions defined in the Model2 for each product if those actions and functions can be bound to that product

    +

    Example 137: the ID property, the ActionName action defined in Model and all actions and functions defined in the Model2 for each product if those actions and functions can be bound to that product

    http://host/service/Products?$select=ID,Model.ActionName,Model2.*

    When multiple select item exist in a $select clause, then the total set of properties, open properties, navigation properties, actions and functions to be returned is equal to the union of the set of those identified by each select item.

    @@ -2310,7 +2317,7 @@

    $search system query option to request entities matching the specified expression. Leading and trailing spaces are not considered part of the search expression.

    Terms can be any single word to be matched within the expression.

    Terms enclosed in double-quotes comprise a phrase.

    -

    Each individual term or phrase comprises a Boolean expression that returns true if the term or phrase is matched, otherwise false. The semantics of what is considered a match is dependent upon the service.

    +

    Each individual term or phrase comprises a Boolean expression that returns true if the term or phrase is matched, otherwise false. The semantics of what is considered a match is dependent upon the service.

    Expressions enclosed in parenthesis comprise a group expression.

    The search expression can contain any number of terms, phrases, or group expressions, along with the case-sensitive keywords NOT, AND, and OR, evaluated in that order.

    -

    Expressions prefaced with NOT evaluate to true if the expression is not matched, otherwise false.

    -

    Two expressions not enclosed in quotes and separated by a space are equivalent to the same two expressions separated by the AND keyword. Such expressions evaluate to true if both expressions evaluate to true, otherwise false.

    -

    Expressions separated by an OR evaluate to true if either of the expressions evaluate to true, otherwise false.

    +

    Expressions prefaced with NOT evaluate to true if the expression is not matched, otherwise false.

    +

    Two expressions not enclosed in quotes and separated by a space are equivalent to the same two expressions separated by the AND keyword. Such expressions evaluate to true if both expressions evaluate to true, otherwise false.

    +

    Expressions separated by an OR evaluate to true if either of the expressions evaluate to true, otherwise false.

    To support type-ahead use cases, incomplete search expressions can be sent as OData string literals enclosed in single-quotes, and single-quotes within the search expression doubled. Such an expression can also be used to search for double quotes: ?$search='"'.

    The OData-ABNF searchExpr syntax rule defines the formal grammar of the search expression.

    @@ -2346,7 +2353,7 @@

    The OData-ABNF compute syntax rule defines the formal grammar of the $compute query option.

    Computed properties SHOULD be included as dynamic properties in the result and MUST be included if $select is specified with the computed property name, or star (*).

    -

    Example 138: compute total price for order items

    +

    Example 139: compute total price for order items

    http://host/service/Orders(10)/Items
       ?$select=Product/Description,Total
       &$filter=Total gt 100
    @@ -2373,7 +2380,7 @@ 

    OData-ABNF.

    Custom query options MUST NOT begin with a $ or @ character.

    -

    Example 139: service-specific custom query option debug-mode

    +

    Example 140: service-specific custom query option debug-mode

    http://host/service/Products?debug-mode=true
    @@ -2384,15 +2391,15 @@

    OData-ABNF.

    The semantics of parameter aliases are covered in OData-Protocol. The OData-ABNF rule aliasAndValue defines the formal grammar for passing parameter alias values as query options.

    -

    Example 140:

    +

    Example 141:

    http://host/service/Movies?$filter=contains(@word,Title)&@word='Black'
    -

    Example 141:

    +

    Example 142:

    http://host/service/Movies?$filter=Title eq @title&@title='Wizard of Oz'
    -

    Example 142: JSON array of strings as parameter alias value — note that [, ], and " need to be percent-encoded in real URLs, the clear-text representation used here is just for readability

    +

    Example 143: JSON array of strings as parameter alias value — note that [, ], and " need to be percent-encoded in real URLs, the clear-text representation used here is just for readability

    http://host/service/Products/Model.WithIngredients(Ingredients=@i)
       ?@i=["Carrots","Ginger","Oranges"]
    diff --git a/docs/odata-url-conventions/odata-url-conventions.md b/docs/odata-url-conventions/odata-url-conventions.md index 3c69e4c9..9914370e 100644 --- a/docs/odata-url-conventions/odata-url-conventions.md +++ b/docs/odata-url-conventions/odata-url-conventions.md @@ -1593,9 +1593,29 @@ The following operators, functions, and literals can be used in The [OData-ABNF](#ODataABNF) `commonExpr` syntax rule defines the formal grammar of common expressions. +The following subsections specify situations in which expressions evaluate to `null` +if operands or parameters do not have the types expected by an operator or function. +Notwithstanding these rules, if a service can infer such a type discrepancy for an expression +that appears in a request independently of the underlying data, +it MUST reject the request with an error message +explaining the discrepancy. The inferral can be based on, for example, the +declared type of a property or the type of a literal value that occurs in the +expression. + +::: example +Example 52: In a search for people above a certain age +``` +http://host/service/People?$filter=Age gt '50' +``` +the expression would always evaluate to `null` because the age 50 is erroneously +given as a string and the [`$filter`](#SystemQueryOptionfilter) would return an empty result, although this is +really the result of a typing error. That's why a "type mismatch" error must +instead be returned in such a case. +::: + #### 5.1.1.1 Logical Operators -OData defines a set of logical operators that evaluate to true or false +OData defines a set of logical operators that evaluate to `true` or `false` (i.e. a `boolCommonExpr` as defined in [OData-ABNF](#ODataABNF)). Logical operators are typically used to filter a collection of resources. @@ -1618,25 +1638,31 @@ The `eq`, `ne`, and `in` operators can be used with collection-valued operands, and the `eq` and `ne` operators can be used with operands of a structured type. +If at least one operand of an `eq`, `ne`, `lt`, `le`, `gt`, or `ge` operator +is non-numeric and the operands have different types, the operator returns `null`. + +The rules for the Boolean operators `and`, `or`, and `not` assume Boolean operands. +If an operand of a Boolean operator is not Boolean, the operator returns `null`. + ##### 5.1.1.1.1 Equals -The `eq` operator returns true if the left operand is equal to the right -operand, otherwise it returns false. +The `eq` operator returns `true` if the left operand is equal to the right +operand, otherwise it returns `false`. -When applied to operands of entity types, the `eq` operator returns true +When applied to operands of entity types, the `eq` operator returns `true` if both operands represent the same entity, or both operands represent -null. +`null`. When applied to operands of complex types, the `eq` operator returns -true if both operands have the same structure and same values, or both -operands represent null. +`true` if both operands have the same structure and same values, or both +operands represent `null`. -When applied to ordered collections, the `eq` operator returns true if +When applied to ordered collections, the `eq` operator returns `true` if both operands have the same cardinality and each member of the left operand is equal to the corresponding member of the right operand. For services that support comparing unordered collections, the `eq` -operator returns true if both operands are equal after applying the same +operator returns `true` if both operands are equal after applying the same ordering on both collections. Each of the special values `null`, `-INF`, and `INF` is equal to itself, @@ -1646,21 +1672,21 @@ The special value `NaN` is not equal to anything, even to itself. ##### 5.1.1.1.2 Not Equals -The `ne` operator returns true if the left operand is not equal to the -right operand, otherwise it returns false. +The `ne` operator returns `true` if the left operand is not equal to the +right operand, otherwise it returns `false`. -When applied to operands of entity types, the `ne` operator returns true +When applied to operands of entity types, the `ne` operator returns `true` if the two operands do not represent the same entity. When applied to operands of complex types, the `ne` operator returns -true if the operands do not have the same structure and same values. +`true` if the operands do not have the same structure and same values. -When applied to ordered collections, the `ne` operator returns true if +When applied to ordered collections, the `ne` operator returns `true` if both operands do not have the same cardinality or any member of the left operand is not equal to the corresponding member of the right operand. For services that support comparing unordered collections, the `ne` -operator returns true if both operands do not have the same cardinality +operator returns `true` if both operands do not have the same cardinality or do not contain the same members, in any order. Each of the special values `null`, `-INF`, and `INF` is not equal to any @@ -1672,8 +1698,8 @@ The `null` value is not equal to any value but itself. ##### 5.1.1.1.3 Greater Than -The `gt` operator returns true if the left operand is greater than the -right operand, otherwise it returns false. +The `gt` operator returns `true` if the left operand is greater than the +right operand, otherwise it returns `false`. The special value `INF` is greater than any number, and any number is greater than `-INF`. @@ -1686,19 +1712,19 @@ with language-dependent order with the term [`Core.IsLanguageDependent`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#IsLanguageDependent), see [OData-VocCore](#ODataVocCore). -If any operand is `null`, the operator returns false. +If any operand is `null`, the operator returns `false`. ##### 5.1.1.1.4 Greater Than or Equal -The `ge` operator returns true if the left operand is greater than or -equal to the right operand, otherwise it returns false. +The `ge` operator returns `true` if the left operand is greater than or +equal to the right operand, otherwise it returns `false`. See rules for [`gt`](#GreaterThan) and [`eq`](#Equals) for details. ##### 5.1.1.1.5 Less Than -The `lt` operator returns true if the left operand is less than the -right operand, otherwise it returns false. +The `lt` operator returns `true` if the left operand is less than the +right operand, otherwise it returns `false`. The special value `-INF` is less than any number, and any number is less than `INF`. @@ -1711,43 +1737,43 @@ with language-dependent order with the term [`Core.IsLanguageDependent`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#IsLanguageDependent), see [OData-VocCore](#ODataVocCore). -If any operand is `null`, the operator returns false. +If any operand is `null`, the operator returns `false`. ##### 5.1.1.1.6 Less Than or Equal -The `le` operator returns true if the left operand is less than or equal -to the right operand, otherwise it returns false. +The `le` operator returns `true` if the left operand is less than or equal +to the right operand, otherwise it returns `false`. See rules for [`lt`](#LessThan) and [`eq`](#Equals) for details. ##### 5.1.1.1.7 And -The `and` operator returns true if both the left and right operands -evaluate to true, otherwise it returns false. +The `and` operator returns `true` if both the left and right operands +evaluate to `true`, otherwise it returns `false`. The `null` value is treated as unknown, so if one operand evaluates to -`null` and the other operand to false, the `and` operator returns false. +`null` and the other operand to `false`, the `and` operator returns `false`. All other combinations with `null` return `null`. ##### 5.1.1.1.8 Or -The `or` operator returns false if both the left and right operands both -evaluate to false, otherwise it returns true. +The `or` operator returns `false` if both the left and right operands both +evaluate to `false`, otherwise it returns `true`. The `null` value is treated as unknown, so if one operand evaluates to -`null` and the other operand to true, the `or` operator returns true. +`null` and the other operand to `true`, the `or` operator returns `true`. All other combinations with `null` return `null`. ##### 5.1.1.1.9 Not -The `not` operator returns true if the operand returns false, otherwise -it returns false. +The `not` operator returns `true` if the operand returns `false`, otherwise +it returns `false`. The `null` value is treated as unknown, so `not null` returns `null`. ##### 5.1.1.1.10 Has -The `has` operator returns true if the right operand is an enumeration +The `has` operator returns `true` if the right operand is an enumeration value whose flag(s) are set on the left operand. The `null` value is treated as unknown, so if one operand evaluates to @@ -1755,11 +1781,12 @@ The `null` value is treated as unknown, so if one operand evaluates to ##### 5.1.1.1.11 In -The `in` operator returns true if the left operand is a member of the -right operand. The right operand MUST be either a comma-separated list +The `in` operator returns `true` if the [equality](#Equals) comparison of the left +operand with at least one member of the right operand returns `true`. +The right operand MUST be either a comma-separated list of zero or more primitive values, enclosed in parentheses, or a single expression that resolves to a collection. If the right operand is an empty collection -or list of values, the expression returns false. +or list of values, the `in` operator returns `false`. ##### 5.1.1.1.12 Logical Operator Examples @@ -1767,49 +1794,49 @@ The following examples illustrate the use and semantics of each of the logical operators. ::: example -Example 52: all products with a `Name` equal to `Milk` +Example 53: all products with a `Name` equal to `Milk` ``` http://host/service/Products?$filter=Name eq 'Milk' ``` ::: ::: example -Example 53: all products with a `Name` not equal to `Milk` +Example 54: all products with a `Name` not equal to `Milk` ``` http://host/service/Products?$filter=Name ne 'Milk' ``` ::: ::: example -Example 54: all products with a `Name` greater than `Milk`: +Example 55: all products with a `Name` greater than `Milk`: ``` http://host/service/Products?$filter=Name gt 'Milk' ``` ::: ::: example -Example 55: all products with a `Name` greater than or equal to `Milk`: +Example 56: all products with a `Name` greater than or equal to `Milk`: ``` http://host/service/Products?$filter=Name ge 'Milk' ``` ::: ::: example -Example 56: all products with a `Name` less than `Milk`: +Example 57: all products with a `Name` less than `Milk`: ``` http://host/service/Products?$filter=Name lt 'Milk' ``` ::: ::: example -Example 57: all products with a `Name` less than or equal to `Milk`: +Example 58: all products with a `Name` less than or equal to `Milk`: ``` http://host/service/Products?$filter=Name le 'Milk' ``` ::: ::: example -Example 58: all products with a `Name` equal to `Milk` that also have a `Price` +Example 59: all products with a `Name` equal to `Milk` that also have a `Price` less than 2.55: ``` http://host/service/Products?$filter=Name eq 'Milk' and Price lt 2.55 @@ -1817,7 +1844,7 @@ http://host/service/Products?$filter=Name eq 'Milk' and Price lt 2.55 ::: ::: example -Example 59: all products that either have a `Name` equal to `Milk` or have a +Example 60: all products that either have a `Name` equal to `Milk` or have a `Price` less than 2.55: ``` http://host/service/Products?$filter=Name eq 'Milk' or Price lt 2.55 @@ -1825,21 +1852,21 @@ http://host/service/Products?$filter=Name eq 'Milk' or Price lt 2.55 ::: ::: example -Example 60: all products that do not have a `Name` that ends with `ilk`: +Example 61: all products that do not have a `Name` that ends with `ilk`: ``` http://host/service/Products?$filter=not endswith(Name,'ilk') ``` ::: ::: example -Example 61: all products whose `style` value includes `Yellow`: +Example 62: all products whose `style` value includes `Yellow`: ``` http://host/service/Products?$filter=style has Sales.Pattern'Yellow' ``` ::: ::: example -Example 62: all products whose `Name` is `Milk` or `Cheese`: +Example 63: all products whose `Name` is `Milk` or `Cheese`: ``` http://host/service/Products?$filter=Name in ('Milk', 'Cheese') ``` @@ -1853,7 +1880,8 @@ filter a collection of resources. However, services MAY allow using arithmetic operators with the [`$orderby`](#SystemQueryOptionorderby) system query option. -If an operand of an arithmetic operator is null, the result is null. +If an operand of an arithmetic operator is `null` or has a non-allowed type, +the result is `null`. The syntax rules for the arithmetic operators are defined in [OData-ABNF](#ODataABNF). 4.01 Services MUST support case-insensitive @@ -1970,49 +1998,49 @@ The following examples illustrate the use and semantics of each of the Arithmetic operators. ::: example -Example 63: all products with a Price of 2.55: +Example 64: all products with a Price of 2.55: ``` http://host/service/Products?$filter=Price add 2.45 eq 5.00 ``` ::: ::: example -Example 64: all products with a Price of 2.55: +Example 65: all products with a Price of 2.55: ``` http://host/service/Products?$filter=Price sub 0.55 eq 2.00 ``` ::: ::: example -Example 65: all products with a Price of 2.55: +Example 66: all products with a Price of 2.55: ``` http://host/service/Products?$filter=Price mul 2.0 eq 5.10 ``` ::: ::: example -Example 66: all products with a Price of 2.55: +Example 67: all products with a Price of 2.55: ``` http://host/service/Products?$filter=Price div 2.55 eq 1 ``` ::: ::: example -Example 67: all products with an integer Rating value of 4 or 5: +Example 68: all products with an integer Rating value of 4 or 5: ``` http://host/service/Products?$filter=Rating div 2 eq 2 ``` ::: ::: example -Example 68: all products with an integer Rating value of 5: +Example 69: all products with an integer Rating value of 5: ``` http://host/service/Products?$filter=Rating divby 2 eq 2.5 ``` ::: ::: example -Example 69: all products with a Rating exactly divisible by 5: +Example 70: all products with a Rating exactly divisible by 5: ``` http://host/service/Products?$filter=Rating mod 5 eq 0 ``` @@ -2025,7 +2053,7 @@ evaluation order of an expression. The Grouping operator returns the expression grouped inside the parenthesis. ::: example -Example 70: all products because 9 mod 3 is 0 +Example 71: all products because 9 mod 3 is 0 ``` http://host/service/Products?$filter=(4 add 5) mod (4 sub 1) eq 0 ``` @@ -2044,7 +2072,8 @@ not defined. Instead, OData defines a [`null`](#null) literal that can be used in comparisons. If a parameter of a canonical function is `null`, the function returns -`null`. +`null`. If the types of parameters do not match the function signature, +the function also returns `null`. The syntax rules for all functions are defined in [OData-ABNF](#ODataABNF). 4.01 Services MUST support case-insensitive @@ -2075,7 +2104,7 @@ The `concatMethodCallExpr` syntax rule defines how the `concat` function is invoked. ::: example -Example 71: all customers from Berlin, Germany +Example 72: all customers from Berlin, Germany ``` http://host/service/Customers?$filter=concat(concat(City,', '),Country) eq 'Berlin, Germany' ``` @@ -2091,14 +2120,14 @@ Edm.Boolean contains(Edm.String,Edm.String) Edm.Boolean contains(OrderedCollection,OrderedCollection) ``` -The `contains` function with string parameter values returns true if the +The `contains` function with string parameter values returns `true` if the second string is a substring of the first string, otherwise it returns -false. String comparison is case-sensitive, case-insensitive comparison +`false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `contains` function with ordered collection parameter values returns -true if the first collection can be transformed into the second +`true` if the first collection can be transformed into the second collection by removing zero or more items from the beginning or the end of the first collection. @@ -2106,7 +2135,7 @@ The `containsMethodCallExpr` syntax rule defines how the `contains` function is invoked. ::: example -Example 72: all customers with a `CompanyName` that contains `Alfreds` +Example 73: all customers with a `CompanyName` that contains `Alfreds` ``` http://host/service/Customers?$filter=contains(CompanyName,'Alfreds') ``` @@ -2122,14 +2151,14 @@ Edm.Boolean endswith(Edm.String,Edm.String) Edm.Boolean endswith(OrderedCollection,OrderedCollection) ``` -The `endswith` function with string parameter values returns true if the -first string ends with the second string, otherwise it returns false. +The `endswith` function with string parameter values returns `true` if the +first string ends with the second string, otherwise it returns `false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `endswith` function with ordered collection parameter values returns -true if the first collection can be transformed into the second +`true` if the first collection can be transformed into the second collection by removing zero or more items from the beginning of the first collection. @@ -2137,7 +2166,7 @@ The `endsWithMethodCallExpr` syntax rule defines how the `endswith` function is invoked. ::: example -Example 73: all customers with a `CompanyName` that ends with +Example 74: all customers with a `CompanyName` that ends with `Futterkiste` ``` http://host/service/Customers?$filter=endswith(CompanyName,'Futterkiste') @@ -2169,7 +2198,7 @@ The `indexOfMethodCallExpr` syntax rule defines how the `indexof` function is invoked. ::: example -Example 74: all customers with a `CompanyName` containing `lfreds` +Example 75: all customers with a `CompanyName` containing `lfreds` starting at the second character ``` http://host/service/Customers?$filter=indexof(CompanyName,'lfreds') eq 1 @@ -2195,7 +2224,7 @@ The `lengthMethodCallExpr` syntax rule defines how the `length` function is invoked. ::: example -Example 75: all customers with a `CompanyName` that is 19 characters +Example 76: all customers with a `CompanyName` that is 19 characters long ``` http://host/service/Customers?$filter=length(CompanyName) eq 19 @@ -2212,14 +2241,14 @@ Edm.Boolean startswith(Edm.String,Edm.String) Edm.Boolean startswith(Collection,Collection) ``` -The `startswith` function with string parameter values returns true if +The `startswith` function with string parameter values returns `true` if the first string starts with the second string, otherwise it returns -false. String comparison is case-sensitive, case-insensitive comparison +`false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `startswith` function with ordered collection parameter values -returns true if the first collection can be transformed into the second +returns `true` if the first collection can be transformed into the second collection by removing zero or more items from the end of the first collection. @@ -2227,7 +2256,7 @@ The `startsWithMethodCallExpr` syntax rule defines how the `startswith` function is invoked. ::: example -Example 76: all customers with a `CompanyName` that starts with `Alfr` +Example 77: all customers with a `CompanyName` that starts with `Alfr` ``` http://host/service/Customers?$filter=startswith(CompanyName,'Alfr') ``` @@ -2281,7 +2310,7 @@ The `substringMethodCallExpr` syntax rule defines how the `substring` function is invoked. ::: example -Example 77: all customers with a `CompanyName` of `lfreds Futterkiste` +Example 78: all customers with a `CompanyName` of `lfreds Futterkiste` once the first character has been removed ``` http://host/service/Customers?$filter=substring(CompanyName,1) eq 'lfreds Futterkiste' @@ -2289,7 +2318,7 @@ http://host/service/Customers?$filter=substring(CompanyName,1) eq 'lfreds Futter ::: ::: example -Example 78: all customers with a `CompanyName` that has `lf` as the +Example 79: all customers with a `CompanyName` that has `lf` as the second and third characters, e.g, `Alfreds Futterkiste` ``` http://host/service/Customers?$filter=substring(CompanyName,1,2) eq 'lf' @@ -2306,13 +2335,13 @@ The `hassubset` function has the following signature: Edm.Boolean hassubset(Collection, Collection) ``` -The `hassubset` function returns true if the first collection can be +The `hassubset` function returns `true` if the first collection can be transformed into the second collection by reordering and/or removing zero or more items. The `hasSubsetMethodCallExpr` syntax rule defines how the `hassubset` function is invoked. ::: example -Example 79: `hassubset` expressions that return true +Example 80: `hassubset` expressions that return `true` ``` hassubset([4,1,3],[4,1,3]) ``` @@ -2335,7 +2364,7 @@ hassubset([4,1,3,1],[1,1]) ::: ::: example -Example 80: `hassubset` expression that returns false: 1 appears only +Example 81: `hassubset` expression that returns `false`: `1` appears only once in the left operand ``` hassubset([1,2],[1,1,2]) @@ -2350,13 +2379,13 @@ The `hassubsequence` function has the following signature: Edm.Boolean hassubsequence(OrderedCollection,OrderedCollection) ``` -The `hassubsequence` function returns true if the first collection can +The `hassubsequence` function returns `true` if the first collection can be transformed into the second collection by removing zero or more items. The `hasSubsequenceMethodCallExpr` syntax rule defines how the `hassubsequence` function is invoked. ::: example -Example 81: `hassubsequence` expressions that return true +Example 82: `hassubsequence` expressions that return `true` ``` hassubsequence([4,1,3],[4,1,3]) ``` @@ -2375,7 +2404,7 @@ hassubsequence([4,1,3,1],[1,1]) ::: ::: example -Example 82: `hassubsequence` expressions that return false +Example 83: `hassubsequence` expressions that return `false` ``` hassubsequence([4,1,3],[1,3,4]) ``` @@ -2401,15 +2430,17 @@ Edm.Boolean matchespattern(Edm.String,Edm.String,Edm.String) ``` The second parameter MUST evaluate to a string containing an -[ECMAScript](#_ECMAScript) (JavaScript) regular expression. The `matchespattern` function returns true if the first parameter evaluates +[ECMAScript](#_ECMAScript) (JavaScript) regular expression, otherwise the function +returns `null`. The `matchespattern` function returns `true` if the first parameter evaluates to a string matching that regular expression, using syntax and semantics of ECMAScript regular expressions, otherwise it -returns false. +returns `false`. If the optional third parameter is provided, it MUST evaluate to a string -consisting of ECMAScript regular expression flags to modify the match. +consisting of ECMAScript regular expression flags to modify the match, otherwise +the function returns `null`. ::: example -Example 83: all customers with a `CompanyName` that match the +Example 84: all customers with a `CompanyName` that match the (percent-encoded) regular expression `^A.*e$` ``` http://host/service/Customers?$filter=matchespattern(CompanyName,'%5EA.*e$') @@ -2417,7 +2448,7 @@ http://host/service/Customers?$filter=matchespattern(CompanyName,'%5EA.*e$') ::: ::: example -Example 84: all customers with a `FormattedAddress` that contains a line ending with `berg` or ends with `berg` +Example 85: all customers with a `FormattedAddress` that contains a line ending with `berg` or ends with `berg` ``` http://host/service/Customers?$filter=matchespattern(FormattedAddress,'berg$','m') ``` @@ -2437,7 +2468,7 @@ The `toLowerMethodCallExpr` syntax rule defines how the `tolower` function is invoked. ::: example -Example 85: all customers with a `CompanyName` that equals +Example 86: all customers with a `CompanyName` that equals `alfreds futterkiste` once any uppercase characters have been converted to lowercase ``` @@ -2459,7 +2490,7 @@ The `toUpperMethodCallExpr` syntax rule defines how the `toupper` function is invoked. ::: example -Example 86: all customers with a `CompanyName` that equals +Example 87: all customers with a `CompanyName` that equals `ALFREDS FUTTERKISTE` once any lowercase characters have been converted to uppercase ``` @@ -2481,7 +2512,7 @@ removed. The `trimMethodCallExpr` syntax rule defines how the `trim` function is invoked. ::: example -Example 87: all customers with a `CompanyName` without leading or +Example 88: all customers with a `CompanyName` without leading or trailing whitespace characters ``` http://host/service/Customers?$filter=trim(CompanyName) eq CompanyName @@ -2523,7 +2554,7 @@ UTC) MUST fail evaluation of the `day` function for literal normalized values. ::: example -Example 88: all employees born on the 8th day of a month +Example 89: all employees born on the 8th day of a month ``` http://host/service/Employees?$filter=day(BirthDate) eq 8 ``` @@ -2545,7 +2576,7 @@ non-negative decimal value less than 1. The `fractionalseconds` function is invoked. ::: example -Example 89: all employees born less than 100 milliseconds after a full +Example 90: all employees born less than 100 milliseconds after a full second of any minute of any hour on any day ``` http://host/service/Employees?$filter=[fractionalseconds(BirthDate) lt 0.1 @@ -2573,7 +2604,7 @@ UTC) MUST fail evaluation of the `hour` function for literal normalized values. ::: example -Example 90: all employees born in hour 4, between 04:00 (inclusive) and +Example 91: all employees born in hour 4, between 04:00 (inclusive) and 05:00 (exclusive) ``` http://host/service/Employees?$filter=hour(BirthDate) eq 4 @@ -2617,7 +2648,7 @@ zone of the `DateTimeOffset` parameter value. The `minuteMethodCallExpr` syntax rule defines how the `minute` function is invoked. ::: example -Example 91: all employees born in minute 40 of any hour on any day +Example 92: all employees born in minute 40 of any hour on any day ``` http://host/service/Employees?$filter=minute(BirthDate) eq 40 ``` @@ -2644,7 +2675,7 @@ UTC) MUST fail evaluation of the `month` function for literal normalized values. ::: example -Example 92: all employees born in May +Example 93: all employees born in May ``` http://host/service/Employees?$filter=month(BirthDate) eq 5 ``` @@ -2683,7 +2714,7 @@ of the `DateTimeOffset` or `TimeOfDay` parameter value. The invoked. ::: example -Example 93: all employees born in second 40 of any minute of any hour on +Example 94: all employees born in second 40 of any minute of any hour on any day ``` http://host/service/Employees?$filter=second(BirthDate) eq 40 @@ -2752,7 +2783,7 @@ UTC) MUST fail evaluation of the `year` function for literal normalized values. ::: example -Example 94: all employees born in 1971 +Example 95: all employees born in 1971 ``` http://host/service/Employees?$filter=year(BirthDate) eq 1971 ``` @@ -2775,7 +2806,7 @@ nearest numeric value with no decimal component. The is invoked. ::: example -Example 95: all orders with freight costs that round up to 32 +Example 96: all orders with freight costs that round up to 32 ``` http://host/service/Orders?$filter=ceiling(Freight) eq 32 ``` @@ -2796,7 +2827,7 @@ nearest numeric value with no decimal component. The invoked. ::: example -Example 96: all orders with freight costs that round down to 32 +Example 97: all orders with freight costs that round down to 32 ``` http://host/service/Orders?$filter=floor(Freight) eq 32 ``` @@ -2818,7 +2849,7 @@ rounded to -1. The `roundMethodCallExpr` syntax rule defines how the `round` function is invoked. ::: example -Example 97: all orders with freight costs that round to 32 +Example 98: all orders with freight costs that round to 32 ``` http://host/service/Orders?$filter=round(Freight) eq 32 ``` @@ -2861,9 +2892,6 @@ The `cast` function follows these assignment rules: [section 3.3.7 dateTime](https://www.w3.org/TR/xmlschema11-2/#dateTime), can be cast to `Edm.DateTimeOffset`. If the string value does not contain a time-zone offset, it is treated as UTC. -The `cast` function is optional for primitive values (first five rules) -and up-casts (seventh rule). - If the cast fails, the `cast` function returns `null`. ##### 5.1.1.10.2 `isof` @@ -2875,19 +2903,19 @@ Edm.Boolean isof(type) Edm.Boolean isof(expression,type) ``` -The single parameter `isof` function returns true if the current +The single parameter `isof` function returns `true` if the current instance is assignable to the type specified, according to the assignment rules for the [`cast`](#cast) function, otherwise it returns `false`. -The two parameter `isof` function returns true if the object referred to +The two parameter `isof` function returns `true` if the object referred to by the expression is assignable to the type specified, according to the -same rules, otherwise it returns false. +same rules, otherwise it returns `false`. The `isofExpr` syntax rule defines how the `isof` function is invoked. ::: example -Example 98: orders that are also `BigOrders` +Example 99: orders that are also `BigOrders` ``` http://host/service/Orders?$filter=isof(NorthwindModel.BigOrder) ``` @@ -2898,7 +2926,7 @@ http://host/service/Orders?$filter=isof($it,NorthwindModel.BigOrder) ::: ::: example -Example 99: orders of a customer that is a `VIPCustomer` +Example 100: orders of a customer that is a `VIPCustomer` ``` http://host/service/Orders?$filter=isof(Customer,NorthwindModel.VIPCustomer) ``` @@ -2928,9 +2956,9 @@ Edm.Boolean geo.intersects(Edm.GeographyPoint,Edm.GeographyPolygon) Edm.Boolean geo.intersects(Edm.GeometryPoint,Edm.GeometryPolygon) ``` -The `geo.intersects` function returns true if the specified point lies +The `geo.intersects` function returns `true` if the specified point lies within the interior or on the boundary of the specified polygon, -otherwise it returns false. +otherwise it returns `false`. ##### 5.1.1.11.3 `geo.length` @@ -2963,7 +2991,7 @@ The case function evaluates the condition in each pair, starting with the leftmost pair, and stops as soon as a condition evaluates to `true`. It then returns the value of the result of this pair. It returns `null` if none of the conditions in any pair evaluates to `true`. Clients can -specify a last pair whose condition is `true` to get a non-null +specify a last pair whose condition is `true` to get a non-`null` "default/else/otherwise" result. Boolean expressions containing `DateTimeOffset` or `TimeOfDay` literals without @@ -2982,7 +3010,7 @@ incompatible types, in which case the case expression is treated as selected by the case statement. ::: example -Example 100: compute signum(X) +Example 101: compute signum(X) ``` $compute=case(X gt 0:1,X lt 0:-1,true:0) as SignumX ``` @@ -3016,15 +3044,15 @@ the lambda operator. ##### 5.1.1.13.1 `any` The `any` operator applies a Boolean expression to each member of a -collection and returns true if and only if the expression is true for -any member of the collection, otherwise it returns false. This implies -that the `any` operator always returns false for an empty collection. +collection and returns `true` if and only if the expression is `true` for +any member of the collection, otherwise it returns `false`. This implies +that the `any` operator always returns `false` for an empty collection. The `any` operator can be used without an argument expression. This -short form returns false if and only if the collection is empty. +short form returns `false` if and only if the collection is empty. ::: example -Example 101: all `Orders` that have any `Items` with a `Quantity` greater +Example 102: all `Orders` that have any `Items` with a `Quantity` greater than `100` ``` http://host/service/Orders?$filter=Items/any(d:d/Quantity gt 100) @@ -3032,7 +3060,7 @@ http://host/service/Orders?$filter=Items/any(d:d/Quantity gt 100) ::: ::: example -Example 102: all customers having an order with a deviating shipping +Example 103: all customers having an order with a deviating shipping address. The `Address` in the argument expression is evaluated in the scope of the `Customers` collection. ``` @@ -3041,7 +3069,7 @@ http://host/service/Customers?$filter=Orders/any(o:o/ShippingAddress ne Address) ::: ::: example -Example 103: all categories along with their products used in some order +Example 104: all categories along with their products used in some order with a deviating unit price. The unprefixed `UnitPrice` in the argument expression is evaluated in the scope of the expanded `Products`. ``` @@ -3053,14 +3081,14 @@ http://host/service/Categories?$expand=Products( ##### 5.1.1.13.2 `all` The `all` operator applies a Boolean expression to each member of a -collection and returns true if the expression is true for all members of -the collection, otherwise it returns false. This implies that the `all` -operator always returns true for an empty collection. +collection and returns `true` if the expression is `true` for all members of +the collection, otherwise it returns `false`. This implies that the `all` +operator always returns `true` for an empty collection. The `all` operator cannot be used without an argument expression. ::: example -Example 104: all `Orders` that have only `Items` with a `Quantity` +Example 105: all `Orders` that have only `Items` with a `Quantity` greater than `100` ``` http://host/service/Orders?$filter=Items/all(d:d/Quantity gt 100) @@ -3077,7 +3105,7 @@ values, and in the query part, for example, as operands in according to the `primitiveLiteral` rule in [OData-ABNF](#ODataABNF). ::: example -Example 105: expressions using primitive literals +Example 106: expressions using primitive literals ``` NullValue eq null ``` @@ -3182,14 +3210,14 @@ percent-encoded in URLs although some browsers will accept and pass them on unencoded. ::: example -Example 106: collection of string literals +Example 107: collection of string literals ``` http://host/service/ProductsByColors(colors=@c)?@c=["red","green"] ``` ::: ::: example -Example 107: check whether a pair of properties has one of several +Example 108: check whether a pair of properties has one of several possible pair values ``` $filter=[FirstName,LastName] in [["John","Doe"],["Jane","Smith"]] @@ -3235,7 +3263,7 @@ function overload on the current instance within an expression. Function names without a path prefix refer to an unbound function overload. ::: example -Example 108: email addresses ending with `.com` assuming +Example 109: email addresses ending with `.com` assuming `EmailAddresses` is a collection of strings ``` http://host/service/Customers(1)/EmailAddresses?$filter=endswith($it,'.com') @@ -3243,7 +3271,7 @@ http://host/service/Customers(1)/EmailAddresses?$filter=endswith($it,'.com') ::: ::: example -Example 109: customers along with their orders that shipped to the same +Example 110: customers along with their orders that shipped to the same city as the customer's address. The nested filter expression is evaluated in the context of Orders; `$it` allows referring to values in the outer context of Customers. @@ -3254,7 +3282,7 @@ http://host/service/Customers?$expand=Orders($filter=$it/Address/City eq ShipTo/ ::: ::: example -Example 110: products with at least 10 positive reviews. +Example 111: products with at least 10 positive reviews. `Model.PositiveReviews` is a function bound to `Model.Product` returning a collection of reviews. ``` @@ -3268,14 +3296,14 @@ The `$root` literal can be used in expressions to refer to resources of the same service. ::: example -Example 111: all employees with the same last name as employee `A1235` +Example 112: all employees with the same last name as employee `A1235` ``` http://host/service/Employees?$filter=LastName eq $root/Employees('A1245')/LastName ``` ::: ::: example -Example 112: products ordered by a set of customers, where the set of +Example 113: products ordered by a set of customers, where the set of customers is passed as a JSON array containing the resource paths from `$root` to each customer ``` @@ -3285,7 +3313,7 @@ http://host/service/ProductsOrderedBy(Customers=@c) ::: ::: example -Example 113: function call returning the average rating of a given employee by their peers (employees in department D1) +Example 114: function call returning the average rating of a given employee by their peers (employees in department D1) ``` http://host/service/Employees('A1245')/self.AvgRating(RatedBy=@peers) ?@peers=$root/Employees/$filter(Department eq 'D1') @@ -3302,7 +3330,7 @@ and navigation properties. It refers to the current instance of the collection. ::: example -Example 114: select only email addresses ending with `.com` +Example 115: select only email addresses ending with `.com` ``` http://host/service/Customers?$select=EmailAddresses($filter=endswith($this,'.com')) ``` @@ -3329,7 +3357,7 @@ target cardinality 0..1), its value, and the values of its components, are treated as `null`. ::: example -Example 115: similar behavior whether `HeadquarterAddress` is a nullable +Example 116: similar behavior whether `HeadquarterAddress` is a nullable complex type or a nullable navigation property ``` Companies(1)/HeadquarterAddress/Street @@ -3344,7 +3372,7 @@ of the specified derived type, the path expression returns `null`. If the property or navigation property is not defined for the type of the resource and that type supports dynamic properties or navigation -properties, then the property or navigation property is treated as null +properties, then the property or navigation property is treated as `null` for all instances on which it has no value. If the property or navigation property is not defined for the type of @@ -3370,14 +3398,14 @@ If an annotation is not applied to the resource or property, then its value, and the values of its components, are treated as `null`. ::: example -Example 116: Return Products that have prices in Euro +Example 117: Return Products that have prices in Euro ``` http://host/service/Products?$filter=Price/@Measures.Currency eq 'EUR' ``` ::: ::: example -Example 117: Return Employees that have any error messages in the +Example 118: Return Employees that have any error messages in the [`Core.Messages`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#Messages) annotation ``` @@ -3459,9 +3487,9 @@ types. The `$filter` system query option allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with `$filter` is evaluated for each resource in the -collection, and only items where the expression evaluates to true are +collection, and only items where the expression evaluates to `true` are included in the response. Resources for which the expression evaluates -to false or to null, or which reference properties that are unavailable +to `false` or to `null`, or which reference properties that are unavailable due to permissions, are omitted from the response. The [OData-ABNF](#ODataABNF) `filter` syntax rule defines the formal @@ -3512,14 +3540,14 @@ segment does not specify a declared property, then the expanded property appears only for those instances on which it has a value. ::: example -Example 118: expand a navigation property of an entity type +Example 119: expand a navigation property of an entity type ``` http://host/service/Products?$expand=Category ``` ::: ::: example -Example 119: expand a navigation property of a complex type +Example 120: expand a navigation property of a complex type ``` http://host/service/Customers?$expand=Addresses/Country ``` @@ -3543,7 +3571,7 @@ Allowed system query options are for collection-valued navigation properties. ::: example -Example 120: all categories and for each category all related products +Example 121: all categories and for each category all related products with a discontinued date equal to `null` ``` http://host/service/Categories?$expand=Products($filter=DiscontinuedDate eq null) @@ -3557,7 +3585,7 @@ property name to return just the count of the related entities. The number of related entities included in the count. ::: example -Example 121: all categories and for each category the number of all +Example 122: all categories and for each category the number of all related products ``` http://host/service/Categories?$expand=Products/$count @@ -3565,7 +3593,7 @@ http://host/service/Categories?$expand=Products/$count ::: ::: example -Example 122: all categories and for each category the number of all +Example 123: all categories and for each category the number of all related blue products ``` http://host/service/Categories?$expand=Products/$count($search=blue) @@ -3582,7 +3610,7 @@ The system query options [`$filter`](#SystemQueryOptionfilter), expanded entity references. ::: example -Example 123: all categories and for each category the references of all +Example 124: all categories and for each category the references of all related products ``` http://host/service/Categories?$expand=Products/$ref @@ -3590,7 +3618,7 @@ http://host/service/Categories?$expand=Products/$ref ::: ::: example -Example 124: all categories and for each category the references of all +Example 125: all categories and for each category the references of all related products of the derived type `Sales.PremierProduct` ``` http://host/service/Categories?$expand=Products/Sales.PremierProduct/$ref @@ -3598,7 +3626,7 @@ http://host/service/Categories?$expand=Products/Sales.PremierProduct/$ref ::: ::: example -Example 125: all categories and for each category the references of all +Example 126: all categories and for each category the references of all related premier products with a current promotion equal to `null` ``` http://host/service/Categories @@ -3615,7 +3643,7 @@ A `$levels` option with a value of 1 specifies a single expand with no recursion. ::: example -Example 126: all employees with their manager, manager's manager, and +Example 127: all employees with their manager, manager's manager, and manager's manager's manager ``` http://host/service/Employees?$expand=ReportsTo($levels=3) @@ -3632,7 +3660,7 @@ which take precedence over the star operator. The star operator does not implicitly include stream properties. ::: example -Example 127: expand `Supplier` and include references for all other +Example 128: expand `Supplier` and include references for all other related entities ``` http://host/service/Categories?$expand=*/$ref,Supplier @@ -3640,7 +3668,7 @@ http://host/service/Categories?$expand=*/$ref,Supplier ::: ::: example -Example 128: expand all related entities and their related entities +Example 129: expand all related entities and their related entities ``` http://host/service/Categories?$expand=*($levels=2) ``` @@ -3650,7 +3678,7 @@ Specifying a stream property includes the media stream inline according to the specified format. ::: example -Example 129: include Employee's `Photo` stream property along with other +Example 130: include Employee's `Photo` stream property along with other properties of the customer ``` http://host/service/Employees?$expand=Photo @@ -3661,7 +3689,7 @@ Specifying `$value` for a media entity includes the media entity's stream value inline according to the specified format. ::: example -Example 130: Include the Product's media stream along with other +Example 131: Include the Product's media stream along with other properties of the product ``` http://host/service/Products?$expand=$value @@ -3720,7 +3748,7 @@ The simplest form of a select item explicitly requests a property defined on the type of the resources identified by the resource path section of the URL. ::: example -Example 131: rating and release date of all products +Example 132: rating and release date of all products ``` http://host/service/Products?$select=Rating,ReleaseDate ``` @@ -3730,7 +3758,7 @@ It is also possible to request all declared and dynamic structural properties using a star (`*`). ::: example -Example 132: all structural properties of all products +Example 133: all structural properties of all products ``` http://host/service/Products?$select=* ``` @@ -3738,7 +3766,7 @@ http://host/service/Products?$select=* If the select item is not defined for the type of the resource, and that type supports dynamic properties or instance annotations, then the -property is treated as null for all instances on which it is not +property is treated as `null` for all instances on which it is not defined. If the select item is not defined for the type of the resource, and that @@ -3758,7 +3786,7 @@ inline content can itself be restricted with a nested `$select` query option, see [section 5.1.2](#SystemQueryOptionfilter). ::: example -Example 133: name and description of all products, plus name of expanded +Example 134: name and description of all products, plus name of expanded category ``` http://host/service/Products?$select=Name,Description @@ -3775,7 +3803,7 @@ be followed by a forward slash, an optional [type-cast segment](#AddressingDeriv complex type (and so on for nested complex types). ::: example -Example 134: the `AccountRepresentative` property of any supplier that +Example 135: the `AccountRepresentative` property of any supplier that is of the derived type `Namespace.PreferredSupplier`, together with the `Street` property of the complex property `Address`, and the Location property of the derived complex type `Namespace.AddressWithLocation` @@ -3797,7 +3825,7 @@ select options specified in more than one place in a request and MUST NOT be specified in more than one expand. ::: example -Example 135: select up to five addresses whose `City` starts with an +Example 136: select up to five addresses whose `City` starts with an `H`, sorted, and with the `Country` expanded ``` http://host/service/Customers @@ -3834,7 +3862,7 @@ qualified name and that operation cannot be bound to the entities requested, the service MUST ignore the select item. ::: example -Example 136: the `ID` property, the `ActionName` action defined in +Example 137: the `ID` property, the `ActionName` action defined in `Model` and all actions and functions defined in the `Model2` for each product if those actions and functions can be bound to that product ``` @@ -3900,7 +3928,7 @@ The [OData-ABNF](#ODataABNF) `search` syntax rule defines the formal grammar of the `$search` query option. ::: example -Example 137: all products that are blue or green. It is up to the +Example 138: all products that are blue or green. It is up to the service to decide what makes a product blue or green. ``` http://host/service/Products?$search=blue OR green @@ -3925,7 +3953,7 @@ Leading and trailing spaces are not considered part of the search expression. Terms enclosed in double-quotes comprise a *phrase*. Each individual term or phrase comprises a Boolean expression that -returns true if the term or phrase is matched, otherwise false. The +returns `true` if the term or phrase is matched, otherwise `false`. The semantics of what is considered a match is dependent upon the service. Expressions enclosed in parenthesis comprise a *group expression*. @@ -3934,16 +3962,16 @@ The search expression can contain any number of terms, phrases, or group expressions, along with the case-sensitive keywords `NOT`, `AND`, and `OR`, evaluated in that order. -Expressions prefaced with `NOT` evaluate to true if the expression is -not matched, otherwise false. +Expressions prefaced with `NOT` evaluate to `true` if the expression is +not matched, otherwise `false`. Two expressions not enclosed in quotes and separated by a space are equivalent to the same two expressions separated by the `AND` keyword. Such expressions evaluate to `true` if both expressions evaluate to -true, otherwise false. +`true`, otherwise `false`. -Expressions separated by an `OR` evaluate to true if either of the -expressions evaluate to true, otherwise false. +Expressions separated by an `OR` evaluate to `true` if either of the +expressions evaluate to `true`, otherwise `false`. To support type-ahead use cases, incomplete search expressions can be sent as OData string literals enclosed in single-quotes, and @@ -3995,7 +4023,7 @@ result and MUST be included if `$select` is specified with the computed property name, or star (`*`). ::: example -Example 138: compute total price for order items +Example 139: compute total price for order items ``` http://host/service/Orders(10)/Items ?$select=Product/Description,Total @@ -4039,7 +4067,7 @@ custom query option is any query option of the form shown by the rule Custom query options MUST NOT begin with a `$` or `@` character. ::: example -Example 139: service-specific custom query option `debug-mode` +Example 140: service-specific custom query option `debug-mode` ``` http://host/service/Products?debug-mode=true ``` @@ -4061,21 +4089,21 @@ The semantics of parameter aliases are covered in values as query options. ::: example -Example 140: +Example 141: ``` http://host/service/Movies?$filter=contains(@word,Title)&@word='Black' ``` ::: ::: example -Example 141: +Example 142: ``` http://host/service/Movies?$filter=Title eq @title&@title='Wizard of Oz' ``` ::: ::: example -Example 142: JSON array of strings as parameter alias value --- note that +Example 143: JSON array of strings as parameter alias value --- note that `[`, `]`, and `"` need to be percent-encoded in real URLs, the clear-text representation used here is just for readability ``` diff --git a/odata-url-conventions/5 Query Options.md b/odata-url-conventions/5 Query Options.md index fb2df09f..73b34c56 100644 --- a/odata-url-conventions/5 Query Options.md +++ b/odata-url-conventions/5 Query Options.md @@ -74,9 +74,29 @@ The following operators, functions, and literals can be used in The [OData-ABNF](#ODataABNF) `commonExpr` syntax rule defines the formal grammar of common expressions. +The following subsections specify situations in which expressions evaluate to `null` +if operands or parameters do not have the types expected by an operator or function. +Notwithstanding these rules, if a service can infer such a type discrepancy for an expression +that appears in a request independently of the underlying data, +it MUST reject the request with an error message +explaining the discrepancy. The inferral can be based on, for example, the +declared type of a property or the type of a literal value that occurs in the +expression. + +::: example +Example ##ex: In a search for people above a certain age +``` +http://host/service/People?$filter=Age gt '50' +``` +the expression would always evaluate to `null` because the age 50 is erroneously +given as a string and the [`$filter`](#SystemQueryOptionfilter) would return an empty result, although this is +really the result of a typing error. That's why a "type mismatch" error must +instead be returned in such a case. +::: + #### ##subsubsubsec Logical Operators -OData defines a set of logical operators that evaluate to true or false +OData defines a set of logical operators that evaluate to `true` or `false` (i.e. a `boolCommonExpr` as defined in [OData-ABNF](#ODataABNF)). Logical operators are typically used to filter a collection of resources. @@ -99,25 +119,31 @@ The `eq`, `ne`, and `in` operators can be used with collection-valued operands, and the `eq` and `ne` operators can be used with operands of a structured type. +If at least one operand of an `eq`, `ne`, `lt`, `le`, `gt`, or `ge` operator +is non-numeric and the operands have different types, the operator returns `null`. + +The rules for the Boolean operators `and`, `or`, and `not` assume Boolean operands. +If an operand of a Boolean operator is not Boolean, the operator returns `null`. + ##### ##subsubsubsubsec Equals -The `eq` operator returns true if the left operand is equal to the right -operand, otherwise it returns false. +The `eq` operator returns `true` if the left operand is equal to the right +operand, otherwise it returns `false`. -When applied to operands of entity types, the `eq` operator returns true +When applied to operands of entity types, the `eq` operator returns `true` if both operands represent the same entity, or both operands represent -null. +`null`. When applied to operands of complex types, the `eq` operator returns -true if both operands have the same structure and same values, or both -operands represent null. +`true` if both operands have the same structure and same values, or both +operands represent `null`. -When applied to ordered collections, the `eq` operator returns true if +When applied to ordered collections, the `eq` operator returns `true` if both operands have the same cardinality and each member of the left operand is equal to the corresponding member of the right operand. For services that support comparing unordered collections, the `eq` -operator returns true if both operands are equal after applying the same +operator returns `true` if both operands are equal after applying the same ordering on both collections. Each of the special values `null`, `-INF`, and `INF` is equal to itself, @@ -127,21 +153,21 @@ The special value `NaN` is not equal to anything, even to itself. ##### ##subsubsubsubsec Not Equals -The `ne` operator returns true if the left operand is not equal to the -right operand, otherwise it returns false. +The `ne` operator returns `true` if the left operand is not equal to the +right operand, otherwise it returns `false`. -When applied to operands of entity types, the `ne` operator returns true +When applied to operands of entity types, the `ne` operator returns `true` if the two operands do not represent the same entity. When applied to operands of complex types, the `ne` operator returns -true if the operands do not have the same structure and same values. +`true` if the operands do not have the same structure and same values. -When applied to ordered collections, the `ne` operator returns true if +When applied to ordered collections, the `ne` operator returns `true` if both operands do not have the same cardinality or any member of the left operand is not equal to the corresponding member of the right operand. For services that support comparing unordered collections, the `ne` -operator returns true if both operands do not have the same cardinality +operator returns `true` if both operands do not have the same cardinality or do not contain the same members, in any order. Each of the special values `null`, `-INF`, and `INF` is not equal to any @@ -153,8 +179,8 @@ The `null` value is not equal to any value but itself. ##### ##subsubsubsubsec Greater Than -The `gt` operator returns true if the left operand is greater than the -right operand, otherwise it returns false. +The `gt` operator returns `true` if the left operand is greater than the +right operand, otherwise it returns `false`. The special value `INF` is greater than any number, and any number is greater than `-INF`. @@ -167,19 +193,19 @@ with language-dependent order with the term [`Core.IsLanguageDependent`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#IsLanguageDependent), see [OData-VocCore](#ODataVocCore). -If any operand is `null`, the operator returns false. +If any operand is `null`, the operator returns `false`. ##### ##subsubsubsubsec Greater Than or Equal -The `ge` operator returns true if the left operand is greater than or -equal to the right operand, otherwise it returns false. +The `ge` operator returns `true` if the left operand is greater than or +equal to the right operand, otherwise it returns `false`. See rules for [`gt`](#GreaterThan) and [`eq`](#Equals) for details. ##### ##subsubsubsubsec Less Than -The `lt` operator returns true if the left operand is less than the -right operand, otherwise it returns false. +The `lt` operator returns `true` if the left operand is less than the +right operand, otherwise it returns `false`. The special value `-INF` is less than any number, and any number is less than `INF`. @@ -192,43 +218,43 @@ with language-dependent order with the term [`Core.IsLanguageDependent`](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Core.V1.md#IsLanguageDependent), see [OData-VocCore](#ODataVocCore). -If any operand is `null`, the operator returns false. +If any operand is `null`, the operator returns `false`. ##### ##subsubsubsubsec Less Than or Equal -The `le` operator returns true if the left operand is less than or equal -to the right operand, otherwise it returns false. +The `le` operator returns `true` if the left operand is less than or equal +to the right operand, otherwise it returns `false`. See rules for [`lt`](#LessThan) and [`eq`](#Equals) for details. ##### ##subsubsubsubsec And -The `and` operator returns true if both the left and right operands -evaluate to true, otherwise it returns false. +The `and` operator returns `true` if both the left and right operands +evaluate to `true`, otherwise it returns `false`. The `null` value is treated as unknown, so if one operand evaluates to -`null` and the other operand to false, the `and` operator returns false. +`null` and the other operand to `false`, the `and` operator returns `false`. All other combinations with `null` return `null`. ##### ##subsubsubsubsec Or -The `or` operator returns false if both the left and right operands both -evaluate to false, otherwise it returns true. +The `or` operator returns `false` if both the left and right operands both +evaluate to `false`, otherwise it returns `true`. The `null` value is treated as unknown, so if one operand evaluates to -`null` and the other operand to true, the `or` operator returns true. +`null` and the other operand to `true`, the `or` operator returns `true`. All other combinations with `null` return `null`. ##### ##subsubsubsubsec Not -The `not` operator returns true if the operand returns false, otherwise -it returns false. +The `not` operator returns `true` if the operand returns `false`, otherwise +it returns `false`. The `null` value is treated as unknown, so `not null` returns `null`. ##### ##subsubsubsubsec Has -The `has` operator returns true if the right operand is an enumeration +The `has` operator returns `true` if the right operand is an enumeration value whose flag(s) are set on the left operand. The `null` value is treated as unknown, so if one operand evaluates to @@ -236,11 +262,12 @@ The `null` value is treated as unknown, so if one operand evaluates to ##### ##subsubsubsubsec In -The `in` operator returns true if the left operand is a member of the -right operand. The right operand MUST be either a comma-separated list +The `in` operator returns `true` if the [equality](#Equals) comparison of the left +operand with at least one member of the right operand returns `true`. +The right operand MUST be either a comma-separated list of zero or more primitive values, enclosed in parentheses, or a single expression that resolves to a collection. If the right operand is an empty collection -or list of values, the expression returns false. +or list of values, the `in` operator returns `false`. ##### ##subsubsubsubsec Logical Operator Examples @@ -334,7 +361,8 @@ filter a collection of resources. However, services MAY allow using arithmetic operators with the [`$orderby`](#SystemQueryOptionorderby) system query option. -If an operand of an arithmetic operator is null, the result is null. +If an operand of an arithmetic operator is `null` or has a non-allowed type, +the result is `null`. The syntax rules for the arithmetic operators are defined in [OData-ABNF](#ODataABNF). 4.01 Services MUST support case-insensitive @@ -525,7 +553,8 @@ not defined. Instead, OData defines a [`null`](#null) literal that can be used in comparisons. If a parameter of a canonical function is `null`, the function returns -`null`. +`null`. If the types of parameters do not match the function signature, +the function also returns `null`. The syntax rules for all functions are defined in [OData-ABNF](#ODataABNF). 4.01 Services MUST support case-insensitive @@ -572,14 +601,14 @@ Edm.Boolean contains(Edm.String,Edm.String) Edm.Boolean contains(OrderedCollection,OrderedCollection) ``` -The `contains` function with string parameter values returns true if the +The `contains` function with string parameter values returns `true` if the second string is a substring of the first string, otherwise it returns -false. String comparison is case-sensitive, case-insensitive comparison +`false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `contains` function with ordered collection parameter values returns -true if the first collection can be transformed into the second +`true` if the first collection can be transformed into the second collection by removing zero or more items from the beginning or the end of the first collection. @@ -603,14 +632,14 @@ Edm.Boolean endswith(Edm.String,Edm.String) Edm.Boolean endswith(OrderedCollection,OrderedCollection) ``` -The `endswith` function with string parameter values returns true if the -first string ends with the second string, otherwise it returns false. +The `endswith` function with string parameter values returns `true` if the +first string ends with the second string, otherwise it returns `false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `endswith` function with ordered collection parameter values returns -true if the first collection can be transformed into the second +`true` if the first collection can be transformed into the second collection by removing zero or more items from the beginning of the first collection. @@ -693,14 +722,14 @@ Edm.Boolean startswith(Edm.String,Edm.String) Edm.Boolean startswith(Collection,Collection) ``` -The `startswith` function with string parameter values returns true if +The `startswith` function with string parameter values returns `true` if the first string starts with the second string, otherwise it returns -false. String comparison is case-sensitive, case-insensitive comparison +`false`. String comparison is case-sensitive, case-insensitive comparison can be achieved in combination with [`tolower`](#tolower) or [`toupper`](#toupper). The `startswith` function with ordered collection parameter values -returns true if the first collection can be transformed into the second +returns `true` if the first collection can be transformed into the second collection by removing zero or more items from the end of the first collection. @@ -787,13 +816,13 @@ The `hassubset` function has the following signature: Edm.Boolean hassubset(Collection, Collection) ``` -The `hassubset` function returns true if the first collection can be +The `hassubset` function returns `true` if the first collection can be transformed into the second collection by reordering and/or removing zero or more items. The `hasSubsetMethodCallExpr` syntax rule defines how the `hassubset` function is invoked. ::: example -Example ##ex: `hassubset` expressions that return true +Example ##ex: `hassubset` expressions that return `true` ``` hassubset([4,1,3],[4,1,3]) ``` @@ -816,7 +845,7 @@ hassubset([4,1,3,1],[1,1]) ::: ::: example -Example ##ex: `hassubset` expression that returns false: 1 appears only +Example ##ex: `hassubset` expression that returns `false`: `1` appears only once in the left operand ``` hassubset([1,2],[1,1,2]) @@ -831,13 +860,13 @@ The `hassubsequence` function has the following signature: Edm.Boolean hassubsequence(OrderedCollection,OrderedCollection) ``` -The `hassubsequence` function returns true if the first collection can +The `hassubsequence` function returns `true` if the first collection can be transformed into the second collection by removing zero or more items. The `hasSubsequenceMethodCallExpr` syntax rule defines how the `hassubsequence` function is invoked. ::: example -Example ##ex: `hassubsequence` expressions that return true +Example ##ex: `hassubsequence` expressions that return `true` ``` hassubsequence([4,1,3],[4,1,3]) ``` @@ -856,7 +885,7 @@ hassubsequence([4,1,3,1],[1,1]) ::: ::: example -Example ##ex: `hassubsequence` expressions that return false +Example ##ex: `hassubsequence` expressions that return `false` ``` hassubsequence([4,1,3],[1,3,4]) ``` @@ -882,13 +911,15 @@ Edm.Boolean matchespattern(Edm.String,Edm.String,Edm.String) ``` The second parameter MUST evaluate to a string containing an -[ECMAScript](#_ECMAScript) (JavaScript) regular expression. The -`matchespattern` function returns true if the first parameter evaluates +[ECMAScript](#_ECMAScript) (JavaScript) regular expression, otherwise the function +returns `null`. The +`matchespattern` function returns `true` if the first parameter evaluates to a string matching that regular expression, using syntax and semantics of ECMAScript regular expressions, otherwise it -returns false. +returns `false`. If the optional third parameter is provided, it MUST evaluate to a string -consisting of ECMAScript regular expression flags to modify the match. +consisting of ECMAScript regular expression flags to modify the match, otherwise +the function returns `null`. ::: example Example ##ex: all customers with a `CompanyName` that match the @@ -1343,9 +1374,6 @@ The `cast` function follows these assignment rules: [section 3.3.7 dateTime](https://www.w3.org/TR/xmlschema11-2/#dateTime), can be cast to `Edm.DateTimeOffset`. If the string value does not contain a time-zone offset, it is treated as UTC. -The `cast` function is optional for primitive values (first five rules) -and up-casts (seventh rule). - If the cast fails, the `cast` function returns `null`. ##### ##subsubsubsubsec `isof` @@ -1357,14 +1385,14 @@ Edm.Boolean isof(type) Edm.Boolean isof(expression,type) ``` -The single parameter `isof` function returns true if the current +The single parameter `isof` function returns `true` if the current instance is assignable to the type specified, according to the assignment rules for the [`cast`](#cast) function, otherwise it returns `false`. -The two parameter `isof` function returns true if the object referred to +The two parameter `isof` function returns `true` if the object referred to by the expression is assignable to the type specified, according to the -same rules, otherwise it returns false. +same rules, otherwise it returns `false`. The `isofExpr` syntax rule defines how the `isof` function is invoked. @@ -1410,9 +1438,9 @@ Edm.Boolean geo.intersects(Edm.GeographyPoint,Edm.GeographyPolygon) Edm.Boolean geo.intersects(Edm.GeometryPoint,Edm.GeometryPolygon) ``` -The `geo.intersects` function returns true if the specified point lies +The `geo.intersects` function returns `true` if the specified point lies within the interior or on the boundary of the specified polygon, -otherwise it returns false. +otherwise it returns `false`. ##### ##subsubsubsubsec `geo.length` @@ -1445,7 +1473,7 @@ The case function evaluates the condition in each pair, starting with the leftmost pair, and stops as soon as a condition evaluates to `true`. It then returns the value of the result of this pair. It returns `null` if none of the conditions in any pair evaluates to `true`. Clients can -specify a last pair whose condition is `true` to get a non-null +specify a last pair whose condition is `true` to get a non-`null` "default/else/otherwise" result. Boolean expressions containing `DateTimeOffset` or `TimeOfDay` literals without @@ -1498,12 +1526,12 @@ the lambda operator. ##### ##subsubsubsubsec `any` The `any` operator applies a Boolean expression to each member of a -collection and returns true if and only if the expression is true for -any member of the collection, otherwise it returns false. This implies -that the `any` operator always returns false for an empty collection. +collection and returns `true` if and only if the expression is `true` for +any member of the collection, otherwise it returns `false`. This implies +that the `any` operator always returns `false` for an empty collection. The `any` operator can be used without an argument expression. This -short form returns false if and only if the collection is empty. +short form returns `false` if and only if the collection is empty. ::: example Example ##ex: all `Orders` that have any `Items` with a `Quantity` greater @@ -1535,9 +1563,9 @@ http://host/service/Categories?$expand=Products( ##### ##subsubsubsubsec `all` The `all` operator applies a Boolean expression to each member of a -collection and returns true if the expression is true for all members of -the collection, otherwise it returns false. This implies that the `all` -operator always returns true for an empty collection. +collection and returns `true` if the expression is `true` for all members of +the collection, otherwise it returns `false`. This implies that the `all` +operator always returns `true` for an empty collection. The `all` operator cannot be used without an argument expression. @@ -1826,7 +1854,7 @@ of the specified derived type, the path expression returns `null`. If the property or navigation property is not defined for the type of the resource and that type supports dynamic properties or navigation -properties, then the property or navigation property is treated as null +properties, then the property or navigation property is treated as `null` for all instances on which it has no value. If the property or navigation property is not defined for the type of @@ -1941,9 +1969,9 @@ types. The `$filter` system query option allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with `$filter` is evaluated for each resource in the -collection, and only items where the expression evaluates to true are +collection, and only items where the expression evaluates to `true` are included in the response. Resources for which the expression evaluates -to false or to null, or which reference properties that are unavailable +to `false` or to `null`, or which reference properties that are unavailable due to permissions, are omitted from the response. The [OData-ABNF](#ODataABNF) `filter` syntax rule defines the formal @@ -2221,7 +2249,7 @@ http://host/service/Products?$select=* If the select item is not defined for the type of the resource, and that type supports dynamic properties or instance annotations, then the -property is treated as null for all instances on which it is not +property is treated as `null` for all instances on which it is not defined. If the select item is not defined for the type of the resource, and that @@ -2408,7 +2436,7 @@ Leading and trailing spaces are not considered part of the search expression. Terms enclosed in double-quotes comprise a *phrase*. Each individual term or phrase comprises a Boolean expression that -returns true if the term or phrase is matched, otherwise false. The +returns `true` if the term or phrase is matched, otherwise `false`. The semantics of what is considered a match is dependent upon the service. Expressions enclosed in parenthesis comprise a *group expression*. @@ -2417,16 +2445,16 @@ The search expression can contain any number of terms, phrases, or group expressions, along with the case-sensitive keywords `NOT`, `AND`, and `OR`, evaluated in that order. -Expressions prefaced with `NOT` evaluate to true if the expression is -not matched, otherwise false. +Expressions prefaced with `NOT` evaluate to `true` if the expression is +not matched, otherwise `false`. Two expressions not enclosed in quotes and separated by a space are equivalent to the same two expressions separated by the `AND` keyword. Such expressions evaluate to `true` if both expressions evaluate to -true, otherwise false. +`true`, otherwise `false`. -Expressions separated by an `OR` evaluate to true if either of the -expressions evaluate to true, otherwise false. +Expressions separated by an `OR` evaluate to `true` if either of the +expressions evaluate to `true`, otherwise `false`. To support type-ahead use cases, incomplete search expressions can be sent as OData string literals enclosed in single-quotes, and