C.08 -- die Suche mit Bindestrich fand nichts. Das Feld wird per translate an "-/:.," in Leerzeichen zerlegt, die Eingabe aber nicht: "Mueller-Weiss" erzeugte das Muster mueller-weiss%, waehrend im Heuhaufen "mueller weiss" stand. Ohne Bindestrich fand man dieselbe Person. Die Trennzeichen stehen jetzt einmal in lib/employee-search.ts und werden von beiden Seiten des Vergleichs benutzt. C.09 -- der Einheitenfilter verlor jede Person mit vorgemerktem Austritt. "Laufend" war valid_to is null, aber terminate_employee setzt das Ende schon beim Erfassen, Monate vor dem Tag. Jetzt zaehlt auch, was noch laeuft (valid_to > heute). Bewusst ohne valid_from <= heute: ein geplanter Eintritt gehoert in die Liste, sonst fiele er aus dem Filter, obwohl der Status "Geplant" ihn ausdruecklich fuehrt. E.07 -- nur die Kostenstelle zu aendern war unmoeglich. update_position weist einen Aufruf ohne Aenderung ab, und die Umkontierung lief erst bei dessen Erfolg. Sie wird jetzt uebersprungen, wenn sich an den Stammangaben nichts geaendert hat. H.06 -- jedes Speichern erzeugte zusaetzlich "Wochenstunden 30.0 -> 30". Der Vergleich laeuft ueber Text, die Spalte ist numeric(4,1), und das Formular schickt 30. Der Kommentar an der Zeile nannte die Absicht richtig, nur reicht ::numeric dafuer nicht -- es muss auf die Genauigkeit der Spalte gehen.
57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
// Wie aus einer Eingabe Suchmuster werden.
|
|
//
|
|
// Getrennt von der Seite, weil hier die Entscheidungen stecken, die man
|
|
// prüfen können muss: was als Wort zählt, was am Wortanfang treffen muss und
|
|
// was von LIKE als Text und nicht als Platzhalter gelesen wird.
|
|
//
|
|
// Die Bedeutung selbst — „trifft am Wortanfang" — liegt im SQL der Seite:
|
|
// verglichen wird gegen Vorname, Nachname und Position zusammengesetzt, mit
|
|
// Trennzeichen als Wortgrenze.
|
|
|
|
/**
|
|
* Die Zeichen, die im Namen als Wortgrenze zählen.
|
|
*
|
|
* Sie stehen hier und nicht in der Seite, weil **beide Seiten des Vergleichs**
|
|
* sie brauchen: das Feld wird per `translate` an diesen Zeichen in Leerzeichen
|
|
* zerlegt, und die Eingabe muss genauso zerlegt werden. Vorher tat es nur das
|
|
* Feld — wer „Müller-Weiß" mit Bindestrich suchte, erzeugte das Muster
|
|
* `müller-weiß%`, während im Heuhaufen „müller weiß" stand. Null Treffer,
|
|
* obwohl die Person da ist; ohne Bindestrich fand man sie. Gemeldet im Test
|
|
* vom 29.09. (C.08).
|
|
*/
|
|
export const TRENNZEICHEN = "-/:.,";
|
|
|
|
/** Für `translate(…, TRENNZEICHEN, TRENNZEICHEN_ERSATZ)`: gleich lang, nur Leerzeichen. */
|
|
export const TRENNZEICHEN_ERSATZ = " ".repeat(TRENNZEICHEN.length);
|
|
|
|
const WORTGRENZE = new RegExp(`[\\s${TRENNZEICHEN.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&")}]+`);
|
|
|
|
/** Nur Ziffern? Dann ist es eine Personalnummer und kein Name. */
|
|
export function istPersonalnummer(term: string): boolean {
|
|
return /^\d+$/.test(term.trim());
|
|
}
|
|
|
|
/**
|
|
* Je Suchwort zwei LIKE-Muster: „am Anfang" und „nach einem Leerzeichen".
|
|
* Zusammen ergeben sie „am Anfang eines Wortes".
|
|
*
|
|
* Ein Wort als Teilzeichenkette zu suchen wäre einfacher und war die erste
|
|
* Fassung — bei „Winkler H" traf das „H" dann auf Thomas, Katharina und
|
|
* CNC-Dreher:in, also auf alle. Je kürzer die Eingabe, desto unbrauchbarer
|
|
* das Ergebnis, und ein Anfangsbuchstabe ist die kürzeste sinnvolle Eingabe.
|
|
*/
|
|
export function suchMuster(term: string): string[][] {
|
|
return term
|
|
.trim()
|
|
// An denselben Zeichen zerlegt wie das Feld, gegen das verglichen wird:
|
|
// „Müller-Weiß" wird zu zwei Wörtern, die beide am Wortanfang treffen
|
|
// müssen — genau wie „Müller Weiß".
|
|
.split(WORTGRENZE)
|
|
.filter(Boolean)
|
|
.map((wort) => {
|
|
// Die Platzhalter von LIKE entschärfen: wer „50 %" tippt, sucht Text.
|
|
const klein = wort.toLowerCase().replace(/[\\%_]/g, (z) => `\\${z}`);
|
|
return [`${klein}%`, `% ${klein}%`];
|
|
});
|
|
}
|