Primer
Purpose and Target Group
This document shall mainly serve as a reference for development teams who want to produce interoperable data definitions in a development environment w/o native CDS support. (CAP and RAP developers create data models in CDS according to their local development guidelines, and the framework will take care of the interoperability. Datasphere content developers use the modeling tools.)
This document shall also serve as a basic reference for consumers of interoperable data definitions who need to parse, validate and interpret externally provided data documents.
Prominent use cases which require the creation and consumption of interoperable data definitions are:
- Deployment of HDLF Delta Share Tables in the context of real-time exchange of large datasets
- Embedded Analytics on a HANA Cloud side car (plus SAC Integration Service)
- Model- and Data Integration with Datasphere
Introduction
The Core Data Services Schema Notation (CSN, pronounced "Season") is a JSON format to exchange metadata about data models, e.g., between the various technology stacks and applications that form the Business Technology Platform (BTP).
Depending on the intended usage we distinguish three CSN flavors:
- "Parsed" for the Modeling Perspective
- "Effective" for the data exchange perspective
- "Persistency" for the persistency flavor
The "Parsed" flavor could e.g. represent a CAP CDS data model 1:1, the "Persistency" flavor could e.g. express HANA SQL tables and views.
This document describes the "Effective" flavor, characterized as being optimized for data exchange purposes. All content that can be standardized (currency keys, language codes, country codes, …) must be presented in standardized form, hence original data definitions must be adapted accordingly if necessary. Technology-specific aspects of the data model shall be left out as far as possible. This standardization includes the basic data types, and annotation (e.g. labels, …).
The document is structured in a way that it starts from an empty JSON document and introduces concepts and their corresponding syntax patterns with development guidance one by one. The example JSON snippets mostly follow the airline example. In order to create a valid Effective CSN document it is only necessary to apply the specification within the intended scope, and the mandatory scope is very small.
Note: According to the purpose the document will evolve. While it is not intended to change any already published content in an incompatible way, new content will be added over time. This implies that early versions of the document will not cover the complete scope of Effective CSN.
Note: The document quotes frequently from the CAP CSN documentation w/o explicit citations. This is done intentionally to increase the consistency between these two sources of information. In case of differences consider that the purpose of this document is not to explain how CSN is derived from CDL, but how Effective CSN is constructed from scratch.
Root Level Structure
There are three mandatory root level properties that need to be added to get a minimal valid CSN Interop document:
{
"csnInteropEffective": "1.0",
"$version": "2.0",
"definitions": { }, // MUST have at least one entry
}
csnInteropEffective
states that this JSON document is a CSN Interop document and the value states the version of the spec that was used.$version
is a mandatory property that defines the version of the general CSN syntax version.definitions
at least one element of a definition modelling artefact- See Root Interface documentation for a complete overview.
Definitions
The model is described in the Definitions section.
{ //..
"definitions": { }
}
Each entry in the definitions dictionary is a definition of a named modeling artefact. The name is the absolute fully qualified name definition, and the value is a record with the definition details.
The name of a definition is its key in the enclosing dictionary.
Each top-level definitions entry has a property kind – one of entity
, type
, service
or context
.
{ //..
"definitions": {
"<name>": {
"kind": "<kind>"
}
}
}
We will now describe the detail patterns per kind. The by far most important kind is entity. But before we proceed we need to introduce Literals and Built-in Types.
Literals
There are several places where literals can show up in models, such as in SQL expressions, calculated fields, or annotations. Standard literals are represented as in JSON. In addition, CSN specifies special forms for references, expressions, and enum symbols:
Kind | Example |
---|---|
Globals | true , false , null |
Numbers | 11 , 2.4 |
Strings | "foo" |
Dates | "2016-11-24" |
Times | "16:11Z" |
DateTimes | "2016-11-24T16:11Z" |
Records | {"foo":\<Literal\>, …} |
Arrays | [\<Literal\>, …] |
References | {"=":"foo.bar"} |
Unparsed Expressions | {"=":"foo.bar \< 9"} |
Enum Symbols | {"#":"asc"} |
Remarks:
Numbers share the same issues as in JSON when decimals are mapped to doubles with potential rounding errors. The same applies to Integer64. Use strings to avoid that, if applicable.
Also, as in JSON, dates, and times are represented just as strings as specified in ISO 8601; consumers are assumed to know the types and handle the values correctly.
Built-in Types
The CDS built-in types shall be used as basis from which other types (if required) are derived (see Custom Type Definitions).
Entity Definitions
In this section we introduce entity definitions which would result in a data persistence at deployment, i.e. a table in a SQL database. Entity definitions always have kind entity, and a property elements.
The fully qualified name of the entity is defined as the key in the definition JSON object (<entity name>
).
{ //..
"definitions": {
"<entity name>": {
"kind": "entity",
"elements": {
}
}
}
}
Elements
Each entry in the elements object must have an entity-locally unique name, and a member type referring to a built-in type, or a type definition, via its fully qualified name (<element name>
).
{ //..
"definitions": {
"<entity name>": {
"kind": "entity",
"elements": {
"<element name>": {
"type": "<type name>"
}
}
}
}
}
Type-specific Properties
If the built-in CDS Types have arguments of type integer (length, precision, scale). These arguments are expressed via additional properties with the (fix) name of the argument. Especially a String has a length, and a Decimal has a precision and a scale. This yields the following specialized patterns:
{ //..
"definitions": {
"<entity name>": {
"kind": "entity",
"elements": {
"<string element name>": {
"type": "cds.String",
"length": <length>
},
"<decimal element name>": {
"type": "cds.Decimal",
"precision": <total number of digits>,
"scale": <number of decimal places>
}
}
}
}
}
These additional properties are usually optional. However, we strongly recommend to always specify them, because otherwise consumer MAY assume different defaults.
Note that there are several built-in types for numbers. We recommend to stick to Integer, if there is no specific reason to use a specialized type. And we strongly recommend to use Decimal (not Double) for data exchange.
Note that it's also possible to create shared, reusable types with Custom Types). With this feature, a new reusable, custom type can be defined in the Definitions section ("kind": "type"). Instead of using a native CDS Types, the type
points to the fully qualified name of the derived type. The custom type itself MUST use a native CDS Type however.
Primary Key
In case the entity has a primary key, it is mandatory to specify it. (It is especially required for data integration with Datasphere.) This is done by adding the member key with boolean value true to each element of the primary key:
{ //..
"definitions": {
"<entity name>": {
"kind": "entity",
"elements": {
"<key element name>": {
"type": "<type name>",
"key": true
},
"<non-key element name>": {
"type": "<type name>"
}
}
}
}
}