Skip to main content

RSDL Semantics

DRAFT Initial Draft. July 2020

The semantic of RSDL (RAPID Schema Definition Language) can be described by mapping syntactical constructs described in rapid-rsdl-abnf to equivalent runtime Service Definition constructs.

Please refer to rapid-rsdl-abnf for the syntactical constructs of RSDL.

Model

A model is mapped to a CSDL Schema named "Model", that has an entity container named "Service".

{
"$Version": "4.01",
"$EntityContainer": "Model.Service",
"Model": {
"Service": { "$Kind": "EntityContainer" }
}
}

The model's service, structured types, and enumeration types are mapped to the respective constructs below and added to the schema (or container respectively)

Structured Types

A structured type is mapped to either an entity type or a complex type when converting from RSDL to CSDL.

A structured type with one or more properties marked with key is mapped to an entity type. Correspondingly, a structured type without key properties is mapped to a complex type.

Structured Types with key Properties

Here, we can see an example of how an RSDL structured type with a key id property maps to a CSDL entity type.

type Employee {
key id: Integer
name : Name
}
"Employee": {
"$Kind": "EntityType",
"$Key": [ "id" ],
"id": { "$Type": "Edm.Int32" },
"name": { "$Type": "Model.Name" }
}

Structured Types without key Properties

On the other hand, an RSDL structured type without a key property maps to a CSDL complex type. Such types don't have keys because they are intended for organizing related properties into a group that is non-unique and does not stand on its own.

type Name {
firstName : String
lastName: String
}
"Name": {
"$Kind": "ComplexType",
"firstName": { "$Type": "Edm.String" },
"lastName": { "$Type": "Edm.String" }
}

Abstract Structured Types

A type may be defined as abstract. An abstract type cannot be instantiated, but can be used as a base type for other type definitions.

abstract type Robot {
model: String
}
"Robot": {
"$Kind": "ComplexType",
"$Abstract": true,
"model": { "$Type": "Edm.String" }
}

Structured Type Inheritance

Types may extend other types through inheritance. The type derived from the base type inherits all properties, relationships, and operations bound to the base type (type inheritance) and can be used anywhere the base type is used (polymorphism).

type Android extends Robot {
name: String
}
"Android": {
"$Kind": "ComplexType",
"$BaseType": "Model.Robot",
"name": { "$Type": "Edm.String" }
}

Properties

The properties of a structured type are mapped to either a Property or a NavigationProperty depending on the property's type.

In the following example, let's assume name is mapped to a complex type and employee is mapped to an entity type.

type Company {
key stockSymbol: String
name: Name
employees: [Employee]
}
"Company": {
"$Kind": "EntityType",
"$Key": [ "stockSymbol" ],
"stockSymbol": { "$Type": "Edm.String" },
"name": { "$Type": "Edm.String" },
"employees": {
"$Kind": "NavigationProperty",
"$Type": "Model.Employee",
"$Collection": true,
"$ContainsTarget": true
}
}

Property Types

The type of a property is one of:

Each of these named types can be marked as

  • optional via a question mark ?
  • multi-valued via enclosing it in brackets [ ]
type Foo {
test1: Integer
test2: Integer?
test3: [Integer]
test4: [Integer?]
test5: String
test6: String(80)
test7: Decimal
test8: Decimal(15,2)
}
"Foo": {
"$Kind": "EntityType",
"test1": { "$Type": "Edm.Int32" },
"test2": { "$Nullable": true, "$Type": "Edm.Int32" },
"test3": { "$Collection": true, "$Type": "Edm.Int32" },
"test4": { "$Collection": true, "$Nullable": true, "$Type": "Edm.Int32" },
"test5": {},
"test6": { "$MaxLength": 80 },
"test7": { "$Type": "Edm.Decimal", "$Scale": "variable" },
"test8": { "$Type": "Edm.Decimal", "$Precision": 15, "$Scale": 2 },
}

Actions and Functions

The syntactical production rule operation is mapped to a bound action or a bound function in CSDL.

  • operations with an action modifier are mapped to a CSDL Action
  • operations without a modifier are mapped to CSDL Function

