From f46db9419d138ce671f15f8e0513ff0276df6d85 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Mon, 28 Jun 2021 23:50:05 -0700 Subject: [PATCH 01/49] Editorial Corrections in Getting Started --- docs/rapid-pro.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/rapid-pro.md b/docs/rapid-pro.md index 0d408165..c13ae121 100644 --- a/docs/rapid-pro.md +++ b/docs/rapid-pro.md @@ -59,7 +59,7 @@ service { } ``` -For details on defining a RAPID service using RSDL, see [RAPID Schema Definition Language (RSDL)](./rsdl/rapid-pro-rsdl-intro.md) +For details on defining a RAPID service using RSDL, see [RAPID Schema Definition Language (RSDL)](./rsdl/rapid-pro-rsdl-intro.md). This simple design time syntax is converted to a runtime service description that client applications and tooling can use to interact with the service. @@ -94,7 +94,7 @@ RAPID uses standard GET, POST, PATCH, and DELETE requests to retrieve and update ### Retrieving a Resource -RAPID services support retrieving a resource using the GET method: +RAPID services support retrieving a resource using the GET method. | Template | GET {resource-path} | | ----------- | :------------------------------------------------------------------------------ | @@ -102,6 +102,8 @@ RAPID services support retrieving a resource using the GET method: RAPID services return individual resources as a json object. +**Body:** + ```json { "@context": "$metadata#company", @@ -143,12 +145,12 @@ For details on modifying data in RAPID, see [Modifying Resources in RAPID](./rap ## Optional Features -Although RAPID services can be very simple, because they follow core patterns they can be extended using optional Features, -as appropriate, to support more advanced scenarios such as those described in [RAPID Features](./spec/rapid-pro-features.md). +Although RAPID services can be very simple because they follow core patterns, they can be extended using optional Features +to support more advanced scenarios such as those described in [RAPID Features](./spec/rapid-pro-features.md). ## RAPID and OpenAPI -OpenAPI is an extremely popular specification for documenting a REST API. +[OpenAPI](https://www.openapis.org/) is an extremely popular specification for documenting a REST API. Because the RAPID profile builds upon REST, it is natural and encouraged for RAPID services to support OpenAPI. As the RAPID service description defines a superset of what a service might want to document through OpenAPI, @@ -163,6 +165,6 @@ A RAPID service can easily support generic OData V4 clients by: - Supporting OData calling conventions - Following OData JSON conventions for OData V4 Clients -RAPID services MAY support any additional conventions defined in the OData specification as appropriate to the service. +RAPID services _may_ support any additional conventions defined in the OData specification as appropriate to the service. -For more information on how RAPID works with OData services, see [RAPID and OData](./related/rapid-pro-odata.md) +For more information on how RAPID works with OData services, see [RAPID and OData](./related/rapid-pro-odata.md). From d90509a629d3dc113846a2d34e337f360ead37dc Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:06:52 -0700 Subject: [PATCH 02/49] Editorial Corrections in Batch Operations --- docs/spec/rapid-pro-batch.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/spec/rapid-pro-batch.md b/docs/spec/rapid-pro-batch.md index 2327d356..8c462c00 100644 --- a/docs/spec/rapid-pro-batch.md +++ b/docs/spec/rapid-pro-batch.md @@ -67,7 +67,7 @@ Requests and responses are correlated via an `id` for each individual request. } ``` -## Error handling +## Error Handling Batch requests return `200 OK` even if some or all of the individual requests in the batch fail. Batch requests only return `4xx` if the batch request body is malformed, @@ -75,7 +75,7 @@ the client is not authenticated or lacks authorization for the `/$batch` resourc or other reasons not related to individual requests in the batch. If an individual request fails, processing continues with the next request. -Individual tequests can be processed in any order, +Individual requests can be processed in any order, not necessarily in the sequence they appear in the batch request. **Body:** From e9b13d52adb33a9dfe5a7580c5233427d235158e Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:28:54 -0700 Subject: [PATCH 03/49] Editorial Changes to Intro to RSDL --- docs/rsdl/rapid-pro-rsdl-intro.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/rsdl/rapid-pro-rsdl-intro.md b/docs/rsdl/rapid-pro-rsdl-intro.md index 41c2ad97..3b341982 100644 --- a/docs/rsdl/rapid-pro-rsdl-intro.md +++ b/docs/rsdl/rapid-pro-rsdl-intro.md @@ -7,7 +7,7 @@ title: RAPID SDL intro RAPID Schema Definition Language (RSDL) is a language to define Web APIs. -RSDL is based on the [RAPID PROfile]() of the +RSDL is based on the [RAPID Profile]() of the [OData](https://en.wikipedia.org/wiki/Open_Data_Protocol) specification. RAPID provides an easy way to envision, create, and consume a Web API that is compatible with the OData Standard and can evolve over time to support more advanced scenarios. @@ -28,9 +28,9 @@ type Company } ``` -Our company has three properties; a stockSymbol, a name, and the date of incorporation. +Our company has three properties: a stockSymbol, a name, and the date of incorporation. -Properties in RAPID can be Integer, String, Boolean, DateTime, Date, Double, Decimal, TimeOfDay, Duration built-in types, an [enum type](#defining-an-enum), a [structured type](#defining-a-structured-type), or a collection of any of the former. +A property in RAPID can be an Integer, String, Boolean, DateTime, Date, Double, Decimal, TimeOfDay, Duration built-in types, an [enum type](#defining-an-enum), a [structured type](#defining-a-structured-type), or a collection of any of the former. ### Defining a Service @@ -182,7 +182,7 @@ type Employee RAPID supports functions and actions. -A function takes zero or more input parameters, and returns a value. Functions must not have side-affects. +A function takes zero or more input parameters, and returns a value. Functions must not have side effects. We can define a "topEmployees" function on our company: From 509216647136288e305870c9ea04c324787fe8e6 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:55:12 -0700 Subject: [PATCH 04/49] Editorial Corrections to RSDL Semantics --- docs/rsdl/rapid-pro-rsdl-semantics.mdx | 76 +++++++++++++------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/docs/rsdl/rapid-pro-rsdl-semantics.mdx b/docs/rsdl/rapid-pro-rsdl-semantics.mdx index 7465ef70..7184a207 100644 --- a/docs/rsdl/rapid-pro-rsdl-semantics.mdx +++ b/docs/rsdl/rapid-pro-rsdl-semantics.mdx @@ -61,14 +61,14 @@ The model's A [structured type](./rapid-pro-rsdl-abnf.md#structured-type) is mapped to either an [entity type](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_EntityType) or a [complex type](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_ComplexType). A structured type with one or more properties marked with `key` is mapped to an entity type. -And respectively a structured type without `key` properties is mapped to a complex type. +Correspondingly, a structured type without `key` properties is mapped to a complex type. -### Structured Types without `key` Properties +### Structured Types with `key` Properties ``` -type Name { - firstName : String - lastName: String +type Employee { + key id: Integer + name : Name } ``` @@ -83,10 +83,11 @@ type Name { ```json -"Name": { - "$Kind": "ComplexType", - "firstName": { "$Type": "Edm.String" }, - "lastName": { "$Type": "Edm.String" } +"Employee": { + "$Kind": "EntityType", + "$Key": [ "id" ], + "id": { "$Type": "Edm.Int32" }, + "name": { "$Type": "Model.Name" } } ``` @@ -94,21 +95,24 @@ type Name { ```xml - - - - + + + + + + + ``` -### Structured Types with `key` Properties +### Structured Types without `key` Properties ``` -type Employee { - key id: Integer - name : Name +type Name { + firstName : String + lastName: String } ``` @@ -123,11 +127,10 @@ type Employee { ```json -"Employee": { - "$Kind": "EntityType", - "$Key": [ "id" ], - "id": { "$Type": "Edm.Int32" }, - "name": { "$Type": "Model.Name" } +"Name": { + "$Kind": "ComplexType", + "firstName": { "$Type": "Edm.String" }, + "lastName": { "$Type": "Edm.String" } } ``` @@ -135,13 +138,10 @@ type Employee { ```xml - - - - - - - + + + + ``` @@ -151,7 +151,7 @@ type Employee { The properties of a type definition are mapped to either a Property or a NavigationProperty depending on the property's type. -In the following example lets assume, name is mapped to a complete type and employee is mapped to a entity type. +In the following example, let's assume name is mapped to a complex type and employee is mapped to a entity type. ``` type Company { @@ -205,8 +205,8 @@ type Company { The type of a property is one of: -- one of the built-in types defined in the [`builtInType`](./rapid-pro-rsdl-abnf.md/#structured-type) syntax rule -- any of the primitive EDM type listed in [OData CSDL XML Representation](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_PrimitiveTypes) +- the built-in types defined in the [`builtInType`](./rapid-pro-rsdl-abnf.md/#structured-type) syntax rule +- the primitive EDM types listed in [OData CSDL XML Representation](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_PrimitiveTypes) - the structured or enumeration types defined in the model Each of these named types can be marked as @@ -319,7 +319,7 @@ type Employee { -#### Function Return Type +#### Function Return Types The return type of a function is mapped similar to a property type with the same semantic for `[` `]` and `?`. @@ -434,7 +434,7 @@ type Employee { ## Enumeration Types -A [Enumeration Type](./rapid-pro-rsdl-abnf.md#enumeration-type) is mapped to an CSDL EnumType. The enumeration members values are automatically assigned. +An [Enumeration Type](./rapid-pro-rsdl-abnf.md#enumeration-type) is mapped to a CSDL EnumType. The enumeration members' values are automatically assigned. ```json enum employmentType { salaried hourly } @@ -473,8 +473,8 @@ enum employmentType { salaried hourly } ## Flag Types -A [Flags Type](./rapid-pro-rsdl-abnf.md#enumeration-type), i.e an enumeration that starts with the keyword flags, is mapped to an CSDL EnumType with the `IsFlags` property set to `true` -The members values are automatically assigned to powers of 2. +A [Flags Type](./rapid-pro-rsdl-abnf.md#enumeration-type), i.e an enumeration that starts with the keyword flags, is mapped to an CSDL EnumType with the `IsFlags` property set to `true`. +The members' values are automatically assigned to powers of 2. ```json flags PhoneService { LandLine Cell Fax Internet Other } @@ -594,7 +594,7 @@ service { If the type is used as a type on a multi-value and as the type of a property of type definitions (i.e. a navigation property in CSDL), the appropriate navigation property bindings get created. -In below example, the `company` type has a `ceo` and an `employees` property of the same type `employee` (except one is single-value and the other multi-value). +In the example below, the `company` type has a `ceo` and an `employees` property of the same type `employee` (except one is single-value and the other multi-value). The binding in CSDL defines that objects of these properties are bound to the `employees` entity set. ``` @@ -642,7 +642,7 @@ service { -### Single-valued Service Member +### Single-Valued Service Member A service member of a single-value type gets mapped to a CSDL singleton. From 613f935dfbcfa63ced5a1b7087ff1f0927beebee Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:56:55 -0700 Subject: [PATCH 05/49] Editorial Corrections to RAPID Pro Syntax --- docs/rsdl/rapid-pro-rsdl-abnf.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-pro-rsdl-abnf.md b/docs/rsdl/rapid-pro-rsdl-abnf.md index 5c0f8144..03cfe3c8 100644 --- a/docs/rsdl/rapid-pro-rsdl-abnf.md +++ b/docs/rsdl/rapid-pro-rsdl-abnf.md @@ -3,7 +3,7 @@ id: rsdl-abnf title: RAPID SDL ABNF --- -# RAPID Pro syntax +# RAPID Pro Syntax > DRAFT > March 2021 From c5aeba4d63ec95710f8d00379f6fece9d4101eb3 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 10:59:29 -0700 Subject: [PATCH 06/49] Editorial Corrections to Features > Overview --- docs/spec/rapid-pro-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/rapid-pro-features.md b/docs/spec/rapid-pro-features.md index 874566f0..e9b81831 100644 --- a/docs/spec/rapid-pro-features.md +++ b/docs/spec/rapid-pro-features.md @@ -9,7 +9,7 @@ and because they follow core patterns they can be extended with optional feature For an overview of RAPID, see [Getting Started](../rapid-pro.md). -The following sections provide more detailed information and walkthroughs for key aspects of RAPID. +The following sections provide more detailed information and walkthroughs for key aspects of RAPID: - [RAPID Schema Definition Language](../rsdl/rapid-pro-rsdl-intro.md) - [Data Retrieval](../rapid-pro-read.md) From 11ed37c8a5fe5663804215be37aaa6740c66f2f6 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 11:03:06 -0700 Subject: [PATCH 07/49] Editorial Corrections to Features > Runtime Service Description --- docs/spec/rapid-pro-resource_description.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/spec/rapid-pro-resource_description.md b/docs/spec/rapid-pro-resource_description.md index 25cbbb7d..3530bb17 100644 --- a/docs/spec/rapid-pro-resource_description.md +++ b/docs/spec/rapid-pro-resource_description.md @@ -68,7 +68,7 @@ Because the `employee` type is used in a collection, it defines a property (`id`) as the key value for referencing instances within the collection. The `company` type has a property for navigating to a collection of employees. -The employees are contained by the company; that is, they do not exist in a separate top-level collection. +The employees are contained within the company; that is, they do not exist in a separate top-level collection. Resources can also include properties not advertised in metadata. These "dynamic" properties can be referenced in query options and included in result payloads, From 295f3081bcd5529895f50a9574731302c8eb7c70 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 29 Jun 2021 11:05:53 -0700 Subject: [PATCH 08/49] Editorial Corrections to Features > Actions and Functions --- docs/rapid-pro-operations.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rapid-pro-operations.md b/docs/rapid-pro-operations.md index 2d3db09f..2cd7307c 100644 --- a/docs/rapid-pro-operations.md +++ b/docs/rapid-pro-operations.md @@ -5,7 +5,7 @@ sidebar_label: Actions and Functions --- Although a pure REST service would perform operations through manipulating the state of resources, -we have found many services require the ability to encapsulate complex processing logic into atomic operations. +we have found that many services require the ability to encapsulate complex processing logic into atomic operations. Rather than requiring services to expose a separate endpoint for such business logic, RAPID allows services to support Operations. Operations are exposed as resources at the root of the service or "bound" to the resource on which they operate. @@ -18,7 +18,7 @@ Operations include Actions and Functions. ## Actions -Actions may have side-affects, are invoked using `POST`, and have parameters specified in the body. +Actions may have side effects, are invoked using `POST`, and have parameters specified in the body. | Template | POST {resource-path}/{actionName} | | -------- | :------------------------------------------------------- | @@ -34,7 +34,7 @@ Actions may have side-affects, are invoked using `POST`, and have parameters spe ## Functions -Functions are invoked using `GET` and must be non-side affecting. +Functions are invoked using `GET` and must have no side effects. Parameters are passed to functions as query options: | Template | GET {resource-path}/{functionName}?{@param=value...} | From 84d3b80913fe93a0750f69d0913d646e212b88c4 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Tue, 6 Jul 2021 10:09:38 -0700 Subject: [PATCH 09/49] Adjusted capitalization Co-authored-by: Ralf Handl --- docs/rapid-pro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rapid-pro.md b/docs/rapid-pro.md index c13ae121..401de1f9 100644 --- a/docs/rapid-pro.md +++ b/docs/rapid-pro.md @@ -145,7 +145,7 @@ For details on modifying data in RAPID, see [Modifying Resources in RAPID](./rap ## Optional Features -Although RAPID services can be very simple because they follow core patterns, they can be extended using optional Features +Although RAPID services can be very simple because they follow core patterns, they can be extended using optional features to support more advanced scenarios such as those described in [RAPID Features](./spec/rapid-pro-features.md). ## RAPID and OpenAPI From 71455b35ec6ff5ae9f1352c20e392dd37c0401b1 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Wed, 21 Jul 2021 08:08:51 -0700 Subject: [PATCH 10/49] Drafted component to interactively make queries within documentation --- docs/rapid-pro-read.md | 6 + website/package.json | 2 + website/src/components/InteractiveQuerying.js | 130 ++++++++++++++++++ 3 files changed, 138 insertions(+) create mode 100644 website/src/components/InteractiveQuerying.js diff --git a/docs/rapid-pro-read.md b/docs/rapid-pro-read.md index 258811f5..e053e791 100644 --- a/docs/rapid-pro-read.md +++ b/docs/rapid-pro-read.md @@ -4,6 +4,8 @@ title: Reading Resources sidebar_label: Reading Resources --- +import InteractiveQuerying from '../website/src/components/InteractiveQuerying.js'; + ## Retrieving a Resource RAPID services support retrieving a resource using the GET method: @@ -12,6 +14,8 @@ RAPID services support retrieving a resource using the GET method: | ----------- | :------------------------------------------------------------------------------ | | **Example** | GET [`http://rapid-pro.org/company`](https://jetsons.azurewebsites.net/company) | + + RAPID services return individual resources as a json object. ```json @@ -40,6 +44,8 @@ The client can select individual properties of the resource using the `select` o | ----------- | :------------------------------------------------------------------------------------------------------------------------------ | | **Example** | GET [`http://rapid-pro.org/company?select=name,stockSymbol`](https://jetsons.azurewebsites.net/company?$select=name,stockSymbol) | + + **Result:** ```json diff --git a/website/package.json b/website/package.json index 36d71d9a..e2d00f4c 100644 --- a/website/package.json +++ b/website/package.json @@ -12,9 +12,11 @@ "dependencies": { "@docusaurus/core": "^2.0.0-beta.0", "@docusaurus/preset-classic": "^2.0.0-beta.0", + "bootstrap": "^5.0.2", "classnames": "^2.2.6", "prettier": "2.0.5", "react": "^16.8.4", + "react-bootstrap": "^1.6.1", "react-dom": "^16.8.4" }, "browserslist": { diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js new file mode 100644 index 00000000..b9da7067 --- /dev/null +++ b/website/src/components/InteractiveQuerying.js @@ -0,0 +1,130 @@ +import React from "react"; +import InputGroup from 'react-bootstrap/InputGroup'; +import FormControl from 'react-bootstrap/FormControl'; +import Button from 'react-bootstrap/Button'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import {Component} from 'react'; + +/* Next Steps: + - Make results a scrollable, static-size box / code-like box + - Distinguish two kinds of results +*/ + +/// Tool to allow a user to make a query on the Jetsons API and see the results. +/// Default query to start with filled in. +/// +/// ID to identify a specific component instance - must be unique; +/// otherwise, setting the default query can impact other instances. +/// +/// +/// ID is required to isolate a specific InteractiveQuerying instance for the default query. +/// +class InteractiveQuerying extends Component { + constructor(props) { + super(props); + + this.state = { + queryUrl: this.props.defaultQuery, + responseElement:

+ } + } + + /// Start with results displayed. + /// Optional + componentDidMount() { + document.getElementById(this.props.id).value = this.props.defaultQuery; + this.fetchResults(this.props.defaultQuery); + } + + /// Gets the results for the query entered by the user. + updateQueryResults = () => { + let newQuery = document.getElementById(this.props.id).value; + if (newQuery !== "") { + this.setState({queryUrl: newQuery}); + this.fetchResults(newQuery); + } else { + this.setToDefault(); + //this.setState({responseElement:

}) + } + } + + /// + /// Sets the query/results to the default given from . + /// + setToDefault = () => { + document.getElementById(this.props.id).value = this.props.defaultQuery; + this.setState({queryUrl: this.props.defaultQuery}); + this.fetchResults(this.props.defaultQuery); + } + + /// + /// Fetches the results for a given and updates the results accordingly. + /// + /// Query on the Jetsons API. + fetchResults(query) { + fetch("https://jetsons.azurewebsites.net/" + query) + .then (res => res.text()) + .then( + (result) => { + if (result === "The page cannot be displayed because an internal server error has occurred.") { + result = "This query is not valid; please try a different query." + } + this.setState({responseElement:

{result}

}) + } + ).catch(function(err) { + console.error(err); + }); + } + + render() { + return ( +
+ + +
+ ); + } +} + +/// Allows a user to enter queries, starting with a default query. +/// Function to set the query to a default query. +/// Function to update the results based on the user-entered query. +class Query extends Component { + render() { + return ( + <> +

Query

+ + GET http://rapid-pro.org/ + + + + + + ); + } +} + +/// Displays the results given by . +/// Results text. +class Results extends Component { + render() { + return ( + <> +

Results

