diff --git a/datacontract/model/data_contract_specification.py b/datacontract/model/data_contract_specification.py
index 3decdfa8..f725bbdf 100644
--- a/datacontract/model/data_contract_specification.py
+++ b/datacontract/model/data_contract_specification.py
@@ -1,5 +1,5 @@
import os
-from typing import List, Dict
+from typing import List, Dict, Optional
import pydantic as pyd
import yaml
@@ -113,6 +113,53 @@ class Quality(pyd.BaseModel):
type: str = None
specification: str | object = None
+class Availability(pyd.BaseModel):
+ description: Optional[str] = None
+ percentage: Optional[str] = None
+
+class Retention(pyd.BaseModel):
+ description: Optional[str] = None
+ period: Optional[str] = None
+ unlimited: Optional[bool] = None
+ timestampField: Optional[str] = None
+
+class Latency(pyd.BaseModel):
+ description: Optional[str] = None
+ threshold: Optional[str] = None
+ sourceTimestampField: Optional[str] = None
+ processedTimestampField: Optional[str] = None
+
+class Freshness(pyd.BaseModel):
+ description: Optional[str] = None
+ threshold: Optional[str] = None
+ timestampField: Optional[str] = None
+
+class Frequency(pyd.BaseModel):
+ description: Optional[str] = None
+ type: Optional[str] = None
+ interval: Optional[str] = None
+ cron: Optional[str] = None
+
+class Support(pyd.BaseModel):
+ description: Optional[str] = None
+ time: Optional[str] = None
+ responseTime: Optional[str] = None
+
+class Backup(pyd.BaseModel):
+ description: Optional[str] = None
+ interval: Optional[str] = None
+ cron: Optional[str] = None
+ recoveryTime: Optional[str] = None
+ recoveryPoint: Optional[str] = None
+
+class ServiceLevel(pyd.BaseModel):
+ availability: Optional[Availability] = None
+ retention: Optional[Retention] = None
+ latency: Optional[Latency] = None
+ freshness: Optional[Freshness] = None
+ frequency: Optional[Frequency] = None
+ support: Optional[Support] = None
+ backup: Optional[Backup] = None
class DataContractSpecification(pyd.BaseModel):
dataContractSpecification: str = None
@@ -125,6 +172,7 @@ class DataContractSpecification(pyd.BaseModel):
# schema: Dict[str, str]
examples: List[Example] = []
quality: Quality = None
+ servicelevels: Optional[ServiceLevel] = None
@classmethod
def from_file(cls, file):
diff --git a/datacontract/templates/datacontract.html b/datacontract/templates/datacontract.html
index 2138f190..f53fb191 100644
--- a/datacontract/templates/datacontract.html
+++ b/datacontract/templates/datacontract.html
@@ -465,7 +465,237 @@
{# TODO add definitions #}
- {# TODO add service levels #}
+ {% if datacontract.servicelevels %}
+
+
+
Service Levels
+
Servicelevels of the data contract
+
+ {% if datacontract.servicelevels.availability %}
+
+ Availability
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.availability.description }}
+
+
+
+
- Percentage
+ -
+ {{ datacontract.servicelevels.availability.percentage }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.retention %}
+
+ Retention
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.retention.description }}
+
+
+
+
- Period
+ -
+ {{ datacontract.servicelevels.retention.period }}
+
+
+
+
- Unlimited
+ -
+ {{ datacontract.servicelevels.retention.unlimited }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.latency %}
+
+ Latency
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.latency.description }}
+
+
+
+
- Threshold
+ -
+ {{ datacontract.servicelevels.latency.threshold }}
+
+
+
+
- Source Timestamp field
+ -
+ {{ datacontract.servicelevels.latency.sourceTimestampField
+ }}
+
+
+
+
- Processed Timestamp field
+ -
+ {{ datacontract.servicelevels.latency.processedTimestampField
+ }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.freshness %}
+
+ Freshness
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.freshness.description }}
+
+
+
+
- Threshold
+ -
+ {{ datacontract.servicelevels.freshness.threshold }}
+
+
+
+
- Timestamp field
+ -
+ {{ datacontract.servicelevels.freshness.timestampField }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.frequency %}
+
+ Frequency
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.frequency.description }}
+
+
+
+
- Type
+ -
+ {{ datacontract.servicelevels.frequency.type }}
+
+
+
+
- Interval
+ -
+ {{ datacontract.servicelevels.frequency.interval }}
+
+
+
+
- Cron
+ -
+ {{ datacontract.servicelevels.frequency.cron }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.support %}
+
+ Support
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.support.description }}
+
+
+
+
- Time
+ -
+ {{ datacontract.servicelevels.support.time }}
+
+
+
+
- Response Time
+ -
+ {{ datacontract.servicelevels.support.responseTime }}
+
+
+
+
+
+ {% endif %}
+ {% if datacontract.servicelevels.backup %}
+
+ Backup
+
+
+
+
+
+
- Description
+ -
+ {{ datacontract.servicelevels.backup.description }}
+
+
+
+
- Interval
+ -
+ {{ datacontract.servicelevels.backup.interval }}
+
+
+
+
- Cron
+ -
+ {{ datacontract.servicelevels.backup.cron }}
+
+
+
+
- Recovery Time
+ -
+ {{ datacontract.servicelevels.backup.recoveryTime }}
+
+
+
+
- Recovery Point
+ -
+ {{ datacontract.servicelevels.backup.recoveryPoint }}
+
+
+
+
+
+ {% endif %}
+
+ {% endif %}
{% if quality_specification %}
diff --git a/tests/fixtures/examples/datacontract_servicelevels.yaml b/tests/fixtures/examples/datacontract_servicelevels.yaml
new file mode 100644
index 00000000..3ec4df10
--- /dev/null
+++ b/tests/fixtures/examples/datacontract_servicelevels.yaml
@@ -0,0 +1,58 @@
+dataContractSpecification: 0.9.2
+id: "61111-0002"
+info:
+ title: "Verbraucherpreisindex: Deutschland, Monate"
+ description: A data contract for the distribution and use of the German Consumer Price Index data.
+ version: 1.0.0
+ owner: my-domain-team
+models:
+ verbraucherpreisindex:
+ description: Model representing the Consumer Price Index for Germany
+ fields:
+ wert:
+ description: Value of the Consumer Price Index
+ type: integer
+ required: true
+ jahrMonat:
+ description: Year and month of the data
+ type: string
+ required: true
+ qualitaet:
+ description: Quality of the data
+ type: string
+ enum:
+ - "vorlaeufig"
+ - "endgueltig"
+ verarbeitet:
+ description: Time when this dataset was processed, year and month
+ type: string
+
+examples:
+ - type: json
+ description: Example entry for CPI data
+ model: verbraucherpreisindex
+ data: |-
+ [{ "wert": 99, "jahrMonat": "2022-00", "verarbeitet": "2022-01" },
+ { "wert": 100, "jahrMonat": "2022-01", "verarbeitet": "2022-02" },
+ { "wert": 101, "jahrMonat": "2022-02", "qualitaet": "vorlaeufig", "verarbeitet": "2022-03" }]
+
+servicelevels:
+ availability:
+ percentage: "99.9%"
+ retention:
+ period: P5Y
+ timestampField: jahrMonat
+ latency:
+ threshold: P1M
+ sourceTimestampField: verarbeitet
+ freshness:
+ threshold: P1M
+ timestampField: verarbeitet
+ frequency:
+ type: streaming
+ support:
+ time: 24/7
+ responseTime: P1h
+ backup:
+ interval: daily
+ recoveryTime: 2 hours
diff --git a/tests/test_test_examples_json.py b/tests/test_test_examples_json.py
index e1128702..45edc87a 100644
--- a/tests/test_test_examples_json.py
+++ b/tests/test_test_examples_json.py
@@ -21,3 +21,10 @@ def test_json():
print(run)
print(run.result)
assert run.result == "passed"
+
+def test_with_service_level():
+ data_contract = DataContract(data_contract_file="fixtures/examples/datacontract_servicelevels.yaml", examples=True)
+ run = data_contract.test()
+ print(run)
+ print(run.result)
+ assert run.result == "passed"