# Struktura modelu danych

## Struktura drzewa

{% columns %}
{% column %}
Model danych ma strukturę drzewa ułatwiającą odwzorowanie hierarchicznej struktury obiektów domeny biznesowej.

**Liście** drzewa reprezentują najbardziej szczegółowy element struktury. Liście, zwane polami, nie posiadają już żadnych innych elementów podrzędnych (dzieci) i reprezentują pojedyncze pole danych. Przykładami mogą być "imię klienta" czy "numer rachunku bankowego".

**Węzły** drzewa reprezentują obiekty złożone z innych obiektów i/lub pól. Przykłady: "adres korespondencyjny", "dochód klienta".
{% endcolumn %}

{% column %}

<figure><img src="https://1082717226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2CssJT0zIo4SJQLbSZ6l%2Fuploads%2FpN14hRagp8jodNrtEt5Q%2Ftree_structure.png?alt=media&#x26;token=512337b9-4e0e-4ad3-982f-cbc14fff00f3" alt="" width="216"><figcaption><p><em><strong>Ilustracja 1.</strong> Struktura drzewa</em></p></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

### Węzły

Każdy węzeł modelu danych posiada atrybuty:

* klucz unikalny wśród swojego rodzeństwa (potomków tego samego węzła)
* liczebność wyrażoną wzorem `n..m` oznaczającym od `n` wystąpień minimalnie do `m` maksymalnie, np:
  * `1..1` - obiekt występuje tylko raz
  * `0..1` - obiekt jest opcjonalny
  * `1..null` - obiekt występuje co najmniej raz, bez ograniczenia na maksymalną liczbę wystąpień
* opis znaczenia obiektu dla aplikacji

{% hint style="info" %}
Węzły można zatem jednoznacznie wskazać za pomocą klucza powstałego poprzez złączenie kluczy węzłów nadrzędnych, np: `client.email`.
{% endhint %}

### Liście

Poza atrybutami węzłów, liście posiadają dodatkowo:

* źródła danych - określają jak i skąd pobierana jest wartość
* domyślna wartość - co zwróci pole, jeżeli żadne ze źródeł danych nie zwróci wartości

Pole może mieć zdefiniowaną listę źródeł danych. Rozstrzyganie wartości pola polega na wywoływaniu źródeł danych w kolejności ich zdefiniowania aż do uzyskania niepustej wartości. Zatem pierwsze źródło zwracające niepustą wartość wygrywa.

Dane z modelu możemy pobierać tylko dla wybranych przez nas pojedynczych kluczy, tj. nie możemy pobierać wartości kluczy, które mają pod sobą dzieci, tak jak nie możemy pobrać całego modelu w jednym zapytaniu.

## Tablice w modelu danych <a href="#strukturamodeludanychbudowanieiuzywanie-definiowanietablicowychpolmodeludanych" id="strukturamodeludanychbudowanieiuzywanie-definiowanietablicowychpolmodeludanych"></a>

Węzły modelu oznaczone jako wielokrotne (liczebność maksymalna `>1`) tworzą tablicę prostych wartości (dla pól) oraz złożonych obiektów (dla węzłów nie będących liśćmi). Możliwe jest również zdefiniowanie kolekcji zagnieżdżonych.

### Klucze i identyfikatory <a href="#strukturamodeludanychbudowanieiuzywanie-kluczeiidentyfikatory" id="strukturamodeludanychbudowanieiuzywanie-kluczeiidentyfikatory"></a>

Odwołując się do węzłów modelu danych zdefiniowanych jako tablica (lub będącymi potomkami tablicy) należy zawsze używać notacji tablicowej:

* tablica\[].pole - pobiera wszystkie wystąpienia pola; zależnie od używanego API zwróci kolekcję lub pojedynczy string z separatorem ","
* tablica\[0].pole - pobierze pojedynczą wartość rozwiązaną wierszem kolekcji wskazanym w kluczu (w przykładzie 0 oznacza pierwszy element tablicy),
* tablica.pole - spowoduje błąd, nie ma możliwości odniesienia się do tablicowego węzła bez notacji tablicy,

### Definiowanie tablicy <a href="#strukturamodeludanychbudowanieiuzywanie-definiowanietablicywmodeludanych" id="strukturamodeludanychbudowanieiuzywanie-definiowanietablicywmodeludanych"></a>

W celu zdefiniowania tablicowego pola konieczne jest:

* wielokrotny węzeł modelu danych musi posiadać krotność większą niż `multiplicityMax=1`, np. `1..null`,
* wielokrotny węzeł modelu danych musi mieć zdefiniowane źródła wskazujące na tablicę, indeksy tej kolekcji zostaną użyte do indeksacji powtórzeń wartości modelu,
* węzły poniżej wielokrotnego węzła modelu danych mogą w mapowaniu stosować indeks iterowanego węzła modelu do wskazania konkretnych elementów wyjścia usługi,
  * nadrzędny węzeł zawsze udostępni w kontekście wykonania swój bieżący indeks (w trakcie rozwiązywania wartości dla kolekcji) pod identyfikatorem *`nazwaWezłaIdx`,*
  * pola iterowane rodzicem powinny wskazywać na obiekty wewnątrz kolekcji, po której iteruje rodzic,
  * nie jest to jednak stricte konieczne, możliwe jest wykorzystanie tego indeksu do iterowania po zupełnie innym polu lub do wyciągania pól w ogóle nie będących tablicami.