+
+ {this.props.results} +
+ + ); + } +} + +export default InteractiveQuerying; \ No newline at end of file From 97a98a90a6f1235bdd6d30b6f93f73cbef187d39 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Thu, 22 Jul 2021 10:37:54 -0700 Subject: [PATCH 11/49] Styled results to be a scrollable box --- website/src/components/InteractiveQuerying.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index b9da7067..6015517d 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -117,12 +117,24 @@ class Query extends Component { class Results extends Component { render() { return ( - <> +

Results

-
+
{this.props.results}
- +
); } } From 547025bf75f011883e73695a02cbc2dd02f3f8e1 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Thu, 22 Jul 2021 13:59:41 -0700 Subject: [PATCH 12/49] Created function to format queries so they work regardless of including the dollar symbol ($) --- website/src/components/InteractiveQuerying.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index 6015517d..a4e65b7b 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -62,7 +62,8 @@ class InteractiveQuerying extends Component { /// /// Query on the Jetsons API. fetchResults(query) { - fetch("https://jetsons.azurewebsites.net/" + query) + let formattedQuery = this.formatQuery(query); + fetch("https://jetsons.azurewebsites.net/" + formattedQuery) .then (res => res.text()) .then( (result) => { @@ -76,6 +77,20 @@ class InteractiveQuerying extends Component { }); } + formatQuery(query) { + let queryPieces = query.split("?"); + let formattedQuery = queryPieces[0]; + for (let i = 1; i < queryPieces.length; i++) { + let piece = queryPieces[i]; + if (!piece.startsWith('$')) { + formattedQuery += "?$" + piece; + } else { + formattedQuery += "?" + piece; + } + } + return formattedQuery; + } + render() { return (
@@ -126,7 +141,7 @@ class Results extends Component { "height": "120px", "borderRadius": "0.4rem", "overflow": "hidden", - "overflow-y": "scroll", + "overflowY": "scroll", "color": "black", "width": "100%", "background": "#eee", From 7d2a8f01c4e1b29b203d3eab7fe714ad0e3417b9 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Fri, 23 Jul 2021 00:56:33 -0700 Subject: [PATCH 13/49] addressed bugs/errors related to requests on unmounted components and incorrect transformation of URLs --- website/src/components/InteractiveQuerying.js | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index a4e65b7b..f6e2b390 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -22,19 +22,26 @@ import {Component} from 'react'; class InteractiveQuerying extends Component { constructor(props) { super(props); + let newController = new AbortController(); this.state = { queryUrl: this.props.defaultQuery, - responseElement:

+ responseElement:

, + controller: newController, + signal: newController.signal } } /// Start with results displayed. - /// Optional componentDidMount() { document.getElementById(this.props.id).value = this.props.defaultQuery; this.fetchResults(this.props.defaultQuery); } + + /// Abandon fetch request before component unmounts. + componentWillUnmount() { + this.state.controller.abort(); + } /// Gets the results for the query entered by the user. updateQueryResults = () => { @@ -63,7 +70,8 @@ class InteractiveQuerying extends Component { /// Query on the Jetsons API. fetchResults(query) { let formattedQuery = this.formatQuery(query); - fetch("https://jetsons.azurewebsites.net/" + formattedQuery) + let signal = this.state.signal; + fetch("https://jetsons.azurewebsites.net/" + formattedQuery, {signal}) .then (res => res.text()) .then( (result) => { @@ -77,8 +85,19 @@ class InteractiveQuerying extends Component { }); } + // select, expand, filter, skip, top, count, orderby formatQuery(query) { - let queryPieces = query.split("?"); + let formattedQuery = query.replace(/select/g, "$select"); + formattedQuery = formattedQuery.replace(/expand/g, "$expand"); + formattedQuery = formattedQuery.replace(/filter/g, "$filter"); + formattedQuery = formattedQuery.replace(/skip/g, "$skip"); + formattedQuery = formattedQuery.replace(/top/g, "$top"); + formattedQuery = formattedQuery.replace(/count/g, "$count"); + formattedQuery = formattedQuery.replace(/orderby/g, "$orderby"); + formattedQuery = formattedQuery.replace(/$$/g, "$"); + formattedQuery = formattedQuery.substring(0, formattedQuery.length - 1); + + /*let queryPieces = query.split("?"); let formattedQuery = queryPieces[0]; for (let i = 1; i < queryPieces.length; i++) { let piece = queryPieces[i]; @@ -87,7 +106,8 @@ class InteractiveQuerying extends Component { } else { formattedQuery += "?" + piece; } - } + }*/ + return formattedQuery; } @@ -133,8 +153,8 @@ class Results extends Component { render() { return (

Results

Date: Fri, 23 Jul 2021 00:57:02 -0700 Subject: [PATCH 14/49] added interactive querying for all examples --- docs/rapid-pro-read.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/docs/rapid-pro-read.md b/docs/rapid-pro-read.md index e053e791..827a4af7 100644 --- a/docs/rapid-pro-read.md +++ b/docs/rapid-pro-read.md @@ -14,8 +14,6 @@ RAPID services support retrieving a resource using the GET method: | ----------- | :------------------------------------------------------------------------------ | | **Example** | GET [`http://rapid-pro.org/company`](https://jetsons.azurewebsites.net/company) | - - RAPID services return individual resources as a json object. ```json @@ -27,6 +25,8 @@ RAPID services return individual resources as a json object. } ``` + + RAPID responses are self-describing. The first line says that the response is described by the `company` singleton defined in the `$metadata` resource. The `$metadata` resource may be represented as a relative or absolute URL. @@ -44,8 +44,6 @@ The client can select individual properties of the resource using the `select` o | ----------- | :------------------------------------------------------------------------------------------------------------------------------ | | **Example** | GET [`http://rapid-pro.org/company?select=name,stockSymbol`](https://jetsons.azurewebsites.net/company?$select=name,stockSymbol) | - - **Result:** ```json @@ -56,6 +54,8 @@ The client can select individual properties of the resource using the `select` o } ``` + + The first line says that only the `name` and `stockSymbol` properties are selected to be returned from the `company` resource. ### Including Related Resources @@ -92,6 +92,8 @@ Related resources can be retrieved as nested resources through the `expand` quer } ``` + + The context property specifies that the `employees` are expanded within the `company`. Because the next link refers to the nested `employees` property, the `nextLink` property is prefixed with the name of the nested property. @@ -122,6 +124,8 @@ you can express the same options for the related resource that you can for any o } ``` + + ## Retrieving a Collection of Resources RAPID services return collections of resources as a JSON array: @@ -153,6 +157,8 @@ RAPID services return collections of resources as a JSON array: } ``` + + If the result is large, the service may include a next link to tell the client that there are more items in the collection. The value of the next link is an opaque URL that the client can use to retrieve the next set of resources from the collection. The absence of the next link signals the client that they have retrieved all of the resources in the collection. @@ -177,6 +183,8 @@ Individual members of a collection can be identified by appending the key to the } ``` + + Here the context property specifies that the result is an individual resource within the `employees` collection of the `company`. ### Selecting Individual Properties of Collection Members @@ -206,6 +214,8 @@ http://rapid-pro.org/company/employees?select=lastName } ``` + + ### Requesting a Range of Members The client can use `top` and/or `skip` query options to select a range of resources within a collection. @@ -238,6 +248,8 @@ They can use the `count` query option to request the count of all resources in t } ``` + + The result skips the first member and returns the next two. The `@count` property denotes the total number of resources in the collection, and is not affected by `skip` or `top`. There is no next link because all two of the requested resources are returned. @@ -279,6 +291,8 @@ The client can use the `orderby` query option to order the results returned with } ``` + + Null values sort before non-null values in ascending order and after non-null values in descending order. If `asc` or `desc` is not specified, the default ordering is ascending. @@ -313,6 +327,8 @@ The client can use the `filter` query option to filter the results returned from } ``` + + In this case, there is no next link since all of the resources matching the filter predicate were returned inline. There is a full expression language to describe what the client can express in the filter. @@ -345,6 +361,8 @@ The order of query options is not significant. ] } ``` +F + ## Passing Query Strings in the Body From d11c00584d9b5de98f1122fa15a435643d3cffb9 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Fri, 23 Jul 2021 01:14:07 -0700 Subject: [PATCH 15/49] improved accuracy and efficiency of reformatting queries --- website/src/components/InteractiveQuerying.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index f6e2b390..05a81d09 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -87,7 +87,7 @@ class InteractiveQuerying extends Component { // select, expand, filter, skip, top, count, orderby formatQuery(query) { - let formattedQuery = query.replace(/select/g, "$select"); + /*let formattedQuery = query.replace(/select/g, "$select"); formattedQuery = formattedQuery.replace(/expand/g, "$expand"); formattedQuery = formattedQuery.replace(/filter/g, "$filter"); formattedQuery = formattedQuery.replace(/skip/g, "$skip"); @@ -95,7 +95,19 @@ class InteractiveQuerying extends Component { formattedQuery = formattedQuery.replace(/count/g, "$count"); formattedQuery = formattedQuery.replace(/orderby/g, "$orderby"); formattedQuery = formattedQuery.replace(/$$/g, "$"); - formattedQuery = formattedQuery.substring(0, formattedQuery.length - 1); + formattedQuery = formattedQuery.substring(0, formattedQuery.length - 1);*/ + + let formattedQuery = ""; + for (let i = 0; i < query.length - 1; i++) { + let currChar = query.charAt(i); + formattedQuery += currChar; + + if ((currChar == '?' || currChar == '(' || currChar == '&' || currChar == ';') + && query.charAt(i+1) != '$') { + formattedQuery += '$'; + } + } + formattedQuery += query.charAt(query.length - 1); /*let queryPieces = query.split("?"); let formattedQuery = queryPieces[0]; From d7561a7ad60d1f65b8c4d29ea5cc1deb1267e9f5 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Fri, 23 Jul 2021 01:19:02 -0700 Subject: [PATCH 16/49] cleaned up code and added method comment --- website/src/components/InteractiveQuerying.js | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index 05a81d09..43f5a939 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -85,41 +85,20 @@ class InteractiveQuerying extends Component { }); } - // select, expand, filter, skip, top, count, orderby + /// Adds '$' before commands if missing, AKA after '?', '(', '&', and ';'. + /// Query to reformat. + /// The reformatted query (unchanged if no '$' are missing). formatQuery(query) { - /*let formattedQuery = query.replace(/select/g, "$select"); - formattedQuery = formattedQuery.replace(/expand/g, "$expand"); - formattedQuery = formattedQuery.replace(/filter/g, "$filter"); - formattedQuery = formattedQuery.replace(/skip/g, "$skip"); - formattedQuery = formattedQuery.replace(/top/g, "$top"); - formattedQuery = formattedQuery.replace(/count/g, "$count"); - formattedQuery = formattedQuery.replace(/orderby/g, "$orderby"); - formattedQuery = formattedQuery.replace(/$$/g, "$"); - formattedQuery = formattedQuery.substring(0, formattedQuery.length - 1);*/ - let formattedQuery = ""; for (let i = 0; i < query.length - 1; i++) { let currChar = query.charAt(i); formattedQuery += currChar; - if ((currChar == '?' || currChar == '(' || currChar == '&' || currChar == ';') && query.charAt(i+1) != '$') { formattedQuery += '$'; } } formattedQuery += query.charAt(query.length - 1); - - /*let queryPieces = query.split("?"); - let formattedQuery = queryPieces[0]; - for (let i = 1; i < queryPieces.length; i++) { - let piece = queryPieces[i]; - if (!piece.startsWith('$')) { - formattedQuery += "?$" + piece; - } else { - formattedQuery += "?" + piece; - } - }*/ - return formattedQuery; } From 988b7593a6fc63af8e60ce953c61f166f115d7e6 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Fri, 23 Jul 2021 02:21:48 -0700 Subject: [PATCH 17/49] reformatted query and results --- website/src/components/InteractiveQuerying.js | 67 +++++++++++++------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/InteractiveQuerying.js index 43f5a939..d2a7c57d 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/InteractiveQuerying.js @@ -4,11 +4,8 @@ import FormControl from 'react-bootstrap/FormControl'; import Button from 'react-bootstrap/Button'; import 'bootstrap/dist/css/bootstrap.min.css'; import {Component} from 'react'; +import CodeBlock from "@theme/CodeBlock"; -/* Next Steps: - - Make results a scrollable, static-size box / code-like box - - Distinguish two kinds of results -*/ /// Tool to allow a user to make a query on the Jetsons API and see the results. /// Default query to start with filled in. @@ -26,7 +23,7 @@ class InteractiveQuerying extends Component { this.state = { queryUrl: this.props.defaultQuery, - responseElement:

, + responseElement: [Loading], controller: newController, signal: newController.signal } @@ -77,8 +74,11 @@ class InteractiveQuerying extends Component { (result) => { if (result === "The page cannot be displayed because an internal server error has occurred.") { result = "This query is not valid; please try a different query." + } else { + result = this.formatJson(result); } - this.setState({responseElement:

{result}

}) + let newResponse = {result} + this.setState({responseElement: newResponse}) } ).catch(function(err) { console.error(err); @@ -102,10 +102,48 @@ class InteractiveQuerying extends Component { return formattedQuery; } + formatJson(json) { + let formattedJson = ""; + let tabLevel = 0; + let inQuote = false; + for (let i = 0; i < json.length; i++) { + let currChar = json.charAt(i); + if (currChar == '{' || currChar == '[') { + tabLevel++; + formattedJson += currChar + '\n' + this.getTabSpaces(tabLevel); + } else if (currChar == ',' && !inQuote) { + formattedJson += currChar + '\n' + this.getTabSpaces(tabLevel); + } else if (currChar == '}' || currChar == ']') { + tabLevel--; + formattedJson += '\n' + this.getTabSpaces(tabLevel) + currChar; + } else if (currChar == ':') { + formattedJson += currChar + " "; + } else { + if (currChar == '\"') { + inQuote = !inQuote; + } + formattedJson += currChar; + } + } + return formattedJson; + } + + getTabSpaces(tabLevel) { + let spaces = ""; + for (let i = 1; i <= tabLevel; i++) { + spaces += " "; + } + return spaces; + } + render() { return (
- +
); @@ -119,7 +157,7 @@ class Query extends Component { render() { return ( <> -

Query

+

Query:

GET http://rapid-pro.org/ -

Results

-
+

Result:

{this.props.results}
-
); } } From cdff501ecb5aeb3ffb9b98c5186e9ab75522b73c Mon Sep 17 00:00:00 2001 From: Clement Habinshuti Date: Mon, 9 Aug 2021 19:49:53 +0300 Subject: [PATCH 18/49] Configure odata uri tools for building as local npm packages --- tools/odataUri/.gitignore | 1 + tools/odataUri/README.md | 43 + tools/odataUri/package.json | 24 +- .../{ => src}/autocomplete-manager.ts | 0 tools/odataUri/{ => src}/autocomplete.ts | 0 tools/odataUri/{ => src}/common.ts | 0 tools/odataUri/{ => src}/index.ts | 0 tools/odataUri/{ => src}/json-model.ts | 0 .../parsers/.antlr/ODataUriPathLexer.interp | 0 .../parsers/.antlr/ODataUriPathLexer.java | 0 .../parsers/.antlr/ODataUriPathLexer.tokens | 0 .../parsers/.antlr/ODataUriQuery.interp | 0 .../parsers/.antlr/ODataUriQuery.tokens | 0 .../parsers/.antlr/ODataUriQueryLexer.interp | 0 .../parsers/.antlr/ODataUriQueryLexer.java | 0 .../parsers/.antlr/ODataUriQueryLexer.tokens | 0 .../parsers/.antlr/ODataUriQueryParser.java | 0 .../{ => src}/parsers/ODataUriQuery.g4 | 0 .../{ => src}/parsers/ODataUriQuery.interp | 0 .../{ => src}/parsers/ODataUriQuery.tokens | 0 .../parsers/ODataUriQueryLexer.interp | 0 .../src/parsers/ODataUriQueryLexer.js | 180 ++ .../parsers/ODataUriQueryLexer.tokens | 0 .../{ => src}/parsers/ODataUriQueryLexer.ts | 0 .../src/parsers/ODataUriQueryParser.js | 1651 +++++++++++++++++ .../{ => src}/parsers/ODataUriQueryParser.ts | 0 .../src/parsers/ODataUriQueryVisitor.js | 3 + .../{ => src}/parsers/ODataUriQueryVisitor.ts | 0 tools/odataUri/{ => src}/path.ts | 0 tools/odataUri/{ => src}/semantic-model.ts | 17 +- tools/odataUri/tsconfig.json | 16 + tools/odataUri/webpack.config.js | 38 + tools/urlEditor/.gitignore | 1 + tools/urlEditor/README.md | 42 + tools/urlEditor/package.json | 15 +- tools/urlEditor/{ => src}/index.ts | 0 tools/urlEditor/{ => src}/uri-editor.ts | 7 +- tools/urlEditor/{ => src}/utils.ts | 2 +- tools/urlEditor/tsconfig.json | 18 + tools/urlEditor/webpack.config.js | 32 + website/README.md | 4 + website/package.json | 3 +- 42 files changed, 2079 insertions(+), 18 deletions(-) create mode 100644 tools/odataUri/.gitignore create mode 100644 tools/odataUri/README.md rename tools/odataUri/{ => src}/autocomplete-manager.ts (100%) rename tools/odataUri/{ => src}/autocomplete.ts (100%) rename tools/odataUri/{ => src}/common.ts (100%) rename tools/odataUri/{ => src}/index.ts (100%) rename tools/odataUri/{ => src}/json-model.ts (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriPathLexer.interp (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriPathLexer.java (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriPathLexer.tokens (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQuery.interp (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQuery.tokens (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQueryLexer.interp (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQueryLexer.java (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQueryLexer.tokens (100%) rename tools/odataUri/{ => src}/parsers/.antlr/ODataUriQueryParser.java (100%) rename tools/odataUri/{ => src}/parsers/ODataUriQuery.g4 (100%) rename tools/odataUri/{ => src}/parsers/ODataUriQuery.interp (100%) rename tools/odataUri/{ => src}/parsers/ODataUriQuery.tokens (100%) rename tools/odataUri/{ => src}/parsers/ODataUriQueryLexer.interp (100%) create mode 100644 tools/odataUri/src/parsers/ODataUriQueryLexer.js rename tools/odataUri/{ => src}/parsers/ODataUriQueryLexer.tokens (100%) rename tools/odataUri/{ => src}/parsers/ODataUriQueryLexer.ts (100%) create mode 100644 tools/odataUri/src/parsers/ODataUriQueryParser.js rename tools/odataUri/{ => src}/parsers/ODataUriQueryParser.ts (100%) create mode 100644 tools/odataUri/src/parsers/ODataUriQueryVisitor.js rename tools/odataUri/{ => src}/parsers/ODataUriQueryVisitor.ts (100%) rename tools/odataUri/{ => src}/path.ts (100%) rename tools/odataUri/{ => src}/semantic-model.ts (98%) create mode 100644 tools/odataUri/tsconfig.json create mode 100644 tools/odataUri/webpack.config.js create mode 100644 tools/urlEditor/.gitignore create mode 100644 tools/urlEditor/README.md rename tools/urlEditor/{ => src}/index.ts (100%) rename tools/urlEditor/{ => src}/uri-editor.ts (95%) rename tools/urlEditor/{ => src}/utils.ts (90%) create mode 100644 tools/urlEditor/tsconfig.json create mode 100644 tools/urlEditor/webpack.config.js diff --git a/tools/odataUri/.gitignore b/tools/odataUri/.gitignore new file mode 100644 index 00000000..53c37a16 --- /dev/null +++ b/tools/odataUri/.gitignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/tools/odataUri/README.md b/tools/odataUri/README.md new file mode 100644 index 00000000..942fc528 --- /dev/null +++ b/tools/odataUri/README.md @@ -0,0 +1,43 @@ +# OData URI tools + +This package contains a URI parsers that provides autocomplete suggestions and error validation. + +## How to build + +Run: + +``` +npm install +``` + +then + +``` +npm run build +``` + +The build command will store the output files in `dist`. + +**Note**: You need to run the build command before setting up packages that depend on this library. This package is not on npm, so the dependent +packages will fetch this package from the local fs as is. + +## Usage + +```ts +import { AutoCompleteManager } from "odata-uri"; + +// `schema` is an object in CSDL JSON format +const parser = new AutoCompleteManager(schema); + +// gets a list of validation errors (both syntax and semantic errors) +// returns an array with objects like { message: "error message", range: { start: 10, stop: 20 } } +const errors = parser.getErrors("http://service/companies?$filter="); + +// second parameter is the cursor position for which suggestions will be provided +// returns an array of strings +const suggestions = parser.getCompletions("http://service/companies?$filter=", 34); + +// updates the schema +parsers.updateSchema(newSchema); + +``` \ No newline at end of file diff --git a/tools/odataUri/package.json b/tools/odataUri/package.json index 41a62119..81758b98 100644 --- a/tools/odataUri/package.json +++ b/tools/odataUri/package.json @@ -2,17 +2,33 @@ "name": "odata-uri", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" }, "author": "", "license": "ISC", "dependencies": { "antlr4-c3": "^1.1.16", - "antlr4ts": "^0.5.0-alpha.4" + "antlr4ts": "^0.5.0-alpha.4", + "process": "^0.11.10", + "util": "^0.12.4" }, "devDependencies": { - "typescript": "^4.3.4" + "@babel/cli": "^7.14.8", + "@babel/core": "^7.15.0", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.7", + "@babel/preset-env": "^7.15.0", + "@babel/preset-typescript": "^7.15.0", + "@parcel/transformer-typescript-tsc": "^2.0.0-alpha.3", + "@parcel/transformer-typescript-types": "^2.0.0-rc.0", + "@tsconfig/recommended": "^1.0.1", + "ts-loader": "^9.2.5", + "typescript": "^4.3.4", + "webpack": "^5.48.0", + "webpack-cli": "^4.7.2" } } diff --git a/tools/odataUri/autocomplete-manager.ts b/tools/odataUri/src/autocomplete-manager.ts similarity index 100% rename from tools/odataUri/autocomplete-manager.ts rename to tools/odataUri/src/autocomplete-manager.ts diff --git a/tools/odataUri/autocomplete.ts b/tools/odataUri/src/autocomplete.ts similarity index 100% rename from tools/odataUri/autocomplete.ts rename to tools/odataUri/src/autocomplete.ts diff --git a/tools/odataUri/common.ts b/tools/odataUri/src/common.ts similarity index 100% rename from tools/odataUri/common.ts rename to tools/odataUri/src/common.ts diff --git a/tools/odataUri/index.ts b/tools/odataUri/src/index.ts similarity index 100% rename from tools/odataUri/index.ts rename to tools/odataUri/src/index.ts diff --git a/tools/odataUri/json-model.ts b/tools/odataUri/src/json-model.ts similarity index 100% rename from tools/odataUri/json-model.ts rename to tools/odataUri/src/json-model.ts diff --git a/tools/odataUri/parsers/.antlr/ODataUriPathLexer.interp b/tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.interp similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriPathLexer.interp rename to tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.interp diff --git a/tools/odataUri/parsers/.antlr/ODataUriPathLexer.java b/tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.java similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriPathLexer.java rename to tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.java diff --git a/tools/odataUri/parsers/.antlr/ODataUriPathLexer.tokens b/tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.tokens similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriPathLexer.tokens rename to tools/odataUri/src/parsers/.antlr/ODataUriPathLexer.tokens diff --git a/tools/odataUri/parsers/.antlr/ODataUriQuery.interp b/tools/odataUri/src/parsers/.antlr/ODataUriQuery.interp similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQuery.interp rename to tools/odataUri/src/parsers/.antlr/ODataUriQuery.interp diff --git a/tools/odataUri/parsers/.antlr/ODataUriQuery.tokens b/tools/odataUri/src/parsers/.antlr/ODataUriQuery.tokens similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQuery.tokens rename to tools/odataUri/src/parsers/.antlr/ODataUriQuery.tokens diff --git a/tools/odataUri/parsers/.antlr/ODataUriQueryLexer.interp b/tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.interp similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQueryLexer.interp rename to tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.interp diff --git a/tools/odataUri/parsers/.antlr/ODataUriQueryLexer.java b/tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.java similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQueryLexer.java rename to tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.java diff --git a/tools/odataUri/parsers/.antlr/ODataUriQueryLexer.tokens b/tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.tokens similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQueryLexer.tokens rename to tools/odataUri/src/parsers/.antlr/ODataUriQueryLexer.tokens diff --git a/tools/odataUri/parsers/.antlr/ODataUriQueryParser.java b/tools/odataUri/src/parsers/.antlr/ODataUriQueryParser.java similarity index 100% rename from tools/odataUri/parsers/.antlr/ODataUriQueryParser.java rename to tools/odataUri/src/parsers/.antlr/ODataUriQueryParser.java diff --git a/tools/odataUri/parsers/ODataUriQuery.g4 b/tools/odataUri/src/parsers/ODataUriQuery.g4 similarity index 100% rename from tools/odataUri/parsers/ODataUriQuery.g4 rename to tools/odataUri/src/parsers/ODataUriQuery.g4 diff --git a/tools/odataUri/parsers/ODataUriQuery.interp b/tools/odataUri/src/parsers/ODataUriQuery.interp similarity index 100% rename from tools/odataUri/parsers/ODataUriQuery.interp rename to tools/odataUri/src/parsers/ODataUriQuery.interp diff --git a/tools/odataUri/parsers/ODataUriQuery.tokens b/tools/odataUri/src/parsers/ODataUriQuery.tokens similarity index 100% rename from tools/odataUri/parsers/ODataUriQuery.tokens rename to tools/odataUri/src/parsers/ODataUriQuery.tokens diff --git a/tools/odataUri/parsers/ODataUriQueryLexer.interp b/tools/odataUri/src/parsers/ODataUriQueryLexer.interp similarity index 100% rename from tools/odataUri/parsers/ODataUriQueryLexer.interp rename to tools/odataUri/src/parsers/ODataUriQueryLexer.interp diff --git a/tools/odataUri/src/parsers/ODataUriQueryLexer.js b/tools/odataUri/src/parsers/ODataUriQueryLexer.js new file mode 100644 index 00000000..1b265503 --- /dev/null +++ b/tools/odataUri/src/parsers/ODataUriQueryLexer.js @@ -0,0 +1,180 @@ +"use strict"; +// Generated from src/js/odata-uri/parsers/ODataUriQuery.g4 by ANTLR 4.9.0-SNAPSHOT +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.ODataUriQueryLexer = void 0; +const ATNDeserializer_1 = require("antlr4ts/atn/ATNDeserializer"); +const Lexer_1 = require("antlr4ts/Lexer"); +const LexerATNSimulator_1 = require("antlr4ts/atn/LexerATNSimulator"); +const VocabularyImpl_1 = require("antlr4ts/VocabularyImpl"); +const Utils = __importStar(require("antlr4ts/misc/Utils")); +class ODataUriQueryLexer extends Lexer_1.Lexer { + // tslint:enable:no-trailing-whitespace + constructor(input) { + super(input); + this._interp = new LexerATNSimulator_1.LexerATNSimulator(ODataUriQueryLexer._ATN, this); + } + // @Override + // @NotNull + get vocabulary() { + return ODataUriQueryLexer.VOCABULARY; + } + // @Override + get grammarFileName() { return "ODataUriQuery.g4"; } + // @Override + get ruleNames() { return ODataUriQueryLexer.ruleNames; } + // @Override + get serializedATN() { return ODataUriQueryLexer._serializedATN; } + // @Override + get channelNames() { return ODataUriQueryLexer.channelNames; } + // @Override + get modeNames() { return ODataUriQueryLexer.modeNames; } + static get _ATN() { + if (!ODataUriQueryLexer.__ATN) { + ODataUriQueryLexer.__ATN = new ATNDeserializer_1.ATNDeserializer().deserialize(Utils.toCharArray(ODataUriQueryLexer._serializedATN)); + } + return ODataUriQueryLexer.__ATN; + } +} +exports.ODataUriQueryLexer = ODataUriQueryLexer; +ODataUriQueryLexer.FILTER = 1; +ODataUriQueryLexer.SELECT = 2; +ODataUriQueryLexer.EXPAND = 3; +ODataUriQueryLexer.ORDERBY = 4; +ODataUriQueryLexer.TOP = 5; +ODataUriQueryLexer.SKIPKW = 6; +ODataUriQueryLexer.DESC = 7; +ODataUriQueryLexer.OR = 8; +ODataUriQueryLexer.AND = 9; +ODataUriQueryLexer.EQ = 10; +ODataUriQueryLexer.NEQ = 11; +ODataUriQueryLexer.GT = 12; +ODataUriQueryLexer.GTE = 13; +ODataUriQueryLexer.LT = 14; +ODataUriQueryLexer.LTE = 15; +ODataUriQueryLexer.AMP = 16; +ODataUriQueryLexer.ASSIGN = 17; +ODataUriQueryLexer.LPAREN = 18; +ODataUriQueryLexer.RPAREN = 19; +ODataUriQueryLexer.COMMA = 20; +ODataUriQueryLexer.NUMBER = 21; +ODataUriQueryLexer.WS = 22; +ODataUriQueryLexer.BOOLEAN = 23; +ODataUriQueryLexer.STRING = 24; +ODataUriQueryLexer.ID = 25; +// tslint:disable:no-trailing-whitespace +ODataUriQueryLexer.channelNames = [ + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", +]; +// tslint:disable:no-trailing-whitespace +ODataUriQueryLexer.modeNames = [ + "DEFAULT_MODE", +]; +ODataUriQueryLexer.ruleNames = [ + "FILTER", "SELECT", "EXPAND", "ORDERBY", "TOP", "SKIPKW", "DESC", "OR", + "AND", "EQ", "NEQ", "GT", "GTE", "LT", "LTE", "AMP", "ASSIGN", "LPAREN", + "RPAREN", "COMMA", "NUMBER", "WS", "BOOLEAN", "STRING", "ID", +]; +ODataUriQueryLexer._LITERAL_NAMES = [ + undefined, "'$filter'", "'$select'", "'$expand'", "'$orderby'", "'$top'", + "'$skip'", "'desc'", "'or'", "'and'", "'eq'", "'neq'", "'gt'", "'gte'", + "'lt'", "'lte'", "'&'", "'='", "'('", "')'", "','", +]; +ODataUriQueryLexer._SYMBOLIC_NAMES = [ + undefined, "FILTER", "SELECT", "EXPAND", "ORDERBY", "TOP", "SKIPKW", "DESC", + "OR", "AND", "EQ", "NEQ", "GT", "GTE", "LT", "LTE", "AMP", "ASSIGN", "LPAREN", + "RPAREN", "COMMA", "NUMBER", "WS", "BOOLEAN", "STRING", "ID", +]; +ODataUriQueryLexer.VOCABULARY = new VocabularyImpl_1.VocabularyImpl(ODataUriQueryLexer._LITERAL_NAMES, ODataUriQueryLexer._SYMBOLIC_NAMES, []); +ODataUriQueryLexer._serializedATN = "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x02\x1B\xB0\b\x01" + + "\x04\x02\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06" + + "\x04\x07\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x04\r" + + "\t\r\x04\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04\x11\t\x11\x04\x12\t" + + "\x12\x04\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04\x16\t\x16\x04\x17\t" + + "\x17\x04\x18\t\x18\x04\x19\t\x19\x04\x1A\t\x1A\x03\x02\x03\x02\x03\x02" + + "\x03\x02\x03\x02\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03\x03\x03" + + "\x03\x03\x03\x03\x03\x03\x03\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04" + + "\x03\x04\x03\x04\x03\x04\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05\x03\x05" + + "\x03\x05\x03\x05\x03\x05\x03\x06\x03\x06\x03\x06\x03\x06\x03\x06\x03\x07" + + "\x03\x07\x03\x07\x03\x07\x03\x07\x03\x07\x03\b\x03\b\x03\b\x03\b\x03\b" + + "\x03\t\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\v\x03\v\x03\v\x03\f\x03" + + "\f\x03\f\x03\f\x03\r\x03\r\x03\r\x03\x0E\x03\x0E\x03\x0E\x03\x0E\x03\x0F" + + "\x03\x0F\x03\x0F\x03\x10\x03\x10\x03\x10\x03\x10\x03\x11\x03\x11\x03\x12" + + "\x03\x12\x03\x13\x03\x13\x03\x14\x03\x14\x03\x15\x03\x15\x03\x16\x06\x16" + + "\x8E\n\x16\r\x16\x0E\x16\x8F\x03\x17\x03\x17\x03\x17\x03\x17\x03\x18\x03" + + "\x18\x03\x18\x03\x18\x03\x18\x03\x18\x03\x18\x03\x18\x03\x18\x05\x18\x9F" + + "\n\x18\x03\x19\x03\x19\x07\x19\xA3\n\x19\f\x19\x0E\x19\xA6\v\x19\x03\x19" + + "\x03\x19\x03\x1A\x03\x1A\x07\x1A\xAC\n\x1A\f\x1A\x0E\x1A\xAF\v\x1A\x03" + + "\xA4\x02\x02\x1B\x03\x02\x03\x05\x02\x04\x07\x02\x05\t\x02\x06\v\x02\x07" + + "\r\x02\b\x0F\x02\t\x11\x02\n\x13\x02\v\x15\x02\f\x17\x02\r\x19\x02\x0E" + + "\x1B\x02\x0F\x1D\x02\x10\x1F\x02\x11!\x02\x12#\x02\x13%\x02\x14\'\x02" + + "\x15)\x02\x16+\x02\x17-\x02\x18/\x02\x191\x02\x1A3\x02\x1B\x03\x02\x06" + + "\x03\x022;\x03\x02\"\"\x04\x02C\\c|\x06\x022;C\\aac|\x02\xB3\x02\x03\x03" + + "\x02\x02\x02\x02\x05\x03\x02\x02\x02\x02\x07\x03\x02\x02\x02\x02\t\x03" + + "\x02\x02\x02\x02\v\x03\x02\x02\x02\x02\r\x03\x02\x02\x02\x02\x0F\x03\x02" + + "\x02\x02\x02\x11\x03\x02\x02\x02\x02\x13\x03\x02\x02\x02\x02\x15\x03\x02" + + "\x02\x02\x02\x17\x03\x02\x02\x02\x02\x19\x03\x02\x02\x02\x02\x1B\x03\x02" + + "\x02\x02\x02\x1D\x03\x02\x02\x02\x02\x1F\x03\x02\x02\x02\x02!\x03\x02" + + "\x02\x02\x02#\x03\x02\x02\x02\x02%\x03\x02\x02\x02\x02\'\x03\x02\x02\x02" + + "\x02)\x03\x02\x02\x02\x02+\x03\x02\x02\x02\x02-\x03\x02\x02\x02\x02/\x03" + + "\x02\x02\x02\x021\x03\x02\x02\x02\x023\x03\x02\x02\x02\x035\x03\x02\x02" + + "\x02\x05=\x03\x02\x02\x02\x07E\x03\x02\x02\x02\tM\x03\x02\x02\x02\vV\x03" + + "\x02\x02\x02\r[\x03\x02\x02\x02\x0Fa\x03\x02\x02\x02\x11f\x03\x02\x02" + + "\x02\x13i\x03\x02\x02\x02\x15m\x03\x02\x02\x02\x17p\x03\x02\x02\x02\x19" + + "t\x03\x02\x02\x02\x1Bw\x03\x02\x02\x02\x1D{\x03\x02\x02\x02\x1F~\x03\x02" + + "\x02\x02!\x82\x03\x02\x02\x02#\x84\x03\x02\x02\x02%\x86\x03\x02\x02\x02" + + "\'\x88\x03\x02\x02\x02)\x8A\x03\x02\x02\x02+\x8D\x03\x02\x02\x02-\x91" + + "\x03\x02\x02\x02/\x9E\x03\x02\x02\x021\xA0\x03\x02\x02\x023\xA9\x03\x02" + + "\x02\x0256\x07&\x02\x0267\x07h\x02\x0278\x07k\x02\x0289\x07n\x02\x029" + + ":\x07v\x02\x02:;\x07g\x02\x02;<\x07t\x02\x02<\x04\x03\x02\x02\x02=>\x07" + + "&\x02\x02>?\x07u\x02\x02?@\x07g\x02\x02@A\x07n\x02\x02AB\x07g\x02\x02" + + "BC\x07e\x02\x02CD\x07v\x02\x02D\x06\x03\x02\x02\x02EF\x07&\x02\x02FG\x07" + + "g\x02\x02GH\x07z\x02\x02HI\x07r\x02\x02IJ\x07c\x02\x02JK\x07p\x02\x02" + + "KL\x07f\x02\x02L\b\x03\x02\x02\x02MN\x07&\x02\x02NO\x07q\x02\x02OP\x07" + + "t\x02\x02PQ\x07f\x02\x02QR\x07g\x02\x02RS\x07t\x02\x02ST\x07d\x02\x02" + + "TU\x07{\x02\x02U\n\x03\x02\x02\x02VW\x07&\x02\x02WX\x07v\x02\x02XY\x07" + + "q\x02\x02YZ\x07r\x02\x02Z\f\x03\x02\x02\x02[\\\x07&\x02\x02\\]\x07u\x02" + + "\x02]^\x07m\x02\x02^_\x07k\x02\x02_`\x07r\x02\x02`\x0E\x03\x02\x02\x02" + + "ab\x07f\x02\x02bc\x07g\x02\x02cd\x07u\x02\x02de\x07e\x02\x02e\x10\x03" + + "\x02\x02\x02fg\x07q\x02\x02gh\x07t\x02\x02h\x12\x03\x02\x02\x02ij\x07" + + "c\x02\x02jk\x07p\x02\x02kl\x07f\x02\x02l\x14\x03\x02\x02\x02mn\x07g\x02" + + "\x02no\x07s\x02\x02o\x16\x03\x02\x02\x02pq\x07p\x02\x02qr\x07g\x02\x02" + + "rs\x07s\x02\x02s\x18\x03\x02\x02\x02tu\x07i\x02\x02uv\x07v\x02\x02v\x1A" + + "\x03\x02\x02\x02wx\x07i\x02\x02xy\x07v\x02\x02yz\x07g\x02\x02z\x1C\x03" + + "\x02\x02\x02{|\x07n\x02\x02|}\x07v\x02\x02}\x1E\x03\x02\x02\x02~\x7F\x07" + + "n\x02\x02\x7F\x80\x07v\x02\x02\x80\x81\x07g\x02\x02\x81 \x03\x02\x02\x02" + + "\x82\x83\x07(\x02\x02\x83\"\x03\x02\x02\x02\x84\x85\x07?\x02\x02\x85$" + + "\x03\x02\x02\x02\x86\x87\x07*\x02\x02\x87&\x03\x02\x02\x02\x88\x89\x07" + + "+\x02\x02\x89(\x03\x02\x02\x02\x8A\x8B\x07.\x02\x02\x8B*\x03\x02\x02\x02" + + "\x8C\x8E\t\x02\x02\x02\x8D\x8C\x03\x02\x02\x02\x8E\x8F\x03\x02\x02\x02" + + "\x8F\x8D\x03\x02\x02\x02\x8F\x90\x03\x02\x02\x02\x90,\x03\x02\x02\x02" + + "\x91\x92\t\x03\x02\x02\x92\x93\x03\x02\x02\x02\x93\x94\b\x17\x02\x02\x94" + + ".\x03\x02\x02\x02\x95\x96\x07v\x02\x02\x96\x97\x07t\x02\x02\x97\x98\x07" + + "w\x02\x02\x98\x9F\x07g\x02\x02\x99\x9A\x07h\x02\x02\x9A\x9B\x07c\x02\x02" + + "\x9B\x9C\x07n\x02\x02\x9C\x9D\x07u\x02\x02\x9D\x9F\x07g\x02\x02\x9E\x95" + + "\x03\x02\x02\x02\x9E\x99\x03\x02\x02\x02\x9F0\x03\x02\x02\x02\xA0\xA4" + + "\x07)\x02\x02\xA1\xA3\v\x02\x02\x02\xA2\xA1\x03\x02\x02\x02\xA3\xA6\x03" + + "\x02\x02\x02\xA4\xA5\x03\x02\x02\x02\xA4\xA2\x03\x02\x02\x02\xA5\xA7\x03" + + "\x02\x02\x02\xA6\xA4\x03\x02\x02\x02\xA7\xA8\x07)\x02\x02\xA82\x03\x02" + + "\x02\x02\xA9\xAD\t\x04\x02\x02\xAA\xAC\t\x05\x02\x02\xAB\xAA\x03\x02\x02" + + "\x02\xAC\xAF\x03\x02\x02\x02\xAD\xAB\x03\x02\x02\x02\xAD\xAE\x03\x02\x02" + + "\x02\xAE4\x03\x02\x02\x02\xAF\xAD\x03\x02\x02\x02\x07\x02\x8F\x9E\xA4" + + "\xAD\x03\b\x02\x02"; diff --git a/tools/odataUri/parsers/ODataUriQueryLexer.tokens b/tools/odataUri/src/parsers/ODataUriQueryLexer.tokens similarity index 100% rename from tools/odataUri/parsers/ODataUriQueryLexer.tokens rename to tools/odataUri/src/parsers/ODataUriQueryLexer.tokens diff --git a/tools/odataUri/parsers/ODataUriQueryLexer.ts b/tools/odataUri/src/parsers/ODataUriQueryLexer.ts similarity index 100% rename from tools/odataUri/parsers/ODataUriQueryLexer.ts rename to tools/odataUri/src/parsers/ODataUriQueryLexer.ts diff --git a/tools/odataUri/src/parsers/ODataUriQueryParser.js b/tools/odataUri/src/parsers/ODataUriQueryParser.js new file mode 100644 index 00000000..71af2231 --- /dev/null +++ b/tools/odataUri/src/parsers/ODataUriQueryParser.js @@ -0,0 +1,1651 @@ +"use strict"; +// Generated from src/js/odata-uri/parsers/ODataUriQuery.g4 by ANTLR 4.9.0-SNAPSHOT +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.IdentifierContext = exports.CompOperatorContext = exports.ParenExpressionContext = exports.BasicExpressionContext = exports.CompExpressionContext = exports.AndExpressionContext = exports.OrExpressionContext = exports.ExpressionContext = exports.OrderFieldContext = exports.OrderSpecContext = exports.ExpandFieldContext = exports.SelectFieldContext = exports.ExpandFieldListContext = exports.SelectFieldListContext = exports.SkipOptionContext = exports.TopOptionContext = exports.OrderByOptionContext = exports.ExpandOptionContext = exports.SelectOptionContext = exports.FilterOptionContext = exports.QueryOptionContext = exports.QueryOptionsListContext = exports.QueryOptionsContext = exports.ODataUriQueryParser = void 0; +const ATN_1 = require("antlr4ts/atn/ATN"); +const ATNDeserializer_1 = require("antlr4ts/atn/ATNDeserializer"); +const FailedPredicateException_1 = require("antlr4ts/FailedPredicateException"); +const NoViableAltException_1 = require("antlr4ts/NoViableAltException"); +const Parser_1 = require("antlr4ts/Parser"); +const ParserRuleContext_1 = require("antlr4ts/ParserRuleContext"); +const ParserATNSimulator_1 = require("antlr4ts/atn/ParserATNSimulator"); +const RecognitionException_1 = require("antlr4ts/RecognitionException"); +const Token_1 = require("antlr4ts/Token"); +const VocabularyImpl_1 = require("antlr4ts/VocabularyImpl"); +const Utils = __importStar(require("antlr4ts/misc/Utils")); +class ODataUriQueryParser extends Parser_1.Parser { + constructor(input) { + super(input); + this._interp = new ParserATNSimulator_1.ParserATNSimulator(ODataUriQueryParser._ATN, this); + } + // @Override + // @NotNull + get vocabulary() { + return ODataUriQueryParser.VOCABULARY; + } + // tslint:enable:no-trailing-whitespace + // @Override + get grammarFileName() { return "ODataUriQuery.g4"; } + // @Override + get ruleNames() { return ODataUriQueryParser.ruleNames; } + // @Override + get serializedATN() { return ODataUriQueryParser._serializedATN; } + createFailedPredicateException(predicate, message) { + return new FailedPredicateException_1.FailedPredicateException(this, predicate, message); + } + // @RuleVersion(0) + queryOptions() { + let _localctx = new QueryOptionsContext(this._ctx, this.state); + this.enterRule(_localctx, 0, ODataUriQueryParser.RULE_queryOptions); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 46; + this.queryOption(); + this.state = 47; + this.queryOptionsList(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + queryOptionsList() { + let _localctx = new QueryOptionsListContext(this._ctx, this.state); + this.enterRule(_localctx, 2, ODataUriQueryParser.RULE_queryOptionsList); + try { + this.state = 54; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case ODataUriQueryParser.AMP: + this.enterOuterAlt(_localctx, 1); + { + this.state = 49; + this.match(ODataUriQueryParser.AMP); + this.state = 50; + this.queryOption(); + this.state = 51; + this.queryOptionsList(); + } + break; + case ODataUriQueryParser.EOF: + this.enterOuterAlt(_localctx, 2); + // tslint:disable-next-line:no-empty + { + } + break; + default: + throw new NoViableAltException_1.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + queryOption() { + let _localctx = new QueryOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 4, ODataUriQueryParser.RULE_queryOption); + try { + this.state = 62; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case ODataUriQueryParser.FILTER: + this.enterOuterAlt(_localctx, 1); + { + this.state = 56; + this.filterOption(); + } + break; + case ODataUriQueryParser.SELECT: + this.enterOuterAlt(_localctx, 2); + { + this.state = 57; + this.selectOption(); + } + break; + case ODataUriQueryParser.EXPAND: + this.enterOuterAlt(_localctx, 3); + { + this.state = 58; + this.expandOption(); + } + break; + case ODataUriQueryParser.ORDERBY: + this.enterOuterAlt(_localctx, 4); + { + this.state = 59; + this.orderByOption(); + } + break; + case ODataUriQueryParser.TOP: + this.enterOuterAlt(_localctx, 5); + { + this.state = 60; + this.topOption(); + } + break; + case ODataUriQueryParser.SKIPKW: + this.enterOuterAlt(_localctx, 6); + { + this.state = 61; + this.skipOption(); + } + break; + default: + throw new NoViableAltException_1.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + filterOption() { + let _localctx = new FilterOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 6, ODataUriQueryParser.RULE_filterOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 64; + this.match(ODataUriQueryParser.FILTER); + this.state = 65; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 66; + this.expression(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + selectOption() { + let _localctx = new SelectOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 8, ODataUriQueryParser.RULE_selectOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 68; + this.match(ODataUriQueryParser.SELECT); + this.state = 69; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 70; + this.selectFieldList(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + expandOption() { + let _localctx = new ExpandOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 10, ODataUriQueryParser.RULE_expandOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 72; + this.match(ODataUriQueryParser.EXPAND); + this.state = 73; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 74; + this.expandFieldList(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + orderByOption() { + let _localctx = new OrderByOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 12, ODataUriQueryParser.RULE_orderByOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 76; + this.match(ODataUriQueryParser.ORDERBY); + this.state = 77; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 78; + this.orderSpec(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + topOption() { + let _localctx = new TopOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 14, ODataUriQueryParser.RULE_topOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 80; + this.match(ODataUriQueryParser.TOP); + this.state = 81; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 82; + this.match(ODataUriQueryParser.NUMBER); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + skipOption() { + let _localctx = new SkipOptionContext(this._ctx, this.state); + this.enterRule(_localctx, 16, ODataUriQueryParser.RULE_skipOption); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 84; + this.match(ODataUriQueryParser.SKIPKW); + this.state = 85; + this.match(ODataUriQueryParser.ASSIGN); + this.state = 86; + this.match(ODataUriQueryParser.NUMBER); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + selectFieldList() { + let _localctx = new SelectFieldListContext(this._ctx, this.state); + this.enterRule(_localctx, 18, ODataUriQueryParser.RULE_selectFieldList); + try { + this.state = 93; + this._errHandler.sync(this); + switch (this.interpreter.adaptivePredict(this._input, 2, this._ctx)) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 88; + this.selectField(); + } + break; + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 89; + this.selectField(); + this.state = 90; + this.match(ODataUriQueryParser.COMMA); + this.state = 91; + this.selectFieldList(); + } + break; + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + expandFieldList() { + let _localctx = new ExpandFieldListContext(this._ctx, this.state); + this.enterRule(_localctx, 20, ODataUriQueryParser.RULE_expandFieldList); + try { + this.state = 100; + this._errHandler.sync(this); + switch (this.interpreter.adaptivePredict(this._input, 3, this._ctx)) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 95; + this.expandField(); + } + break; + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 96; + this.expandField(); + this.state = 97; + this.match(ODataUriQueryParser.COMMA); + this.state = 98; + this.expandFieldList(); + } + break; + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + selectField() { + let _localctx = new SelectFieldContext(this._ctx, this.state); + this.enterRule(_localctx, 22, ODataUriQueryParser.RULE_selectField); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 102; + this.identifier(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + expandField() { + let _localctx = new ExpandFieldContext(this._ctx, this.state); + this.enterRule(_localctx, 24, ODataUriQueryParser.RULE_expandField); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 104; + this.identifier(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + orderSpec() { + let _localctx = new OrderSpecContext(this._ctx, this.state); + this.enterRule(_localctx, 26, ODataUriQueryParser.RULE_orderSpec); + try { + this.state = 110; + this._errHandler.sync(this); + switch (this.interpreter.adaptivePredict(this._input, 4, this._ctx)) { + case 1: + this.enterOuterAlt(_localctx, 1); + { + this.state = 106; + this.orderField(); + } + break; + case 2: + this.enterOuterAlt(_localctx, 2); + { + this.state = 107; + this.orderField(); + this.state = 108; + this.match(ODataUriQueryParser.DESC); + } + break; + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + orderField() { + let _localctx = new OrderFieldContext(this._ctx, this.state); + this.enterRule(_localctx, 28, ODataUriQueryParser.RULE_orderField); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 112; + this.identifier(); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + expression() { + let _localctx = new ExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 30, ODataUriQueryParser.RULE_expression); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 114; + this.orExpression(0); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + orExpression(_p) { + if (_p === undefined) { + _p = 0; + } + let _parentctx = this._ctx; + let _parentState = this.state; + let _localctx = new OrExpressionContext(this._ctx, _parentState); + let _prevctx = _localctx; + let _startState = 32; + this.enterRecursionRule(_localctx, 32, ODataUriQueryParser.RULE_orExpression, _p); + try { + let _alt; + this.enterOuterAlt(_localctx, 1); + { + { + this.state = 117; + this.andExpression(0); + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 124; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 5, this._ctx); + while (_alt !== 2 && _alt !== ATN_1.ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + { + _localctx = new OrExpressionContext(_parentctx, _parentState); + this.pushNewRecursionContext(_localctx, _startState, ODataUriQueryParser.RULE_orExpression); + this.state = 119; + if (!(this.precpred(this._ctx, 1))) { + throw this.createFailedPredicateException("this.precpred(this._ctx, 1)"); + } + this.state = 120; + this.match(ODataUriQueryParser.OR); + this.state = 121; + this.andExpression(0); + } + } + } + this.state = 126; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 5, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.unrollRecursionContexts(_parentctx); + } + return _localctx; + } + // @RuleVersion(0) + andExpression(_p) { + if (_p === undefined) { + _p = 0; + } + let _parentctx = this._ctx; + let _parentState = this.state; + let _localctx = new AndExpressionContext(this._ctx, _parentState); + let _prevctx = _localctx; + let _startState = 34; + this.enterRecursionRule(_localctx, 34, ODataUriQueryParser.RULE_andExpression, _p); + try { + let _alt; + this.enterOuterAlt(_localctx, 1); + { + { + this.state = 128; + this.compExpression(0); + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 135; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 6, this._ctx); + while (_alt !== 2 && _alt !== ATN_1.ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + { + _localctx = new AndExpressionContext(_parentctx, _parentState); + this.pushNewRecursionContext(_localctx, _startState, ODataUriQueryParser.RULE_andExpression); + this.state = 130; + if (!(this.precpred(this._ctx, 1))) { + throw this.createFailedPredicateException("this.precpred(this._ctx, 1)"); + } + this.state = 131; + this.match(ODataUriQueryParser.AND); + this.state = 132; + this.compExpression(0); + } + } + } + this.state = 137; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 6, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.unrollRecursionContexts(_parentctx); + } + return _localctx; + } + // @RuleVersion(0) + compExpression(_p) { + if (_p === undefined) { + _p = 0; + } + let _parentctx = this._ctx; + let _parentState = this.state; + let _localctx = new CompExpressionContext(this._ctx, _parentState); + let _prevctx = _localctx; + let _startState = 36; + this.enterRecursionRule(_localctx, 36, ODataUriQueryParser.RULE_compExpression, _p); + try { + let _alt; + this.enterOuterAlt(_localctx, 1); + { + { + this.state = 139; + this.basicExpression(); + } + this._ctx._stop = this._input.tryLT(-1); + this.state = 147; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 7, this._ctx); + while (_alt !== 2 && _alt !== ATN_1.ATN.INVALID_ALT_NUMBER) { + if (_alt === 1) { + if (this._parseListeners != null) { + this.triggerExitRuleEvent(); + } + _prevctx = _localctx; + { + { + _localctx = new CompExpressionContext(_parentctx, _parentState); + this.pushNewRecursionContext(_localctx, _startState, ODataUriQueryParser.RULE_compExpression); + this.state = 141; + if (!(this.precpred(this._ctx, 1))) { + throw this.createFailedPredicateException("this.precpred(this._ctx, 1)"); + } + this.state = 142; + this.compOperator(); + this.state = 143; + this.basicExpression(); + } + } + } + this.state = 149; + this._errHandler.sync(this); + _alt = this.interpreter.adaptivePredict(this._input, 7, this._ctx); + } + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.unrollRecursionContexts(_parentctx); + } + return _localctx; + } + // @RuleVersion(0) + basicExpression() { + let _localctx = new BasicExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 38, ODataUriQueryParser.RULE_basicExpression); + try { + this.state = 155; + this._errHandler.sync(this); + switch (this._input.LA(1)) { + case ODataUriQueryParser.NUMBER: + this.enterOuterAlt(_localctx, 1); + { + this.state = 150; + this.match(ODataUriQueryParser.NUMBER); + } + break; + case ODataUriQueryParser.STRING: + this.enterOuterAlt(_localctx, 2); + { + this.state = 151; + this.match(ODataUriQueryParser.STRING); + } + break; + case ODataUriQueryParser.BOOLEAN: + this.enterOuterAlt(_localctx, 3); + { + this.state = 152; + this.match(ODataUriQueryParser.BOOLEAN); + } + break; + case ODataUriQueryParser.ID: + this.enterOuterAlt(_localctx, 4); + { + this.state = 153; + this.identifier(); + } + break; + case ODataUriQueryParser.LPAREN: + this.enterOuterAlt(_localctx, 5); + { + this.state = 154; + this.parenExpression(); + } + break; + default: + throw new NoViableAltException_1.NoViableAltException(this); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + parenExpression() { + let _localctx = new ParenExpressionContext(this._ctx, this.state); + this.enterRule(_localctx, 40, ODataUriQueryParser.RULE_parenExpression); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 157; + this.match(ODataUriQueryParser.LPAREN); + this.state = 158; + this.expression(); + this.state = 159; + this.match(ODataUriQueryParser.RPAREN); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + compOperator() { + let _localctx = new CompOperatorContext(this._ctx, this.state); + this.enterRule(_localctx, 42, ODataUriQueryParser.RULE_compOperator); + let _la; + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 161; + _la = this._input.LA(1); + if (!((((_la) & ~0x1F) === 0 && ((1 << _la) & ((1 << ODataUriQueryParser.EQ) | (1 << ODataUriQueryParser.NEQ) | (1 << ODataUriQueryParser.GT) | (1 << ODataUriQueryParser.GTE) | (1 << ODataUriQueryParser.LT) | (1 << ODataUriQueryParser.LTE))) !== 0))) { + this._errHandler.recoverInline(this); + } + else { + if (this._input.LA(1) === Token_1.Token.EOF) { + this.matchedEOF = true; + } + this._errHandler.reportMatch(this); + this.consume(); + } + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + // @RuleVersion(0) + identifier() { + let _localctx = new IdentifierContext(this._ctx, this.state); + this.enterRule(_localctx, 44, ODataUriQueryParser.RULE_identifier); + try { + this.enterOuterAlt(_localctx, 1); + { + this.state = 163; + this.match(ODataUriQueryParser.ID); + } + } + catch (re) { + if (re instanceof RecognitionException_1.RecognitionException) { + _localctx.exception = re; + this._errHandler.reportError(this, re); + this._errHandler.recover(this, re); + } + else { + throw re; + } + } + finally { + this.exitRule(); + } + return _localctx; + } + sempred(_localctx, ruleIndex, predIndex) { + switch (ruleIndex) { + case 16: + return this.orExpression_sempred(_localctx, predIndex); + case 17: + return this.andExpression_sempred(_localctx, predIndex); + case 18: + return this.compExpression_sempred(_localctx, predIndex); + } + return true; + } + orExpression_sempred(_localctx, predIndex) { + switch (predIndex) { + case 0: + return this.precpred(this._ctx, 1); + } + return true; + } + andExpression_sempred(_localctx, predIndex) { + switch (predIndex) { + case 1: + return this.precpred(this._ctx, 1); + } + return true; + } + compExpression_sempred(_localctx, predIndex) { + switch (predIndex) { + case 2: + return this.precpred(this._ctx, 1); + } + return true; + } + static get _ATN() { + if (!ODataUriQueryParser.__ATN) { + ODataUriQueryParser.__ATN = new ATNDeserializer_1.ATNDeserializer().deserialize(Utils.toCharArray(ODataUriQueryParser._serializedATN)); + } + return ODataUriQueryParser.__ATN; + } +} +exports.ODataUriQueryParser = ODataUriQueryParser; +ODataUriQueryParser.FILTER = 1; +ODataUriQueryParser.SELECT = 2; +ODataUriQueryParser.EXPAND = 3; +ODataUriQueryParser.ORDERBY = 4; +ODataUriQueryParser.TOP = 5; +ODataUriQueryParser.SKIPKW = 6; +ODataUriQueryParser.DESC = 7; +ODataUriQueryParser.OR = 8; +ODataUriQueryParser.AND = 9; +ODataUriQueryParser.EQ = 10; +ODataUriQueryParser.NEQ = 11; +ODataUriQueryParser.GT = 12; +ODataUriQueryParser.GTE = 13; +ODataUriQueryParser.LT = 14; +ODataUriQueryParser.LTE = 15; +ODataUriQueryParser.AMP = 16; +ODataUriQueryParser.ASSIGN = 17; +ODataUriQueryParser.LPAREN = 18; +ODataUriQueryParser.RPAREN = 19; +ODataUriQueryParser.COMMA = 20; +ODataUriQueryParser.NUMBER = 21; +ODataUriQueryParser.WS = 22; +ODataUriQueryParser.BOOLEAN = 23; +ODataUriQueryParser.STRING = 24; +ODataUriQueryParser.ID = 25; +ODataUriQueryParser.RULE_queryOptions = 0; +ODataUriQueryParser.RULE_queryOptionsList = 1; +ODataUriQueryParser.RULE_queryOption = 2; +ODataUriQueryParser.RULE_filterOption = 3; +ODataUriQueryParser.RULE_selectOption = 4; +ODataUriQueryParser.RULE_expandOption = 5; +ODataUriQueryParser.RULE_orderByOption = 6; +ODataUriQueryParser.RULE_topOption = 7; +ODataUriQueryParser.RULE_skipOption = 8; +ODataUriQueryParser.RULE_selectFieldList = 9; +ODataUriQueryParser.RULE_expandFieldList = 10; +ODataUriQueryParser.RULE_selectField = 11; +ODataUriQueryParser.RULE_expandField = 12; +ODataUriQueryParser.RULE_orderSpec = 13; +ODataUriQueryParser.RULE_orderField = 14; +ODataUriQueryParser.RULE_expression = 15; +ODataUriQueryParser.RULE_orExpression = 16; +ODataUriQueryParser.RULE_andExpression = 17; +ODataUriQueryParser.RULE_compExpression = 18; +ODataUriQueryParser.RULE_basicExpression = 19; +ODataUriQueryParser.RULE_parenExpression = 20; +ODataUriQueryParser.RULE_compOperator = 21; +ODataUriQueryParser.RULE_identifier = 22; +// tslint:disable:no-trailing-whitespace +ODataUriQueryParser.ruleNames = [ + "queryOptions", "queryOptionsList", "queryOption", "filterOption", "selectOption", + "expandOption", "orderByOption", "topOption", "skipOption", "selectFieldList", + "expandFieldList", "selectField", "expandField", "orderSpec", "orderField", + "expression", "orExpression", "andExpression", "compExpression", "basicExpression", + "parenExpression", "compOperator", "identifier", +]; +ODataUriQueryParser._LITERAL_NAMES = [ + undefined, "'$filter'", "'$select'", "'$expand'", "'$orderby'", "'$top'", + "'$skip'", "'desc'", "'or'", "'and'", "'eq'", "'neq'", "'gt'", "'gte'", + "'lt'", "'lte'", "'&'", "'='", "'('", "')'", "','", +]; +ODataUriQueryParser._SYMBOLIC_NAMES = [ + undefined, "FILTER", "SELECT", "EXPAND", "ORDERBY", "TOP", "SKIPKW", "DESC", + "OR", "AND", "EQ", "NEQ", "GT", "GTE", "LT", "LTE", "AMP", "ASSIGN", "LPAREN", + "RPAREN", "COMMA", "NUMBER", "WS", "BOOLEAN", "STRING", "ID", +]; +ODataUriQueryParser.VOCABULARY = new VocabularyImpl_1.VocabularyImpl(ODataUriQueryParser._LITERAL_NAMES, ODataUriQueryParser._SYMBOLIC_NAMES, []); +ODataUriQueryParser._serializedATN = "\x03\uC91D\uCABA\u058D\uAFBA\u4F53\u0607\uEA8B\uC241\x03\x1B\xA8\x04\x02" + + "\t\x02\x04\x03\t\x03\x04\x04\t\x04\x04\x05\t\x05\x04\x06\t\x06\x04\x07" + + "\t\x07\x04\b\t\b\x04\t\t\t\x04\n\t\n\x04\v\t\v\x04\f\t\f\x04\r\t\r\x04" + + "\x0E\t\x0E\x04\x0F\t\x0F\x04\x10\t\x10\x04\x11\t\x11\x04\x12\t\x12\x04" + + "\x13\t\x13\x04\x14\t\x14\x04\x15\t\x15\x04\x16\t\x16\x04\x17\t\x17\x04" + + "\x18\t\x18\x03\x02\x03\x02\x03\x02\x03\x03\x03\x03\x03\x03\x03\x03\x03" + + "\x03\x05\x039\n\x03\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x03\x04\x05" + + "\x04A\n\x04\x03\x05\x03\x05\x03\x05\x03\x05\x03\x06\x03\x06\x03\x06\x03" + + "\x06\x03\x07\x03\x07\x03\x07\x03\x07\x03\b\x03\b\x03\b\x03\b\x03\t\x03" + + "\t\x03\t\x03\t\x03\n\x03\n\x03\n\x03\n\x03\v\x03\v\x03\v\x03\v\x03\v\x05" + + "\v`\n\v\x03\f\x03\f\x03\f\x03\f\x03\f\x05\fg\n\f\x03\r\x03\r\x03\x0E\x03" + + "\x0E\x03\x0F\x03\x0F\x03\x0F\x03\x0F\x05\x0Fq\n\x0F\x03\x10\x03\x10\x03" + + "\x11\x03\x11\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x03\x12\x07\x12}" + + "\n\x12\f\x12\x0E\x12\x80\v\x12\x03\x13\x03\x13\x03\x13\x03\x13\x03\x13" + + "\x03\x13\x07\x13\x88\n\x13\f\x13\x0E\x13\x8B\v\x13\x03\x14\x03\x14\x03" + + "\x14\x03\x14\x03\x14\x03\x14\x03\x14\x07\x14\x94\n\x14\f\x14\x0E\x14\x97" + + "\v\x14\x03\x15\x03\x15\x03\x15\x03\x15\x03\x15\x05\x15\x9E\n\x15\x03\x16" + + "\x03\x16\x03\x16\x03\x16\x03\x17\x03\x17\x03\x18\x03\x18\x03\x18\x02\x02" + + "\x05\"$&\x19\x02\x02\x04\x02\x06\x02\b\x02\n\x02\f\x02\x0E\x02\x10\x02" + + "\x12\x02\x14\x02\x16\x02\x18\x02\x1A\x02\x1C\x02\x1E\x02 \x02\"\x02$\x02" + + "&\x02(\x02*\x02,\x02.\x02\x02\x03\x03\x02\f\x11\x02\xA0\x020\x03\x02\x02" + + "\x02\x048\x03\x02\x02\x02\x06@\x03\x02\x02\x02\bB\x03\x02\x02\x02\nF\x03" + + "\x02\x02\x02\fJ\x03\x02\x02\x02\x0EN\x03\x02\x02\x02\x10R\x03\x02\x02" + + "\x02\x12V\x03\x02\x02\x02\x14_\x03\x02\x02\x02\x16f\x03\x02\x02\x02\x18" + + "h\x03\x02\x02\x02\x1Aj\x03\x02\x02\x02\x1Cp\x03\x02\x02\x02\x1Er\x03\x02" + + "\x02\x02 t\x03\x02\x02\x02\"v\x03\x02\x02\x02$\x81\x03\x02\x02\x02&\x8C" + + "\x03\x02\x02\x02(\x9D\x03\x02\x02\x02*\x9F\x03\x02\x02\x02,\xA3\x03\x02" + + "\x02\x02.\xA5\x03\x02\x02\x0201\x05\x06\x04\x0212\x05\x04\x03\x022\x03" + + "\x03\x02\x02\x0234\x07\x12\x02\x0245\x05\x06\x04\x0256\x05\x04\x03\x02" + + "69\x03\x02\x02\x0279\x03\x02\x02\x0283\x03\x02\x02\x0287\x03\x02\x02\x02" + + "9\x05\x03\x02\x02\x02:A\x05\b\x05\x02;A\x05\n\x06\x02A\x05\x10\t\x02?A\x05\x12\n\x02@:\x03\x02\x02\x02@;\x03" + + "\x02\x02\x02@<\x03\x02\x02\x02@=\x03\x02\x02\x02@>\x03\x02\x02\x02@?\x03" + + "\x02\x02\x02A\x07\x03\x02\x02\x02BC\x07\x03\x02\x02CD\x07\x13\x02\x02" + + "DE\x05 \x11\x02E\t\x03\x02\x02\x02FG\x07\x04\x02\x02GH\x07\x13\x02\x02" + + "HI\x05\x14\v\x02I\v\x03\x02\x02\x02JK\x07\x05\x02\x02KL\x07\x13\x02\x02" + + "LM\x05\x16\f\x02M\r\x03\x02\x02\x02NO\x07\x06\x02\x02OP\x07\x13\x02\x02" + + "PQ\x05\x1C\x0F\x02Q\x0F\x03\x02\x02\x02RS\x07\x07\x02\x02ST\x07\x13\x02" + + "\x02TU\x07\x17\x02\x02U\x11\x03\x02\x02\x02VW\x07\b\x02\x02WX\x07\x13" + + "\x02\x02XY\x07\x17\x02\x02Y\x13\x03\x02\x02\x02Z`\x05\x18\r\x02[\\\x05" + + "\x18\r\x02\\]\x07\x16\x02\x02]^\x05\x14\v\x02^`\x03\x02\x02\x02_Z\x03" + + "\x02\x02\x02_[\x03\x02\x02\x02`\x15\x03\x02\x02\x02ag\x05\x1A\x0E\x02" + + "bc\x05\x1A\x0E\x02cd\x07\x16\x02\x02de\x05\x16\f\x02eg\x03\x02\x02\x02" + + "fa\x03\x02\x02\x02fb\x03\x02\x02\x02g\x17\x03\x02\x02\x02hi\x05.\x18\x02" + + "i\x19\x03\x02\x02\x02jk\x05.\x18\x02k\x1B\x03\x02\x02\x02lq\x05\x1E\x10" + + "\x02mn\x05\x1E\x10\x02no\x07\t\x02\x02oq\x03\x02\x02\x02pl\x03\x02\x02" + + "\x02pm\x03\x02\x02\x02q\x1D\x03\x02\x02\x02rs\x05.\x18\x02s\x1F\x03\x02" + + "\x02\x02tu\x05\"\x12\x02u!\x03\x02\x02\x02vw\b\x12\x01\x02wx\x05$\x13" + + "\x02x~\x03\x02\x02\x02yz\f\x03\x02\x02z{\x07\n\x02\x02{}\x05$\x13\x02" + + "|y\x03\x02\x02\x02}\x80\x03\x02\x02\x02~|\x03\x02\x02\x02~\x7F\x03\x02" + + "\x02\x02\x7F#\x03\x02\x02\x02\x80~\x03\x02\x02\x02\x81\x82\b\x13\x01\x02" + + "\x82\x83\x05&\x14\x02\x83\x89\x03\x02\x02\x02\x84\x85\f\x03\x02\x02\x85" + + "\x86\x07\v\x02\x02\x86\x88\x05&\x14\x02\x87\x84\x03\x02\x02\x02\x88\x8B" + + "\x03\x02\x02\x02\x89\x87\x03\x02\x02\x02\x89\x8A\x03\x02\x02\x02\x8A%" + + "\x03\x02\x02\x02\x8B\x89\x03\x02\x02\x02\x8C\x8D\b\x14\x01\x02\x8D\x8E" + + "\x05(\x15\x02\x8E\x95\x03\x02\x02\x02\x8F\x90\f\x03\x02\x02\x90\x91\x05" + + ",\x17\x02\x91\x92\x05(\x15\x02\x92\x94\x03\x02\x02\x02\x93\x8F\x03\x02" + + "\x02\x02\x94\x97\x03\x02\x02\x02\x95\x93\x03\x02\x02\x02\x95\x96\x03\x02" + + "\x02\x02\x96\'\x03\x02\x02\x02\x97\x95\x03\x02\x02\x02\x98\x9E\x07\x17" + + "\x02\x02\x99\x9E\x07\x1A\x02\x02\x9A\x9E\x07\x19\x02\x02\x9B\x9E\x05." + + "\x18\x02\x9C\x9E\x05*\x16\x02\x9D\x98\x03\x02\x02\x02\x9D\x99\x03\x02" + + "\x02\x02\x9D\x9A\x03\x02\x02\x02\x9D\x9B\x03\x02\x02\x02\x9D\x9C\x03\x02" + + "\x02\x02\x9E)\x03\x02\x02\x02\x9F\xA0\x07\x14\x02\x02\xA0\xA1\x05 \x11" + + "\x02\xA1\xA2\x07\x15\x02\x02\xA2+\x03\x02\x02\x02\xA3\xA4\t\x02\x02\x02" + + "\xA4-\x03\x02\x02\x02\xA5\xA6\x07\x1B\x02\x02\xA6/\x03\x02\x02\x02\v8" + + "@_fp~\x89\x95\x9D"; +class QueryOptionsContext extends ParserRuleContext_1.ParserRuleContext { + queryOption() { + return this.getRuleContext(0, QueryOptionContext); + } + queryOptionsList() { + return this.getRuleContext(0, QueryOptionsListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_queryOptions; } + // @Override + accept(visitor) { + if (visitor.visitQueryOptions) { + return visitor.visitQueryOptions(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.QueryOptionsContext = QueryOptionsContext; +class QueryOptionsListContext extends ParserRuleContext_1.ParserRuleContext { + AMP() { return this.tryGetToken(ODataUriQueryParser.AMP, 0); } + queryOption() { + return this.tryGetRuleContext(0, QueryOptionContext); + } + queryOptionsList() { + return this.tryGetRuleContext(0, QueryOptionsListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_queryOptionsList; } + // @Override + accept(visitor) { + if (visitor.visitQueryOptionsList) { + return visitor.visitQueryOptionsList(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.QueryOptionsListContext = QueryOptionsListContext; +class QueryOptionContext extends ParserRuleContext_1.ParserRuleContext { + filterOption() { + return this.tryGetRuleContext(0, FilterOptionContext); + } + selectOption() { + return this.tryGetRuleContext(0, SelectOptionContext); + } + expandOption() { + return this.tryGetRuleContext(0, ExpandOptionContext); + } + orderByOption() { + return this.tryGetRuleContext(0, OrderByOptionContext); + } + topOption() { + return this.tryGetRuleContext(0, TopOptionContext); + } + skipOption() { + return this.tryGetRuleContext(0, SkipOptionContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_queryOption; } + // @Override + accept(visitor) { + if (visitor.visitQueryOption) { + return visitor.visitQueryOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.QueryOptionContext = QueryOptionContext; +class FilterOptionContext extends ParserRuleContext_1.ParserRuleContext { + FILTER() { return this.getToken(ODataUriQueryParser.FILTER, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + expression() { + return this.getRuleContext(0, ExpressionContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_filterOption; } + // @Override + accept(visitor) { + if (visitor.visitFilterOption) { + return visitor.visitFilterOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.FilterOptionContext = FilterOptionContext; +class SelectOptionContext extends ParserRuleContext_1.ParserRuleContext { + SELECT() { return this.getToken(ODataUriQueryParser.SELECT, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + selectFieldList() { + return this.getRuleContext(0, SelectFieldListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_selectOption; } + // @Override + accept(visitor) { + if (visitor.visitSelectOption) { + return visitor.visitSelectOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.SelectOptionContext = SelectOptionContext; +class ExpandOptionContext extends ParserRuleContext_1.ParserRuleContext { + EXPAND() { return this.getToken(ODataUriQueryParser.EXPAND, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + expandFieldList() { + return this.getRuleContext(0, ExpandFieldListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_expandOption; } + // @Override + accept(visitor) { + if (visitor.visitExpandOption) { + return visitor.visitExpandOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.ExpandOptionContext = ExpandOptionContext; +class OrderByOptionContext extends ParserRuleContext_1.ParserRuleContext { + ORDERBY() { return this.getToken(ODataUriQueryParser.ORDERBY, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + orderSpec() { + return this.getRuleContext(0, OrderSpecContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_orderByOption; } + // @Override + accept(visitor) { + if (visitor.visitOrderByOption) { + return visitor.visitOrderByOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.OrderByOptionContext = OrderByOptionContext; +class TopOptionContext extends ParserRuleContext_1.ParserRuleContext { + TOP() { return this.getToken(ODataUriQueryParser.TOP, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + NUMBER() { return this.getToken(ODataUriQueryParser.NUMBER, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_topOption; } + // @Override + accept(visitor) { + if (visitor.visitTopOption) { + return visitor.visitTopOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.TopOptionContext = TopOptionContext; +class SkipOptionContext extends ParserRuleContext_1.ParserRuleContext { + SKIPKW() { return this.getToken(ODataUriQueryParser.SKIPKW, 0); } + ASSIGN() { return this.getToken(ODataUriQueryParser.ASSIGN, 0); } + NUMBER() { return this.getToken(ODataUriQueryParser.NUMBER, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_skipOption; } + // @Override + accept(visitor) { + if (visitor.visitSkipOption) { + return visitor.visitSkipOption(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.SkipOptionContext = SkipOptionContext; +class SelectFieldListContext extends ParserRuleContext_1.ParserRuleContext { + selectField() { + return this.getRuleContext(0, SelectFieldContext); + } + COMMA() { return this.tryGetToken(ODataUriQueryParser.COMMA, 0); } + selectFieldList() { + return this.tryGetRuleContext(0, SelectFieldListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_selectFieldList; } + // @Override + accept(visitor) { + if (visitor.visitSelectFieldList) { + return visitor.visitSelectFieldList(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.SelectFieldListContext = SelectFieldListContext; +class ExpandFieldListContext extends ParserRuleContext_1.ParserRuleContext { + expandField() { + return this.getRuleContext(0, ExpandFieldContext); + } + COMMA() { return this.tryGetToken(ODataUriQueryParser.COMMA, 0); } + expandFieldList() { + return this.tryGetRuleContext(0, ExpandFieldListContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_expandFieldList; } + // @Override + accept(visitor) { + if (visitor.visitExpandFieldList) { + return visitor.visitExpandFieldList(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.ExpandFieldListContext = ExpandFieldListContext; +class SelectFieldContext extends ParserRuleContext_1.ParserRuleContext { + identifier() { + return this.getRuleContext(0, IdentifierContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_selectField; } + // @Override + accept(visitor) { + if (visitor.visitSelectField) { + return visitor.visitSelectField(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.SelectFieldContext = SelectFieldContext; +class ExpandFieldContext extends ParserRuleContext_1.ParserRuleContext { + identifier() { + return this.getRuleContext(0, IdentifierContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_expandField; } + // @Override + accept(visitor) { + if (visitor.visitExpandField) { + return visitor.visitExpandField(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.ExpandFieldContext = ExpandFieldContext; +class OrderSpecContext extends ParserRuleContext_1.ParserRuleContext { + orderField() { + return this.getRuleContext(0, OrderFieldContext); + } + DESC() { return this.tryGetToken(ODataUriQueryParser.DESC, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_orderSpec; } + // @Override + accept(visitor) { + if (visitor.visitOrderSpec) { + return visitor.visitOrderSpec(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.OrderSpecContext = OrderSpecContext; +class OrderFieldContext extends ParserRuleContext_1.ParserRuleContext { + identifier() { + return this.getRuleContext(0, IdentifierContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_orderField; } + // @Override + accept(visitor) { + if (visitor.visitOrderField) { + return visitor.visitOrderField(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.OrderFieldContext = OrderFieldContext; +class ExpressionContext extends ParserRuleContext_1.ParserRuleContext { + orExpression() { + return this.getRuleContext(0, OrExpressionContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_expression; } + // @Override + accept(visitor) { + if (visitor.visitExpression) { + return visitor.visitExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.ExpressionContext = ExpressionContext; +class OrExpressionContext extends ParserRuleContext_1.ParserRuleContext { + andExpression() { + return this.getRuleContext(0, AndExpressionContext); + } + orExpression() { + return this.tryGetRuleContext(0, OrExpressionContext); + } + OR() { return this.tryGetToken(ODataUriQueryParser.OR, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_orExpression; } + // @Override + accept(visitor) { + if (visitor.visitOrExpression) { + return visitor.visitOrExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.OrExpressionContext = OrExpressionContext; +class AndExpressionContext extends ParserRuleContext_1.ParserRuleContext { + compExpression() { + return this.getRuleContext(0, CompExpressionContext); + } + andExpression() { + return this.tryGetRuleContext(0, AndExpressionContext); + } + AND() { return this.tryGetToken(ODataUriQueryParser.AND, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_andExpression; } + // @Override + accept(visitor) { + if (visitor.visitAndExpression) { + return visitor.visitAndExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.AndExpressionContext = AndExpressionContext; +class CompExpressionContext extends ParserRuleContext_1.ParserRuleContext { + basicExpression() { + return this.getRuleContext(0, BasicExpressionContext); + } + compExpression() { + return this.tryGetRuleContext(0, CompExpressionContext); + } + compOperator() { + return this.tryGetRuleContext(0, CompOperatorContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_compExpression; } + // @Override + accept(visitor) { + if (visitor.visitCompExpression) { + return visitor.visitCompExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.CompExpressionContext = CompExpressionContext; +class BasicExpressionContext extends ParserRuleContext_1.ParserRuleContext { + NUMBER() { return this.tryGetToken(ODataUriQueryParser.NUMBER, 0); } + STRING() { return this.tryGetToken(ODataUriQueryParser.STRING, 0); } + BOOLEAN() { return this.tryGetToken(ODataUriQueryParser.BOOLEAN, 0); } + identifier() { + return this.tryGetRuleContext(0, IdentifierContext); + } + parenExpression() { + return this.tryGetRuleContext(0, ParenExpressionContext); + } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_basicExpression; } + // @Override + accept(visitor) { + if (visitor.visitBasicExpression) { + return visitor.visitBasicExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.BasicExpressionContext = BasicExpressionContext; +class ParenExpressionContext extends ParserRuleContext_1.ParserRuleContext { + LPAREN() { return this.getToken(ODataUriQueryParser.LPAREN, 0); } + expression() { + return this.getRuleContext(0, ExpressionContext); + } + RPAREN() { return this.getToken(ODataUriQueryParser.RPAREN, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_parenExpression; } + // @Override + accept(visitor) { + if (visitor.visitParenExpression) { + return visitor.visitParenExpression(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.ParenExpressionContext = ParenExpressionContext; +class CompOperatorContext extends ParserRuleContext_1.ParserRuleContext { + EQ() { return this.tryGetToken(ODataUriQueryParser.EQ, 0); } + NEQ() { return this.tryGetToken(ODataUriQueryParser.NEQ, 0); } + GTE() { return this.tryGetToken(ODataUriQueryParser.GTE, 0); } + GT() { return this.tryGetToken(ODataUriQueryParser.GT, 0); } + LTE() { return this.tryGetToken(ODataUriQueryParser.LTE, 0); } + LT() { return this.tryGetToken(ODataUriQueryParser.LT, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_compOperator; } + // @Override + accept(visitor) { + if (visitor.visitCompOperator) { + return visitor.visitCompOperator(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.CompOperatorContext = CompOperatorContext; +class IdentifierContext extends ParserRuleContext_1.ParserRuleContext { + ID() { return this.getToken(ODataUriQueryParser.ID, 0); } + constructor(parent, invokingState) { + super(parent, invokingState); + } + // @Override + get ruleIndex() { return ODataUriQueryParser.RULE_identifier; } + // @Override + accept(visitor) { + if (visitor.visitIdentifier) { + return visitor.visitIdentifier(this); + } + else { + return visitor.visitChildren(this); + } + } +} +exports.IdentifierContext = IdentifierContext; diff --git a/tools/odataUri/parsers/ODataUriQueryParser.ts b/tools/odataUri/src/parsers/ODataUriQueryParser.ts similarity index 100% rename from tools/odataUri/parsers/ODataUriQueryParser.ts rename to tools/odataUri/src/parsers/ODataUriQueryParser.ts diff --git a/tools/odataUri/src/parsers/ODataUriQueryVisitor.js b/tools/odataUri/src/parsers/ODataUriQueryVisitor.js new file mode 100644 index 00000000..466cebe1 --- /dev/null +++ b/tools/odataUri/src/parsers/ODataUriQueryVisitor.js @@ -0,0 +1,3 @@ +"use strict"; +// Generated from src/js/odata-uri/parsers/ODataUriQuery.g4 by ANTLR 4.9.0-SNAPSHOT +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/tools/odataUri/parsers/ODataUriQueryVisitor.ts b/tools/odataUri/src/parsers/ODataUriQueryVisitor.ts similarity index 100% rename from tools/odataUri/parsers/ODataUriQueryVisitor.ts rename to tools/odataUri/src/parsers/ODataUriQueryVisitor.ts diff --git a/tools/odataUri/path.ts b/tools/odataUri/src/path.ts similarity index 100% rename from tools/odataUri/path.ts rename to tools/odataUri/src/path.ts diff --git a/tools/odataUri/semantic-model.ts b/tools/odataUri/src/semantic-model.ts similarity index 98% rename from tools/odataUri/semantic-model.ts rename to tools/odataUri/src/semantic-model.ts index 27ccafdf..9f402961 100644 --- a/tools/odataUri/semantic-model.ts +++ b/tools/odataUri/src/semantic-model.ts @@ -1,4 +1,4 @@ -import { AbstractParseTreeVisitor, TerminalNode } from 'antlr4ts/tree'; +import { AbstractParseTreeVisitor, RuleNode, TerminalNode } from 'antlr4ts/tree'; import { AndExpressionContext, BasicExpressionContext, CompExpressionContext, ExpandFieldListContext, ExpandOptionContext, @@ -332,7 +332,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return null; } - visitQueryOptions(ctx: QueryOptionsContext) { + visitQueryOptions(ctx: QueryOptionsContext): SemanticNode { if (!ctx) return null; const node = new QueryOptionsNode(ctx, this.rootType); this.root = node; @@ -351,7 +351,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return node; } - visitQueryOption(ctx: QueryOptionContext) { + visitQueryOption(ctx: QueryOptionContext): SemanticNode { if (!ctx) return null; const options = ['filterOption', 'selectOption', 'expandOption', 'orderByOption', 'topOption', 'skipOption']; @@ -360,7 +360,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return null; } - visitQueryOptionsList(ctx: QueryOptionsListContext) { + visitQueryOptionsList(ctx: QueryOptionsListContext): SemanticNode { if (ctx.childCount ===0 ) return; const option = ctx.queryOption(); if (option) { @@ -376,12 +376,15 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor } checkAndAddQueryOption(option: string, ctx: QueryOptionContext) { + // @ts-ignore const optionCtx = ctx[option]() as ParserRuleContext; if (optionCtx) { + // @ts-ignore if (this.root[option]) { const optName = option.split('Option')[0]; this.addError(`Duplicate query option $${optName}`, optionCtx); } + // @ts-ignore this.root[option] = optionCtx.accept(this); } } @@ -441,7 +444,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return node; } - visitSelectNodeFields(ctx: SelectFieldListContext, selectNode: SelectNode) { + visitSelectNodeFields(ctx: SelectFieldListContext, selectNode: SelectNode): SemanticNode { this.semanticMap.set(ctx, selectNode); // this helps with auto-complete since this ctx is visited even when there's no field const field = ctx.children && ctx.tryGetRuleContext(0, SelectFieldContext); if (!field) return; @@ -513,7 +516,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return node; } - visitExpandNodeFields(ctx: ExpandFieldListContext, expandNode: ExpandNode) { + visitExpandNodeFields(ctx: ExpandFieldListContext, expandNode: ExpandNode): SemanticNode { this.semanticMap.set(ctx, expandNode); // this helps with auto-complete since this ctx is visited even when there's no field if (ctx.childCount == 0) return null; const field = ctx.expandField(); @@ -769,7 +772,7 @@ export class QueryOptionsVisitor extends AbstractParseTreeVisitor return node; } - visitTerminal(ctx: TerminalNode) { + visitTerminal(ctx: TerminalNode): SemanticNode { const tokenIndex = ctx._symbol.tokenIndex; if (tokenIndex === ODataUriQueryParser.NUMBER) { // todo: the forced cast could be an error diff --git a/tools/odataUri/tsconfig.json b/tools/odataUri/tsconfig.json new file mode 100644 index 00000000..32c9cdc8 --- /dev/null +++ b/tools/odataUri/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@tsconfig/recommended/tsconfig.json", + "compilerOptions": { + "strictNullChecks": false, + "sourceMap": true, + "outDir": "dist", + "declaration": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules/*", + "dist/*" + ] +} \ No newline at end of file diff --git a/tools/odataUri/webpack.config.js b/tools/odataUri/webpack.config.js new file mode 100644 index 00000000..8a017b35 --- /dev/null +++ b/tools/odataUri/webpack.config.js @@ -0,0 +1,38 @@ +const path = require("path"); +const webpack = require("webpack"); + +module.exports = { + entry: "./src/index.ts", + devtool: "inline-source-map", + module: { + rules: [ + { + test: /\.ts/, + use: 'ts-loader', + exclude: /node_modules/, + } + ] + }, + resolve: { + extensions: ['.ts', '.js'], + fallback: { + util: require.resolve("util"), + assert: require.resolve("assert"), + } + }, + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + library: { + name: "odataUri", + type: "umd" + }, + globalObject: 'this', + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) + }) + ], + mode: "production" +} diff --git a/tools/urlEditor/.gitignore b/tools/urlEditor/.gitignore new file mode 100644 index 00000000..53c37a16 --- /dev/null +++ b/tools/urlEditor/.gitignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/tools/urlEditor/README.md b/tools/urlEditor/README.md new file mode 100644 index 00000000..4d1ea93a --- /dev/null +++ b/tools/urlEditor/README.md @@ -0,0 +1,42 @@ +# OData URL Editor + +A URL editor component that provides autocomplete suggestions and error highlighting based on CSDL JSON schema. + +## Installation + +First make sure to build the [odata-uri](../odataUri) package. + +Then run: + +``` +npm install +``` + +Then run: + +``` +npm run build +``` + +**Note**: You need to run the build command before setting up packages that depend on this library. This package is not on npm, so the dependent +packages will fetch this package from the local fs as is. + +## Usage + +```ts +import { initUrlEditor } from "odata-url-editor"; + +const editor = initUrlEditor(document.getElementById("editor"), onUrlUpdated); +// schema is a string in rsdl format +const schema: string = "..."; +editor.updateSchema(schema); + +// this handler will be called when the user updates the url input in the editor +function onUrlUpdated(url: string) { + console.log("URL has been updated to", url); +} + +// gets the current contents of the editor +const url = editor.getUrl(); + +``` \ No newline at end of file diff --git a/tools/urlEditor/package.json b/tools/urlEditor/package.json index 63379c36..a065b176 100644 --- a/tools/urlEditor/package.json +++ b/tools/urlEditor/package.json @@ -2,14 +2,23 @@ "name": "urlbuilder", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "dist/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "build": "webpack" }, "author": "", "license": "ISC", "dependencies": { "@codemirror/basic-setup": "^0.18.2", - "rsdl-js": "^0.2.0" + "rsdl-js": "^0.2.0", + "odata-uri": "file:../odataUri" + }, + "devDependencies": { + "@tsconfig/recommended": "^1.0.1", + "ts-loader": "^9.2.5", + "typescript": "^4.3.5", + "webpack": "^5.48.0", + "webpack-cli": "^4.7.2" } } diff --git a/tools/urlEditor/index.ts b/tools/urlEditor/src/index.ts similarity index 100% rename from tools/urlEditor/index.ts rename to tools/urlEditor/src/index.ts diff --git a/tools/urlEditor/uri-editor.ts b/tools/urlEditor/src/uri-editor.ts similarity index 95% rename from tools/urlEditor/uri-editor.ts rename to tools/urlEditor/src/uri-editor.ts index a9666b53..b8fd3891 100644 --- a/tools/urlEditor/uri-editor.ts +++ b/tools/urlEditor/src/uri-editor.ts @@ -1,7 +1,6 @@ import { basicSetup, EditorState, EditorView } from "@codemirror/basic-setup"; import { autocompletion, CompletionSource } from '@codemirror/autocomplete'; import { linter, Diagnostic } from '@codemirror/lint'; -// TODO: This should be imported from the odataUri library once it's turned into a package import { AutoCompleteManager } from "odata-uri"; import { getDocContent, convertToCsdl } from "./utils"; @@ -79,7 +78,11 @@ function initUrlEditor(domElement: HTMLElement, onUrlUpdated: UrlUpdatedCallback manager.updateSchema(jsonCsdl); }; - return { updateSchema }; + function getUrl() { + return getDocContent(editor.state.doc); + } + + return { updateSchema, getUrl }; } export { initUrlEditor }; diff --git a/tools/urlEditor/utils.ts b/tools/urlEditor/src/utils.ts similarity index 90% rename from tools/urlEditor/utils.ts rename to tools/urlEditor/src/utils.ts index 4a136386..433a6f36 100644 --- a/tools/urlEditor/utils.ts +++ b/tools/urlEditor/src/utils.ts @@ -17,7 +17,7 @@ export function includeReader(source) { }; } -export function convertToCsdl(rsdl: string): Record { +export function convertToCsdl(rsdl: string): any { const json = parse(rsdl, includeReader(rsdl)); // TODO: proper error handling diff --git a/tools/urlEditor/tsconfig.json b/tools/urlEditor/tsconfig.json new file mode 100644 index 00000000..ca4bcc52 --- /dev/null +++ b/tools/urlEditor/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "@tsconfig/recommended/tsconfig.json", + "compilerOptions": { + "strictNullChecks": false, + "strict": false, + "noImplicitAny": false, + "sourceMap": true, + "outDir": "dist", + "declaration": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules/*", + "dist/*" + ] +} \ No newline at end of file diff --git a/tools/urlEditor/webpack.config.js b/tools/urlEditor/webpack.config.js new file mode 100644 index 00000000..471619ae --- /dev/null +++ b/tools/urlEditor/webpack.config.js @@ -0,0 +1,32 @@ +const path = require("path"); + +module.exports = { + entry: "./src/index.ts", + devtool: "inline-source-map", + module: { + rules: [ + { + test: /\.ts/, + use: 'ts-loader', + exclude: /node_modules/, + } + ] + }, + resolve: { + extensions: ['.ts', '.js'], + fallback: { + util: false, + assert: false, + fs: false, + } + }, + output: { + filename: 'index.js', + path: path.resolve(__dirname, 'dist'), + library: { + name: "odataUriEditor", + type: "umd" + } + }, + mode: "development" +} diff --git a/website/README.md b/website/README.md index fc9afb44..500bac17 100644 --- a/website/README.md +++ b/website/README.md @@ -14,6 +14,10 @@ yarn build ### Installation +Build the required [urlEditor](../tools/urlEditor) package. + +Then: + ``` $ yarn ``` diff --git a/website/package.json b/website/package.json index e2d00f4c..52b52cb5 100644 --- a/website/package.json +++ b/website/package.json @@ -17,7 +17,8 @@ "prettier": "2.0.5", "react": "^16.8.4", "react-bootstrap": "^1.6.1", - "react-dom": "^16.8.4" + "react-dom": "^16.8.4", + "odata-uri-editor": "file:../tools/urlEditor" }, "browserslist": { "production": [ From 5160f5c8a12dda8c657ecdc1028f94c560cb1ff4 Mon Sep 17 00:00:00 2001 From: Lisi Case <49213376+lisicase@users.noreply.github.com> Date: Thu, 26 Aug 2021 08:59:55 -0700 Subject: [PATCH 19/49] Interactive Querying in Documentation (#275) * Drafted component to interactively make queries within documentation * Styled results to be a scrollable box * Created function to format queries so they work regardless of including the dollar symbol ($) * addressed bugs/errors related to requests on unmounted components and incorrect transformation of URLs * added interactive querying for all examples * improved accuracy and efficiency of reformatting queries * cleaned up code and added method comment * reformatted query and results * integrated intellisense query component * reformatted/removed old version of template/example queries * made stylistic changes to fonts, buttons, etc. * implemented better responsivity with scrolling of query editor; documented code * fixed parsing of JSON results * Fixed occasional bug with rendering results by changing results format for CodeBlock * removed unnecessary console log --- docs/rapid-pro-read.md | 308 +++--------------- tools/odataUri/package.json | 1 + tools/odataUri/webpack.config.js | 4 +- tools/urlEditor/package.json | 5 +- tools/urlEditor/src/uri-editor.ts | 10 +- tools/urlEditor/webpack.config.js | 6 + website/package.json | 4 +- .../InteractiveQuerying.css | 53 +++ .../InteractiveQuerying.js | 91 +++--- .../documentation-queries/Request.js | 18 + .../documentation-queries/TemplateRequest.js | 16 + 11 files changed, 189 insertions(+), 327 deletions(-) create mode 100644 website/src/components/documentation-queries/InteractiveQuerying.css rename website/src/components/{ => documentation-queries}/InteractiveQuerying.js (70%) create mode 100644 website/src/components/documentation-queries/Request.js create mode 100644 website/src/components/documentation-queries/TemplateRequest.js diff --git a/docs/rapid-pro-read.md b/docs/rapid-pro-read.md index 827a4af7..8ff90f91 100644 --- a/docs/rapid-pro-read.md +++ b/docs/rapid-pro-read.md @@ -4,28 +4,19 @@ title: Reading Resources sidebar_label: Reading Resources --- -import InteractiveQuerying from '../website/src/components/InteractiveQuerying.js'; +import InteractiveQuerying from '../website/src/components/documentation-queries/InteractiveQuerying.js'; -## Retrieving a Resource +import TemplateRequest from '../website/src/components/documentation-queries/TemplateRequest.js'; -RAPID services support retrieving a resource using the GET method: +import Request from '../website/src/components/documentation-queries/Request.js'; -| Template | GET {resource-path} | -| ----------- | :------------------------------------------------------------------------------ | -| **Example** | GET [`http://rapid-pro.org/company`](https://jetsons.azurewebsites.net/company) | +## Retrieving a Resource -RAPID services return individual resources as a json object. +RAPID services support retrieving a resource using the GET method, then returning it as a json object. -```json -{ - "@context": "$metadata#company", - "name": "Spacely's Space Sprockets", - "incorporated": "2054-10-04", - "stockSymbol": "spcly" -} -``` + - + RAPID responses are self-describing. The first line says that the response is described by the `company` singleton defined in the `$metadata` resource. @@ -40,21 +31,9 @@ Dates, Times, and DateTimeOffset values are represented as ISO-8601 strings. The client can select individual properties of the resource using the `select` option: -| Template | GET {resource-path}?select={propertyName,…} | -| ----------- | :------------------------------------------------------------------------------------------------------------------------------ | -| **Example** | GET [`http://rapid-pro.org/company?select=name,stockSymbol`](https://jetsons.azurewebsites.net/company?$select=name,stockSymbol) | - -**Result:** + -```json -{ - "@context": "$metadata#company(name,stockSymbol)", - "name": "Spacely's Space Sprockets", - "stockSymbol": "spcly" -} -``` - - + The first line says that only the `name` and `stockSymbol` properties are selected to be returned from the `company` resource. @@ -62,37 +41,9 @@ The first line says that only the `name` and `stockSymbol` properties are select Related resources can be retrieved as nested resources through the `expand` query option. -| Template | GET {collection-resource-path}?expand={navigationProperty,…} | -| ----------- | :---------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company?expand=employees`](https://jetsons.azurewebsites.net/company?$expand=employees) | - -**Result:** - -```json -{ - "@context": "$metadata#company(employees())", - "name": "Spacely's Space Sprockets", - "incoporated": "2054-10-4", - "stockSymbol": "spcly", - "employees": [ - { - "id": 1, - "firstName": "Cosmo", - "lastName": "Spacely", - "title": "CEO" - }, - { - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" - } - ], - "employees@nextLink": "company/employees?skiptoken=xyz" -} -``` - - + + + The context property specifies that the `employees` are expanded within the `company`. Because the next link refers to the nested `employees` property, the `nextLink` property is prefixed with the name of the nested property. @@ -100,64 +51,17 @@ Because the next link refers to the nested `employees` property, the `nextLink` When expanding related resources, you can express the same options for the related resource that you can for any other resource path. -| Template | GET {collection-resource-path}?expand={navigationProp(queryOptions),…} | -| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company?expand=employees(select=firstName)`]() | - -**Result:** - -```json -{ - "@context": "$metadata#company(employees(firstName))", - "name": "Spacely's Space Sprockets", - "incoporated": "2054-10-4", - "stockSymbol": "spcly", - "employees": [ - { - "firstName": "Cosmo" - }, - { - "firstName": "George" - } - ], - "employees@nextLink": "company/employees?select=firstName&skiptoken=xyz" -} -``` - - + + + ## Retrieving a Collection of Resources -RAPID services return collections of resources as a JSON array: - -| Template | GET {collection-resource-path} | -| ----------- | :-------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company/employees`](https://jetsons.azurewebsites.net/company/employees) | - -**Result:** - -```json -{ - "@context": "$metadata#company/employees", - "value": [ - { - "id": 1, - "firstName": "Cosmo", - "lastName": "Spacely", - "title": "CEO" - }, - { - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" - } - ], - "@nextLink": "company/employees?skiptoken=xyz" -} -``` - - +RAPID services return collections of resources as a JSON array: + + + + If the result is large, the service may include a next link to tell the client that there are more items in the collection. The value of the next link is an opaque URL that the client can use to retrieve the next set of resources from the collection. @@ -167,23 +71,9 @@ The absence of the next link signals the client that they have retrieved all of Individual members of a collection can be identified by appending the key to the URL of the collection. -| Template | GET {collection-resource-path}/{key} | -| ----------- | :------------------------------------------------------------------------------------------------------ | -| **Example** | GET [`http://rapid-pro.org/company/employees/2`](https://jetsons.azurewebsites.net/company/employees/2) | - -**Result:** + -```json -{ - "@context": "$metadata#company/employees/$entity", - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" -} -``` - - + Here the context property specifies that the result is an individual resource within the `employees` collection of the `company`. @@ -192,63 +82,22 @@ Here the context property specifies that the result is an individual resource wi Query options are composable; the client can select a subset of properties to be returned for each instance in the collection. -| Template | GET {collection-resource-path}?select={propertyName,…} | -| ----------- | :---------------------------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company/employees?select=lastName`](https://jetsons.azurewebsites.net/company/employees?$select=lastName) | - -**Result:** - -```json -http://rapid-pro.org/company/employees?select=lastName -{ - "@context": "$metadata#company/employees(lastName)", - "value": [ - { - "lastName": "Spacely" - }, - { - "lastName": "Jetson" - } - ], - "@nextLink": "company/employees?select=lastName&skiptoken=xyz" -} -``` - - + + + ### Requesting a Range of Members The client can use `top` and/or `skip` query options to select a range of resources within a collection. They can use the `count` query option to request the count of all resources in the collection. -| Template | GET {collection-resource-path}?skip={int}
GET {collection-resource-path}?top={int}
GET {collection-resource-path}?count=true | -| ----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company/employees?skip=1&top=2&count=true`](https://jetsons.azurewebsites.net/company/employees?$skip=1&$top=2&$count=true) | - -**Result:** - -```json -{ - "@context": "$metadata#company/employees", - "@count": 4, - "value": [ - { - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" - }, - { - "id": 3, - "firstName": "R.U.D.I.", - "lastName": null, - "title": "Computer" - } - ] -} -``` - - + + + + + + + The result skips the first member and returns the next two. The `@count` property denotes the total number of resources in the collection, and is not affected by `skip` or `top`. @@ -258,40 +107,9 @@ There is no next link because all two of the requested resources are returned. The client can use the `orderby` query option to order the results returned within a collection. -| Template | GET {collection-resource-path}?orderby={propertyName [asc \| desc],…} | -| ----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company/employees?orderby=lastName asc, id desc`](https://jetsons.azurewebsites.net/company/employees?$orderby=lastName%20asc,%20id%20desc) | - -**Result:** - -```json -{ - "@context": "$metadata#company/employees", - "value": [ - { - "id": 3, - "firstName": "R.U.D.I.", - "lastName": null, - "title": "Computer" - }, - { - "id": 4, - "firstName": "Judy", - "lastName": "Jetson", - "title": "Intern" - }, - { - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" - } - ], - "@nextLink": "company/employees?orderby=lastName,id desc&skiptoken=xyz" -} -``` - - + + + Null values sort before non-null values in ascending order and after non-null values in descending order. @@ -301,33 +119,9 @@ If `asc` or `desc` is not specified, the default ordering is ascending. The client can use the `filter` query option to filter the results returned from the collection. -| Template | GET {collection-resource-path}?filter={filter-expression} | -| ----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Example** | GET [`http://rapid-pro.org/company/employees?filter=lastName eq 'Jetson'`](https://jetsons.azurewebsites.net/company/employees?$filter=lastName%20eq%20'Jetson') | - -**Result:** - -```json -{ - "@context": "$metadata#company/employees", - "value": [ - { - "id": 2, - "firstName": "George", - "lastName": "Jetson", - "title": "Digital Index Operator" - }, - { - "id": 4, - "firstName": "Judy", - "lastName": "Jetson", - "title": "Intern" - } - ] -} -``` - - + + + In this case, there is no next link since all of the resources matching the filter predicate were returned inline. @@ -340,29 +134,9 @@ Query options can be combined using the ampersand (`&`). To comply with URL parsing rules, query options within an expand clause are separated using semi-colons (`;`). The order of query options is not significant. -| Template | GET {resource-path}?select={propertyName,…}&expand={navigationProperty(queryOptions),…} | -| ----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| | GET {collection-resource-path}?
select={propertyName,…}
&top={int}
&skip={int}
&count=true
&filter={filter-expression}
&orderby={propertyName [asc \| desc],…}
&expand={navigationProperty(queryOptions),…} | -| **Example** | GET [`http://rapid-pro.org/company?select=name&expand=employees(select=firstName;filter=lastName eq 'Jetson')`]() | - -**Result:** - -```json -{ - "@context": "$metadata#company(name,employees(firstName))", - "name": "Spacely's Space Sprockets", - "employees": [ - { - "firstName": "George" - }, - { - "firstName": "Judy" - } - ] -} -``` -F - + + + ## Passing Query Strings in the Body diff --git a/tools/odataUri/package.json b/tools/odataUri/package.json index 81758b98..c1bf8144 100644 --- a/tools/odataUri/package.json +++ b/tools/odataUri/package.json @@ -13,6 +13,7 @@ "dependencies": { "antlr4-c3": "^1.1.16", "antlr4ts": "^0.5.0-alpha.4", + "assert": "^2.0.0", "process": "^0.11.10", "util": "^0.12.4" }, diff --git a/tools/odataUri/webpack.config.js b/tools/odataUri/webpack.config.js index 8a017b35..617a411d 100644 --- a/tools/odataUri/webpack.config.js +++ b/tools/odataUri/webpack.config.js @@ -30,8 +30,8 @@ module.exports = { globalObject: 'this', }, plugins: [ - new webpack.DefinePlugin({ - 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) + new webpack.ProvidePlugin({ + process: "process/browser" }) ], mode: "production" diff --git a/tools/urlEditor/package.json b/tools/urlEditor/package.json index a065b176..e9d09a1f 100644 --- a/tools/urlEditor/package.json +++ b/tools/urlEditor/package.json @@ -11,8 +11,9 @@ "license": "ISC", "dependencies": { "@codemirror/basic-setup": "^0.18.2", - "rsdl-js": "^0.2.0", - "odata-uri": "file:../odataUri" + "odata-uri": "file:../odataUri", + "process": "^0.11.10", + "rsdl-js": "^0.2.0" }, "devDependencies": { "@tsconfig/recommended": "^1.0.1", diff --git a/tools/urlEditor/src/uri-editor.ts b/tools/urlEditor/src/uri-editor.ts index b8fd3891..edb1f709 100644 --- a/tools/urlEditor/src/uri-editor.ts +++ b/tools/urlEditor/src/uri-editor.ts @@ -1,7 +1,8 @@ import { basicSetup, EditorState, EditorView } from "@codemirror/basic-setup"; import { autocompletion, CompletionSource } from '@codemirror/autocomplete'; import { linter, Diagnostic } from '@codemirror/lint'; -import { AutoCompleteManager } from "odata-uri"; +// import { AutoCompleteManager } from "odata-uri"; +import { AutoCompleteManager } from "../../odataUri/src/autocomplete-manager"; import { getDocContent, convertToCsdl } from "./utils"; type UrlUpdatedCallback = (url: string) => any; @@ -82,7 +83,12 @@ function initUrlEditor(domElement: HTMLElement, onUrlUpdated: UrlUpdatedCallback return getDocContent(editor.state.doc); } - return { updateSchema, getUrl }; + function setUrl(url: string) { + const transaction = editor.state.update({ changes: { from: 0, to: editor.state.doc.length, insert: url }}); + editor.dispatch(transaction); + } + + return { updateSchema, getUrl, setUrl }; } export { initUrlEditor }; diff --git a/tools/urlEditor/webpack.config.js b/tools/urlEditor/webpack.config.js index 471619ae..7acf754d 100644 --- a/tools/urlEditor/webpack.config.js +++ b/tools/urlEditor/webpack.config.js @@ -1,4 +1,5 @@ const path = require("path"); +const webpack = require("webpack"); module.exports = { entry: "./src/index.ts", @@ -28,5 +29,10 @@ module.exports = { type: "umd" } }, + plugins: [ + new webpack.ProvidePlugin({ + process: "process/browser" + }) + ], mode: "development" } diff --git a/website/package.json b/website/package.json index 52b52cb5..2abb56d0 100644 --- a/website/package.json +++ b/website/package.json @@ -14,11 +14,11 @@ "@docusaurus/preset-classic": "^2.0.0-beta.0", "bootstrap": "^5.0.2", "classnames": "^2.2.6", + "odata-uri-editor": "file:../tools/urlEditor", "prettier": "2.0.5", "react": "^16.8.4", "react-bootstrap": "^1.6.1", - "react-dom": "^16.8.4", - "odata-uri-editor": "file:../tools/urlEditor" + "react-dom": "^16.8.4" }, "browserslist": { "production": [ diff --git a/website/src/components/documentation-queries/InteractiveQuerying.css b/website/src/components/documentation-queries/InteractiveQuerying.css new file mode 100644 index 00000000..a7d1fa39 --- /dev/null +++ b/website/src/components/documentation-queries/InteractiveQuerying.css @@ -0,0 +1,53 @@ +/* Query editor */ + +div.query-editor { + display: block; + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} + +div.cm-gutters { + display: none !important; +} + +div.cm-focused { + outline: none !important; +} + +div.cm-line { + line-height: 2.3rem; + padding-left: 0 !important; +} + +div.cm-content { + padding: 0 !important; + border-top: 1px solid rgb(206, 212, 218); + border-bottom: 1px solid rgb(206, 212, 218); +} + +div.cm-scroller { + overflow-x: scroll; + padding: 0; +} + +div.cm-scroller::-webkit-scrollbar { + display:none; +} + +/* Code samples */ + +span.input-group-text { + font-family: monospace; +} + +/* Override bootstrap */ + +a.menu__link, a.table-of-contents__link { + text-decoration: none; +} + +.navbar--fixed-top { + position: sticky !important; +} \ No newline at end of file diff --git a/website/src/components/InteractiveQuerying.js b/website/src/components/documentation-queries/InteractiveQuerying.js similarity index 70% rename from website/src/components/InteractiveQuerying.js rename to website/src/components/documentation-queries/InteractiveQuerying.js index d2a7c57d..9c6711ce 100644 --- a/website/src/components/InteractiveQuerying.js +++ b/website/src/components/documentation-queries/InteractiveQuerying.js @@ -1,11 +1,11 @@ import React from "react"; import InputGroup from 'react-bootstrap/InputGroup'; -import FormControl from 'react-bootstrap/FormControl'; import Button from 'react-bootstrap/Button'; import 'bootstrap/dist/css/bootstrap.min.css'; +import './InteractiveQuerying.css'; import {Component} from 'react'; import CodeBlock from "@theme/CodeBlock"; - +import { initUrlEditor } from "odata-uri-editor"; /// Tool to allow a user to make a query on the Jetsons API and see the results. /// Default query to start with filled in. @@ -20,6 +20,7 @@ class InteractiveQuerying extends Component { constructor(props) { super(props); let newController = new AbortController(); + this.editor = null; this.state = { queryUrl: this.props.defaultQuery, @@ -31,24 +32,46 @@ class InteractiveQuerying extends Component { /// Start with results displayed. componentDidMount() { - document.getElementById(this.props.id).value = this.props.defaultQuery; + this.editor = initUrlEditor(document.getElementById(this.props.id)); + this.editor.setUrl(this.props.defaultQuery); + let schema = ` + type Company + { + stockSymbol: String + name: String + incorporated: Date + employees: [Employee] + } + + type Employee + { + key id: Integer + firstName: String + lastName: String + title: String + } + + service { + company: Company + competitors: [Company] + }` + this.editor.updateSchema(schema); this.fetchResults(this.props.defaultQuery); } - /// Abandon fetch request before component unmounts. + /// Abandons fetch request before component unmounts. componentWillUnmount() { this.state.controller.abort(); } /// Gets the results for the query entered by the user. updateQueryResults = () => { - let newQuery = document.getElementById(this.props.id).value; + let newQuery = this.editor.getUrl(); if (newQuery !== "") { this.setState({queryUrl: newQuery}); this.fetchResults(newQuery); } else { this.setToDefault(); - //this.setState({responseElement:

}) } } @@ -56,7 +79,7 @@ class InteractiveQuerying extends Component { /// Sets the query/results to the default given from . /// setToDefault = () => { - document.getElementById(this.props.id).value = this.props.defaultQuery; + this.editor.setUrl(this.props.defaultQuery); this.setState({queryUrl: this.props.defaultQuery}); this.fetchResults(this.props.defaultQuery); } @@ -75,7 +98,8 @@ class InteractiveQuerying extends Component { if (result === "The page cannot be displayed because an internal server error has occurred.") { result = "This query is not valid; please try a different query." } else { - result = this.formatJson(result); + result = JSON.parse(result); + result = JSON.stringify(result, null, 4); } let newResponse = {result} this.setState({responseElement: newResponse}) @@ -102,40 +126,6 @@ class InteractiveQuerying extends Component { return formattedQuery; } - formatJson(json) { - let formattedJson = ""; - let tabLevel = 0; - let inQuote = false; - for (let i = 0; i < json.length; i++) { - let currChar = json.charAt(i); - if (currChar == '{' || currChar == '[') { - tabLevel++; - formattedJson += currChar + '\n' + this.getTabSpaces(tabLevel); - } else if (currChar == ',' && !inQuote) { - formattedJson += currChar + '\n' + this.getTabSpaces(tabLevel); - } else if (currChar == '}' || currChar == ']') { - tabLevel--; - formattedJson += '\n' + this.getTabSpaces(tabLevel) + currChar; - } else if (currChar == ':') { - formattedJson += currChar + " "; - } else { - if (currChar == '\"') { - inQuote = !inQuote; - } - formattedJson += currChar; - } - } - return formattedJson; - } - - getTabSpaces(tabLevel) { - let spaces = ""; - for (let i = 1; i <= tabLevel; i++) { - spaces += " "; - } - return spaces; - } - render() { return (
@@ -157,19 +147,16 @@ class Query extends Component { render() { return ( <> -

Query:

+

Example Query:

- GET http://rapid-pro.org/ - + GET / +
+ - ); diff --git a/website/src/components/documentation-queries/Request.js b/website/src/components/documentation-queries/Request.js new file mode 100644 index 00000000..d55c996c --- /dev/null +++ b/website/src/components/documentation-queries/Request.js @@ -0,0 +1,18 @@ +import React from "react"; +import InputGroup from 'react-bootstrap/InputGroup'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import {Component} from 'react'; + +class Request extends Component { + render() { + return ( +
+ + {this.props.command} {this.props.query} + +
+ ); + } +} + +export default Request; \ No newline at end of file diff --git a/website/src/components/documentation-queries/TemplateRequest.js b/website/src/components/documentation-queries/TemplateRequest.js new file mode 100644 index 00000000..e4a81e26 --- /dev/null +++ b/website/src/components/documentation-queries/TemplateRequest.js @@ -0,0 +1,16 @@ +import React from "react"; +import {Component} from 'react'; +import Request from './Request.js'; + +class TemplateRequest extends Component { + render() { + return ( +
+

Template:

+ +
+ ); + } +} + +export default TemplateRequest; \ No newline at end of file From 75761433778f1a09a546a3731ed647fa2f96d507 Mon Sep 17 00:00:00 2001 From: Christof Sprenger Date: Wed, 1 Sep 2021 10:09:00 -0700 Subject: [PATCH 20/49] 1st draft --- docs/rapid-pro-capabilities.md | 77 ++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 docs/rapid-pro-capabilities.md diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md new file mode 100644 index 00000000..31e82331 --- /dev/null +++ b/docs/rapid-pro-capabilities.md @@ -0,0 +1,77 @@ +--- +id: rapid-pro-capabilities +title: Path centric service capabilities. +sidebar_label: Capabilities +--- + +# Path Centric Service Capabilities. + +The previous sections demonstrate how to define the format of the request/response bodies based on types and their relationship. This structure also implies which URLs are valid in the service: starting with the service properties and following properties that have a structured type. + +Without further constraints this would allow a huge number of URLs that a service would need to support. And it is important not just to specify which paths are allowed, but also to specify different functionality and behaviors supported for different paths. + +The following sections introduce the notion of paths and descriptions of capabilities that the service provides per path. + +# Example + +``` +path /orders +{ + POST { } + GET { ... } +} + +path /orders/{id} +{ + GET { expand { items } } + PATCH { ... } +} + +path /orders/{id}/items/{id} +{ + GET { filter } + DELETE { } +} + +path /skus { + GET { + facets { + quota: 500 + permissions: "xyz" + } + } +} + +``` + +# Syntax + +``` ABNF +path-capability = "path" path "{" + [ get-capabilities ] + [ post-capabilities ] + [ patch-capabilities ] + [ delete-capabilities ] + "}" + +esf-capabilities = [ expand-capabilities ] [ select-capabilities ] [ filter-capabilities ] +get-capabilities = "GET" "{" [ esf-capabilities ] [ paging-capabilities ] "}" +post-capabilities = "POST" "{" "}" +patch-capabilities = "PATCH" "{" "}" +delete-capabilities = "DELETE" "{" [ filter-capabilities ] "}" + +expand-capabilities = "expand" ["{" *( property-name "{" esf-capabilities "}" ) "}"] +select-capabilities = "select" ["{" *( property-name ) "}"] +filter-capabilities = "filter" ["{" *( property-name ) [ *filter-operator-group ] "}"] +filter-operator-group = "eq" / "in" / "range" / "ranges" / "strings" + +paging-capabilities = "paging" ["{" "}"] + + +property-name = identifier +path = "`" *( "/" identifier ) "`" + +``` + + +# Capabilities document From 83d568dbf1e1b9f77046f4e5a0e9fb7b9a4f6800 Mon Sep 17 00:00:00 2001 From: Christof Sprenger Date: Wed, 1 Sep 2021 19:16:49 -0700 Subject: [PATCH 21/49] updates to capabilitites document --- .vscode/settings.json | 11 +-- docs/rapid-pro-capabilities.md | 159 +++++++++++++++++++++++++++++---- 2 files changed, 147 insertions(+), 23 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 25edaadf..b718225d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,16 +1,17 @@ { "cSpell.words": [ + "abnf", + "capabiliti", "dotnet", + "eset", + "jetsons", "nuget", "nupkg", + "odata", "rapid", "rsdl", - "tools", - "abnf", - "eset", - "jetsons", - "odata", "svel", + "tools", "xunit" ], "dotnet-test-explorer.testProjectPath": "**/*tests.@(csproj|vbproj|fsproj)" diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md index 31e82331..625d3c57 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rapid-pro-capabilities.md @@ -6,44 +6,167 @@ sidebar_label: Capabilities # Path Centric Service Capabilities. -The previous sections demonstrate how to define the format of the request/response bodies based on types and their relationship. This structure also implies which URLs are valid in the service: starting with the service properties and following properties that have a structured type. +The previous sections go into detail how to define the format of the request and response bodies based on types and their relationships. This structure also implies which URLs are valid in the service: starting with the service properties and following properties of a structured type. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders//items` and `/orders//items` are also a valid URLs. Without further constraints this would allow a huge number of URLs that a service would need to support. And it is important not just to specify which paths are allowed, but also to specify different functionality and behaviors supported for different paths. The following sections introduce the notion of paths and descriptions of capabilities that the service provides per path. -# Example +# Example service + +for the following examples we assume the following type definitions for a service that has a top level orders entity set together with and their (contained) order items. Each item references a SKU, that is also available via a top level entity set. ``` -path /orders +type Order { - POST { } - GET { ... } + key id: String + created: DateTime + status: OrderStatus + items: [OrderItem] +} + +enum OrderStatus { + Open, Archived, Canceled } -path /orders/{id} +type OrderItem { - GET { expand { items } } - PATCH { ... } + key id: String + sku: *SKU + amount: Integer } -path /orders/{id}/items/{id} +type SKU { - GET { filter } - DELETE { } + key id: String + name: String + description: String + unitPrice: Decimal +} + +service { + orders: [Order] + skus: [SKU] +} +``` + +The amount of potential URLs that the service needs to support is large. Just to name some of the more important ones: + +- /skus +- /skus/{id?} +- /orders +- /orders/{id} +- /orders/{id}items +- /orders/{id}/items/{id} +- /orders/{id}/items/{id}/skus +- /orders/{id}/items/{id}/skus/{id} + +The path-centric view in RSDL now allows to enumerate the allowed requests (URL + verb) + and which query options are supported for these requests + + +The first level of this (i.e. URL + verb ) looks for example like the following + +``` +path `/orders` { + GET { ... } + POST { ... } +} + +path `/orders/{id}` { + GET { ... } + PATCH { ... } + DELETE { ... } +} + +path `/orders/{id}/items/{id}` { + GET { ... } + DELETE { ... } +} + +path `/skus` { + GET { ... } } -path /skus { - GET { - facets { - quota: 500 - permissions: "xyz" - } - } +``` +The effect of this declaration is that for each URL and HTTP method combination the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but these ones are required. + +The `...` is used to declare which query options are supported by the service. FOr example a GET capability lists that certain $filter options are allow of that paging is supported via the $top, $skip options. More details in the next sections + +The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in teh example above can vary by HTTP method. Here is an overview + +| | select | filter | expand | paging | count | create | update | delete | | +|--------|--------|--------|--------|--------|-------|--------|--------|--------|---| +| GET | x | x | x | x | x | | | | | +| POST | | | | | | x | | | | +| PATCH | | | | | | | x | | | +| DELETE | | x | | | | | | x | | + + +### select capabilities + +The select capability allows to specify which properties can be used in the `$select` query parameter. + +It's format is just a sequence of names of the properties that are allowed to be specified in the `$select` system query options. + +``` +select { prop1, prop2, ... } +``` + +### filter capabilities + +The filter capability allows to specify which property can be used in conjunction to which operator. + +It's format is a sequence of pairs of property name and a list of allowed, so called operator groups. An operator group is constraining the form of the expression allowed in the $filter system query option. (see [odata abnf]([y](https://github.com/oasis-tcs/odata-abnf/blob/main/abnf/odata-abnf-construction-rules.txt#L502)) for reference. ) + +| operator group | comment | +|----------------|-------------------------------------------------------------------------------------------------------------| +| eq | ` eq ` or ` in (, , ... ) ` | +| range | ` <= and <= ` | +| ranges | a disjunction of the `range` expressions | +| prefix | ` startswith ` | +| text | ` `, where `` is one of `startswith`, `endswith`, `contains` | +| any | any expression including expressions combined with `and` and `or` | + +In RSDL this + +``` +filter { + id: [eq], + createdDate: [range, eq], + description: [eq, text], + fulfillmentDate: [range, ranges] } +``` + +### expand capabilities + +The expand capability allows to specify which property can be used in `$expand` query parameter. +The format is a sequence of properties together with a description how they can be expanded. The expand capability introduces a nesting of capabilities since the type od the expandable property type can allow for select, filter, and expand. + +```RSDL + +expand { + items { + expand { + sku { + filter { id: [eq], name: [prefix] } + select: [name, description, unitPrice ] + } + } + } +} ``` +### create capabilities +### update capabilities +### delete capabilities + +### paging capabilities + +### count capabilities + # Syntax ``` ABNF From 5b781090529a07186142dc0f5840653237dcf94d Mon Sep 17 00:00:00 2001 From: Ralf Handl Date: Thu, 2 Sep 2021 11:29:36 +0200 Subject: [PATCH 22/49] Update rapid-pro-capabilities.md --- docs/rapid-pro-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md index 625d3c57..a22dd0eb 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rapid-pro-capabilities.md @@ -6,7 +6,7 @@ sidebar_label: Capabilities # Path Centric Service Capabilities. -The previous sections go into detail how to define the format of the request and response bodies based on types and their relationships. This structure also implies which URLs are valid in the service: starting with the service properties and following properties of a structured type. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders//items` and `/orders//items` are also a valid URLs. +The previous sections go into detail how to define the format of the request and response bodies based on types and their relationships. This structure also implies which URLs are valid in the service: starting with the service properties and following properties of a structured type. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders//items` and `/orders//items/` are also a valid URLs. Without further constraints this would allow a huge number of URLs that a service would need to support. And it is important not just to specify which paths are allowed, but also to specify different functionality and behaviors supported for different paths. From 0888c645b4f29d27dcd5ac26200b7e1240e14faf Mon Sep 17 00:00:00 2001 From: Ralf Handl Date: Thu, 2 Sep 2021 11:32:52 +0200 Subject: [PATCH 23/49] Update rapid-pro-capabilities.md --- docs/rapid-pro-capabilities.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md index a22dd0eb..dc0b3f62 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rapid-pro-capabilities.md @@ -26,7 +26,9 @@ type Order } enum OrderStatus { - Open, Archived, Canceled + Open + Archived + Canceled } type OrderItem @@ -45,7 +47,7 @@ type SKU } service { - orders: [Order] + orders: [Order] skus: [SKU] } ``` From 4532baff5a2babc9718cd488014834556c32bc25 Mon Sep 17 00:00:00 2001 From: Ralf Handl Date: Thu, 2 Sep 2021 11:34:39 +0200 Subject: [PATCH 24/49] Update rapid-pro-capabilities.md --- docs/rapid-pro-capabilities.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md index dc0b3f62..4aaacc7f 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rapid-pro-capabilities.md @@ -55,10 +55,10 @@ service { The amount of potential URLs that the service needs to support is large. Just to name some of the more important ones: - /skus -- /skus/{id?} +- /skus/{id} - /orders - /orders/{id} -- /orders/{id}items +- /orders/{id}/items - /orders/{id}/items/{id} - /orders/{id}/items/{id}/skus - /orders/{id}/items/{id}/skus/{id} From c6d60d80fca4fe9259321e18d3a0d598b865fdb2 Mon Sep 17 00:00:00 2001 From: Ralf Handl Date: Thu, 2 Sep 2021 11:39:14 +0200 Subject: [PATCH 25/49] Update rapid-pro-capabilities.md --- docs/rapid-pro-capabilities.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/rapid-pro-capabilities.md b/docs/rapid-pro-capabilities.md index 4aaacc7f..c7cf74ba 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rapid-pro-capabilities.md @@ -93,9 +93,9 @@ path `/skus` { ``` The effect of this declaration is that for each URL and HTTP method combination the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but these ones are required. -The `...` is used to declare which query options are supported by the service. FOr example a GET capability lists that certain $filter options are allow of that paging is supported via the $top, $skip options. More details in the next sections +The `...` is used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections. -The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in teh example above can vary by HTTP method. Here is an overview +The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in the example above can vary by HTTP method. Here is an overview | | select | filter | expand | paging | count | create | update | delete | | |--------|--------|--------|--------|--------|-------|--------|--------|--------|---| From d4a106e369e36412b62f564b8edb3361a24f6d5d Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Fri, 3 Sep 2021 22:28:15 +0000 Subject: [PATCH 26/49] include syntax highlighting --- docs/related/rapd-pro-graphql.md | 2 +- docs/rsdl/rapid-pro-rsdl-abnf.md | 4 +- .../rapid-pro-rsdl-capabilities.md} | 99 ++++++++++--------- docs/rsdl/rapid-pro-rsdl-intro.md | 1 + docs/rsdl/rapid-pro-rsdl-semantics.mdx | 1 + website/docusaurus.config.js | 4 + website/sidebars.js | 1 + website/src/theme/prism-include-languages.js | 27 +++++ website/src/theme/prism-rsdl.js | 41 ++++++++ 9 files changed, 128 insertions(+), 52 deletions(-) rename docs/{rapid-pro-capabilities.md => rsdl/rapid-pro-rsdl-capabilities.md} (65%) create mode 100644 website/src/theme/prism-include-languages.js create mode 100644 website/src/theme/prism-rsdl.js diff --git a/docs/related/rapd-pro-graphql.md b/docs/related/rapd-pro-graphql.md index 244e8859..ff51a9ba 100644 --- a/docs/related/rapd-pro-graphql.md +++ b/docs/related/rapd-pro-graphql.md @@ -17,7 +17,7 @@ GraphQL defines a simple syntax for defining the shape of a service. In a GraphQL query, the developer describes the properties to be retrieved, and depth traversed, through a JSON-like structure. -In a RAPID query, the developer describes the properties to be retrieved through a [projection](..\rapid-pro-read.md#selecting-individual-properties-of-a-resource), +In a RAPID query, the developer describes the properties to be retrieved through a [projection](rapid-read#selecting-individual-properties-of-a-resource), and the depth traversed through an [expansion](..\rapid-pro-read.md#including-related-resources) operator. ## Filter diff --git a/docs/rsdl/rapid-pro-rsdl-abnf.md b/docs/rsdl/rapid-pro-rsdl-abnf.md index 34bd725a..3c5ae2bb 100644 --- a/docs/rsdl/rapid-pro-rsdl-abnf.md +++ b/docs/rsdl/rapid-pro-rsdl-abnf.md @@ -1,6 +1,6 @@ --- id: rsdl-abnf -title: RAPID SDL ABNF +title: RSDL ABNF --- # RAPID Pro Syntax @@ -16,7 +16,7 @@ Note: to increase readability of the grammar, whitespace is not reflected ## Syntax rules -- [RAPID Pro syntax](#rapid-pro-syntax) +- [RAPID Pro Syntax](#rapid-pro-syntax) - [Overview](#overview) - [Syntax rules](#syntax-rules) - [Model](#model) diff --git a/docs/rapid-pro-capabilities.md b/docs/rsdl/rapid-pro-rsdl-capabilities.md similarity index 65% rename from docs/rapid-pro-capabilities.md rename to docs/rsdl/rapid-pro-rsdl-capabilities.md index c7cf74ba..df631bef 100644 --- a/docs/rapid-pro-capabilities.md +++ b/docs/rsdl/rapid-pro-rsdl-capabilities.md @@ -1,7 +1,7 @@ --- -id: rapid-pro-capabilities +id: rsdl-capabilities title: Path centric service capabilities. -sidebar_label: Capabilities +sidebar_label: RSDL Capabilities --- # Path Centric Service Capabilities. @@ -12,11 +12,11 @@ Without further constraints this would allow a huge number of URLs that a servic The following sections introduce the notion of paths and descriptions of capabilities that the service provides per path. -# Example service +## Example service for the following examples we assume the following type definitions for a service that has a top level orders entity set together with and their (contained) order items. Each item references a SKU, that is also available via a top level entity set. -``` +```rsdl type Order { key id: String @@ -66,88 +66,80 @@ The amount of potential URLs that the service needs to support is large. Just to The path-centric view in RSDL now allows to enumerate the allowed requests (URL + verb) and which query options are supported for these requests - +## HTTP capabilities The first level of this (i.e. URL + verb ) looks for example like the following -``` -path `/orders` { +```rsdl +path /orders { GET { ... } POST { ... } } -path `/orders/{id}` { +path /orders/{id} { GET { ... } PATCH { ... } DELETE { ... } } -path `/orders/{id}/items/{id}` { +path /orders/{id}/items/{id} { GET { ... } DELETE { ... } } -path `/skus` { +path /skus { GET { ... } } ``` The effect of this declaration is that for each URL and HTTP method combination the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but these ones are required. -The `...` is used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections. +The placeholders `...` are used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections. The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in the example above can vary by HTTP method. Here is an overview -| | select | filter | expand | paging | count | create | update | delete | | -|--------|--------|--------|--------|--------|-------|--------|--------|--------|---| -| GET | x | x | x | x | x | | | | | -| POST | | | | | | x | | | | -| PATCH | | | | | | | x | | | -| DELETE | | x | | | | | | x | | - +| | filter | expand | paging | count | read-model | write-model +|--------|:------:|:------:|:------:|:-----:|----- | --- | +| GET | x | x | x | x | +| POST | | | | | +| PATCH | | | | | +| PUT | | | | | +| DELETE | x | | | | -### select capabilities - -The select capability allows to specify which properties can be used in the `$select` query parameter. - -It's format is just a sequence of names of the properties that are allowed to be specified in the `$select` system query options. - -``` -select { prop1, prop2, ... } -``` +## Individual Query capabilities -### filter capabilities +### Filter capabilities -The filter capability allows to specify which property can be used in conjunction to which operator. +The filter capability allows to specify which property can be used in which filter expression. There is a vast amount of possible filter expressions (see [odata abnf](https://github.com/oasis-tcs/odata-abnf/blob/main/abnf/odata-abnf-construction-rules.txt#L502)). Therefore, the filter capabilities allow to specify a few well-known but restrictive expressions or allow any expression. -It's format is a sequence of pairs of property name and a list of allowed, so called operator groups. An operator group is constraining the form of the expression allowed in the $filter system query option. (see [odata abnf]([y](https://github.com/oasis-tcs/odata-abnf/blob/main/abnf/odata-abnf-construction-rules.txt#L502)) for reference. ) +The format for filter capabilities is a sequence of pairs of a so called operator group and a list of property names. An operator group is constraining the form of the expression allowed in the $filter system query option. | operator group | comment | |----------------|-------------------------------------------------------------------------------------------------------------| -| eq | ` eq ` or ` in (, , ... ) ` | -| range | ` <= and <= ` | +| eq | ` eq ` or
` in (, , ... ) ` | +| range | ` le and le `
or equivalent with `ge`, `gt`, `lt` | | ranges | a disjunction of the `range` expressions | -| prefix | ` startswith ` | -| text | ` `, where `` is one of `startswith`, `endswith`, `contains` | -| any | any expression including expressions combined with `and` and `or` | +| prefix | `startswith(, )` | +| text | `( )`,
where `` is one of `startswith`, `endswith`, `contains` | +| any | any expression including expressions combined with `not`, `and`, and `or` | In RSDL this -``` +```rsdl filter { - id: [eq], - createdDate: [range, eq], - description: [eq, text], - fulfillmentDate: [range, ranges] + eq { id name description createdDate fulfillmentDate } + ranges { createdDate description } + prefix { name } + text { description } } ``` -### expand capabilities +### Expand capabilities The expand capability allows to specify which property can be used in `$expand` query parameter. The format is a sequence of properties together with a description how they can be expanded. The expand capability introduces a nesting of capabilities since the type od the expandable property type can allow for select, filter, and expand. -```RSDL +```rsdl expand { items { @@ -161,17 +153,26 @@ expand { } ``` -### create capabilities -### update capabilities -### delete capabilities -### paging capabilities +### Paging capabilities + +### Count capabilities + +### Select capabilities + + +```rsdl +select { + read-only { createdDate, lastUpdateDate, fulfillmentDate } + write-only { password attachment } +} +``` -### count capabilities +## Extensibility -# Syntax +## Syntax -``` ABNF +``` abnf path-capability = "path" path "{" [ get-capabilities ] [ post-capabilities ] diff --git a/docs/rsdl/rapid-pro-rsdl-intro.md b/docs/rsdl/rapid-pro-rsdl-intro.md index 3b341982..1b800c75 100644 --- a/docs/rsdl/rapid-pro-rsdl-intro.md +++ b/docs/rsdl/rapid-pro-rsdl-intro.md @@ -1,6 +1,7 @@ --- id: rsdl-intro title: RAPID SDL intro +sidebar_label: RSDL Intro --- # Introduction to RAPID Schema Definition Language (RSDL) diff --git a/docs/rsdl/rapid-pro-rsdl-semantics.mdx b/docs/rsdl/rapid-pro-rsdl-semantics.mdx index e283b9a4..206ccbaa 100644 --- a/docs/rsdl/rapid-pro-rsdl-semantics.mdx +++ b/docs/rsdl/rapid-pro-rsdl-semantics.mdx @@ -1,6 +1,7 @@ --- id: rsdl-semantics title: RAPID Schema Definition Language Semantics +sidebar_label: RSDL Semantics --- > DRAFT diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index f06f10dd..8a7aebcf 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -7,6 +7,10 @@ module.exports = { organizationName: 'oasis-open', // Usually your GitHub org/user name. projectName: 'odata-rapid', // Usually your repo name. themeConfig: { + prism: { + // theme: require('prism-react-renderer/themes/dracula'), + theme: require('prism-react-renderer/themes/nightOwl'), + }, navbar: { title: 'RAPID', logo: { diff --git a/website/sidebars.js b/website/sidebars.js index 3c94310c..23fc5e03 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -24,6 +24,7 @@ module.exports = { label: 'RAPID Schema Definition Language (RSDL)', items: [ 'rsdl/rsdl-intro', + 'rsdl/rsdl-capabilities', 'rsdl/rsdl-semantics', 'rsdl/rsdl-abnf', ] diff --git a/website/src/theme/prism-include-languages.js b/website/src/theme/prism-include-languages.js new file mode 100644 index 00000000..9410ba8d --- /dev/null +++ b/website/src/theme/prism-include-languages.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; +import siteConfig from '@generated/docusaurus.config'; + +const prismIncludeLanguages = (PrismObject) => { + if (ExecutionEnvironment.canUseDOM) { + const { + themeConfig: {prism = {}}, + } = siteConfig; + const {additionalLanguages = []} = prism; + window.Prism = PrismObject; + additionalLanguages.forEach((lang) => { + require(`prismjs/components/prism-${lang}`); // eslint-disable-line + }); + // require(`prismjs/components/prism-abnf`) + require(`./prism-rsdl.js`); + + delete window.Prism; + } +}; + +export default prismIncludeLanguages; diff --git a/website/src/theme/prism-rsdl.js b/website/src/theme/prism-rsdl.js new file mode 100644 index 00000000..08c75ad5 --- /dev/null +++ b/website/src/theme/prism-rsdl.js @@ -0,0 +1,41 @@ +Prism.languages.rsdl = { + 'comment': /(?:#).*/, + 'heredoc': { + pattern: /@\w+:/, + greedy: true, + alias: 'string' + }, + 'builtin': [ + { + pattern: /\b(?:String|Decimal|DateTime)\b/, + }, + ], + 'keyword': [ + { + pattern: /\b(?:type|enum|service|abstract|open|key|extends|path)\b/, + }, + { + pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count)\b/, + }, + { + pattern: /\b(?:eq|range|ranges|prefix|text|any)\b/, + } + ], + 'property': [ + /[-\w\.]+(?=\s*=(?!=))/, + /"(?:\\[\s\S]|[^\\"])+"(?=\s*[:=])/, + ], + 'string': [ + { + pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, + greedy: true, + }, + { + pattern: /(:?\/(:?[a-z]+|{[a-z]+}))+/, + greedy: true, + } + ], + 'number': /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i, + 'boolean': /\b(?:true|false)\b/i, + 'punctuation': /[=\[\]{}:*?]/, +}; \ No newline at end of file From 552d52fd57109d9ddcac637930c121fd25e595e2 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Fri, 3 Sep 2021 22:31:50 +0000 Subject: [PATCH 27/49] update filter abnf --- docs/rsdl/rapid-pro-rsdl-capabilities.md | 8 ++++---- website/src/theme/prism-include-languages.js | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/rsdl/rapid-pro-rsdl-capabilities.md b/docs/rsdl/rapid-pro-rsdl-capabilities.md index df631bef..3048f580 100644 --- a/docs/rsdl/rapid-pro-rsdl-capabilities.md +++ b/docs/rsdl/rapid-pro-rsdl-capabilities.md @@ -187,11 +187,11 @@ patch-capabilities = "PATCH" "{" "}" delete-capabilities = "DELETE" "{" [ filter-capabilities ] "}" expand-capabilities = "expand" ["{" *( property-name "{" esf-capabilities "}" ) "}"] -select-capabilities = "select" ["{" *( property-name ) "}"] -filter-capabilities = "filter" ["{" *( property-name ) [ *filter-operator-group ] "}"] -filter-operator-group = "eq" / "in" / "range" / "ranges" / "strings" -paging-capabilities = "paging" ["{" "}"] +filter-capabilities = "filter" ["{" *( operator-group ) [ *operator-group ] "}"] +operator-group = "eq" / "in" / "range" / "ranges" / "strings" +operator-group-filter = operator-group "{" "}" +paging-capabilities = "paging" ["{" property-name* "}"] property-name = identifier diff --git a/website/src/theme/prism-include-languages.js b/website/src/theme/prism-include-languages.js index 9410ba8d..d0fa5749 100644 --- a/website/src/theme/prism-include-languages.js +++ b/website/src/theme/prism-include-languages.js @@ -17,7 +17,8 @@ const prismIncludeLanguages = (PrismObject) => { additionalLanguages.forEach((lang) => { require(`prismjs/components/prism-${lang}`); // eslint-disable-line }); - // require(`prismjs/components/prism-abnf`) + + require(`prismjs/components/prism-abnf`) require(`./prism-rsdl.js`); delete window.Prism; From be9a9bc056f31ee4f0c8934111bd6ef0bd6b313b Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Sep 2021 23:46:22 +0000 Subject: [PATCH 28/49] adding more detail to expand/paging/count and extensipility --- .vscode/settings.json | 6 +- ...bilities.md => rapid-rsdl-capabilities.md} | 159 +++++++++++++----- website/src/theme/prism-rsdl.js | 4 +- 3 files changed, 122 insertions(+), 47 deletions(-) rename docs/rsdl/{rapid-pro-rsdl-capabilities.md => rapid-rsdl-capabilities.md} (50%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 34ed52b5..aa1bca79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "cSpell.words": [ "abnf", - "capabiliti", + "capability", "CSDL", "dotnet", "eset", @@ -11,10 +11,10 @@ "odata", "rapid", "rsdl", - "Spacely", - "Spacely's", + "Spacely", "svel", "tools", + "writeonly", "xunit" ], "dotnet-test-explorer.testProjectPath": "**/*tests.@(csproj|vbproj|fsproj)" diff --git a/docs/rsdl/rapid-pro-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md similarity index 50% rename from docs/rsdl/rapid-pro-rsdl-capabilities.md rename to docs/rsdl/rapid-rsdl-capabilities.md index 3048f580..20f9c714 100644 --- a/docs/rsdl/rapid-pro-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -1,6 +1,6 @@ --- id: rsdl-capabilities -title: Path centric service capabilities. +title: Path Centric Service Capabilities. sidebar_label: RSDL Capabilities --- @@ -14,11 +14,10 @@ The following sections introduce the notion of paths and descriptions of capabil ## Example service -for the following examples we assume the following type definitions for a service that has a top level orders entity set together with and their (contained) order items. Each item references a SKU, that is also available via a top level entity set. +For the following examples we assume the following type definitions for a service that has a top level orders entity set together with their (contained) order items. Each item references a SKU, that can be accessed via the top level entity set. ```rsdl -type Order -{ +type Order { key id: String created: DateTime status: OrderStatus @@ -31,15 +30,13 @@ enum OrderStatus { Canceled } -type OrderItem -{ +type OrderItem { key id: String sku: *SKU amount: Integer } -type SKU -{ +type SKU { key id: String name: String description: String @@ -63,11 +60,10 @@ The amount of potential URLs that the service needs to support is large. Just to - /orders/{id}/items/{id}/skus - /orders/{id}/items/{id}/skus/{id} -The path-centric view in RSDL now allows to enumerate the allowed requests (URL + verb) - and which query options are supported for these requests +The path-centric view in RSDL allows to enumerate the allowed requests and specify which query options are supported for these requests. ## HTTP capabilities -The first level of this (i.e. URL + verb ) looks for example like the following +The first level of the above mentioned capabilities is to specify the path of theURL and the HTTP method, Here is a partial RSDL to demonstrate this. ```rsdl path /orders { @@ -81,6 +77,11 @@ path /orders/{id} { DELETE { ... } } +path /orders/{id}/items { + GET { ... } + POST { ... } +} + path /orders/{id}/items/{id} { GET { ... } DELETE { ... } @@ -91,19 +92,26 @@ path /skus { } ``` -The effect of this declaration is that for each URL and HTTP method combination the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but these ones are required. +The effect of this is that for each declared `path` declaration and HTTP method the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but the service guarantees to work for the ones listed. + +Important to notice is that the path after the `path` keyword are not literal paths but sort of templates. Many of the interesting paths in a REST service have path segments that are entity ids. this is indicated via the `{id}` syntax. the `id` in there is exactly the name of the key. The placeholders `...` are used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections. The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in the example above can vary by HTTP method. Here is an overview -| | filter | expand | paging | count | read-model | write-model -|--------|:------:|:------:|:------:|:-----:|----- | --- | -| GET | x | x | x | x | -| POST | | | | | -| PATCH | | | | | -| PUT | | | | | -| DELETE | x | | | | +| | filter | expand | paging | count | +|--------|:-------------:|:-------------:|:-------------:|:-------------:| +| GET | x | x | x | x | +| POST | x1 | x1 | x1 | x1 | +| PATCH | x1 | x1 | x1 | x1 | +| PUT | x1 | x1 | x1 | x1 | +| DELETE | x2 | | | | + +

+[1] to shape the POST/PATCH/PUT response. Rarely used but supported
+[2] deleting multiple items. Rarely used but supported
+

## Individual Query capabilities @@ -113,14 +121,14 @@ The filter capability allows to specify which property can be used in which filt The format for filter capabilities is a sequence of pairs of a so called operator group and a list of property names. An operator group is constraining the form of the expression allowed in the $filter system query option. -| operator group | comment | -|----------------|-------------------------------------------------------------------------------------------------------------| -| eq | ` eq ` or
` in (, , ... ) ` | -| range | ` le and le `
or equivalent with `ge`, `gt`, `lt` | -| ranges | a disjunction of the `range` expressions | -| prefix | `startswith(, )` | -| text | `( )`,
where `` is one of `startswith`, `endswith`, `contains` | -| any | any expression including expressions combined with `not`, `and`, and `or` | +| operator group | comment | +|----------------|-----------------------------------------------------------------------------------------------------------------------| +| eq | ` eq ` or
` in (, , ... ) ` | +| range | ` le and le `
or equivalent expressions with operators `ge`, `gt`, `lt` | +| ranges | a disjunction of `range` expressions | +| prefix | `startswith(, )` | +| text | `(, )`,
where `` is one of `startswith`, `endswith`, `contains` | +| any | any expression including expressions combined with `not`, `and`, and `or` | In RSDL this @@ -137,41 +145,110 @@ filter { The expand capability allows to specify which property can be used in `$expand` query parameter. -The format is a sequence of properties together with a description how they can be expanded. The expand capability introduces a nesting of capabilities since the type od the expandable property type can allow for select, filter, and expand. +The format is a sequence of properties that can be expanded. ```rsdl +path /orders { + GET { + expand { + items + } + } +} +``` + + The expand capability introduces a nesting of capabilities since the type of the expandable property can itself be used in select, filter, and expand. -expand { - items { - expand { - sku { - filter { id: [eq], name: [prefix] } - select: [name, description, unitPrice ] - } +```rsdl +path /orders { + GET { + expand { + items { + filter { + eq { id name } + prefix { name } + } + expand { + sku + } + } } - } + } } ``` ### Paging capabilities +The paging capability allows to specify if a request returning a collection can specify $top and $skip query parameters. + +```rsdl +path /orders { + GET { + paging + } +} +``` + +The paging capability has no parameters itself. If a service uses a different way to implement paging, please refer to the [extensibility](#extensibility) section below + +The paging capability is typically seen in a GET capability but can also be nested in an expand capability. + ### Count capabilities -### Select capabilities +The count capability allows to specify if a request returning a collection can specify $count query parameter. +```rsdl +path /orders { + GET { + count + } +} +``` + +The count capability is typically seen in a GET capability but can also be nested in an expand capability. + +### Select capabilities (DRAFT) + +The select capability allows to specify if a response contains certain properties. To be precise, it specifies the properties that are not returned in a request or response respectively. ```rsdl -select { - read-only { createdDate, lastUpdateDate, fulfillmentDate } - write-only { password attachment } +path /orders { + GET { + select { + readonly { createDate lastUpdateDate } + writeonly { password attachment } + } + } } ``` +The properties in `readonly` are written by the service (hence the readonly) and any value sent in a request is ignored.
+The properties in `writeonly` are never returned by the service (hence the writeonly) but can be used in create and update requests. + + ## Extensibility +The RSDL capabilities allow to specify custom patterns, so called traits, for the service to implement that are outside the scope of the RSDL specification. One example for these could be the handling of requests when throttling is needed, where the service responds with certain headers for requests that cross a throttling threshold. This could be a well established pattern (protocol) but is not covered in RSDL. The service implementation can read the traits and configure the right behavior based on the settings in RSDL. + +The individual traits are treated by RSDL as simple opaque (meta-) data that is passed on the the service in the form of a trait name and a list of key-value pairs. The implementation is then free to interpret the presence of the trait and the parameters as it sees fit. + +```rsdl +path /orders { + GET { + traits { + longRunningOperation + throttling { level: "premium" } + } + } +} +``` + + ## Syntax +!! NOTE: incomplete + ``` abnf path-capability = "path" path "{" [ get-capabilities ] @@ -199,5 +276,3 @@ path = "`" *( "/" identifier ) "`" ``` - -# Capabilities document diff --git a/website/src/theme/prism-rsdl.js b/website/src/theme/prism-rsdl.js index 68c96c5c..2d323d0d 100644 --- a/website/src/theme/prism-rsdl.js +++ b/website/src/theme/prism-rsdl.js @@ -5,10 +5,10 @@ Prism.languages.rsdl = { pattern: /\b(?:type|enum|service|abstract|open|key|extends|path)\b/, }, { - pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count)\b/, + pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count|select|readonly|writeonly|traits)\b/, }, { - pattern: /\b(?:eq|range|prefix|text|any)\b/, + pattern: /\b(?:eq|range|ranges|prefix|text|any)\b/, } ], 'property': [ From 49789c75abfa01eb1ed5412ac5ae94f2c1543471 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Thu, 9 Sep 2021 15:16:44 +0000 Subject: [PATCH 29/49] small formatting fixes --- .vscode/settings.json | 5 +- docs/rsdl/rapid-rsdl-capabilities.md | 95 +++++++++++++++------------- website/docusaurus.config.js | 1 + 3 files changed, 56 insertions(+), 45 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index aa1bca79..d2da9b75 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,6 +4,7 @@ "capability", "CSDL", "dotnet", + "endswith", "eset", "jetsons", "nuget", @@ -11,7 +12,9 @@ "odata", "rapid", "rsdl", - "Spacely", + "sku", + "Spacely", + "startswith", "svel", "tools", "writeonly", diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 20f9c714..6dbfcf45 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -1,20 +1,20 @@ --- id: rsdl-capabilities -title: Path Centric Service Capabilities. +title: Capabilities sidebar_label: RSDL Capabilities --- -# Path Centric Service Capabilities. +# Path Centric Service Capabilities -The previous sections go into detail how to define the format of the request and response bodies based on types and their relationships. This structure also implies which URLs are valid in the service: starting with the service properties and following properties of a structured type. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders//items` and `/orders//items/` are also a valid URLs. +The previous sections described how to define the format of the request and response bodies based on types and their relationships. These structures also imply which URL paths are valid in the service: starting with the service properties and following properties of the structured types. For example in the service below, `orders` is a service property which allows access via the `/orders` URL. Since an order has multiple order items via the `items` property, the URL `/orders//items` and `/orders//items/` are also a valid URLs. Without further constraints this would allow a huge number of URLs that a service would need to support. And it is important not just to specify which paths are allowed, but also to specify different functionality and behaviors supported for different paths. -The following sections introduce the notion of paths and descriptions of capabilities that the service provides per path. +The following sections introduce the notion of paths and capabilities that the service provides per path. ## Example service -For the following examples we assume the following type definitions for a service that has a top level orders entity set together with their (contained) order items. Each item references a SKU, that can be accessed via the top level entity set. +For the examples in the section of this document, we assume the following type definitions. This is a simplified service that provides a top level orders collection together with their (contained) order items. Each item references a SKU, that can be accessed via the top level entity set. ```rsdl type Order { @@ -49,16 +49,12 @@ service { } ``` -The amount of potential URLs that the service needs to support is large. Just to name some of the more important ones: +The amount of potential URLs that the service may support is large - in larger services potentially unbounded. Just to name a few of the more important ones: -- /skus -- /skus/{id} -- /orders -- /orders/{id} -- /orders/{id}/items -- /orders/{id}/items/{id} -- /orders/{id}/items/{id}/skus -- /orders/{id}/items/{id}/skus/{id} +``` http +/skus, /skus/{id}, /orders, /orders/{id}, /orders/{id}/items, /orders/{id}/items/{id}, +/orders/{id}/items/{id}/skus, /orders/{id}/items/{id}/skus/{id}, ... +``` The path-centric view in RSDL allows to enumerate the allowed requests and specify which query options are supported for these requests. @@ -100,18 +96,16 @@ The placeholders `...` are used to declare which query options are supported by The specific capabilities that can be used in the HTTP capabilities section instead of the `...` in the example above can vary by HTTP method. Here is an overview -| | filter | expand | paging | count | -|--------|:-------------:|:-------------:|:-------------:|:-------------:| -| GET | x | x | x | x | -| POST | x1 | x1 | x1 | x1 | -| PATCH | x1 | x1 | x1 | x1 | -| PUT | x1 | x1 | x1 | x1 | -| DELETE | x2 | | | | +| | filter | expand | paging | count | +|--------|:--------------------:|:--------------------:|:--------------------:|:--------------------:| +| GET | ✓ | ✓ | ✓ | ✓ | +| POST | ✓1 | ✓1 | ✓1 | ✓1 | +| PATCH | ✓1 | ✓1 | ✓1 | ✓1 | +| PUT | ✓1 | ✓1 | ✓1 | ✓1 | +| DELETE | ✓2 | | | | -

-[1] to shape the POST/PATCH/PUT response. Rarely used but supported
-[2] deleting multiple items. Rarely used but supported
-

+[1] to shape the POST/PATCH/PUT response. Rarely used but supported
+[2] deleting multiple items. Rarely used but supported
## Individual Query capabilities @@ -133,11 +127,15 @@ The format for filter capabilities is a sequence of pairs of a so called operato In RSDL this ```rsdl -filter { - eq { id name description createdDate fulfillmentDate } - ranges { createdDate description } - prefix { name } - text { description } +path /orders { + GET { + filter { + eq { id name description createdDate fulfillmentDate } + ranges { createdDate description } + prefix { name } + text { description } + } + } } ``` @@ -208,7 +206,7 @@ path /orders { The count capability is typically seen in a GET capability but can also be nested in an expand capability. -### Select capabilities (DRAFT) +### Select capabilities The select capability allows to specify if a response contains certain properties. To be precise, it specifies the properties that are not returned in a request or response respectively. @@ -251,25 +249,34 @@ path /orders { ``` abnf path-capability = "path" path "{" - [ get-capabilities ] - [ post-capabilities ] - [ patch-capabilities ] - [ delete-capabilities ] - "}" - -esf-capabilities = [ expand-capabilities ] [ select-capabilities ] [ filter-capabilities ] -get-capabilities = "GET" "{" [ esf-capabilities ] [ paging-capabilities ] "}" + [ get-capabilities ] + [ post-capabilities ] + [ patch-capabilities ] + [ delete-capabilities ] + "}" + +query-capabilities = [ expand-capabilities ] / + [ filter-capabilities ] / [ select-capabilities ] / + [ paging-capabilities ] / [ count-capabilities ] / + +get-capabilities = "GET" "{" [ query-capabilities ] "}" + post-capabilities = "POST" "{" "}" + patch-capabilities = "PATCH" "{" "}" + delete-capabilities = "DELETE" "{" [ filter-capabilities ] "}" -expand-capabilities = "expand" ["{" *( property-name "{" esf-capabilities "}" ) "}"] +expand-capabilities = "expand" ["{" + *( property-name "{" query-capabilities "}" ) + "}"] -filter-capabilities = "filter" ["{" *( operator-group ) [ *operator-group ] "}"] -operator-group = "eq" / "in" / "range" / "ranges" / "strings" -operator-group-filter = operator-group "{" "}" -paging-capabilities = "paging" ["{" property-name* "}"] +filter-capabilities = "filter" ["{" operator-filter "}"] +operator-filter = operator-group "{" *property-name "}" +operator-group = "eq" / "range" / "ranges" / "prefix" / "strings" / "any" +paging-capabilities = "paging" ["{" "}"] +count-capabilities = "count" ["{" "}"] property-name = identifier path = "`" *( "/" identifier ) "`" diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index fe271543..9523bd55 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -6,6 +6,7 @@ module.exports = { favicon: 'img/rest.svg', organizationName: 'oasis-open', // Usually your GitHub org/user name. projectName: 'odata-rapid', // Usually your repo name. + trailingSlash :true, themeConfig: { prism: { theme: require('prism-react-renderer/themes/oceanicNext'), From b6f1431d4381450212ec0dae8ab0b883781b5ff2 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Dec 2021 20:00:00 -0800 Subject: [PATCH 30/49] Create capability-mapping.md --- docs/rsdl/capability-mapping.md | 158 ++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/rsdl/capability-mapping.md diff --git a/docs/rsdl/capability-mapping.md b/docs/rsdl/capability-mapping.md new file mode 100644 index 00000000..35d360d5 --- /dev/null +++ b/docs/rsdl/capability-mapping.md @@ -0,0 +1,158 @@ +# capability mapping + + + +## delete + +```RSDL +path /skus/{id} { + DELETE +} +``` + +```XML + + + + + + + +``` + +## update + +```RSDL +path /skus/{id} { + PATCH { + excluded { id releaseDate } + } +} + +```XML + + + + + + + id + releaseDate + + + + + +``` + +## insert + +```RSDL +path /orders { + POST { + required { externalId } + excluded { id orderDate } + } +} +``` + +```XML + + + + + + + id + orderDate + + + + + id + orderDate + + + + + +``` + +```JSON +"$Annotations": { + "orders": { + "@Org.OData.Capabilities.V1.InsertRestrictions": { + "$Type": "Org.OData.Capabilities.V1.InsertRestrictionsType", + "Insertable": true, + "RequiredProperties": [ + "id", + "orderDate" + ], + "NonInsertableProperties": [ + "id", + "orderDate" + ] + } + } +} +``` + +## paging + +```RSDL +path /skus { + GET { + paging + } +} +``` + +```XML + + + + +``` + +## filtering + +```RSDL +path /orders { + GET { + filter { + eq { id name description createdDate fulfillmentDate } + ranges { createdDate description } + prefix { name } + text { description } + } + } +} +``` + +```JSON +"$Annotations": { + "orders": { + "@Org.OData.Capabilities.V1.FilterRestrictions": { + "$Type": "Org.OData.Capabilities.V1.FilterRestrictionsType", + "Filterable": true, + "FilterExpressionRestrictions": [ + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "id", + "AllowedExpressions": "SingleValue" + }, + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "name", + "AllowedExpressions": "SingleValue" + }, + // some FilterExpressionRestrictionType removed for readability + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "description", + "AllowedExpressions": "SearchExpression" + } + ] + } + } +``` From bf0b894e29d33ecd5eaba3f0adddebeefe53a83a Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Dec 2021 20:02:19 -0800 Subject: [PATCH 31/49] Update and rename capability-mapping.md to rapid-capability-mapping.md --- docs/rsdl/{capability-mapping.md => rapid-capability-mapping.md} | 1 + 1 file changed, 1 insertion(+) rename docs/rsdl/{capability-mapping.md => rapid-capability-mapping.md} (99%) diff --git a/docs/rsdl/capability-mapping.md b/docs/rsdl/rapid-capability-mapping.md similarity index 99% rename from docs/rsdl/capability-mapping.md rename to docs/rsdl/rapid-capability-mapping.md index 35d360d5..6ff0c571 100644 --- a/docs/rsdl/capability-mapping.md +++ b/docs/rsdl/rapid-capability-mapping.md @@ -28,6 +28,7 @@ path /skus/{id} { excluded { id releaseDate } } } +``` ```XML From dcad7a7a13c588551576c672b1d9ad191cbac913 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Dec 2021 20:04:38 -0800 Subject: [PATCH 32/49] Update and rename rapid-capability-mapping.md to rapid-rsdl-capability-mapping.md --- ...ability-mapping.md => rapid-rsdl-capability-mapping.md} | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) rename docs/rsdl/{rapid-capability-mapping.md => rapid-rsdl-capability-mapping.md} (96%) diff --git a/docs/rsdl/rapid-capability-mapping.md b/docs/rsdl/rapid-rsdl-capability-mapping.md similarity index 96% rename from docs/rsdl/rapid-capability-mapping.md rename to docs/rsdl/rapid-rsdl-capability-mapping.md index 6ff0c571..9da12e56 100644 --- a/docs/rsdl/rapid-capability-mapping.md +++ b/docs/rsdl/rapid-rsdl-capability-mapping.md @@ -1,5 +1,10 @@ -# capability mapping +--- +id: rsdl-capability-mapping +title: Capability mapping +sidebar_label: RSDL Capability mapping to CSDL +--- +# RSDL Capability mapping to CSDL ## delete From 3deaedb278be00545c6ac2bedb286edcbb116a92 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Dec 2021 21:05:49 -0800 Subject: [PATCH 33/49] adding minimal expand capability --- docs/rsdl/rapid-rsdl-capability-mapping.md | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.md b/docs/rsdl/rapid-rsdl-capability-mapping.md index 9da12e56..d3c00fb5 100644 --- a/docs/rsdl/rapid-rsdl-capability-mapping.md +++ b/docs/rsdl/rapid-rsdl-capability-mapping.md @@ -162,3 +162,39 @@ path /orders { } } ``` + + +# expansion + +```RSDL +path /orders { + GET { + expand { + items { + expand { + sku + } + } + } + } +} +``` + +```XML + + + + + + + + + + + + + + + +``` + From e55240172ad4a2839a8ef90ab2c6cc2995cf189e Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Wed, 8 Dec 2021 21:17:01 -0800 Subject: [PATCH 34/49] Update rapid-rsdl-capability-mapping.md --- docs/rsdl/rapid-rsdl-capability-mapping.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.md b/docs/rsdl/rapid-rsdl-capability-mapping.md index d3c00fb5..6b806125 100644 --- a/docs/rsdl/rapid-rsdl-capability-mapping.md +++ b/docs/rsdl/rapid-rsdl-capability-mapping.md @@ -135,7 +135,7 @@ path /orders { } ``` -```JSON +```javascript "$Annotations": { "orders": { "@Org.OData.Capabilities.V1.FilterRestrictions": { From 68ad6db0d9ed1044ce819bff7991019f34a15fd2 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Thu, 9 Dec 2021 06:47:43 -0800 Subject: [PATCH 35/49] Rename rapid-rsdl-capability-mapping.md to mapping.md --- docs/rsdl/{rapid-rsdl-capability-mapping.md => mapping.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/rsdl/{rapid-rsdl-capability-mapping.md => mapping.md} (100%) diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.md b/docs/rsdl/mapping.md similarity index 100% rename from docs/rsdl/rapid-rsdl-capability-mapping.md rename to docs/rsdl/mapping.md From 471331d5c6f71a2b7de461094d50da7de9700573 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Thu, 9 Dec 2021 15:29:50 +0000 Subject: [PATCH 36/49] adding capability semantics --- .vscode/settings.json | 1 + docs/rsdl/mapping.md | 18 +- docs/rsdl/rapid-rsdl-authorization.md | 71 +++++++ docs/rsdl/rapid-rsdl-capabilities.md | 118 ++++++++--- docs/rsdl/rapid-rsdl-capability-mapping.mdx | 221 ++++++++++++++++++++ website/package.json | 2 +- website/sidebars.js | 1 + website/src/theme/prism-rsdl.js | 21 +- 8 files changed, 404 insertions(+), 49 deletions(-) create mode 100644 docs/rsdl/rapid-rsdl-authorization.md create mode 100644 docs/rsdl/rapid-rsdl-capability-mapping.mdx diff --git a/.vscode/settings.json b/.vscode/settings.json index d2da9b75..af355459 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,6 +6,7 @@ "dotnet", "endswith", "eset", + "Insertable", "jetsons", "nuget", "nupkg", diff --git a/docs/rsdl/mapping.md b/docs/rsdl/mapping.md index 6b806125..9bd07ad6 100644 --- a/docs/rsdl/mapping.md +++ b/docs/rsdl/mapping.md @@ -1,8 +1,4 @@ ---- -id: rsdl-capability-mapping -title: Capability mapping -sidebar_label: RSDL Capability mapping to CSDL ---- + # RSDL Capability mapping to CSDL @@ -122,6 +118,18 @@ path /skus { ## filtering +FilterExpressionRestrictions is a list of FilterExpressionRestrictionType, that in itself is a pair of a property name one of the literal values : + +| value | description | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| SingleValue | Property can be used in a single `eq` clause | +| MultiValue | Property can be used in multiple `eq` and `in` clauses, combined by `or` (which is logically equivalent to a single `in` clause) | +| SingleRange | Property can be used in at most one `ge` and/or one `le` clause, separated by `and` | +| MultiRange | Property can be compared to a union of one or more closed, half-open, or open intervals"
The filter expression for this property consists of one or more interval expressions combined by `or`. A single interval expression is either a single comparison of the property and a literal value with `eq`, `le`, `lt`, `ge`, or `gt`, or pair of boundaries combined by `and` and enclosed in parentheses. The lower boundary is either `ge` or `gt`, the upper boundary either `le` or `lt`. | +| SearchExpression | String property can be used as first operand in `startswith`, `endswith`, and `contains` clauses" | +| MultiRangeOrSearchExpression | Property can be compared to a union of zero or more closed, half-open, or open intervals plus zero or more simple string patterns"
The filter expression for this property consists of one or more interval expressions or string comparison functions combined by `or`. See MultiRange for a definition of an interval expression. See SearchExpression for the allowed string comparison functions. | + + ```RSDL path /orders { GET { diff --git a/docs/rsdl/rapid-rsdl-authorization.md b/docs/rsdl/rapid-rsdl-authorization.md new file mode 100644 index 00000000..a61b4975 --- /dev/null +++ b/docs/rsdl/rapid-rsdl-authorization.md @@ -0,0 +1,71 @@ +--- +id: rsdl-security +title: RSDL Security Requirements +sidebar_label: Security Requirements +--- + +# Path Centric Service Authorization + +The previous section (RSDL Capabilities)[rsdl-capabilitites] describes how capabilities can be specified on a per path basis. In a similar way we need to be able to specify the authorization requirements for each allowed path. + +The syntax to specify the authorization requirements is similar to the capabilities. +For a given path and HTTP ver it list the requirements + +``` rsdl +path /orders { + GET { + security { + authorization { + + } + } + } + POST { + security { + authorization { + + } + } + } +} + +``` + +## Syntax + +!! NOTE: incomplete + +``` abnf +path-capability = "path" path "{" + [ get-capabilities ] + [ post-capabilities ] + [ patch-capabilities ] + [ delete-capabilities ] + "}" + +query-capabilities = [ expand-capabilities ] / + [ filter-capabilities ] / [ select-capabilities ] / + [ paging-capabilities ] / [ count-capabilities ] / + +get-capabilities = "GET" "{" [ query-capabilities ] [ security-capabilities ] "}" + +post-capabilities = "POST" "{" [ security-capabilities ] "}" + +patch-capabilities = "PATCH" "{"[ security-capabilities ] "}" + +delete-capabilities = "DELETE" "{" [ filter-capabilities ] [ security-capabilities ] "}" + +expand-capabilities = "security" "{" + "scopes" ":" security-scopes + "authorization" ":" authorization + "}" + +security-scopes = "security" "{" + +authorization = + +security-capabilities = "GET" "{" [ query-capabilities ] "}" + + +``` + diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 6dbfcf45..c74e047e 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -1,7 +1,7 @@ --- id: rsdl-capabilities title: Capabilities -sidebar_label: RSDL Capabilities +sidebar_label: RSDL API Capabilities --- # Path Centric Service Capabilities @@ -61,7 +61,7 @@ The path-centric view in RSDL allows to enumerate the allowed requests and speci ## HTTP capabilities The first level of the above mentioned capabilities is to specify the path of theURL and the HTTP method, Here is a partial RSDL to demonstrate this. -```rsdl +``` rsdl path /orders { GET { ... } POST { ... } @@ -102,10 +102,11 @@ The specific capabilities that can be used in the HTTP capabilities section inst | POST | ✓1 | ✓1 | ✓1 | ✓1 | | PATCH | ✓1 | ✓1 | ✓1 | ✓1 | | PUT | ✓1 | ✓1 | ✓1 | ✓1 | -| DELETE | ✓2 | | | | +| DELETE | | | | | [1] to shape the POST/PATCH/PUT response. Rarely used but supported
[2] deleting multiple items. Rarely used but supported
+[!!TODO: check if filter segment on delete is allowed in RAPID ] ## Individual Query capabilities @@ -135,6 +136,13 @@ path /orders { prefix { name } text { description } } + + filter { + eq except { description } + ranges { createdDate description } + prefix { name } + text { description } + } } } ``` @@ -158,23 +166,57 @@ path /orders { The expand capability introduces a nesting of capabilities since the type of the expandable property can itself be used in select, filter, and expand. ```rsdl + + +type Order { + +} + +capability Order defaultOrder { + filter { + eq { id name } + prefix { nam description } + range { createdDateTime } + } + expand { + items { + filter { + eq { id name } + prefix { name } + } + expand { + sku + } + } + } + paging + count +} + +capability Order limitedOrder { + filter { + eq { id name } + } +} + path /orders { GET { - expand { - items { - filter { - eq { id name } - prefix { name } - } - expand { - sku - } - } - } + defaultOrder + } +} + +path /customers/{id}/orders { + GET { + limitedOrder } } ``` +- `/order?$expand=items` +- `/order?$expand=items(expand=sku)` +- `/order?$expand=items(expand=sku; filter=id eq '100')` +- `/order?$expand=items(select=id; expand=sku; filter=id eq '100')` + ### Paging capabilities @@ -204,45 +246,55 @@ path /orders { } ``` -The count capability is typically seen in a GET capability but can also be nested in an expand capability. +## Extensibility + +The RSDL API capabilities allow to specify custom capabilities, so called traits, for the service to implement that are outside the scope of the patterns known by the RSDL specification. -### Select capabilities +One example for these could be the handling of requests when throttling is needed, where the service responds with certain headers for requests that cross a throttling threshold. There are multiple established pattern (protocol) to implement this but it is not covered in RSDL directly. But it can be specified in RSDL as an extension and the service implementation can read it and configure the right behavior based on the traits in RSDL. -The select capability allows to specify if a response contains certain properties. To be precise, it specifies the properties that are not returned in a request or response respectively. +The individual trait is treated as simple opaque (meta-) data that is passed on the service in the form of a trait name and a list of key-value pairs. The implementation is then free to interpret the presence of the trait and the parameters as it sees fit. ```rsdl path /orders { GET { - select { - readonly { createDate lastUpdateDate } - writeonly { password attachment } + traits { + longRunningOperation + topWithoutSkip + throttling { level: "premium\u12a4" } } } } ``` -The properties in `readonly` are written by the service (hence the readonly) and any value sent in a request is ignored.
-The properties in `writeonly` are never returned by the service (hence the writeonly) but can be used in create and update requests. +## Other path based characteristics -## Extensibility - -The RSDL capabilities allow to specify custom patterns, so called traits, for the service to implement that are outside the scope of the RSDL specification. One example for these could be the handling of requests when throttling is needed, where the service responds with certain headers for requests that cross a throttling threshold. This could be a well established pattern (protocol) but is not covered in RSDL. The service implementation can read the traits and configure the right behavior based on the settings in RSDL. +```rsdl +path /user/{id}/recentOrders { + # references an Order contained in /orders + targets: /orders + targets: unbound + # 'targets' ':' ( path / 'unbound' ) -The individual traits are treated by RSDL as simple opaque (meta-) data that is passed on the the service in the form of a trait name and a list of key-value pairs. The implementation is then free to interpret the presence of the trait and the parameters as it sees fit. + GET { } +} -```rsdl path /orders { - GET { - traits { - longRunningOperation - throttling { level: "premium" } - } - } + # top level entity set + GET { } + +} + +path /orders/{id}/items { + # containment navigation (informally an entity set) + GET { } + } ``` + + ## Syntax !! NOTE: incomplete diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.mdx b/docs/rsdl/rapid-rsdl-capability-mapping.mdx new file mode 100644 index 00000000..3105ce46 --- /dev/null +++ b/docs/rsdl/rapid-rsdl-capability-mapping.mdx @@ -0,0 +1,221 @@ +--- +id: rsdl-capability-mapping +title: Capability semantics +sidebar_label: RSDL API Capability semantics +--- + +> DRAFT +> Initial Draft. Dec 2021 + +Mapping RSDL capabilities to CSDL annotations + +## Delete + +```rsdl +path /skus/{id} { + DELETE +} +``` + +```xml + + + + + + + +``` + +## Update + +```rsdl +path /skus/{id} { + PATCH { + excluded { id releaseDate } + } +} +``` + +```xml + + + + + + + id + releaseDate + + + + + +``` + +## Insert + +```rsdl +path /orders { + POST { + required { externalId } + excluded { id orderDate } + } +} +``` + +```json +{ + "$Annotations": { + "orders": { + "@Org.OData.Capabilities.V1.InsertRestrictions": { + "$Type": "Org.OData.Capabilities.V1.InsertRestrictionsType", + "Insertable": true, + "RequiredProperties": ["id", "orderDate"], + "NonInsertableProperties": ["id", "orderDate"] + } + } + } +} +``` + +```xml + + + + + + + id + orderDate + + + + + id + orderDate + + + + + +``` + +## Paging + +```rsdl +path /skus { + GET { + paging + } +} +``` + +```xml + + + + +``` + +## Filtering + +```rsdl +path /orders { + GET { + filter { + eq { id name description createdDate fulfillmentDate } + ranges { createdDate description } + prefix { name } + text { description } + } + } +} +``` + +```json +"$Annotations": { + "orders": { + "@Org.OData.Capabilities.V1.FilterRestrictions": { + "$Type": "Org.OData.Capabilities.V1.FilterRestrictionsType", + "Filterable": true, + "FilterExpressionRestrictions": [ + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "id", + "AllowedExpressions": "SingleValue" + }, + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "name", + "AllowedExpressions": "SingleValue" + }, + // some FilterExpressionRestrictionType removed for readability + { + "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", + "Property": "description", + "AllowedExpressions": "SearchExpression" + } + ] + } + } +``` + +### Filter restrictions + +The RSDL filter restriction is a simplified version of the EDM filter restrictions. +Instead of listing each pair of property/filter-restrictions, properties are group together by filter restriction. +e.g. `eq { a b } prefix { c }` in rsdl is represented in CSDL as a "flattend" list of pairs `eq: a, eq: b, prefix: c` + +The keywords for the filter restrictions are also simplified: + +| RSDL | CSDL | | +| :------: | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `eq` | `SingleValue` | Compare a property and a constant value with the eq operator | +| `in` | `MultiValue` | Compare a property with the in operator and a set of constant values | +| `range` | `SingleRange` | Compare a property with the open interval (i.e. `a < p and p < b`) where a and b are constants and p is the property. the `<` can be any of the comparison operators `<`, `<=`, `>`, `>=` | +| `ranges` | `MultiRange` | One of more `range` expressions combined by or | +| `prefix` | a specialization of `SearchExpression` | Compare a property with a constant using the startsWith function | +| `text` | `SearchExpression` | Compare a property with a constant using any of the string comparison functions startsWith, contains, endsWith | +| -/- | `MultiRangeOrSearchExpression` | | +| `any` | no restrictions | Any combination of the above using `and`, `or`, and `not` and any of the built-in functions | + +## Expansion + +```rsdl +path /orders { + GET { + expand { + items { + expand { + sku + } + } + } + } +} +``` + +```xml + + + + + + + + + + + + + + + +``` + +## References + +- [OData Capability Vocabulary](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Capabilities.V1.md) + +- [Filter Restrictions](https://github.com/oasis-tcs/odata-vocabularies/blob/main/vocabularies/Org.OData.Capabilities.V1.xml#L410:~:text=%3CTerm%20Name=%22-,FilterRestrictions,-%22) diff --git a/website/package.json b/website/package.json index 9da6358c..316772f6 100644 --- a/website/package.json +++ b/website/package.json @@ -32,4 +32,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/website/sidebars.js b/website/sidebars.js index 23fc5e03..45f009b7 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -27,6 +27,7 @@ module.exports = { 'rsdl/rsdl-capabilities', 'rsdl/rsdl-semantics', 'rsdl/rsdl-abnf', + 'rsdl/rsdl-capability-mapping' ] }, { diff --git a/website/src/theme/prism-rsdl.js b/website/src/theme/prism-rsdl.js index 2d323d0d..fb50add7 100644 --- a/website/src/theme/prism-rsdl.js +++ b/website/src/theme/prism-rsdl.js @@ -2,23 +2,24 @@ Prism.languages.rsdl = { 'keyword': [ { - pattern: /\b(?:type|enum|service|abstract|open|key|extends|path)\b/, + pattern: /\b(?:type|enum|service|abstract|open|key|extends|path|capability)\b/ }, { - pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count|select|readonly|writeonly|traits)\b/, + pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count|select|readonly|writeonly|traits)\b/ }, { - pattern: /\b(?:eq|range|ranges|prefix|text|any)\b/, + pattern: /\b(?:except|eq|range|ranges|prefix|text|any)\b/ + }, + { + pattern: /\b(?:selectoptions)\b/ } ], - 'property': [ - /[-\w\.]+(?=\s*=(?!=))/, - /"(?:\\[\s\S]|[^\\"])+"(?=\s*[:=])/, - ], + 'string': [ { - pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, - greedy: true, + // pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, + pattern: /(?:"(?:[^"\\]|\\["\\\/bfnrt]|\\u[0-9A-Fa-f]{4})*")/, // javascript strings https://www.json.org/json-en.html + greedy: true } ], 'description': { @@ -42,6 +43,6 @@ Prism.languages.rsdl = { }, 'number': /\b0x[\da-f]+\b|\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i, 'boolean': /\b(?:true|false)\b/i, - 'punctuation': /[\[\]{}:]/, + 'punctuation': /[\[\]{}():]/, 'symbol': /[=]/, }; \ No newline at end of file From 068e90504ba172b09e2f239f09828d8a4ce06d83 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Thu, 9 Dec 2021 16:00:11 +0000 Subject: [PATCH 37/49] fix browser only setting --- .../InteractiveQuerying.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/website/src/components/documentation-queries/InteractiveQuerying.js b/website/src/components/documentation-queries/InteractiveQuerying.js index 2a180574..bd95ae58 100644 --- a/website/src/components/documentation-queries/InteractiveQuerying.js +++ b/website/src/components/documentation-queries/InteractiveQuerying.js @@ -5,8 +5,32 @@ import 'bootstrap/dist/css/bootstrap.min.css'; import './InteractiveQuerying.css'; import {Component} from 'react'; import CodeBlock from "@theme/CodeBlock"; +import BrowserOnly from '@docusaurus/BrowserOnly'; import { initUrlEditor } from "odata-uri-editor"; +/// +/// Tool to allow a user to make a query on the Jetsons API and see the results +/// that is safe for deployment online. +/// +/// Default query to start with filled in. +/// +/// ID to identify a specific component instance - must be unique; +/// otherwise, setting the default query can impact other instances. +/// +/// +/// ID is required to isolate a specific InteractiveQuerying instance for the default query. +/// +const InteractiveQuerying = (props) => { + return ( + + {() => { + const initUrlEditor = require("odata-uri-editor").initUrlEditor; + return ; + }} + + ) +} + /// Tool to allow a user to make a query on the Jetsons API and see the results. /// Default query to start with filled in. /// From 230b808eca1cb2fe4000aa4fd267ab228b4e52cf Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Fri, 10 Dec 2021 18:29:27 +0000 Subject: [PATCH 38/49] fix build --- website/package.json | 2 +- website/sidebars.js | 2 +- .../documentation-queries/InteractiveQuerying.js | 1 - website/src/theme/prism-rsdl.js | 11 ++++------- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/website/package.json b/website/package.json index 153cfdb1..fdb3b8ee 100644 --- a/website/package.json +++ b/website/package.json @@ -33,4 +33,4 @@ "last 1 safari version" ] } -} +} \ No newline at end of file diff --git a/website/sidebars.js b/website/sidebars.js index 45f009b7..5252ee33 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -24,9 +24,9 @@ module.exports = { label: 'RAPID Schema Definition Language (RSDL)', items: [ 'rsdl/rsdl-intro', - 'rsdl/rsdl-capabilities', 'rsdl/rsdl-semantics', 'rsdl/rsdl-abnf', + 'rsdl/rsdl-capabilities', 'rsdl/rsdl-capability-mapping' ] }, diff --git a/website/src/components/documentation-queries/InteractiveQuerying.js b/website/src/components/documentation-queries/InteractiveQuerying.js index bd95ae58..84647e51 100644 --- a/website/src/components/documentation-queries/InteractiveQuerying.js +++ b/website/src/components/documentation-queries/InteractiveQuerying.js @@ -6,7 +6,6 @@ import './InteractiveQuerying.css'; import {Component} from 'react'; import CodeBlock from "@theme/CodeBlock"; import BrowserOnly from '@docusaurus/BrowserOnly'; -import { initUrlEditor } from "odata-uri-editor"; /// /// Tool to allow a user to make a query on the Jetsons API and see the results diff --git a/website/src/theme/prism-rsdl.js b/website/src/theme/prism-rsdl.js index fb50add7..b636d5cc 100644 --- a/website/src/theme/prism-rsdl.js +++ b/website/src/theme/prism-rsdl.js @@ -5,20 +5,17 @@ Prism.languages.rsdl = { pattern: /\b(?:type|enum|service|abstract|open|key|extends|path|capability)\b/ }, { - pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count|select|readonly|writeonly|traits)\b/ + pattern: /\b(?:GET|POST|PATCH|DELETE|expand|filter|paging|count|required|excluded|traits)\b/ }, { - pattern: /\b(?:except|eq|range|ranges|prefix|text|any)\b/ - }, - { - pattern: /\b(?:selectoptions)\b/ + pattern: /\b(?:eq|range|ranges|prefix|text|any)\b/ } ], 'string': [ { - // pattern: /"""[ \t]*[\r\n](?:(?:"|"")?(?:\\.|[^"\\]))*"""/, - pattern: /(?:"(?:[^"\\]|\\["\\\/bfnrt]|\\u[0-9A-Fa-f]{4})*")/, // javascript strings https://www.json.org/json-en.html + // javascript strings https://www.json.org/json-en.html + pattern: /(?:"(?:[^"\\]|\\["\\\/bfnrt]|\\u[0-9A-Fa-f]{4})*")/, greedy: true } ], From d0bc868f099982c3cef6c17f0dcec8ebff336a50 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Fri, 10 Dec 2021 18:30:30 +0000 Subject: [PATCH 39/49] deleted obsolete files from branch --- docs/rsdl/mapping.md | 208 -------------------------- docs/rsdl/rapid-rsdl-authorization.md | 71 --------- 2 files changed, 279 deletions(-) delete mode 100644 docs/rsdl/mapping.md delete mode 100644 docs/rsdl/rapid-rsdl-authorization.md diff --git a/docs/rsdl/mapping.md b/docs/rsdl/mapping.md deleted file mode 100644 index 9bd07ad6..00000000 --- a/docs/rsdl/mapping.md +++ /dev/null @@ -1,208 +0,0 @@ - - -# RSDL Capability mapping to CSDL - - -## delete - -```RSDL -path /skus/{id} { - DELETE -} -``` - -```XML - - - - - - - -``` - -## update - -```RSDL -path /skus/{id} { - PATCH { - excluded { id releaseDate } - } -} -``` - -```XML - - - - - - - id - releaseDate - - - - - -``` - -## insert - -```RSDL -path /orders { - POST { - required { externalId } - excluded { id orderDate } - } -} -``` - -```XML - - - - - - - id - orderDate - - - - - id - orderDate - - - - - -``` - -```JSON -"$Annotations": { - "orders": { - "@Org.OData.Capabilities.V1.InsertRestrictions": { - "$Type": "Org.OData.Capabilities.V1.InsertRestrictionsType", - "Insertable": true, - "RequiredProperties": [ - "id", - "orderDate" - ], - "NonInsertableProperties": [ - "id", - "orderDate" - ] - } - } -} -``` - -## paging - -```RSDL -path /skus { - GET { - paging - } -} -``` - -```XML - - - - -``` - -## filtering - -FilterExpressionRestrictions is a list of FilterExpressionRestrictionType, that in itself is a pair of a property name one of the literal values : - -| value | description | -| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| SingleValue | Property can be used in a single `eq` clause | -| MultiValue | Property can be used in multiple `eq` and `in` clauses, combined by `or` (which is logically equivalent to a single `in` clause) | -| SingleRange | Property can be used in at most one `ge` and/or one `le` clause, separated by `and` | -| MultiRange | Property can be compared to a union of one or more closed, half-open, or open intervals"
The filter expression for this property consists of one or more interval expressions combined by `or`. A single interval expression is either a single comparison of the property and a literal value with `eq`, `le`, `lt`, `ge`, or `gt`, or pair of boundaries combined by `and` and enclosed in parentheses. The lower boundary is either `ge` or `gt`, the upper boundary either `le` or `lt`. | -| SearchExpression | String property can be used as first operand in `startswith`, `endswith`, and `contains` clauses" | -| MultiRangeOrSearchExpression | Property can be compared to a union of zero or more closed, half-open, or open intervals plus zero or more simple string patterns"
The filter expression for this property consists of one or more interval expressions or string comparison functions combined by `or`. See MultiRange for a definition of an interval expression. See SearchExpression for the allowed string comparison functions. | - - -```RSDL -path /orders { - GET { - filter { - eq { id name description createdDate fulfillmentDate } - ranges { createdDate description } - prefix { name } - text { description } - } - } -} -``` - -```javascript -"$Annotations": { - "orders": { - "@Org.OData.Capabilities.V1.FilterRestrictions": { - "$Type": "Org.OData.Capabilities.V1.FilterRestrictionsType", - "Filterable": true, - "FilterExpressionRestrictions": [ - { - "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", - "Property": "id", - "AllowedExpressions": "SingleValue" - }, - { - "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", - "Property": "name", - "AllowedExpressions": "SingleValue" - }, - // some FilterExpressionRestrictionType removed for readability - { - "$Type": "Org.OData.Capabilities.V1.FilterExpressionRestrictionType", - "Property": "description", - "AllowedExpressions": "SearchExpression" - } - ] - } - } -``` - - -# expansion - -```RSDL -path /orders { - GET { - expand { - items { - expand { - sku - } - } - } - } -} -``` - -```XML - - - - - - - - - - - - - - - -``` - diff --git a/docs/rsdl/rapid-rsdl-authorization.md b/docs/rsdl/rapid-rsdl-authorization.md deleted file mode 100644 index a61b4975..00000000 --- a/docs/rsdl/rapid-rsdl-authorization.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -id: rsdl-security -title: RSDL Security Requirements -sidebar_label: Security Requirements ---- - -# Path Centric Service Authorization - -The previous section (RSDL Capabilities)[rsdl-capabilitites] describes how capabilities can be specified on a per path basis. In a similar way we need to be able to specify the authorization requirements for each allowed path. - -The syntax to specify the authorization requirements is similar to the capabilities. -For a given path and HTTP ver it list the requirements - -``` rsdl -path /orders { - GET { - security { - authorization { - - } - } - } - POST { - security { - authorization { - - } - } - } -} - -``` - -## Syntax - -!! NOTE: incomplete - -``` abnf -path-capability = "path" path "{" - [ get-capabilities ] - [ post-capabilities ] - [ patch-capabilities ] - [ delete-capabilities ] - "}" - -query-capabilities = [ expand-capabilities ] / - [ filter-capabilities ] / [ select-capabilities ] / - [ paging-capabilities ] / [ count-capabilities ] / - -get-capabilities = "GET" "{" [ query-capabilities ] [ security-capabilities ] "}" - -post-capabilities = "POST" "{" [ security-capabilities ] "}" - -patch-capabilities = "PATCH" "{"[ security-capabilities ] "}" - -delete-capabilities = "DELETE" "{" [ filter-capabilities ] [ security-capabilities ] "}" - -expand-capabilities = "security" "{" - "scopes" ":" security-scopes - "authorization" ":" authorization - "}" - -security-scopes = "security" "{" - -authorization = - -security-capabilities = "GET" "{" [ query-capabilities ] "}" - - -``` - From 1fd839c6ae0ffbeaee7500d826c05c6ea226263b Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Fri, 10 Dec 2021 18:33:33 +0000 Subject: [PATCH 40/49] fix markdown rendering for json --- docs/rsdl/rapid-rsdl-capability-mapping.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.mdx b/docs/rsdl/rapid-rsdl-capability-mapping.mdx index 3105ce46..74f6d0ba 100644 --- a/docs/rsdl/rapid-rsdl-capability-mapping.mdx +++ b/docs/rsdl/rapid-rsdl-capability-mapping.mdx @@ -133,7 +133,7 @@ path /orders { } ``` -```json +```javascript "$Annotations": { "orders": { "@Org.OData.Capabilities.V1.FilterRestrictions": { From f7db280db10059f03d42510c430aefc870e810ba Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:39:38 -0800 Subject: [PATCH 41/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index c74e047e..3168a191 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -59,7 +59,7 @@ The amount of potential URLs that the service may support is large - in larger s The path-centric view in RSDL allows to enumerate the allowed requests and specify which query options are supported for these requests. ## HTTP capabilities -The first level of the above mentioned capabilities is to specify the path of theURL and the HTTP method, Here is a partial RSDL to demonstrate this. +The first level of the above mentioned capabilities is to specify the path of the URL and the HTTP method, Here is a partial RSDL to demonstrate this. ``` rsdl path /orders { From 21363c02f7db024e08b2f17462eb28620563f7e6 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:39:44 -0800 Subject: [PATCH 42/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 3168a191..603f4b5b 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -32,7 +32,7 @@ enum OrderStatus { type OrderItem { key id: String - sku: *SKU + sku: SKU amount: Integer } From 2d99e3465bf018f685d46b342abc66f91c69ba53 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:40:17 -0800 Subject: [PATCH 43/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 603f4b5b..2b2d54d5 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -88,7 +88,7 @@ path /skus { } ``` -The effect of this is that for each declared `path` declaration and HTTP method the service is expected to return data, data in the form as specified by the corresponding type. The service is free to respond with success messages for other combinations but the service guarantees to work for the ones listed. +The effect of this is that for each declared `path` and HTTP method the service is expected to return data, in the form specified by the corresponding type. The service is free to respond with success messages for other combinations but the service guarantees to work for the ones listed. Important to notice is that the path after the `path` keyword are not literal paths but sort of templates. Many of the interesting paths in a REST service have path segments that are entity ids. this is indicated via the `{id}` syntax. the `id` in there is exactly the name of the key. From fe933767295a9084fbd6f4ba48a25b4163048984 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:40:45 -0800 Subject: [PATCH 44/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 2b2d54d5..187c8b36 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -90,7 +90,7 @@ path /skus { ``` The effect of this is that for each declared `path` and HTTP method the service is expected to return data, in the form specified by the corresponding type. The service is free to respond with success messages for other combinations but the service guarantees to work for the ones listed. -Important to notice is that the path after the `path` keyword are not literal paths but sort of templates. Many of the interesting paths in a REST service have path segments that are entity ids. this is indicated via the `{id}` syntax. the `id` in there is exactly the name of the key. +Important to notice is that the paths after the `path` keyword are not literal paths but sort of templates. Many of the interesting paths in a REST service have path segments that are entity ids. This is indicated via the `{id}` syntax: the `id` in there is exactly the name of the key property. The placeholders `...` are used to declare which query options are supported by the service. For example a GET capability lists that certain $filter options are allowed or that paging is supported via the $top, $skip options. More details in the next sections. From cf7d3454655f6ed163acce587123f12849cb1e92 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:41:25 -0800 Subject: [PATCH 45/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 187c8b36..f0ad3420 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -112,7 +112,7 @@ The specific capabilities that can be used in the HTTP capabilities section inst ### Filter capabilities -The filter capability allows to specify which property can be used in which filter expression. There is a vast amount of possible filter expressions (see [odata abnf](https://github.com/oasis-tcs/odata-abnf/blob/main/abnf/odata-abnf-construction-rules.txt#L502)). Therefore, the filter capabilities allow to specify a few well-known but restrictive expressions or allow any expression. +The filter capability allows to specify which property can be used in which filter expression. There is a vast amount of possible filter expressions (see [OData System Query Option `$filter`](https://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-protocol.html#sec_SystemQueryOptionfilter)). Therefore, the filter capabilities allow to specify a few well-known but restrictive expressions or allow any expression. The format for filter capabilities is a sequence of pairs of a so called operator group and a list of property names. An operator group is constraining the form of the expression allowed in the $filter system query option. From 24cc57f8aaf46051a4738b8ac3229e557b62e30e Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:42:18 -0800 Subject: [PATCH 46/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index f0ad3420..1c5272a8 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -149,7 +149,7 @@ path /orders { ### Expand capabilities -The expand capability allows to specify which property can be used in `$expand` query parameter. +The expand capability allows to specify which properties can be used in `$expand` query parameter. The format is a sequence of properties that can be expanded. From 2d00eb682369152e97b6f074302565dfd2a455c6 Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:42:31 -0800 Subject: [PATCH 47/49] Update docs/rsdl/rapid-rsdl-capabilities.md Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capabilities.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capabilities.md b/docs/rsdl/rapid-rsdl-capabilities.md index 1c5272a8..9ece70a6 100644 --- a/docs/rsdl/rapid-rsdl-capabilities.md +++ b/docs/rsdl/rapid-rsdl-capabilities.md @@ -317,7 +317,7 @@ post-capabilities = "POST" "{" "}" patch-capabilities = "PATCH" "{" "}" -delete-capabilities = "DELETE" "{" [ filter-capabilities ] "}" +delete-capabilities = "DELETE" "{" "}" expand-capabilities = "expand" ["{" *( property-name "{" query-capabilities "}" ) From d8ec19eb403db93a4436e5156af56506619841ab Mon Sep 17 00:00:00 2001 From: Christof Sprenger <53094940+chrisspre@users.noreply.github.com> Date: Mon, 13 Dec 2021 09:45:16 -0800 Subject: [PATCH 48/49] Update docs/rsdl/rapid-rsdl-capability-mapping.mdx Co-authored-by: Ralf Handl --- docs/rsdl/rapid-rsdl-capability-mapping.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/rsdl/rapid-rsdl-capability-mapping.mdx b/docs/rsdl/rapid-rsdl-capability-mapping.mdx index 74f6d0ba..b43ca13e 100644 --- a/docs/rsdl/rapid-rsdl-capability-mapping.mdx +++ b/docs/rsdl/rapid-rsdl-capability-mapping.mdx @@ -70,7 +70,6 @@ path /orders { "orders": { "@Org.OData.Capabilities.V1.InsertRestrictions": { "$Type": "Org.OData.Capabilities.V1.InsertRestrictionsType", - "Insertable": true, "RequiredProperties": ["id", "orderDate"], "NonInsertableProperties": ["id", "orderDate"] } From ee52f4745406d79ae854b272967f962777fe6fa3 Mon Sep 17 00:00:00 2001 From: Ralf Handl Date: Thu, 30 Jun 2022 17:39:22 +0200 Subject: [PATCH 49/49] Fixed broken links --- docs/rsdl/rapid-rsdl-semantics.mdx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/rsdl/rapid-rsdl-semantics.mdx b/docs/rsdl/rapid-rsdl-semantics.mdx index c13cd00d..5938f426 100644 --- a/docs/rsdl/rapid-rsdl-semantics.mdx +++ b/docs/rsdl/rapid-rsdl-semantics.mdx @@ -4,19 +4,19 @@ title: RSDL Semantics --- > DRAFT -> Initial Draft. July 2020 +> Initial Draft. June 2022 The semantic of RSDL (RAPID Schema Definition Language) can be described by mapping -syntactical constructs described in [rapid-rsdl-abnf](rsdl-abnf) to equivalent runtime [Service Definition](../spec/rapid-pro-resource_description.md) constructs. +syntactical constructs described in [RSDL ABNF](../rsdl-abnf) to equivalent runtime [Service Definition](../spec/rapid-pro-resource_description.md) constructs. -Please refer to [rapid-rsdl-abnf](./rsdl-abnf) for the syntactical constructs of RSDL. +Please refer to [RSDL ABNF](../rsdl-abnf) for the syntactical constructs of RSDL. import Tabs from "@theme/Tabs"; import TabItem from "@theme/TabItem"; ## Model -A [model](rsdl-abnf#model) is mapped to a CSDL Schema named "Model", that has an entity container named "Service". +A [model](../rsdl-abnf#model) is mapped to a CSDL Schema named "Model", that has an entity container named "Service". The model's -[service](rsdl-abnf#service), -[structured types](rsdl-abnf#structured-type), and -[enumeration types](rsdl-abnf#enumeration-type) are mapped to the respective constructs below and added to the schema (or container respectively) +[service](../rsdl-abnf#service), +[structured types](../rsdl-abnf#structured-type), and +[enumeration types](../rsdl-abnf#enumeration-type) are mapped to the respective constructs below and added to the schema (or container respectively) ## Structured Types -A [structured type](rsdl-abnf#structured-type) is mapped to either +A [structured type](../rsdl-abnf#structured-type) is mapped to either an [entity type](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_EntityType) or a [complex type](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_ComplexType) when converting from RSDL to CSDL. @@ -296,7 +296,7 @@ type Company { The type of a property is one of: -- the built-in types defined in the [`builtInType`](rsdl-abnf/#structured-type) syntax rule +- the built-in types defined in the [`builtInType`](../rsdl-abnf/#structured-type) syntax rule - the primitive EDM types listed in [OData CSDL JSON Representation](http://docs.oasis-open.org/odata/odata-csdl-json/v4.01/odata-csdl-json-v4.01.html#sec_PrimitiveTypes) and [OData CSDL XML Representation](http://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_PrimitiveTypes) - the structured or enumeration types defined in the model @@ -525,7 +525,7 @@ type Employee { ## Enumeration Types -An [Enumeration Type](rsdl-abnf#enumeration-type) is mapped to a CSDL EnumType. The enumeration members' values are automatically assigned. +An [Enumeration Type](../rsdl-abnf#enumeration-type) is mapped to a CSDL EnumType. The enumeration members' values are automatically assigned. ```json enum employmentType { salaried hourly } @@ -564,7 +564,7 @@ enum employmentType { salaried hourly } ## Flag Types -A [Flags Type](rsdl-abnf#enumeration-type), i.e an enumeration that starts with the keyword flags, is mapped to an CSDL EnumType with the `IsFlags` property set to `true`. +A [Flags Type](../rsdl-abnf#enumeration-type), i.e an enumeration that starts with the keyword flags, is mapped to an CSDL EnumType with the `IsFlags` property set to `true`. The members' values are automatically assigned to powers of 2. ```json