OData TC meeting #207 Thursday March 15, 2018

Acting chair: Mike

Chat transcript from room: odatatc
2018-03-15 0800-1000 PDT

1. Roll call

1.1 Members present

    George Ericson (Dell)
    Gerald Kraue (SAP SE)
    Hubert Heijkers (IBM)
    Matthew Borges (SAP SE) a.k.a. Matt
    Michael Pizzo (Microsoft) a.k.a. Mike
    Stefan Hagen (Individual)
    Ted Jones (Red Hat)

Quorum achieved. Details cf. normative attendance sheet for this meeting (event_id=46247).

Notes taken by all and subsequently edited for readability by Stefan.

2. Approve agenda

Agenda approved unchanged as published

3. Approve minutes from previous meeting(s)

3.1 Minutes from March 08, 2018 TC meeting #206

https://www.oasis-open.org/committees/download.php/62674/odata-meeting-206_on-20180308-minutes.html

Minutes approved unchanged as published.

4. Review action items [Link to Action item list]

4.1 Action items due

Reviewed action items. None due; heads up on approaching deadlines.

5. Issues

5.1 V4.01: NEW or OPEN

5.1.1 ODATA-1166 - Update JSON references to RFC8259

Mike: reference to new RFC: https://tools.ietf.org/html/rfc8259

Mike: Question: are there any updates that would affect us? From RFC8529:

Appendix A.  Changes from RFC 7159

   This section lists changes between this document and the text in
   RFC 7159.

   o  Section 1.2 has been updated to reflect the removal of a JSON
      specification from ECMA-262, to make ECMA-404 a normative
      reference, and to explain the particular meaning of "normative".

   o  Section 1.3 has been updated to reflect errata filed against
      RFC 7159, not RFC 4627.

   o  Section 8.1 was changed to require the use of UTF-8 when
      transmitted over a network.

   o  Section 12 has been updated to increase the precision of the
      description of the security risk that follows from using the
      ECMAScript "eval()" function.

   o  Section 14.1 has been updated to include ECMA-404 as a normative
      reference.

   o  Section 14.2 has been updated to remove ECMA-404, update the
      version of ECMA-262, and refresh the errata list.

Mike: Does not appear that any of these changes would have an impact on our use of JSON.

Mike: Note: JSON apparently requires JSON readers to support escaped forward slashes, though writers are not required to escape. Our examples do not escape, which is fine.

Hubert: I move to resolve ODATA-1166 as proposed. Ted seconds.

Mike: Motion approved by unanimous consent.

5.1.2 ODATA-1165 - Describe $expand and $select via prose text and examples, remove ABNF snippets

Mike: We will wait on ODATA-1166 until ralf can explain the overly restrictive nature of the ABNF.

Mike: (that is, we will wait on ODATA-1165)

5.1.3 ODATA-1164 - List of use cases for canonical functions is incomplete

Mike: ODATA-1164 is open

Mike: (btw; we did open 1166 prior to moving to approve...)

Mike:

5.1.1.4 Canonical Functions
In addition to operators, a set of functions is also defined for use with the $filter or 
$orderby system query options. 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.

Mike: Statement should be more general, but current wording does help people understand where functions can be used.

Gerald: The set of functions can be used anywhere a common expression is applied such as $filter or $orderby.

Mike: Perhaps make the statement more specific, but include filter and orderby as examples...

Mike: Gerald has updated the proposal.

Hubert: I move to resolve ODATA-1164 as per the updated proposal. Matt seconds.

Mike: ODATA-1164 is approved as proposed.

5.1.4 ODATA-1163 - A Case for Common Expressions

Mike:

1. Core OData: Ad-hoc calculations with logic on the current property values:

Example: Signum(x)

GET ~/XValues?$compute=case(X > 0 : 1,X < 0 : -1, 0) as SignumX&$select=X,SignumX

2. Data Aggregation extension: Restricting aggregation to those values that occur in combination with certain groupable property values:
Example: Comparing company revenues for years 2000 and 2017

GET ~/Sales?$apply=groupby((Company), aggregate(case(Time/Year eq 2000 : Revenue) with sum as TotalRevenue2000, case(Time/Year eq 2017 : Revenue) with sum as TotalRevenue2017))

3. Data Aggregation extension: Defining dynamic groupable properties
Example: From a collection of incidents with fine-grained state model (e.g., new, assigned, resolved, verified, reopened, closed) retrieve the aggregated count of open and closed incidents:

GET ~/Incidents?$apply=compute(case(Status eq Closed : Closed, Open) as ProcessingStatus)/groupby((ProcessingStatus), aggregate($count as IncidentCount))

Mike: RESO was asking for this just last week.