{% hint style="info" %}
Przykładowo, mając wynik usługi, który składa się ze stałego pola i dwóch tablic - o których wiadomo, że mają tę samą długość (tablicaA, tablicaB, poleC) - możliwe jest stworzenie mapowania, w którym model iteruje po tablicyA, ale jego podpola wyciągają kolejne pola tablicyB i stałą wartość z polaC.
{% endhint %}

## Powiązanie providera z modelem danych

Provider to lokalne źródło danych napisane w [ScriptCode](https://docs.eximee.com/budowanie-aplikacji/logika-biznesowa/scriptcode/wprowadzenie-do-scriptcode), które definiuje sposób pozyskiwania wartości dla pól modelu. Może być wykorzystywane przez pola do zasilania ich watości. Źródłem danych może być funkcja:

* skryptowa,
* wywołująca zewnętrzną usługę REST,
* odwołująca się do innego elementu modelu,
* pobierająca wartość z konfiguracji aplikacji.

Opisany poniżej provider stanowi **źródło danych dla liścia modelu danych**. Służy ono do pobrania aktualnego kursu waluty z zewnętrznego API (NBP):

* `exchangeRate` jest **liściem (polem)** w drzewie,
* pole to nie posiada dzieci i reprezentuje pojedynczą wartość (kurs waluty),
* może być zagnieżdżone w węźle, np.: `exchangeRates.exchangeRateEUR`.

<figure><img src="https://1082717226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2CssJT0zIo4SJQLbSZ6l%2Fuploads%2Fgit-blob-74883de5f437263604a380103f4f7162dfe2e315%2FkodProvidera.png?alt=media" alt="przykład z kodem providera"><figcaption><p><em><strong>Ilustracja 2.</strong> Przykład providera pobierającego aktualny kurs waluty z API (NBP)</em></p></figcaption></figure>

Przebieg działania:

* z parametrów wejściowych providera pobierany jest klucz, czyli kod waluty (`currencyCode`), np. „EUR” lub „USD”,
* wartość ta jest przekazywana do providera z modelu danych,
* provider wykonuje zapytanie GET do skonfigurowanego endpointu `nbpExchangeRate` przy użyciu `api.rest.v1.get`,
* parametry ścieżki (`pathParams`) budują adres zapytania w postaci: `/rates/A/{currencyCode}` (litera „A” oznacza tabelę średnich kursów walut publikowanych przez NBP),
* odpowiedź z API zawiera obiekt `body`, w którym znajduje się tablica `rates`, a z tablicy pobierany jest pierwszy element (`rates[0]`), następnie jego pole `mid`, które reprezentuje średni kurs waluty,
* provider zwraca obiekt zawierający pole `exchangeRate`, wartość tego pola odpowiada pobranemu kursowi waluty i może być dalej wykorzystana w modelu danych lub formularzu.

### Konfiguracja źródeł danych dla pola

Każde pole w modelu danych posiada możliwość zdefiniowania **źródeł danych**.\
Konfiguracja dostępna jest po kliknięciu ikony ołówka przy wybranym polu, co otwiera szufladę ustawień źródeł danych powiązanych z tym polem. Jeżeli dla danego klucza zostały już zdefiniowane źródła danych, ich nazwy są widoczne w panelu - w przedstawionym przykładzie jest to `exchangeRateFromNBPProvider`. Po wybraniu źródła możliwa jest konfiguracja parametrów wejściowych oraz mapowania wyjścia.

<figure><img src="https://1082717226-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F2CssJT0zIo4SJQLbSZ6l%2Fuploads%2Fgit-blob-a86d2faadc46924920ac10b4eee1c1654cadf497%2FzrodlaDanychParametryMapowanie.png?alt=media" alt="przykład z kodem providera"><figcaption><p><em><strong>Ilustracja 3.</strong> Przykład wykorzystania providera jako źródła danych w modelu</em></p></figcaption></figure>

W zakładce **Parametry** definiowane są wartości przekazywane do providera.\
W opisywanym przypadku:

* klucz: `currencyCode`
* wartość: `EUR`

Parametr ten jest wykorzystywany przez provider do wywołania zewnętrznego API.

W sekcji **Mapowanie** określane jest, które dane z odpowiedzi providera zostaną przypisane do pola w modelu. W tym przykładzie mapowana jest wartość `exchangeRate`.

Uzyskana wartość może być następnie wykorzystana w modelu danych lub bezpośrednio w formularzu. Więcej o wykorzystaniu modelu danych na wniosku w zakładce [Model danych na interfejsie](https://docs.eximee.com/~/revisions/6RARJsssdz6tDsOideLu/budowanie-aplikacji/interfejs-uzytkownika/formularze/praca-z-komponentami-bazowymi/model-danych-na-interfejsie).