The binding parameter of the function is inferred from the containing type production rule and named it

type Employee {
key id: Integer
foo()
}
"foo": [
{
"$Kind": "Function",
"$IsBound": true,
"$IsComposable": true,
"$Parameter": [ { "$Name": "it", "$Type": "Model.Employee" } ]
}
]

Function Return Types

The return type of a function is mapped similar to a property type with the same semantic for [ ] and ?.

type Employee {
key id: Integer
foo() : Integer
bar() : [Integer]
}
"foo": [
{
"$Kind": "Function",
"$IsBound": true,
"$IsComposable": true,
"$Parameter": [ { "$Name": "it", "$Type": "Model.Employee" } ],
"$ReturnType": { "$Type": "Edm.Int32" }
}
],
"bar": [
{
"$Kind": "Function",
"$IsBound": true,
"$IsComposable": true,
"$Parameter": [ { "$Name": "it", "$Type": "Model.Employee" } ],
"$ReturnType": { "$Collection": true, "$Type": "Edm.Int32" }
}
]

Functions Parameters

Parameters are similar to properties in that they have a name and reference a type.

type Employee {
key id: Integer
foo(a: Integer, b: [Integer?])
}
  "foo": [
{
"$Kind": "Function",
"$IsBound": true,
"$IsComposable": true,
"$Parameter": [
{ "$Name": "it", "$Type": "Model.Employee" },
{ "$Name": "a", "$Type": "Edm.Int32" },
{ "$Name": "b", "$Collection": true, "$Type": "Edm.Int32", "$Nullable": true }
]
}
]

TODO: decide on optional parameters, how they are different from nullable required parameters, and if that is a feature required now or too much for RAPID

Enumeration Types

An Enumeration Type is mapped to a CSDL EnumType. The enumeration members' values are automatically assigned.

enum employmentType { salaried hourly }
"employmentType": {
"$Kind": "EnumType",
"salaried": 0,
"hourly": 1
}

Flag Types

A Flags 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.

flags PhoneService { LandLine Cell Fax Internet Other }
  "PhoneService": {
"$Kind": "EnumType",
"$IsFlags": true,
"LandLine": 1,
"Cell": 2,
"Fax": 4,
"Internet": 8,
"Other": 16
}

Service

As mentioned above, every RAPID service model creates a CSDL entity container named "Service"

service {
}
"Service": {
"$Kind": "EntityContainer"
}

Multi-Valued Service Member

A service member of a multi-valued type is mapped to a CSDL entity set.

service {
employees: [Employee]
}
"Service": {
"$Kind": "EntityContainer",
"employees": { "$Collection": true, "$Type": "Model.Employee" }
}

If the type is used as a type on a multi-value and as the type of a property of a structured type (i.e. a navigation property in CSDL), the appropriate navigation property bindings get created. The Company type from the Properties section has an employees property of the type Employee. The binding in CSDL defines that objects of these properties are bound to the employees entity set.

service {
competitors: [Company]
}
"Service": {
"$Kind": "EntityContainer",
"competitors": {
"$Collection": true,
"$Type": "Model.Company",
"$NavigationPropertyBinding": {
"employees": "employees"
}
}
}

Single-Valued Service Member

A service member of a single-value type gets mapped to a CSDL singleton.

service {
company: Company
}
"Service": {
"$Kind": "EntityContainer",
"company": { "$Type": "Model.Company" }
}

Descriptions and Comments

All elements of a model can be described by lines starting with ## preceding the model element. These descriptions are mapped to annotations with term Core.Description in the corresponding CSDL construct.

In addition anything after a single # character will be treated as a comment and ignored when mapping to CSDL.

## The Employees Service
# still needs some work
service {
## List of all employees
employees: [Employee]
}
"Service": {
"$Kind": "EntityContainer",
"@Core.Description": "The Employees Service",
"employees": { "$Collection": true, "$Type": "Model.Employee", "@Core.Description": "List of all employees" }
}

Appendix

References