Übung 2 · Evolution von Datenkontrakten
Einen Breaking Change als neue Major-Version veröffentlichen und migrieren.
Einen Breaking Change als neue Major-Version veröffentlichen und migrieren.
Das Business möchte wissen, wie viele Einheiten eines Artikels pro Bestellung gekauft werden.
Das Orders-Team ergänzt in line_items eine Spalte quantity mit Standardwert 1.
Harmlos? Nicht für eine Pipeline, die genau drei Spalten erwartet, etwa ein SELECT * in eine feste Zieltabelle.
Deshalb veröffentlichst du die Änderung als neue Major-Version: orders_v2, in einem eigenen Datenbankschema, neben orders_v1.
datacontract changelog und datacontract breaking vergleichendeprecated (neu in ODCS 3.2)Das Schema orders_v2 enthält beide Tabellen: orders ist unverändert, line_items hat die neue Spalte quantity.
docker compose exec postgres psql -U workshop -d workshop -c '\dt orders_v2.*' -c 'SELECT * FROM orders_v2.line_items LIMIT 5;' List of relations
Schema | Name | Type | Owner
-----------+------------+-------+----------
orders_v2 | line_items | table | workshop
orders_v2 | orders | table | workshop
(2 rows)
lines_item_id | order_id | sku | quantity
--------------------------------------+--------------------------------------+---------------+----------
94aa82c8-50ba-47fb-994a-9b041b4127af | a8c38fec-2acd-4b55-883b-4b48572d4a26 | D3KT74L5EV46T | 1
d67c963f-42a4-4aa8-afff-d7869008e3a9 | 9e44da97-4f72-4bcf-821a-9d9500d06651 | E202K62FT | 3
270ad2c1-f651-438e-a81a-d77713c1d3a3 | 8fc4621c-66ae-4031-91f1-5313beb9f541 | 1O7RID9Y5QJ | 1
cc763a72-cc07-4bc4-8ddf-c88d09db5daa | 98d48daf-3532-4a59-b7c2-3777164bdc65 | 7KJ8466FI39LW | 5
d7ea7f72-a266-469c-a9ef-60063d5ac243 | 2fd9df43-77e8-4d00-b380-ab270e8b73f8 | 7HXBABF0AOT5 | 2
(5 rows)Kopiere deinen v1-Kontrakt und öffne die Kopie im Editor:
cp orders_v1.odcs.yaml orders_v2.odcs.yaml
datacontract edit orders_v2.odcs.yamlSetze in Fundamentals die neue Major-Version:
| Feld | Wert |
|---|---|
| ID | orders_v2 |
| Version | 2.0.0 |
| Status | draft |
Die ID ändert sich mit der Major-Version: Consumer wechseln bewusst auf orders_v2, und orders_v1 bleibt verfügbar, bis sie migriert haben.
Ändere unter Servers das Schema auf orders_v2.
Ersetze dann in allen SQL-Quality Checks orders_v1. durch orders_v2. (z. B. im Check für customer_email_address). Sonst prüfen sie weiter die alten Tabellen.
Die Kopie hat auch deinen KI-context-Block übernommen. Seine verifiedStatements enthalten SQL-Antworten auf orders_v1. Stelle sie ebenfalls auf orders_v2 um, sonst beantwortet ein KI-Agent Fragen aus der alten Version.
Ergänze unter Schemas → line_items die neue Property:
| Property | Logical Type | Physical Type |
|---|---|---|
quantity | integer | BIGINT |
Füge einen Quality Check hinzu, dass quantity immer größer als 0 ist. Nutze das Muster „fehlerhafte Zeilen zählen, null erwarten“.
Speichere und führe die Tests aus:
datacontract test orders_v2.odcs.yamlTesting orders_v2.odcs.yaml
Server: Orders (type=postgres, host=localhost, port=5433, database=workshop, schema=orders_v2)
╭────────┬───────────────────────────────────────────────┬───────────────────────────────┬─────────╮
│ Result │ Check │ Field │ Details │
├────────┼───────────────────────────────────────────────┼───────────────────────────────┼─────────┤
│ passed │ Ensure line_items table has data │ line_items │ │
…
│ passed │ Check that field 'quantity' is present │ line_items.quantity │ │
│ passed │ Check that field quantity has physical type │ line_items.quantity │ │
│ │ bigint │ │ │
│ passed │ Ensure quantity is positive │ line_items.quantity │ │
…
╰────────┴───────────────────────────────────────────────┴───────────────────────────────┴─────────╯
🟢 data contract is valid. Run 37 checks. Took 0.63683 seconds.Alle Checks sollten grün sein, auch der neue Check für quantity.
Vor einem Release willst du wissen, was sich geändert hat und ob es Consumer bricht. Die CLI vergleicht zwei Kontraktdateien.
datacontract changelog orders_v1.odcs.yaml orders_v2.odcs.yamlSummary
[ 1 Added ] [ 16 Updated ]
╭─────────┬─────────────────────────────────────────────────────────────────╮
│ Change │ Field │
├─────────┼─────────────────────────────────────────────────────────────────┤
│ Updated │ context.verifiedStatements.How many orders were placed in 2023? │
│ Updated │ context.verifiedStatements.What was the revenue per year? │
│ Updated │ id │
│ Updated │ schema.line_items.properties.lines_item_id.quality.[1] │
│ Added │ schema.line_items.properties.quantity │
…
│ Updated │ servers.Orders │
│ Updated │ version │
╰─────────┴─────────────────────────────────────────────────────────────────╯
Details
…Du bekommst eine Zusammenfassung und eine detaillierte Liste aller Änderungen, auch der umgestellten Quality-Queries und Verified Statements. Eine gute Grundlage für Release Notes.
breaking stuft jede Änderung nach Schweregrad ein:
datacontract breaking orders_v1.odcs.yaml orders_v2.odcs.yaml
echo "exit code: $?"Summary
[ 11 Warning ] [ 6 Info ]
╭──────────┬─────────┬─────────────────────────────────────────────────────────────────╮
│ Severity │ Change │ Field │
├──────────┼─────────┼─────────────────────────────────────────────────────────────────┤
│ INFO │ Updated │ context.verifiedStatements.How many orders were placed in 2023? │
│ INFO │ Updated │ context.verifiedStatements.What was the revenue per year? │
│ INFO │ Updated │ id │
│ WARNING │ Updated │ schema.line_items.properties.lines_item_id.quality.[1] │
│ INFO │ Added │ schema.line_items.properties.quantity │
…
│ INFO │ Updated │ servers.Orders │
│ INFO │ Updated │ version │
╰──────────┴─────────┴─────────────────────────────────────────────────────────────────╯
…
exit code: 0quantity wird als INFO gemeldet: Eine zusätzliche Spalte ist schemakompatibel. Die geänderten Quality-Queries sind WARNINGs, weil die Checks jetzt gegen andere Tabellen laufen. Nichts ist ein ERROR, daher ist der Exit-Code 0.
Jetzt provozierst du einen echten Breaking Change. Lege eine Kopie an, ändere den physicalType von quantity auf text (oder lösche customer_id) und vergleiche:
cp orders_v2.odcs.yaml orders_v2.before.odcs.yaml
# jetzt orders_v2.odcs.yaml bearbeiten: physicalType von quantity auf text setzen
datacontract breaking orders_v2.before.odcs.yaml orders_v2.odcs.yaml
echo "exit code: $?"Summary
[ 1 Error ]
╭──────────┬─────────┬───────────────────────────────────────╮
│ Severity │ Change │ Field │
├──────────┼─────────┼───────────────────────────────────────┤
│ ERROR │ Updated │ schema.line_items.properties.quantity │
╰──────────┴─────────┴───────────────────────────────────────╯
Details
╭──────────┬─────────┬────────────────────────────────────────────────────┬───────────┬───────────┬────────────────────────────────╮
│ Severity │ Change │ Path │ Old Value │ New Value │ Message │
├──────────┼─────────┼────────────────────────────────────────────────────┼───────────┼───────────┼────────────────────────────────┤
│ ERROR │ Updated │ schema.line_items.properties.quantity.physicalType │ bigint │ text │ Changed type at │
│ │ │ │ │ │ schema.line_items.properties.… │
│ │ │ │ │ │ from 'bigint' to 'text' │
╰──────────┴─────────┴────────────────────────────────────────────────────┴───────────┴───────────┴────────────────────────────────╯
exit code: 1Diesmal gibt es einen ERROR und Exit-Code 1. Dieser Exit-Code macht den Check zum Gate in CI/CD, siehe CI/CD mit GitHub Actions.
Mach es rückgängig und führe die Tests erneut aus:
mv orders_v2.before.odcs.yaml orders_v2.odcs.yaml
datacontract test orders_v2.odcs.yamlTesting orders_v2.odcs.yaml
…
🟢 data contract is valid. Run 37 checks. Took 0.63683 seconds.Das Orders-Team will customer_id in einer künftigen v3 streichen. Kündige es jetzt an. Lege zuerst eine Kopie der aktuellen Version an:
cp orders_v2.odcs.yaml orders_v2.before.odcs.yamlErgänze in orders_v2.odcs.yaml an der Property customer_id die Zeile deprecated: true:
- name: customer_id
deprecated: true
physicalType: text
logicalType: stringVergleiche beide Versionen:
datacontract breaking orders_v2.before.odcs.yaml orders_v2.odcs.yamlSummary
[ 1 Info ]
╭──────────┬────────┬──────────────────────────────────────╮
│ Severity │ Change │ Field │
├──────────┼────────┼──────────────────────────────────────┤
│ INFO │ Added │ schema.orders.properties.customer_id │
╰──────────┴────────┴──────────────────────────────────────╯
…
│ INFO │ Added │ schema.orders.properties.customer_id.deprecated │ │ True │ Added contract at │
…Nur INFO: Abkündigen ist non-breaking. Lösche orders_v2.before.odcs.yaml danach.
Setze in orders_v1.odcs.yaml status: deprecated und ergänze eine SLA-Property endOfSupport:
slaProperties:
# ... retention, frequency
- property: endOfSupport
value: "2026-12-31"
description: orders_v1 is replaced by orders_v2. Please migrate until end of 2026.Prüfe, dass der Kontrakt gültig bleibt:
datacontract lint orders_v1.odcs.yaml╭────────┬────────────────────────────────────────────┬───────┬─────────╮
│ Result │ Check │ Field │ Details │
├────────┼────────────────────────────────────────────┼───────┼─────────┤
│ passed │ Data contract is valid against ODCS v3.2.0 │ │ │
╰────────┴────────────────────────────────────────────┴───────┴─────────╯
🟢 data contract is valid. Run 1 checks. Took 0.122955 seconds.Als Abkürzung springst du direkt zum Endzustand:
orders_v2.odcs.yaml auf status: activeorders_v1.odcs.yaml auf status: retiredFühre die Tests für v2 ein letztes Mal aus:
datacontract test orders_v2.odcs.yamlTesting orders_v2.odcs.yaml
…
🟢 data contract is valid. Run 37 checks. Took 0.63683 seconds.datacontract export html orders_v2.odcs.yaml --output orders_v2.odcs.htmldatacontract breaking ausführst: ein Feld umbenennen, required: true entfernen, eine neue Tabelle hinzufügen.customer_id aus einer Kopie von v2 und führe datacontract breaking aus. Das Flag macht das Entfernen nicht kompatibel.