Moduły, biblioteki i bazy danych
Zakres weryfikacji
Treść zachowana z obecnego źródła. Publikacja dokumentacji nie oznacza ponownego potwierdzenia wszystkich komend, przykładów i deklaracji możliwości.
Poziom: średniozaawansowany i ekspert. Początkujący może bezpiecznie uruchomić gotowy projekt referencyjny, ale utworzenie nowego adaptera storage wymaga dziś pracy średniozaawansowanej.
Projekt Junexis może składać się z wielu plików .jnx i lokalnych bibliotek.
Ten sam kontrakt łączy kod domenowy z pamięcią procesu, SQLite albo PostgreSQL
po stronie @server i przekazuje stan do @report. Pełny pion restartu jest
zweryfikowany dla SQLite. PostgreSQL przechodzi kompilację i test kontraktu bez
serwera; jego sieciowy E2E czeka na dostępny endpoint testowy.
Jeżeli chcesz od razu zbudować własny projekt, przejdź do praktycznego przewodnika pracy z modułami i bazą danych. Ta strona wyjaśnia model i granice odpowiedzialności.
Pięć pojęć, których nie należy mieszać
| Pojęcie | Znaczenie w Junexis | Przykład |
|---|---|---|
| kontrakt domenowy | operacje potrzebne systemowi, niezależne od technologii | HomeStore.save, HomeStore.snapshot |
extern storage |
deklaracja granicy I/O i jej efektów dla kompilatora | zapis, odczyt, transakcja, health check |
| provider | implementacja wspólnej semantyki przechowywania | memory, SQLite, PostgreSQL |
| adapter autora | mapowanie typów domenowych i konfiguracji na API providera | user/server/home_store.go |
| binding | decyzja uruchomieniowa, którego providera i ustawień użyć | memory w teście, SQLite z data/home.db lokalnie |
Provider nie powinien znać pojęć domu, pomiaru ani użytkownika. Adapter zna
domenę i provider, ale pozostaje za granicą @server. Task zna wyłącznie
kontrakt domenowy. Dzięki temu można wymienić technologię bez przepisywania
reguł systemu.
Provider nie należy do @server
@server określa miejsce wykonania tasku. Nie oznacza Go, C#, Javy ani
Pythona i nie może być właścicielem sterownika bazy. Obecne generowane pakiety
Go pozostają działającym rozwiązaniem przejściowym, ale po przeglądzie
architektury nie są już modelem docelowym.
Nowy model rozdziela sześć pojęć:
| Pojęcie | Rola |
|---|---|
| deklaracja storage | typowane operacje i ich efekty |
| provider | technologia, np. PostgreSQL |
| driver | biblioteka dostawcy, np. Npgsql |
| Provider Runtime | niezależny host wykonujący provider |
| binding | jawny wybór providera i konfiguracji środowiska |
| środowisko docelowe | miejsce wykonania tasku korzystającego z zasobu |
flowchart LR
TASK["task w obsługiwanym środowisku"] --> STORAGE["deklaracja storage"]
STORAGE --> BINDING["binding deploymentu"]
BINDING --> ABI["Storage Runtime ABI"]
ABI --> RUNTIME["niezależny Provider Runtime"]
RUNTIME --> DRIVER["driver dostawcy"]
DRIVER --> DATABASE[("baza danych")]
Techniczne ABI runtime nie zastępuje deklaracji protocol. protocol nadal
opisuje komunikację logicznych części systemu. Granica Provider Runtime będzie
widoczna w deployment, diagnostyce i Narrative, ale aplikacja nie będzie
udawała, że zapytanie do bazy jest metodą HTTP.
Pierwszy referencyjny host powstanie jako niezależny runtime .NET. Memory, SQLite i PostgreSQL zostaną do niego przeniesione dopiero po ustanowieniu manifestu pakietu, bindingu, lockfile i wspólnej bramki zgodności.
flowchart LR
DOMAIN["moduły domenowe .jnx"] --> SERVICE["zadania @server"]
SERVICE --> CONTRACT["extern storage / storage.Store"]
CONTRACT --> MEMORY["przejściowy Go: memory"]
CONTRACT --> SQLITE["przejściowy Go: SQLite"]
CONTRACT --> POSTGRESQL["przejściowy Go: PostgreSQL"]
SQLITE --> RESTART["restart procesu"]
POSTGRESQL --> REMOTE["zdalny serwer bazy"]
RESTART --> SERVICE
SERVICE --> PANEL["typowany @report"]
Uproszczony wzorzec modelu storage
Gdy skupiamy się wyłącznie na przepływie związanym z bazą danych, przyjmujemy następujący uproszczony wzorzec:
flowchart LR
EMBEDDED["@embedded<br/>generuje dane"] -->|"typowane komunikaty"| SERVER["@server<br/>zapisuje i odczytuje storage"]
SERVER --> DB[("SQLite lub PostgreSQL")]
DB --> SERVER
SERVER -->|"typowana projekcja"| REPORT["@report<br/>prezentuje dane"]
REPORT -.->|"intencja użytkownika"| SERVER
W tym wzorcu:
@embeddeddostarcza dane do systemu,@serverjest jedynym właścicielem dostępu do bazy,@reportotrzymuje przygotowany wynik i prezentuje go człowiekowi,- działanie użytkownika w
@reportwraca do@serverjako typowana intencja, - dopiero zadanie
@servermoże autoryzować intencję i zmienić trwały stan.
@embedded → @server → storage → @server → @report
▲ │
└── intencja ────────┘
Jest to wzorzec dydaktyczny dotyczący storage, a nie pełna definicja ról
platform. @embedded może również podejmować lokalne decyzje i sterować
urządzeniem, a @report może inicjować działania użytkownika. W obecnie
zweryfikowanym pionie żadna z tych platform nie otwiera jednak bezpośrednio
serwerowego pliku SQLite.
Moduł to nie tekstowe include
Import rozwiązuje symbole i zachowuje pochodzenie diagnostyki. Nie wkleja tekstu jednego pliku do drugiego.
import home::domain
import home::persistence as persistence
import home::reports { HomeObservation, BuildHomeStatus as BuildStatus }
Obsługiwane są importy całego modułu, alias modułu, wybór symboli i alias symbolu. Kompilator wykrywa brak modułu, brak symbolu, kolizję, cykl, różnicę wielkości liter i próbę wyjścia poza dozwolone katalogi projektu. LSP przechodzi do definicji, wyszukuje referencje i wykonuje rename między plikami.
Projekt może również wskazać namespacowaną bibliotekę lokalną. Build zapisuje
deterministyczny plik blokady junexis.modules.lock/0.1 z listą modułów,
ścieżkami i sumami SHA-256. Publiczny rejestr zdalnych pakietów nie jest jeszcze
częścią tego kontraktu.
W codziennej pracy oznacza to, że deweloper:
- ustala
sourceRootswjunexis.project.toml, - traktuje ścieżkę pliku jako tożsamość modułu,
- importuje tylko potrzebne symbole albo nadaje modułowi alias,
- pozostawia
pipeline,protocoli deployment w module wejściowym, - kontroluje wynik w
out/debug/junexis.modules.lock.json.
Poznaj: ten sam system bez trwałych danych
Provider pamięciowy realizuje ten sam interfejs operacji co SQLite. Nadaje się do nauki i szybkiego eksperymentu, ponieważ nowa instancja zaczyna pusta, a zamknięcie świadomie usuwa jej stan.
Nie jest udawanym testem trwałości. Pozwala zobaczyć znaczenie zapisu, odczytu, listowania, usuwania, commitu, rollbacku, anulowania i lifecycle bez tworzenia pliku bazy.
Gotowy projekt referencyjny zawiera adapter wybierający provider, dlatego początkujący może porównać oba zachowania. W nowym projekcie taki adapter nie jest jeszcze generowany automatycznie.
Eksperymentuj: podmień provider na SQLite
SQLite działa w procesie serwera. Panel nie otwiera pliku bazy i nie zna SQL.
Otrzymuje typowany wynik z zadania @server.
intencja użytkownika
→ zadanie @server
→ kontrakt domenowy storage
→ parametryzowana operacja SQLite
→ wynik domenowy
→ kanał do @report
Referencyjny provider:
- nie wymaga CGO ani lokalnego kompilatora C,
- stosuje parametryzowane zapytania,
- ma ograniczony timeout blokady i operacji,
- obsługuje jawny commit i rollback,
- uruchamia uporządkowane migracje,
- zapisuje SHA-256 zastosowanej migracji i odrzuca jej późniejszą zmianę,
- rozróżnia m.in.
not-found,conflict,busy,timeout,cancellediunknown-outcome.
Przejmij kontrolę: jawna granica adaptera
Aktualny pion nie jest ORM-em. Deklaracja extern storage opisuje operacje, a
adapter domenowy autora mapuje typy Junexis na rekordy wspólnego interfejsu
storage.Store. Dzięki temu wybór memory albo SQLite nie zmienia tasków
domenowych.
W bieżącej składni każda operacja extern storage wywoływana z tasku wymaga
również odpowiadającej deklaracji extern task. Plik Go w user/server jest
własnością dewelopera. junexis extern scaffold nie nadpisuje tego pliku, ale
obecnie skanuje tylko moduł wejściowy, nie importowany moduł storage. Przewodnik
pokazuje oba warianty pracy bez ukrywania tego ograniczenia.
Ta jawność jest dziś zaletą eksperta i zarazem granicą produktu. Następnym
krokiem będzie automatyczny binding providera, jego lifecycle i generowanie
typowanego adaptera, tak aby początkujący mógł dodać lokalną bazę bez ręcznego
kodu Go. Docelowa składnia resource pozostaje projektem; nie jest jeszcze
częścią gramatyki języka.
Co zostało sprawdzone od początku do końca
Referencyjny system składa się z pięciu modułów. Próba wykonuje kolejno:
- sprawdzenie grafu importów i semantyki,
- zbudowanie serwera, panelu, migracji i blokady modułów,
- zapis obserwacji przez zadanie serwerowe,
- kontrolowany rollback bez pozostawienia rekordu,
- zakończenie procesu,
- uruchomienie drugiego procesu na tej samej bazie,
- odczyt zatwierdzonego rekordu,
- przekazanie
HomeSnapshotdo@report, - uruchomienie serwera i panelu z gotowego System Bundle bez checkoutu i toolchainu.
sequenceDiagram
participant U as Użytkownik
participant S1 as Serwer 1
participant DB as SQLite
participant S2 as Serwer 2
participant P as Panel
U->>S1: zapisz obserwację
S1->>DB: commit
S1--xS1: kontrolowane zakończenie
S2->>DB: odczytaj po restarcie
DB-->>S2: zatwierdzony rekord
S2->>P: HomeSnapshot
P-->>U: odtworzony stan
Granice pozostają jawne: nie ma jeszcze rejestru zdalnych bibliotek,
automatycznego ORM-u, rozproszonych transakcji ani bezpośredniego dostępu
@report do bazy.
Przejdź do przewodnika: moduły i baza danych, aby zobaczyć strukturę projektu, kod kontraktu, wybór providera, migracje, artefakty kontrolne oraz rytm pracy dewelopera.