OData Extension for Temporal Data Version 1.0



OData Extension for Temporal Data Version 4.0Working Draft 0120 28 November January 20143Technical Committee:OASIS Open Data Protocol (OData) TCChairs:Barbara Hartel (barbara.hartel@), SAP AGRam Jeyaraman (Ram.Jeyaraman@), MicrosoftEditor:Ralf Handl (ralf.handl@), SAP AGHubert Heijkers (hubert.heijkers@nl.), IBMMichael Pizzo (mikep@), MicrosoftMartin Zurmuehl (martin.zurmuehl@), SAP AGAdditional artifacts:This prose specification is one component of a Work Product that consists of:OData Extension for Temporal Data Version 4.0 (this document) HYPERLINK "" OData Temporal ABNF Construction Rules Version 4.0 HYPERLINK "" OData Temporal ABNF Test Cases HYPERLINK "" OData Temporal VocabularyRelated work:This specification is related to:OData Version 4.0 Part 1: ProtocolOData Version 4.0 Part 2: URL ConventionsOData Version 4.0 Part 3: CSDLOData ABNF Construction Rules Version 4.0OData Core VocabularyOData JSON Format Version 4.0This specification replaces or supersedes:NoneDeclared XML namespaces:NoneAbstract:This specification defines how to represent and interact with temporal data using the Open Data Protocol (OData).Status:This Working Draft (WD) has been produced by one or more TC Members; it has not yet been voted on by the TC or approved as a Committee Draft (Committee Specification Draft or a Committee Note Draft). The OASIS document Approval Process begins officially with a TC vote to approve a WD as a Committee Draft. A TC may approve a Working Draft, revise it, and re-approve it any number of times as a Committee Draft.Copyright ? OASIS Open 2012. All Rights Reserved.All capitalized terms in the following text have the meanings assigned to them in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The full Policy may be found at the OASIS website.This document and translations of it may be copied and furnished to others, and derivative works that comment on or otherwise explain it or assist in its implementation may be prepared, copied, published, and distributed, in whole or in part, without restriction of any kind, provided that the above copyright notice and this section are included on all such copies and derivative works. However, this document itself may not be modified in any way, including by removing the copyright notice or references to OASIS, except as needed for the purpose of developing any document or deliverable produced by an OASIS Technical Committee (in which case the rules applicable to copyrights, as set forth in the OASIS IPR Policy, must be followed) or as required to translate it into languages other than English.The limited permissions granted above are perpetual and will not be revoked by OASIS or its successors or assigns.This document and the information contained herein is provided on an "AS IS" basis and OASIS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY OWNERSHIP RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.Table of Contents TOC \o "1-4" \h \z \u 1Introduction PAGEREF _Toc378680795 \h 51.1 Terminology PAGEREF _Toc378680796 \h 51.2 Normative References PAGEREF _Toc378680797 \h 51.3 Non-Normative References PAGEREF _Toc378680798 \h 51.4 Typographical Conventions PAGEREF _Toc378680799 \h 62Overview PAGEREF _Toc378680800 \h 72.1 Interacting with Temporal Data PAGEREF _Toc378680801 \h 72.1.1 Single Entities PAGEREF _Toc378680802 \h 72.1.2 Collections of Entities PAGEREF _Toc378680803 \h 102.1.3 Related Entities PAGEREF _Toc378680804 \h 112.1.4 Time as a Key Part PAGEREF _Toc378680811 \h 142.1.5 System Time PAGEREF _Toc378680816 \h 172.2 Definitions PAGEREF _Toc378680819 \h 202.2.1 Application Time PAGEREF _Toc378680820 \h 202.2.2 System Time PAGEREF _Toc378680821 \h 202.2.3 Bi-Temporal PAGEREF _Toc378680822 \h 212.2.4 Time-Travel Query PAGEREF _Toc378680823 \h 212.2.5 Time-Series Query PAGEREF _Toc378680824 \h 212.2.6 Temporal Entity PAGEREF _Toc378680825 \h 212.2.7 Time Slice PAGEREF _Toc378680826 \h 212.2.8 Time Series PAGEREF _Toc378680827 \h 212.3 Example Model PAGEREF _Toc378680828 \h 212.4 Example Data PAGEREF _Toc378680829 \h 222.5 Example Use Cases PAGEREF _Toc378680830 \h 223Temporal Query Options PAGEREF _Toc378680831 \h 233.1 Temporal Expression PAGEREF _Toc378680832 \h 233.2 Time-Travel Query Options PAGEREF _Toc378680833 \h 233.2.1 System Query Option $at PAGEREF _Toc378680834 \h 233.2.2 System Query Option $systemat PAGEREF _Toc378680835 \h 233.3 Time-Series Query Options PAGEREF _Toc378680836 \h 233.3.1 System Query Option $from PAGEREF _Toc378680837 \h 243.3.2 System Query Option $to PAGEREF _Toc378680838 \h 243.3.3 System Query Option $systemfrom PAGEREF _Toc378680839 \h 243.3.4 System Query Option $systemto PAGEREF _Toc378680840 \h 244Vocabulary for Temporal Entities PAGEREF _Toc378680841 \h 255Representing Temporal Entities PAGEREF _Toc378680842 \h 275.1 Time Slices PAGEREF _Toc378680843 \h 275.2 Time Series PAGEREF _Toc378680844 \h 286Temporal Requests PAGEREF _Toc378680845 \h 296.1 Querying Temporal Entities PAGEREF _Toc378680846 \h 296.1.1 Time-Travel Queries PAGEREF _Toc378680847 \h 296.1.2 Time-Series Queries PAGEREF _Toc378680848 \h 296.1.3 Interaction with Standard System Query Options PAGEREF _Toc378680849 \h 306.2 Modifying Temporal Entities PAGEREF _Toc378680850 \h 316.2.1 Create Entity PAGEREF _Toc378680851 \h 316.2.2 Update Entity PAGEREF _Toc378680852 \h 316.2.3 Delete Entity PAGEREF _Toc378680853 \h 316.2.4 Create Relation PAGEREF _Toc378680854 \h 326.2.5 Update Relation PAGEREF _Toc378680855 \h 326.2.6 Delete Relation PAGEREF _Toc378680856 \h 326.3 ETags PAGEREF _Toc378680857 \h 326.4 Actions and Functions PAGEREF _Toc378680858 \h 327REMOVE: F2F January 2013 Zürich Notes PAGEREF _Toc378680859 \h 337.1 Thursday PAGEREF _Toc378680860 \h 337.2 Wednesday PAGEREF _Toc378680861 \h 337.2.1 "Timeless" model supports point-in-time travel PAGEREF _Toc378680862 \h 337.2.2 Business-time-only model PAGEREF _Toc378680863 \h 337.2.3 System-time-only model PAGEREF _Toc378680864 \h 347.2.4 Bi-temporal model PAGEREF _Toc378680865 \h 347.2.5 Difference to previous approach PAGEREF _Toc378680866 \h 347.2.6 Experimental Syntax PAGEREF _Toc378680867 \h 347.2.7 Model differences PAGEREF _Toc378680868 \h 357.2.8 Further thoughts PAGEREF _Toc378680869 \h 358REMOVE: F2F July 2012 Redmond Presentation PAGEREF _Toc378680870 \h 378.1 Requirements PAGEREF _Toc378680871 \h 378.2 Open Questions, Issues, and Work Items PAGEREF _Toc378680872 \h 378.3 Additional Notes PAGEREF _Toc378680873 \h 379Conformance PAGEREF _Toc378680874 \h 39Appendix A.Acknowledgments PAGEREF _Toc378680875 \h 40Appendix B.Revision History PAGEREF _Toc378680876 \h 41IntroductionThis specification adds the notion of time-dependency to the Open Data Protocol (OData) without changing any of the base principles of OData. It defines semantics and a representation for temporal data, especially:Semantics and operations for querying temporal data,Results format for queries containing temporal data,Vocabulary terms to annotate which data depends on time, and how.TerminologyThe key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in REF rfc2119 \h [RFC2119].Normative References[OData-ABNF]OData ABNF Construction Rules Version 4.0. See the link in "Related work" section on cover page.[OData-Tmp-ABNF]OData Temporal ABNF Construction Rules Version 4.0. See link in "Additional artifacts" section on cover page. [OData-CSDL]OData Version 4.0 Part 3: CSDL. See link in "Related work" section on cover page.[OData-Protocol]OData Version 4.0 Part 1: Protocol. See link in "Related work" section on cover page.[OData-URL]OData Version 4.0 Part 2: URL Conventions. See link in "Related work" section on cover page.[OData-VocTemp]OData Temporal Vocabulary. See link in "Additional artifacts" section on cover page.[RFC2119]Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, March 1997. References[Fowler]Temporal Patterns, Martin Fowler, .[Kulkarni]Temporal Features in SQL standard, Krishna Kulkarni, May 13, 2011, .[Saracco]A matter of time: Temporal data management in DB2 10, IBM developerWorks, Cynthia M. Saracco, Matthias Nicola, Lenisha Gandhi, April 3, 2012, .[SQL:2011]ISO/IEC 9075-2:2011 Information technology - Database languages - SQL - Part 2: Foundation (SQL/Foundation).Typographical ConventionsKeywords defined by this specification use this monospaced font.Normative source code uses this paragraph style.Some sections of this specification are illustrated with non-normative examples.Example SEQ Example \* ARABIC 1: text describing an example uses this paragraph styleNon-normative examples use this paragraph style.All examples in this document are non-normative and informative only.All other text is normative unless otherwise labeled.OverviewWhen keeping track of time, the most important questions are:When did or will something happen?When did we learn that it happened?This leads to two dimensions of time: application time, also called actual time, business time, or valid time, and system time, also called recording time or transaction time.Keeping track of time is typically done by storing each fact together with the period of time for which this fact is valid, using separate periods for each time dimension, and the time periods are part of the logical key for “fact records”. See REF SQL2011 \h [SQL:2011] or REF Kulkarni \h [Kulkarni] on how this is done in the SQL standard.A consumer's perspective on these facts can be different: even if a time dimension is tracked internally, it may or may not be visible in a consumer's perspective, and even if visible it is often not considered part of the logical entity key. For example an employee is still the same person even after switching to another department.The goals of this extension are:Keep the models as simple as possible by allowing to hide time, andProvide easy means for time-travel and time-series queries even if time is hidden.More sophisticated queries are still possible in models that make time visible, even if time is not made part of the entity keys.Interacting with Temporal DataSingle EntitiesAssume a simple model: employees will work in different roles and in different departments during their career, and sometimes they even change their name. So employees are assigned an immutable ID when first entering the company and all employee-related information will be recorded with a validity period attached:Example SEQ Example \* ARABIC 2: possible temporal database table for employee data using the validity start date as part of the database keyIf an employee gets a different job title, this information can already be entered into the system and stored as a new record:Example SEQ Example \* ARABIC 3: employee data stored with from-inclusive, to-exclusive validity periodNote that this also allows entering planned changes ahead of time, using a future validity start date.For consumers only interested in the information as of now, the natural OData model uses the employee ID as the entity key and either omits the validity start and end dates, or represents them only as dependent information:Example SEQ Example \* ARABIC 4: OData model with time-independent entity keyThe OData service will expose only the information from the one record valid at the time the request is processed. Example SEQ Example \* ARABIC 5: request processed before 2013-10-01GET ~/Employees('E314')results in { "@odata.context": "$metadata#Employees/$entity", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior"}Example SEQ Example \* ARABIC 6: request processed at or after 2013-10-01GET ~/Employees('E314')results in{ "@odata.context": "$metadata#Employees/$entity", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior"}Clients that are aware of the time-tracking capabilities underlying this seemingly timeless model may be interested in the information at a certain point in time. These time-traveling clients use the system query option $at to request data at a specific point in time:Example SEQ Example \* ARABIC 7: rRetrieve employee in the pastGET ~/Employees('E314')?$at=2012-01-01results in{ "@odata.context": "$metadata#Employees/$entity/$timeslice", "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior"}Example SEQ Example \* ARABIC 8: rRetrieve employee in the futureGET ~/Employees('E314')?$at=2025-01-01results in{ "@odata.context": "$metadata#Employees/$entity/$timeslice", "@Temporal.From": "2013-10-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior"}The returned results are called time slices, and the validity period of each time slice is automatically included in the response. A null value for the period start means the beginning of time, and a null value for the period end means the end of time. Time-period boundaries that are not declared properties of the requested entities are represented as instance annotations with terms from a vocabulary for temporal entities.This is necessary for the next type of question time-tracking aware clients will want to ask: how did the information change over time:Example SEQ Example \* ARABIC 9: rRetrieve employee in a time periodGET ~/Employees('E314')?$from=2012-01-01&$to=2025-01-01results in{ "@odata.context": "$metadata#Employees/$entity/$timeseries", "value": [ { "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior" }, { "@Temporal.From": "2013-10-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior" } ]}This returns all time slices whose validity period overlaps with the requested time period.Collections of EntitiesThese temporal query options also work with resource paths identifying collections of entities. Requesting data at a specific point in time results in a collection of time slices:Example SEQ Example \* ARABIC 10: rRetrieve multiple employee in the pastGET ~/Employees?$filter=contains(Name,Jobtitle eq 'Junior')&$at=2012-01-01results in one time slice for each employee matching the filter at the specified point in time{ "@odata.context": "$metadata#Employees/$timeslice", "value": [ { "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior" }, ... ]}Requesting data for a period of time results in a collection of time series, one for each entity. The time series for each entity is itself a collection of time slices for that entity: Example SEQ Example \* ARABIC 11: rRetrieve multiple employee in the pastGET ~/Employees?$filter=Jobtitle contains(Name,eq 'Junior')&$from=2012-01-01&$to=2025-01-01results in one time series for each employee matching the filter at some point within the specified period, and returns the time slices within that series that match the filter. So the value is an array of arrays:{ "@odata.context": "$metadata#Employees/$timeseries", "value": [ [ { "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior" }, { "@Temporal.From": "2013-10-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior" } ], [ { "@Temporal.From": "2012-03-01", "@Temporal.To": null, "ID": "E314E401", "Name": "Gibson", "Jobtitle": "Expert" } ] ... ]}The interpretation of non-temporal system query options in combination with $at is straight-forward: the request is simply interpreted at this point in time. The combination with $from and $to is less straight-forward and needs to be defined per standard system query option: a $filter is considered matching if the validity period of the time slice partially or fully overlaps with the request period and filter condition is true for the property values of the time slice at any point in time during the requested period, and only those time slices during that period matching the filter are part of the result.For $orderby the last value in the resulting time series (after filtering) is used, assuming that typically the last value is of most interest. For details see section REF _Ref367092962 \r \h 6.1.3.Related EntitiesEach employee is assigned to a department, and this assignment can change over time, as can properties of the department. Both types of changes are tracked, and again this need not be visible in the model. Example SEQ Example \* ARABIC 12: OData model with time-independent entity key and navigationIf the assigned department is internally stored per employee record, this can influence the visible representation; see next example. Reassigning an employee to a different department without changing any of the visible employee properties may result in time slices that do not differ other than in their time-period boundaries, see REF _Ref366752223 \h \* MERGEFORMAT Example 14. Services may or may not “compress” the returned time series by joining adjacent time slices that do not differ in the selected properties, so the service could also have returned the response of REF _Ref366752735 \h \* MERGEFORMAT Example 9. This can also happen if only a subset of the properties is requested using the system query option $select.Example SEQ Example \* ARABIC 13: employee data stored with foreign key to departmentExample SEQ Example \* ARABIC 14: rRetrieve employee in a time period during which a relationship changedGET ~/Employees('McDevitt')?$from=2012-01-01&$to=2025-01-01results in{ "@odata.context": "$metadata#Employees/$entity/$timeseries", "value": [ { "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior" }, { "@Temporal.From": "2013-10-01", "@Temporal.To": "2014-01-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior" }, { "@Temporal.From": "2014-01-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior" } ]}Expanding related entities in combination with HYPERLINK \l "_System_Query_Option" $at is straight-forward: nested within the time slice of a base entity are those time slices of related entities that are valid at the requested point in time:Example SEQ Example \* ARABIC 15: rRetrieve employee in the past with expanded departmentGET ~/Employees('E314')?$at=2012-01-01&$expand=Departmentresults in{ "@odata.context": "$metadata#Employees/$entity/$timeslice", "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior", "Department": { "@Temporal.From": "2010-01-01", "@Temporal.To": "2012-06-01", "ID": "D08", "Name": "Support" }}Example SEQ Example \* ARABIC 16: rRetrieve department in the future with expanded employeesGET ~/Departments('D15')?$at=2025-01-01&$expand=Employeesresults in{ "@odata.context": "$metadata#Departments/$entity/$timeslice", "@Temporal.From": "2010-01-01", "@Temporal.To": null, "ID": "D15", "Name": "Services", "Employees": [ { "@Temporal.From": "2014-01-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior" }, { "@Temporal.From": "2012-03-01", "@Temporal.To": null, "ID": "E401", "Name": "Gibson", "Jobtitle": "Expert" }, ... ]}The time-slice boundaries of the nested entities reflect the actual validity of the related entities and are independent of the time-slice boundaries of the base entity.Expanding related entities in combination with HYPERLINK \l "_System_Query_Option_4" $from and HYPERLINK \l "_System_Query_Option_5" $to adds the challenge that for single-valued navigation properties the related entity needs to be represented as a time series, i.e. in JSON as an array instead of as an object.Example SEQ Example \* ARABIC 17: rRetrieve employee in a time period and expand the departmentGET ~/Employees('McDevitt')?$from=2012-01-01&$to=2025-01-01&$expand=Departmentresults inAn employee time slice with an array of expanded departments because the department (name) changed during the validity period of the employee time slice. Note that the validity periods of the department time slices completely cover the validity period of the employee time slice, but are not truncated to match the employee time slice.An employee time slice with a different job title. The expanded department time slice is a copy of the last time slice in the expanded department of the preceding employee time slice. If the request had specified a preference of odata.allow-entityreferences (see [ REF odata \h \* MERGEFORMAT OData-Protocol, section 8.2.8.1], this could have been expressed as an entity reference containing annotations for the validity period.An employee time slice with a different expanded department.{ "@odata.context": "$metadata#Employees/$entity/$timeseries", "value": [ { "@Temporal.From": "2011-01-01", "@Temporal.To": "2013-10-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Junior", "Department@odata.context": "$metadata#Departments/$entity/$timeseries", "Department": [ { "@Temporal.From": "2010-01-01", "@Temporal.To": "2012-06-01", "ID": "D08", "Name": "Support" }, { "@Temporal.From": "2012-06-01", "@Temporal.To": null, "ID": "D08", "Name": "1st Level Support" } ] }, { "@Temporal.From": "2013-10-01", "@Temporal.To": "2014-01-01", "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior", "Department": [ { "@Temporal.From": "2012-06-01", "@Temporal.To": null, "ID": "D08", "Name": "1st Level Support" } ] }, { "@Temporal.From": "2014-01-01", "@Temporal.To": null, "ID": "E314", "Name": "McDevitt", "Jobtitle": "Senior", "Department": [ { "@Temporal.From": "2010-01-01", "@Temporal.To": null, "ID": "D15", "Name": "Services" } ] } ]}Describe the result: Department name changesJob title changes – same department, time-slice is repeated → could send entity/time-slice reference (separate example)Department changesNested time-series always covers validity period of "outer" time-sliceNested validity periods not truncated to match "outer"Time as a Key PartFor some entities it may be desirable to make their time-dependency visible in the model, e.g. the budget allocated to a department in a certain period of time.Example SEQ Example \* ARABIC 18: eEntity type with visible time-dependencyExample SEQ Example \* ARABIC 19: department budget over timeThe temporal query options also work in this case: although time-traveling could be achieved with $filter conditions, $at, $from, and $to are more concise and even work when only one of the time-slice boundaries is visible in the model. The result of a $at request is almost identical to the result of a request with an equivalent $filter on the temporal properties, the only difference is the context URL.Example SEQ Example \* ARABIC 20: retrieve department budget at a specific point in time: bothGET ~/DepartmentBudgets?$at=2012-07-01result in{ "@odata.context": "$metadata#DepartmentBudgets/$timeslice", "value": [ { "DepartmentID": "D08", "ValidFrom": "2012-01-01", "ValidTo": "2014-01-01", "Budget": 1250 }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170 } ]}andGET ~/DepartmentBudgets?$filter=ValidFrom le 2012-07-01 and (ValidTo gt 2012-07-01 or ValidTo eq null)result in{ "@odata.context": "$metadata#DepartmentBudgets", "value": [ { "DepartmentID": "D08", "ValidFrom": "2012-01-01", "ValidTo": "2014-01-01", "Budget": 1250 }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170 } ]}The result of a $from-$to request groups the time slices per entity into nested arrays, whereas the equivalent $filter request contains the same time slices in a single array.Example SEQ Example \* ARABIC 21: retrieve department budgets during a time periodGET ~/DepartmentBudgets?$from=2010-07-01&$to=2012-07-01results in{ "@odata.context": "$metadata#DepartmentBudgets/$timeseries", "value": [ [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 1000 }, { "DepartmentID": "D08", "ValidFrom": "2012-01-01", "ValidTo": "2014-01-01", "Budget": 1250 } ], [ { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100 }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170 } ] ]}andGET ~/DepartmentBudgets?$filter=(ValidFrom lt 2012-07-01 or ValidFrom eq null and (ValidTo gt 2010-07-01 or ValidTo eq null)results in{ "@odata.context": "$metadata#DepartmentBudgets", "value": [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 1000 }, { "DepartmentID": "D08", "ValidFrom": "2012-01-01", "ValidTo": "2014-01-01", "Budget": 1250 }, { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100 }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170 } ]}Second example with removed ValidTo to highlight the fact that $at adds value and @Temporal.To is part of the resultShow $metadata snippet showing @Temporal.From with Path to ValidFromNo suffix /$timeslice here because result is collection of "normal" entities, not time slicesSystem TimeErrors happen and need to be corrected, and in many situations the system needs to keep track of these corrections and allow clients to access the system state as of before the error correction. This is done by attaching a validity period to data that is completely managed by the system behind the scenes, disallowing changes in the past or future. When data is corrected, the validity end date of the currently valid record is set to the current system timestamp, and a new record is inserted with the same timestamp as its validity start date.Example SEQ Example \* ARABIC 22: entity type with partially visible system timeExample SEQ Example \* ARABIC 23: department budget over time with correctionsThe OData model may show the system validity period or partly or fully as read-only properties, and will show the current data in standard OData requests.The query option HYPERLINK \l "_System_Query_Option_1" $systemat allows accessing the system state at a given point in the past.Example SEQ Example \* ARABIC 24: retrieve department budgets as of a past point in timeGET ~/DepartmentBudgets?$systemat=2009-11-11T00:00results in{ "@odata.context": "$metadata#DepartmentBudgets/$timeslice", "value": [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 950, "ChangedAt": "2009-10-15T23:41", "@Temporal.SystemTo": "2009-12-21T14:00" }, { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100 "ChangedAt": "2009-10-15T23:42", "@Temporal.SystemTo": null } ]}andGET ~/DepartmentBudgets?$systemat=2010-10-24T12:00results in{ "@odata.context": "$metadata#DepartmentBudgets/$timeslice", "value": [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 1000, "ChangedAt": "2009-12-21T14:00", "@Temporal.SystemTo": null }, { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100, "ChangedAt": "2009-10-15T23:42", "@Temporal.SystemTo": null }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170, "ChangedAt": "2010-10-21T17:22", "@Temporal.SystemTo": null } ]}The query optionsAdd system time to DepartmentBudgetIntroduce , HYPERLINK \l "_System_Query_Option_2" $systemfrom, and HYPERLINK \l "_System_Query_Option_3" $systemto allow accessing the corrections made over a period of time.Example SEQ Example \* ARABIC 25: retrieve department budgets at past point in application time for a system time periodGET ~/DepartmentBudgets?$at=2010-07-01 &$systemfrom=2009-01-01T00:00&$systemto=maxresults in{ "@odata.context": "$metadata#DepartmentBudgets/$timeseries", "value": [ [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 950, "ChangedAt": "2009-10-15T23:41", "@Temporal.SystemTo": "2009-12-21T14:00" }, { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 1000, "ChangedAt": "2009-12-21T14:00", "@Temporal.SystemTo": null } ], [ { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100 "ChangedAt": "2009-10-15T23:42", "@Temporal.SystemTo": null } ] ]}When combining HYPERLINK \l "_System_Query_Option_2" $systemfrom and HYPERLINK \l "_System_Query_Option_3" $systemto with HYPERLINK \l "_System_Query_Option_4" $from and HYPERLINK \l "_System_Query_Option_5" $to the result is tagged as a time series and grouped by temporal entity although it actually is a "time surface": adding another nesting level and context URL part would add more complexity than value.Example SEQ Example \* ARABIC 26: retrieve department budgets over periods in both application time and system timeGET ~/DepartmentBudgets?$from=min&$to=max &$systemfrom=min&$systemto=nowresults in{ "@odata.context": "$metadata#DepartmentBudgets/$timeseries", "value": [ [ { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 950, "ChangedAt": "2009-10-15T23:41", "@Temporal.SystemTo": "2009-12-21T14:00" }, { "DepartmentID": "D08", "ValidFrom": "2010-01-01", "ValidTo": "2012-01-01", "Budget": 1000, "ChangedAt": "2009-12-21T14:00", "@Temporal.SystemTo": null }, { "DepartmentID": "D08", "ValidFrom": "2012-01-01", "ValidTo": "2014-01-01", "Budget": 1250, "ChangedAt": "2011-11-11T11:11", "@Temporal.SystemTo": null }, { "DepartmentID": "D08", "ValidFrom": "2014-01-01", "ValidTo": null, "Budget": 1400, "ChangedAt": "2013-10-04T09:21", "@Temporal.SystemTo": null } ], [ { "DepartmentID": "D15", "ValidFrom": "2010-01-01", "ValidTo": "2011-01-01", "Budget": 1100 "ChangedAt": "2009-10-15T23:42", "@Temporal.SystemTo": null }, { "DepartmentID": "D15", "ValidFrom": "2011-01-01", "ValidTo": null, "Budget": 1170 "ChangedAt": "2010-10-21T17:22", "@Temporal.SystemTo": null } ] ]}Second example for DepartmentBudget with ChangedAt visible and read-only, system_to hiddenuberDefinitionsApplication TimeApplication time is used to describe facts that are known to change over time, e.g. the budget of a department, or which department an employee works for. This time dimension may capture planned changes in the future, e.g. transferring an employee to a new department next month, or capturing next year's budget for a department. Both future and past facts can be changed.System TimeSystem time is used to record when a fact has become known in the “system of record”. This time dimension does not extend into the future, and record entries are only added and are never changed.System time is never manipulated directly. If it is visible, the corresponding properties are read-only.Bi-TemporalBi-temporal facts are tracked both in application time and system time to capture their change over time as well as the changes in the knowledge about these facts.Time-Travel QueryTime-travel queries request the knowledge of facts as of a certain point in time. If the queried model is bi-temporal, this requires specifying two time coordinates.Time-Series QueryTime-series queries request how knowledge of facts has varied over a certain period in time. In bi-temporal models this can be combined with time-travel in the second time dimension, or it can request all variations over a time period in each dimension.Temporal Entity A temporal entity is an entity whose change over application and/or system time is tracked by the service. The tracked time dimensions may or may not be part of the entity key.Time SliceA temporal entity does not have a single representation; its full representation is a collection of instances of its entity type, each instance annotated with the start and end point of the time period in each tracked time dimension. These instances are called entity time slices.Time SeriesA collection of time slices for a temporal entity.Example Data ModelExample SEQ Example \* ARABIC 27: The following example data OData model will be used to further illustrate the capabilities introduced by this extension. The fields depicted with a grey background are only known to the service implementation and are not part of the entity data model. They only become visible as temporal instance annotations in time-slice representations.Example DataExample SEQ Example \* ARABIC 28: The following example data will be used to further illustrate the capabilities introduced by this extension. It assumes that the example service only supports four-digit years.Example Use CasesA client might wish to query the example model in a number of ways:Retrieve a current employee, together with the employee’s current department.Retrieve employees that worked for the “Performance Analysis” department in 2010.Retrieve an employee as of a particular moment, including the employee’s department as of that same moment.Retrieve all time slices of an employee in the past, present, and future.Retrieve all time slices of the department that a specific time slice of an employee works for, within the application-time period of that employee time slice.Retrieve all time slices of an employee for a given application-time period, including all time slices of the related departments within the application-time period of each employee time slice that occurred within that time period.Retrieve all time slices of an employee, including all time slices of the department related to each time slice of the employee within the application-time period of that employee time slice.Change a department's budget in the past, present, or future.Change an employee’s association to a department in the past, present, or future.Temporal Query OptionsSix system query options allow time-travel as well as time-series queries in both time dimensions, and can be combined for bi-temporal models. They take a temporal expression as their argument whose type MUST match the granularity of the corresponding time dimension.Temporal ExpressionA temporal expression ismay beA date in the form dateValue, see REF ABNF \h [OData-ABNF]A timestamp in the form dateTimeOffsetValue, see REF ABNF \h [OData-ABNF]One of the literals now, min, and maxnow(), mindatetime() maxdatetime(), date(mindatetime()), date(maxdatetime())An arithmetic expression resulting in a date or timestamp valueThe literals now, min, and max are interpreted depending on the granularity of the time dimension. For granularity DateTimeOffset they are defined asnow ? now()min ? mindatetime()max ? maxdatetime()For granularity Date they are defined asnow ? date(now())min ? date(mindatetime())max ? date(maxdatetime())Note that services are free to choose the time zone for the current point in time returned by now(), so the result of date(now()) may differ from the current date in the client's local time zone.Time-Travel Query OptionsIf one of the following query options is combined with a resource path that addresses a single temporal entity, the resulting URL addresses a single time slice for that entity. If no matching time slice exists, the service MUST return 404 Not Found.If combined with a resource path that addresses a collection of temporal entities, the resulting URL addresses a collection of time slices for these entities. The collection can be empty. System Query Option $atThe $at system query option takes a temporal expression as its argument.It restricts the result to time slices with application-time start less than or equal to the result of the temporal expression, and application-time end greater than the result of the temporal expression.System Query Option $systematThe $systemat system query option takes a temporal expression as its argument.It restricts the result to time slices with system-time start less than or equal to the result of the temporal expression, and system-time end greater than the result of the temporal expression.Time-Series Query OptionsIf one of the following query options is combined with a resource path that addresses a single temporal entity, the resulting URL addresses a collection of time slices for that entity. The collection can be empty.If combined with a resource path that addresses a collection of temporal entities, the resulting URL addresses a collection of time slices for these entities. The collection can be empty.System Query Option $fromThe $from system query option takes a temporal expression as its argument.If $to is not explicitly specified in the same request, it defaults to maxdatetime().It restricts the result to time slices with application-time start less than the result of the $to temporal expression, and application-time end greater than the result of the $from temporal expression.System Query Option $toThe $to system query option takes a temporal expression as its argument.If $from is not explicitly specified in the same request, it defaults to mindatetime().It restricts the result to time slices with application-time start less than the result of the $to temporal expression, and application-time end greater than the result of the $from temporal expression.System Query Option $systemfromThe $systemfrom system query option takes a temporal expression as its argument.If $systemto is not explicitly specified in the same request, it defaults to maxdatetime().It restricts the result to time slices with system-time start less than the result of the $systemto temporal expression, and system-time end greater than the result of the $systemfrom temporal expression.System Query Option $systemtoThe $systemto system query option takes a temporal expression as its argument.If $systemfrom is not explicitly specified in the same request, it defaults to mindatetime().It restricts the result to time slices with system-time start less than the result of the $systemto temporal expression, and system-time end greater than the result of the $systemfrom temporal expression.Vocabulary for Temporal EntitiesThe following terms are defined in the vocabulary for temporal data REF VocTemp \h [OData-VocTemp].The term SupportsTemporal describes the temporal capabilities of the annotated entity set or container. It has a structured type with the following properties:ApplicationTimeGranularity describes the granularity of the application-time dimension. It is either Date or DateTimeOffset.SystemTimeGranularity describes the granularity of the system-time dimension. It is either Date or DateTimeOffset.At least one of these properties needs to be specified. If both are specified, the entity set or container is bi-temporal.Four terms describe the boundaries of the application- and system-time periods. They use the abstract type Edm.PrimitiveType, but in fact their type MUST match the granularity of the corresponding time dimension: From is the start of the application-time period and included in the period. To is the end of the application-time period and excluded from the period. SystemFrom is the start of the system-time period and included in the period. SystemTo is the end of the system-time period and excluded from the period. Example SEQ Example \* ARABIC 29: example data model annotated with temporal terms. Employee has no metadata annotations for the application-time boundaries, so they have to be represented as instance annotations. Department has three of the four boundaries annotated, so only SystemTo will be represented as an instance annotation.<edmx:Edmx ... Version="4.0"> <edmx:Reference Uri=""> <edmx:Include Namespace="Org.OData.Core.V1" Alias="Core" /> </edmx:Reference> <edmx:Reference Uri=""> <edmx:Include Alias="Temporal" Namespace="Org.OData.Temporal.V1" /> </edmx:Reference> <edmx:DataServices> <Schema ... Alias="OrgModel" Namespace="org.example.service"> <EntityType Name="Employee"> <Key> <PropertyRef Name="ID" /> </Key> <Property Name="ID" Type="Edm.String" Nullable="false" /> <Property Name="Name" Type="Edm.String" Nullable="false" /> <NavigationProperty Name="Department" Type="OrgModel.Department" /> </EntityType> <EntityType Name="Department"> <Annotation Term="@Temporal.From" Path="ValidFrom" /> <Annotation Term="@Temporal.To" Path="ValidTo" /> <Annotation Term="@Temporal.SystemFrom" Path="ChangedAt" /> <Key> <PropertyRef Name="ID" /> </Key> <Property Name="ID" Type="Edm.String" Nullable="false" /> <Property Name="Name" Type="Edm.String" Nullable="false" /> <Property Name="Budget" Type="Edm.Decimal" /> <Property Name="ValidFrom" Type="Edm.Date" Nullable="false" /> <Property Name="ValidTo" Type="Edm.Date" Nullable="false" /> <Property Name="ChangedAt" Type="Edm.DateTimeOffset" Nullable="false"> <Annotation Term="Core.Permissions" EnumMember="Core.Permission/Read" /> </Property> <NavigationProperty Name="Employees" Type="Collection(OrgModel.Employee)" /> </NavigationProperty> </EntityType> <EntityContainer Name="Default"> <EntitySet Name="Employees" EntityType="OrgModel.Employee"> <Annotation Term="@Temporal.SupportsTemporal"> <Record> <PropertyValue Property="ApplicationTimeGranularity" EnumMember="@Temporal.Granularity/Date" /> </Record> </Annotation> </EntitySet> <EntitySet Name="Departments" EntityType="OrgModel.Department"> <Annotation Term="@Temporal.SupportsTemporal"> <Record> <PropertyValue Property="ApplicationTimeGranularity" EnumMember="@Temporal.Granularity/Date" /> <PropertyValue Property="SystemTimeGranularity" EnumMember="@Temporal.Granularity/DateTimeOffset" /> </Record> </Annotation> </EntitySet> </EntityContainer> </Schema> </edmx:DataServices></edmx:Edmx>Representing Temporal Entities Time SlicesA time slice describes of the state of an entity for a specific period of each tracked time dimension. It is represented as an entity that is annotated with the terms From, To, SystemFrom, and SystemTo defined in REF VocTemp \h [OData-VocTemp].For application-time temporal data the values of the terms From and To MUST be defined for each instance, either as metadata annotations or as instance annotations. The value of From MUST be less than the value of To for each time slice.For system-time temporal data the values of the terms SystemFrom and SystemTo MUST be defined for each instance, either as metadata annotations, or as instance annotations. The value of SystemFrom MUST be less than the value of SystemTo for each time slice.If more than one time slice of an entity is part of a response, the time periods of any two time slices of the same entity MUST NOT overlap. For bi-temporal time slices this means that the periods for at least one of the time dimensions do not overlap.Entity-id: time slices as transient entities that do not have an id, or time slices with entity-id of their entity?Edit URLs, read URLs, navigation URLs and association URLs MUST NOT encode the time periods.Example SEQ Example \* ARABIC 30: time slice of an employee{"@odata.context": "$metadata#Employees/$entity", "@Temporal.From": "2013-01-01", "@Temporal.To": null, "ID": "E314","Name": "McDevitt", "Jobtitle": "Senior",}Example SEQ Example \* ARABIC 31: time slice of a department{"@odata.context": "$metadata#Departments/$entity", "ValidFrom": "2013-01-01", "ValidTo": "2013-12-31", "ChangedAt": "2012-12-28T14:31:25Z", "@Temporal.SystemTo": null, "ID": "D1", "Name": "Help Desk", "Budget": 735.41}Representation of expanded to-many navigation property with multiple related time slicesRepresentation of a collection of time slices in a time-series query to a resource path for a single entityRepresentation of a collection of time series in a time-series query to a resource path for a collection of entitiesContainment combined with TemporalRepresentation of constituents of temporal entities, e.g. ~/Employees('E314')/Address Property representation annotated with time period boundaries; collection in case of time-series queries Representing Time SeriesAtomJSONTemporal RequestsQuerying Temporal EntitiesRead, edit, navigation and association URLs in responses, and especially in the service document, MUST NOT encode time periods. Requests to these URLs without appending one of the temporal query options return the current representation of each temporal entity matching the request.Example SEQ Example \* ARABIC 32: Retrieve a current employeeGET ~/Employees('McDevitt')results in...Time-Travel QueriesSpecifying $at=now and $systemat=now also returns the current time slice for each matching temporal entity, and in addition includes instance annotations for all time-period boundaries that are not declared and annotated properties of the entity type.Example SEQ Example \* ARABIC 33: Retrieve a current employee, with instance annotations for time-period boundaries.GET ~/Employees('McDevitt')?$at=nowresults in...Specifying $at or $systemat for entities that are not tracked in the corresponding time dimension MUST NOT change the service behavior, the result MUST be identical to the result of a request without the superfluous time-travel option. This is semantically correct: without tracking time the current facts are the only known truth at any point in time.Example SEQ Example \* ARABIC 34: Retrieve an employee as of a particular moment, including the employee’s department as of that same moment.GET ~/Employees('McDevitt')?$expand=Departments&$at=2011-07-01GET ~/Employees('McDevitt')?$expand=Departments&$at=2011-07-01&$systemat=minboth result in...Time-Series QueriesThe query options $from and $to allow requesting all time slices whose application-time periods overlap with the specified time range. The lower boundary is included, the upper boundary excluded from the requested period. Example SEQ Example \* ARABIC 35: Retrieve employees that worked for the “Performance Analysis” department in 2010. Note that the value of $to is not included in the results.GET ~/Departments('Performance Analysis')/Employees?$from=2010-01-01 &$to=2011-01-01results in...Example SEQ Example \* ARABIC 36: Retrieve all time slices of an employee in the past, present, and future.GET ~/Employees('McDevitt')?$from=min&$to=maxresults in...Specifying $from $to, $systemfrom, or $systemto for entities that are not tracked in the corresponding time dimension MUST NOT change the service behavior, the result MUST be identical to the result of a request without the superfluous time-series option. This is semantically correct: without tracking time the current facts are the only known truth in any period of time.Allow services to "condense" time slices, especially when combined with $selectThe temporal system query options apply to all returned time slices: to those of entities identified by the resource path as well as to those of expanded entities. Example SEQ Example \* ARABIC 37: Retrieve all time slices of an employee for a given time period, including all time slices of the related departments within the application-time period of each employee time slice that occurred within that time period.GET ~/Employees('McDevitt')?$expand=Department &$from=2010—01-01&$to=2010-12-31results in...The special resource $entity that allows resolving entity-ids SHOULD also allow resolving time slice ids.Example SEQ Example \* ARABIC 38: Retrieve all time slices of the department that a specific time slice of an employee works for, within the application-time period of that employee time slice.GET ~/$entity?$id=<id of employee time slice>?$expand=Departmentresults in...Note: could also be achieved by selecting the employee and specifying the from- and to-property values of the time slice in $from and $to.Interaction with Standard System Query Options$at: all options are evaluated at this point in time, same semantics.$from/$to needs special handling:$filter: entity matches if condition is true at any point within [$from,$to[ (right-open)$orderby: order is determined with value of latest time slice that intersects with [$from,$to[ (right-open)$top: entities, i.e. number of returned time series, no limit to number of time slices within series, [$from,$to[ is completely covered$skip: entities, i.e. number of skipped time series$count: entities, i.e. number of time series$select: allow compression of adjacent time slices that do not differ in selected properties$search: entity matches if condition is true at any point within [$from,$to[ (right-open)$expand without nested $at or $from/$to: for each time slice: related time series that covers [T.From,T.To[ (right-open) of this time slice; means that "border" time slices of related entities may show up twice, once as last, then as first time slice$expand with nested $at or $from/$to: ???$apply: ???Modifying Temporal EntitiesCreate EntityAllow $from/$to in request URL if start/end are not part of the model, or require using instance annotations? Better not: keep data in the request payload, only resort to query options if there's no request body, i.e. for GET and DELETE. This also avoids conflicting values in query options and corresponding properties.Do we have to consider Create in combination with If-(None-)Match? Check with Part 1.Update EntityUpsert now allowed, so update within undefined period no conceptual problem, even if no period is defined at allNeed a way to specify "max" as upper boundary: years have no digit limit in our ABNF, limit is service/server-specificCould use null for that, but then the properties have to be nullableCould omit them, but that means "don't change" in normal PATCHExample SEQ Example \* ARABIC 39: Change a department's budget for a period of time.PATCH ~/Departments('Performance Analysis') HTTP/1.1Content-Type: application/json{"@Temporal.From": "2013-04-01","@Temporal.To": "2013-06-30","Budget": 20000000.00 ...}Delete EntityA temporal entity can be deleted by No body, have to use system query options for partial deleteExample SEQ Example \* ARABIC 40: Delete an entity for a period of time.DELETE ~/Employees('E314')?$from=2013-04-01&$to=2013-06-30 HTTP/1.1Create RelationNo PUT needed as because we require all navigation properties to be collection-valued? Update RelationExample SEQ Example \* ARABIC 41: Change an employee’s department in the past, present, or future.PATCH ~/Employees('McDevitt')/Department/$ref HTTP/1.1Content-Type: application/json{"@odata.id": "~/Departments('Support')","@Temporal.From": "2010-01-01","@Temporal.To": "2010-12-31"}Example SEQ Example \* ARABIC 42: Modify a department's employees in the past, present, or future.Delete RelationExample SEQ Example \* ARABIC 43: Delete a relation for a period of time.DELETE ~/Employees('E314')/$ref?$id=...?$from=2013-04-01&$to=2013-06-30 HTTP/1.1ETagsETags need special handling: in system-temporal stores you can't really change data, just add new versions, so actually "write conflict" doesn't mean losing data, it just means "shadowing" data unintentionally.How do we want to use ETags in this context? Actions and FunctionsREMOVE: F2F January 2013 Zürich NotesThis section contains notes taken during the discussions on Temporal during the third Face-to-Face meeting in Zürich in January 2013. Remove this chapter and its sections before publication.ThursdayRequest period NOT encoded in read, edit and navigation linksID does contain time information, identifies the time sliceSusan: IDs with temporal information may be confusing in non-temporal view for clients unaware of temporalMike: non-temporal (simplified) view could be exposed as second entity container in same serviceSimplified view by default returns system-current, application-currentTemporal view by default returns system-current, application-allRalf: only if application time is part of key Updatessystem-time property values are ignored, system manages system timeApplication-time values have to be specified, from:null means from beginning of time, to:null means to infinityDiscuss: have default from=now, to=infinity if not specified?DeletesIn system time creates "tombstone" time slice or truncates last time slice, up to implementationIn application time marks period as deletedApplication period specified via $from, $to; may look odd but is really simpler than all discussed alternativesInsertsConsider POST also working as UPSERT provided that solves more problems that it causesWednesday"Timeless" model supports point-in-time travel All navigation keeps 2D time coordinate fixedNo change to model due to time travelNavigationProperties have "natural" cardinalitySystem-start/end and business-start/end may be present and useful for point-in-time travelBusiness-time-only modelMakes one time dimension visibleSystem time is "frozen" to one point in time"time series" instead of instances per "business key"Model changes: all navigation cardinalities become "many"OperationsChange property from to infinityChange property from to[HH] In our discussions that followed we said/agreed one would always have to specify the from to for changes and to be honest I'd think the cases would be very rare where the business time you'd want to use would the moment you do something in the system although I can come up with an example or two presuming systems would be fast enough to actually do true real time updates. Get history from toNavigate from history slice to related (slices of) entitiesChoice: get slices that exactly cover the "source" slice, or get slices that at least cover the "source" sliceAssumptionsGET Mike → current slice for MikereadLink for slice returns that slice, at least until next update on underlying store that changes the slice borderseditLink for slice may NOT encode slice, it may be "just Mike"The time range affected is NOT determined from the editLink but from the request payloadFrom-To queries get slices that cover from-to but might be larger; no "virtual slicing" based on queryNavigation/expansion starting from a slice without explicit time range returns minimal set of related slices that cover the "source" sliceRequested time period NOT encoded in navigation linksQuestionsHow does Delta work with Time? [HH] Delta links would encode the requested time coordinate/period and would act as if the application date and related records would have been exactly the same without the implicit notion of temporal right? What does the ID of the change records encode? Probably they encode the slice borders: changes to slice borders are combinations of deletes of "before-slices" and inserts of "after-slices"System-time-only modelHistory is read-only, changes stack new time slices on topIn read cases no difference to business-time onlySystem-start and system-end are read-only and ignored in update requestsBi-temporal modelSystem-time history is read-onlyUpdates specify business-time range only, system-time implicitly handled by systemRead operations have to specify both time ranges[HH] They don't have to specify both nor would both need to be time ranges right, any combo of having them or not and coordinate vs range would be valid (just asking because you wrote 'have to'). Difference to previous approachRequest time periods are NOT encoded in responseHave to be re-specified when re-querying or navigatingTime periods probably best expressed as query optionsApparently no requirements towards CoreTime-slices are in ID, not in readLink, editLink, or navigationLinkExperimental SyntaxGET ~/Employees('Andrew')→ current Andrew?GET ~/Employees('Andrew')?$from=last_month&$to=now→ one or more slices for Andrew covering $from $to Anmerkung: liefert einen FEED...ist das erlaubt? Ja: --> Bei ZeitRAUM Queries ist die Kardinalit?t immer *Ist ?quivalent zu:GET ~/Employees?$filter=empID eq 'Andrew'&$from=last_month&$to=now→ one or more slices for Andrew covering $from $to??GET ~/Employees('Andrew')/DirectReports?$from=last_month&$to=now?GET ~/Employees('Andrew')?$from=last_month&$to=now&$expand=DirectReports?GET ~/Employees('Andrew')?$from=last_month&$to=now&$expand=DirectReports($from=last_year;$to=tomorrow)?$from$to$at as shortcut for from=to$systemfrom$systemto$systemat?Model differences$at can work with the "non-temporal" model$from and $to require a "temporal" model where all navigation target cardinalities are "many"Hubert: expose "temporal" model as separate service, do not implicitly switch models when temporal query option is used$at also works on "temporal" modelAdvertise existence of "temporal" service via special link in service document or annotation in metadataFurther thoughtsFor temporal queries that support time-series queries, all (non-contained) relationships MUST be many:many.The service SHOULD expose start/end application/system timesMAY be exposed together as a complex type or as individual propertiesThese are marked with annotationsMAY be queried with application/system point or rangeDefault is all for application, current for systemThe set SHOULD be marked as supporting application or system timesYou may get the same id multiple times in your resultThe service MAY expose a simplified viewThe service MAY expose start/end application/system timesMAY be exposed together as a complex type or as individual propertiesMAY be queried as current, or any single point in timeDefault is currentQueryIf no temporal argument is specified, the current values are returnedfor system time, always use current.for simplified view, always use current for application timefor temporal view, use all for application timea point of time may be specified for any requestmay be different for expanded childrendefault is same as parentnavigating a result uses the default unless temporal arguments are specifiedup to client to use consistent times in requests as requiredselflink DOES NOT encode a start/end timethe same selflink may return different ids-would be strange in simplified viewconsider encoding start/end times in the selflink for the simplified viewid logically encodes start/end time. any change that modifies start/end logically deletes the entity(ies) and adds a new entity(ies)issue: if I want different time periods within a request, I can express in individual periods in $expandfor Andrew's employees as of 2000, what departments were they in 2012?Update (PUT/MERGE)EditLink represents the entry throughout time (doesn't encode time periods)Patch always patches currentUpdates against a SystemTime table MUST NOT try to change system time propertiessystemtime start/end properties are readonlyinvalid or ignored in update?Updates against an ApplicationTime MAY specify start/end times to be updated (as update parameters).if not specified, should we have a default (current, no end?) no from default? default for end is max?Updates may create/delete/split recordsDelete (DELETE)Deletes against a SystemTime table creates a new recordDeletes against an ApplicationTime table MAY specify start/end times (using query options)if not specified, delete from now on? Or all?Insert (POST)Creates new resource (may add/delete other resources)error if the resources with those keys exist in any other timeMay specify application start/end timesif not specified, create from now on? from beginning of time?MUST NOT specify system start/end timeserror or ignoreissue: If I delete a record then try to post it will fail because the ids existed in timeconsider POST doing an upsert?REMOVE: F2F July 2012 Redmond PresentationThis section contains extracts of the presentation given by Andrew Eisenberg during the initial Face-to-Face meeting in Redmond in July 2012. Remove this chapter and its sections before publication.RequirementsThe following capabilities must be supported in this extension to OData:Annotate OData entity types that expose temporal dataSupport both application time periods and system time periodsThe result of queries on temporal data must be represented in ODataFor system time periods, allow only current entities to be returnedSupport AS OF, FROM, and BETWEEN operations on these entitiesAllow entities reflecting application time temporal data to be updatedAllow entities reflecting current entities of system time temporal data to be updatedOpen Questions, Issues, and Work ItemsIt may be desirable to allow a query to apply “as of”, “from”, and “between” to an entire request, an entity set, or possibly at some finer level of granularity.The current approach requires that any relationship to a temporal type be many in order to handle cases where navigating the relationship could return different time slices of the entity (for example, if an employee was requested using a time range, rather than a point in time, it may have multiple departments during that time). An alternative design would be to define relationships as always being tied to a moment in time. This would allow more natural navigations, both in query (i.e., Employee('McDevitt')/Department/City eq 'London') and in generating strongly typed results (String city = employee.Department.City). Fixing the relationships at a moment in time is not an issue for "current" or "as of" queries, which anchor navigation to the moment in time specified in the initial request (in fact, it is what we propose), but it is an issue for navigating relationships from entities retrieved using "from" and "between" requests. One proposal was to define relationships for entities requested with a time span as returning the related time slice as of the last valid time for the parent entity within that queried timespan (i.e., the most recent department time slice for the given employee time slice within the specified timespan).Additional NotesWe considered making application start/end time part of the key so that time slices of each entity were unique. In this case we could have more comfortably exposed all time slices in an application time entity set and uniquely identified each. However, clients may want to update the start and end times and OData does not allow updating keys.We considered the following options for specifying a temporal period in the request:Use new system query option(s). The primary issue with this approach was composability. We wanted the entry to be able to return a self/edit link that the client could compose on top of, which favors the temporal modifier to be in the path portion of the requestUse top-level Functions. We could have separate top level entry points (functions?) for each temporal entity set (i.e., EmployeesByApplicationTime(…), EmployeesBySystemTime(…), etc. ) Once we made the simplification that a temporal period applied to an entire request, this implied that any temporal request would have to be rooted in one of these functions. This doesn't work well for composing temporal aspects to an existing URL (i.e., if I wanted to see all departments related to a particular employee for a specified period of time independent of how that employee was retrieved, or if I wanted to navigate from a nontemporal entity to a particular time slice of a temporal entity).Use Functions. We discussed applying functions to collections in order to apply temporal aspects to the set. This made for an elegant composable navigation model syntactically, but it seemed a little weird to define a function on a collection which changed the membership of that collection. Also, once we made the simplifying assumption that the entire request was as of a particular temporal period, exposing as composable functions provided more flexibility than we wanted.Path Modifiers. We discussed including system-defined “function-like” operators in the path that would mean “interpret the path from the preceding collection on as being of this time”. The semantics of the method affecting the membership of the collection identified by the previous segment was a little strange as it wasn't a filter over the membership but rather changed the time slice of the entities exposed by that collection. ConformanceConforming services MUST follow all rules of this specification for the time dimensions and temporal system query options they support. They MUST implement all time dimensions they advertise via the SupportsTemporal annotation. Conforming clients MUST be prepared to consume a model that uses any or all of the temporal constructs defined in this specification, and MUST ignore any temporal constructs not defined in this version of the specification.AcknowledgmentsThe contributions of the OASIS OData Technical Committee members, enumerated in [OData-Protocol], are gratefully acknowledged.Especial thanks to Andrew Eisenberg, whose contributions in the early stages of the OData TC were invaluable to getting this extension specification on track.Revision HistoryRevisionDateEditorChanges MadeWD012013-08-ddRalf HandlInitial working draft ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download