Zum Hauptinhalt springen

Wie die Generierung funktioniert

Die Generierung nimmt zwei Eingaben und erzeugt Dateien. Das Modell gehört Ihnen; die Regeln kommen aus einem Paket. Nichts dazwischen ist auf Data Vault, auf JSON Schema oder auf irgendeine andere Ausgabe zugeschnitten – deshalb ändert ein anderes Paket das Ergebnis, ohne die Anwendung zu ändern.

Der Weg vom Modell und Paket zu den ArtefaktenModell und Paketkonfiguration speisen beide den Dispatcher. Der Dispatcher passt Definitionen gegen das Modell, ruft je Treffer den Context Builder des Pakets, rendert die Vorlage und schreibt ein Artefakt je Treffer.Ihr ModellEntitäten, Attribute,Beziehungen, EigenschaftenDas Paketconfig.json – Typenund DefinitionenBuilder + VorlagenDispatcherfür jede Definition:passt sie?scope entscheidet,wie oft sie läuftRenderContext Builderliest das Modelldie Vorlage machtText darausArtefakteeine Datei je Treffer,benannt nach Muster

Die zwei Fragen, die eine Definition beantwortet​

Die definitions eines Pakets sind die Regeln. Jede beantwortet zwei Fragen, und alles an der Generierung folgt daraus:

Auf welche Modellelemente trifft sie zu? Eine Definition nennt einen type_key, und eine Entität, deren Typ diesen Schlüssel trägt, passt. Sie kann weiter einschränken, und das sind die verfügbaren Bedingungen – derselbe Satz, über den der Dialog Explain why berichtet:

BedingungTrifft zu, wenn
type_keyder Typ der Entität diesen Schlüssel hat
cp_equals / cp_not_equalseine benutzerdefinierte Eigenschaft diesen Wert hat oder nicht hat
cp_existsdie Eigenschaft überhaupt gesetzt ist
effective_cp_equals / effective_cp_not_equalsdasselbe, nachdem die Vererbung angewandt wurde
name_ends_withder Name der Entität auf diesen Text endet
group_path_not_containsder Gruppenpfad der Entität diesen Text nicht enthält

Sie lassen sich mit ALL, ANY und NOT verknüpfen; ein Entitätstyp kann also je nach Konfiguration durch verschiedene Vorlagen geschickt werden – das Data-Vault-Paket macht genau das. Was es nicht gibt, ist Priorität, Rückfall oder eine Standardregel: eine Definition passt oder sie passt nicht.

Wie oft läuft sie? Das ist der scope:

ScopeLäuftErzeugt
entityeinmal je passender Entitäteine Datei je Element
modeleinmal, für das ganze Modelleine Datei über alles

Jede Definition, deren Treffer zutrifft, generiert. Sie konkurrieren nicht und wissen nichts voneinander; zwei zusammen installierte Pakete laufen also einfach beide – und ignorieren stillschweigend die Typen des jeweils anderen. „Keine Vorlage für diesen Typ gefunden" ist die richtige Antwort, kein Fehlschlag.

Was je Treffer läuft​

Für jeden Treffer ruft die Engine den Context Builder der Definition – eine Python-Funktion im Paket – und übergibt das Ergebnis ihrer Vorlage. Der Builder ist die Stelle, an der das Modell gelesen wird: er läuft über Attribute, folgt Beziehungen, liest benutzerdefinierte Eigenschaften und gibt eine einfache Datenstruktur zurück. Die Vorlage formatiert nur noch, was sie bekommt.

Diese Trennung ist Absicht. Eine Vorlage, die das Modell durchlaufen müsste, vermischte zwei schwierige Dinge – zu entscheiden, was wahr ist, und zu entscheiden, wie es aussieht – und keines davon wäre für sich prüfbar. Mit der Trennung testen die Tests eines Pakets den Builder gegen ein Stub-Modell und rendern überhaupt nichts.

info

Die Jinja-Trennzeichen der Engine sind nicht die üblichen: ein Ausdruck ist {@ … @} und ein Block {= … =}. So kann eine Vorlage dbt- oder Jinja-Code in die erzeugte Datei schreiben, ohne dass die Engine ihn verschluckt. Die Standardtrennzeichen lösen keinen Fehler aus – sie werden als wörtlicher Text gerendert und der Wert kommt leer heraus, der Fehler sieht also wie ein Kontextproblem aus.

Weiterlesen​