Gabinet dentystyczny - zapis zmian i podsumowanie

Dziś wpis o ostatnim etapie implementacji Gabinetu oraz podsumowanie całego eksperymentu. Jak teraz wygląda aplikacja? Czego się nauczyłam? Zapraszam.
Wysyłanie zmian
Dziś piszę kod, który zamieni klikanie na diagramie w zapisy do bazy danych na serwerze.
Wysyłanie zdarzeń
Mój rysowacz diagramu (TeethDrawer) jest również kontrolerem (w znaczeniu MVC) - reaguje na zdarzenia kliknięć (i koloruje odpowiednie fragmenty SVG). Chcę, aby każde kliknięcie - zmiana stanu - była wysyłana na serwer, ale nie chcę, aby wysyłaniem zajmował się rysowacz, ponieważ on powinien zajmować się jedynie rysowaniem. Wysyłaniem żądań na serwer będzie zajmował się wysyłacz (Sender).
W jaki sposób rysowacz powiadomi wysyłacza, że dokonała się zmiana? Rysowacz i wysyłacz wspólnie mają dostęp do obiektu emitera zdarzeń, który może “emitować” zdarzenia oraz rejestrować callbacki do obsługi tych zdarzeń. Rysowacz będzie wysyłał zdarzenia update używając emitera, a wysyłacz zarejestruje się w emiterze jako obserwator zdarzeń update.
Reakcja na kliknięcie w rysowaczu obsługiwana jest przez metodę onclick, która wywołuje updateState:
onclick(v) {
return (e) => this.updateState(v)
}
updateState(v) {
let {toothside, toothnum} = v
let switcher = this.teeth.get(toothnum)
if (v.i !== undefined) {
stateid = switcher.updatePart(toothside)
} else {
stateid = switcher.updateWhole()
}
this.es.emit("update",
{toothnum, stateid, toothside})
}Klasa Sender
Klasa Sender otrzymuje w konstruktorze obiekt es - emiter zdarzeń - w którym rejestruje ona swoją metodę sendUpdate. Metoda ta zostanie wywołana (z parametrami przekazanymi przez stronę wysyłającą event)
w reakcji na event update i spodziewa się mapy {toothnum, stateid, toothside}:
class Sender {
constructor(pid, vid, es) {
this.pid = pid
this.vid = vid
this.es = es
es.on("update", this.sendUpdate)
}
sendUpdate(data) {
console.log("sendUpdate: data = ", data)
let {toothnum, stateid, toothside} = data
(async () => {
const rawResponse = await fetch('/api/visits/%{this.vid}/add', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
VisitId: this.vid,
PatientId: this.pid,
StateId: stateid,
ToothNum: toothnum,
Toothside: toothside})
});
const content = await rawResponse.json();
console.log(content)
})();
}
}Kompatybilność
Nie używam żadnej biblioteki do wysyłania żądań HTTP. Korzystam z funkcji fetch WebAPI (patrz: Fetch API). Wszyscy dentyści chcący korzystać z mojego programu powinni zainstalować sobie porządną przeglądarkę, bo IE tej funkcji nie wspiera.
Aktualizacja
Dziś rano napisałam kod, który aktualizuje diagram - rysuje listę zmian aż do bieżącej wizyty (włącznie). Dzięki temu mam już przepływ danych w obie strony: klikanie na diagramie jest serializowane do serii rekordów w tabeli change, a po załadowaniu danych bieżącej wizyty widoczne są wszystkie zmiany nie późniejsze niż czas utworzenia wizyty.
Zapytanie do wyciągania serii zmian, które są w tej właśnie kolejności “aplikowane” do diagramu:
with
pv(id, patient_id, vdatetime) as (
select id, patient_id, vdatetime
from visit
where visit.id = ?)
select
c.id, c.visit_id, v.patient_id, c.state_id, c.tooth_num, c.tooth_side
from
change c
left join
visit v
on
c.visit_id = v.id
join
pv
on
v.patient_id = pv.patient_id
where
v.vdatetime <= pv.vdatetime
order by
v.vdatetime asc,
c.time ascScreenshoty
Tak wygląda przykładowo seria wizyt Pszczółki Mai:
Podsumowanie
Myślę, że mój program posiada już wszystkie funkcje potrzebne minimalistycznemu stomatologowi. Można w nim:
- Dodawać i edytować pacjentów
- Dodawać i edytować wizyty
- Zapisywać zmiany w uzębieniu
Niestety:
- programu nikt nie używa, więc
- ma pewnie mnóstwo błędów
- nie posiada żadnych testów
- nie ma sprawdzania danych w formularzach
- program nie udostępnia operacji undo
- ani nie posiada żadnego mechanizmu backupowania bazy
Jednym słowem - jest to jedynie POC, częściowo działający prototyp.
Czego się nauczyłam - negatywy
- pisanie aplikacji frontendowych jest jednak strasznie nudne
- przełączanie sie między językami (które się słabo zna) jest nieprzyjemne - zmiana kontekstu (czytaj: paradygmatów, sposobów iteracji,rodzajów kolekcji, mechanizmu obsługi błędów etc) wymaga dużo energii i jest wyczerpujące
- używanie w projekcie bibliotek, których się dobrze nie zna jest dość karkołomne, więc dobrze najpierw sobie sprawdzić “na boczku”, jak wszystko działa
- niemałą trudność sprawiło mi trzymanie się wersji “minimalistycznej” i powstrzymywanie się przed wielkimi refaktoryzacjami - gdzieś tam w głowie zawsze majaczą jakieś pomysły na lepsze mechanizmy czy efektywniejsze struktury danych
Czego się nauczyłam - pozytywy
- posiadanie pełnej kontroli nad kodem to potężnie motywujące uczucie
- Go jest super szybkie, serwer wstaje w ciągu milisekund
- nauczyłam się podstaw Go i napisałam backend aplikacji webowej
- nauczyłam się biblioteki svgjs
Zakończenie
Koniec zabawy, zamykam projekt. Czas na inne wyzwania!
Jakie? O tym w następnym wpisie.
Zapraszam już niedługo.
(Źródła: dent)
This text is part of the series gabinet...
- 2021-13-09 - Gabinet dentystyczny - zapis zmian i podsumowanie
- 2021-11-09 - Gabinet dentystyczny - Legenda
- 2021-07-09 - Gabinet dentystyczny - diagram
- 2021-27-08 - Gabinet dentystyczny - przygotowania do rysowania diagramu
- 2021-26-08 - Gabinet dentystyczny - usuwanie pacjentów i wizyt
- 2021-23-08 - Gabinet dentystyczny - dodanie wizyt
- 2021-15-08 - Gabinet dentystyczny - prosta aplikacja webowa w Go