Mike: is case(X > 0 : 1,X < 0 : -1, 0) equivalent to if(X>0,1,if(X<0,-1,0)?

Mike: sum is defined as returning null if there are no non-null values, so for 2017, the expression:

Mike: GET ~/Sales?$apply=groupby((Company), aggregate(case(Time/Year eq 2000 : Revenue) with sum as TotalRevenue2000, case(Time/Year eq 2017 : Revenue) with sum as TotalRevenue2017))

Mike: would be equivalent to writing:

GET ~/Sales?$apply=groupby((Company), aggregate(null, case(Time/Year eq 2017 : Revenue) with sum as TotalRevenue2017))
GET ~/Sales?$apply=groupby((Company), aggregate(null, Revenue with sum as TotalRevenue2017))
GET ~/Sales?$apply=groupby((Company), aggregate(null with sum as TotalRevenue2000, Revenue with sum as TotalRevenue2017))

Mike: (never mind above; aggregate is applying to each row in the input set...)

Would it be equally expressive to use something like if-then-else? 
Would that be more intuitive to a programmer?
Or would switch be more similar for programmers?

George: are we trying to put too much in the expressions, making it hard on services to implement?

Mike:

Would we need a way to tell whether services support the new expression?
(add to existing capabilities for supported canonical functions)
could be done as a custom function if(condition,value-if-true,value-if-false), 
but that would be more verbose and less standardized.

Gerald: how do we define the type of the expression result?

Mike: Easiest would be to force all result expressions to be of the same type.

Mike: Alternative would be to cast to common type; i.e., if one expression returned an integer and one a string, the type of the expression would be a string.

Mike: OData 1163 is open. Gerald will flesh out a complete proposal.

5.1.5 ODATA-1154 - Clarify which OData-Version a service should return

Mike: Discussed in meeting march 1st. Open questions:

Mike: Questions:

1) What if no OData-MaxVersion is specified? 
2) Does specifying an OData-Version limit the constructs that the request can use in the URL? 
   i.e., if I have a 4.0 payload, am I restricted to 4.0 URL constructs, even if I know the service supports them? 
3) What if the client *only* support 4.01? Do we have a way to specify NOT to return 4.0? 
4) Does a service have to return a 4.01 payload if the request uses a 4.01 construct?

Mike: The following is a legal delta payload for describing changes to a collection of customers:

{
  "value": [
    {
      "CustomerID": "EASTC",
      "CompanyName": "Eastern Connection",
      "ContactName": "Ann Devon",
      "ContactTitle": "Sales Agent"
    },
    {
      "CustomerID": "ALFKI",
      "Orders@delta": [
        {
          "OrderID": 11011,
          "CustomerID": "ALFKI",
          "EmployeeID": 3,
          "OrderDate": "1998-04-09T00:00:00Z",
          "RequiredDate": "1998-05-07T00:00:00Z",
          "ShippedDate": "1998-04-13T00:00:00Z"
        },
      ]
    }
  ]
}

Mike: This could be a delta response from an initial query of GET ~Customers, or to a PATCH Customers

Mike: Similarly, changes to a single item *within the customers collection*

{
  "@context":"#$delta",
  "value": [
    {
      "CustomerID": "ALFKI",
      "Orders@delta": [
        {
          "OrderID": 11011,
          "CustomerID": "ALFKI",
          "EmployeeID": 3,
          "OrderDate": "1998-04-09T00:00:00Z",
          "RequiredDate": "1998-05-07T00:00:00Z",
          "ShippedDate": "1998-04-13T00:00:00Z"
        }
      ]
    }
  ]
}

Mike: Today, we can patch an individual customer (PATCH ~Customers('ALFKI'):

{
  "@context":"#$delta",
  "CustomerID": "ALFKI",
}

Mike: I would expect you could also PATCH ~Customers('ALFKI'):

{
  "@context":"#$delta",
  "CustomerID": "ALFKI",
  "Orders@delta": [
        {
          "OrderID": 11011,
          "CustomerID": "ALFKI",
          "EmployeeID": 3,
          "OrderDate": "1998-04-09T00:00:00Z",
          "RequiredDate": "1998-05-07T00:00:00Z",
          "ShippedDate": "1998-04-13T00:00:00Z"
        }
  ]
}

Mike: (without the @context)

Mike: (and without the CustomerID, but you could instead change a different properties of alfki:

{
  "Name": "Bob",
  "Orders@delta": [
        {
          "OrderID": 11011,
          "CustomerID": "ALFKI",
          "EmployeeID": 3,
          "OrderDate": "1998-04-09T00:00:00Z",
          "RequiredDate": "1998-05-07T00:00:00Z",
          "ShippedDate": "1998-04-13T00:00:00Z"
        }
  ]
}

Mike: So, if I did a GET ~Customers('ALFKI')?$expand=Orders, and asked for a delta link, that delta link could return this same payload.

Mike: (with the addition of the context url)

Mike: In a response, the context url would be "@context":"#$delta"

GET ~Customers('ALFKI') = > context: ...Customers/$entity
GET ~CustomerSingleton => context: ...CustomerSingleton (with no trailing /$entity)

Mike: same thing for a single valued nav prop...

Mike: (strike that; Hubert points out that, for a single valued nav prop bound to a collection, the contextUrl is the bound set with /$entity)

6. Next meetings

Ralf:

Thursday March 22, 2018 during 8-10 am PDT (16:00-18:00 CET) – Daylight Saving Time in North America
Thursday March 29, 2018 during 8-10 am PDT (17:00-19:00 CEST) – back to normal time difference, Easter is coming

7. AOB and wrap up

None.

Meeting adjourned by chair.