added fpdart demo
This commit is contained in:
parent
89e12bdf9f
commit
caf6007c26
@ -1,254 +0,0 @@
|
|||||||
**Vergleich und Vorstellung der funktionalen Aspekte von Go und Dart (mit fpdart) sowie Bezug zum Lambda-Kalkül**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Einführung**
|
|
||||||
|
|
||||||
Sowohl **Go** als auch **Dart** sind moderne Programmiersprachen, die hauptsächlich imperativ und objektorientiert ausgerichtet sind. Dennoch unterstützen beide Sprachen funktionale Programmierparadigmen in unterschiedlichem Maße. Die Bibliothek **fpdart** erweitert Dart um fortgeschrittene funktionale Programmierkonzepte. Im Folgenden werden die funktionalen Aspekte von Go und Dart (mit fpdart) verglichen und erläutert, wie diese mit dem **Lambda-Kalkül** in Verbindung stehen.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Funktionale Programmierung**
|
|
||||||
|
|
||||||
**Funktionale Programmierung** ist ein Programmierparadigma, das Funktionen als zentrale Bausteine betrachtet. Es fördert:
|
|
||||||
|
|
||||||
- **Unveränderlichkeit**: Daten werden nicht verändert, sondern es werden neue Datenstrukturen erzeugt.
|
|
||||||
- **Reine Funktionen**: Funktionen ohne Seiteneffekte.
|
|
||||||
- **Funktionen höherer Ordnung**: Funktionen, die andere Funktionen als Argumente nehmen oder zurückgeben.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Go und funktionale Programmierung**
|
|
||||||
|
|
||||||
**1. Funktionen als erstklassige Objekte**
|
|
||||||
|
|
||||||
- **Definition und Verwendung**: In Go können Funktionen wie Variablen behandelt werden. Sie können zugewiesen, als Parameter übergeben und zurückgegeben werden.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func add(a, b int) int {
|
|
||||||
return a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
func compute(a int, b int, op func(int, int) int) int {
|
|
||||||
return op(a, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := compute(5, 3, add) // Ergebnis: 8
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Anonyme Funktionen und Closures**
|
|
||||||
|
|
||||||
- **Anonyme Funktionen**: Go unterstützt anonyme Funktionen, die direkt definiert und verwendet werden können.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
increment := func(x int) int {
|
|
||||||
return x + 1
|
|
||||||
}
|
|
||||||
fmt.Println(increment(5)) // Ausgabe: 6
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Closures**: Anonyme Funktionen können auf Variablen aus ihrem umgebenden Kontext zugreifen.
|
|
||||||
|
|
||||||
```go
|
|
||||||
func main() {
|
|
||||||
x := 0
|
|
||||||
increment := func() int {
|
|
||||||
x++
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
fmt.Println(increment()) // Ausgabe: 1
|
|
||||||
fmt.Println(increment()) // Ausgabe: 2
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Fehlende erweiterte funktionale Konzepte**
|
|
||||||
|
|
||||||
- **Keine Immutabilität**: Go fördert nicht standardmäßig unveränderliche Datenstrukturen.
|
|
||||||
- **Fehlende Funktionen höherer Ordnung im Standardpaket**: Es gibt keine eingebauten Funktionen wie `map`, `filter` oder `reduce` für Slices oder Arrays.
|
|
||||||
- **Seiteneffekte**: Go erlaubt und verwendet häufig Funktionen mit Seiteneffekten.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Dart und funktionale Programmierung mit fpdart**
|
|
||||||
|
|
||||||
**1. Funktionen als erstklassige Objekte**
|
|
||||||
|
|
||||||
- **Definition und Verwendung**: Dart behandelt Funktionen ebenfalls als erstklassige Objekte.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
int add(int a, int b) => a + b;
|
|
||||||
|
|
||||||
int compute(int a, int b, int Function(int, int) op) => op(a, b);
|
|
||||||
|
|
||||||
var result = compute(5, 3, add); // Ergebnis: 8
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. Anonyme Funktionen und Closures**
|
|
||||||
|
|
||||||
- **Anonyme Funktionen (Lambdas)**:
|
|
||||||
|
|
||||||
```dart
|
|
||||||
var increment = (int x) => x + 1;
|
|
||||||
print(increment(5)); // Ausgabe: 6
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Closures**: Zugriff auf Variablen aus dem umgebenden Kontext.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
void main() {
|
|
||||||
var x = 0;
|
|
||||||
var increment = () {
|
|
||||||
x++;
|
|
||||||
return x;
|
|
||||||
};
|
|
||||||
print(increment()); // Ausgabe: 1
|
|
||||||
print(increment()); // Ausgabe: 2
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. fpdart-Bibliothek**
|
|
||||||
|
|
||||||
- **Überblick**:
|
|
||||||
|
|
||||||
- **fpdart** ist eine funktionale Programmierbibliothek für Dart, inspiriert von Haskell und anderen funktionalen Sprachen.
|
|
||||||
- Sie bietet Werkzeuge und Datenstrukturen für funktionale Programmierkonzepte wie **Option**, **Either**, **Monad**, **Functor** usw.
|
|
||||||
|
|
||||||
- **Hauptmerkmale**:
|
|
||||||
|
|
||||||
- **Option (Maybe)**: Umgang mit optionalen Werten, die vorhanden sein können oder nicht.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Option<int> parseInt(String str) {
|
|
||||||
final value = int.tryParse(str);
|
|
||||||
return value != null ? Some(value) : None<int>();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Either**: Behandlung von Berechnungen, die entweder einen Wert oder einen Fehler liefern.
|
|
||||||
|
|
||||||
```dart
|
|
||||||
Either<String, int> divide(int a, int b) {
|
|
||||||
return b == 0 ? Left('Division durch Null') : Right(a ~/ b);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **Functor und Monad**: Unterstützung für Funktionstransformationen und Sequenzierung von Berechnungen.
|
|
||||||
|
|
||||||
- **Vorteile**:
|
|
||||||
|
|
||||||
- **Immutabilität**: Fördert unveränderliche Datenstrukturen.
|
|
||||||
- **Reine Funktionen**: Ermutigt zur Verwendung von Funktionen ohne Seiteneffekte.
|
|
||||||
- **Typensicherheit**: Durch generische Typen und klare Strukturen werden Laufzeitfehler reduziert.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Vergleich zwischen Go und Dart (mit fpdart)**
|
|
||||||
|
|
||||||
**1. Sprachdesign und Paradigmen**
|
|
||||||
|
|
||||||
- **Go**:
|
|
||||||
|
|
||||||
- Primär eine imperative Sprache mit einigen funktionalen Merkmalen.
|
|
||||||
- Legt Wert auf Einfachheit, Leistung und Parallelität.
|
|
||||||
- Funktionale Programmierung ist möglich, aber nicht im Fokus.
|
|
||||||
|
|
||||||
- **Dart (mit fpdart)**:
|
|
||||||
|
|
||||||
- Unterstützt objektorientierte und funktionale Programmierung.
|
|
||||||
- Durch fpdart werden fortgeschrittene funktionale Konzepte zugänglich.
|
|
||||||
- Ideal für Anwendungen, die von funktionaler Programmierung profitieren, z. B. bei der Entwicklung mit Flutter.
|
|
||||||
|
|
||||||
**2. Funktionale Features**
|
|
||||||
|
|
||||||
- **Go**:
|
|
||||||
|
|
||||||
- Funktionen als Werte, anonyme Funktionen, Closures.
|
|
||||||
- Keine eingebauten funktionalen Datenstrukturen oder Monaden.
|
|
||||||
- Keine direkte Unterstützung für Immutabilität oder reine Funktionen.
|
|
||||||
|
|
||||||
- **Dart (mit fpdart)**:
|
|
||||||
|
|
||||||
- Erweiterte funktionale Bibliothek mit Monaden, Funktoren, Option, Either usw.
|
|
||||||
- Förderung von Immutabilität und reinen Funktionen.
|
|
||||||
- Bessere Unterstützung für funktionale Programmiermuster.
|
|
||||||
|
|
||||||
**3. Community und Ökosystem**
|
|
||||||
|
|
||||||
- **Go**:
|
|
||||||
|
|
||||||
- Starkes Ökosystem für serverseitige Anwendungen und Systemprogrammierung.
|
|
||||||
- Funktionale Programmierung wird weniger betont, aber es gibt Drittanbieterbibliotheken.
|
|
||||||
|
|
||||||
- **Dart (mit fpdart)**:
|
|
||||||
|
|
||||||
- Wachsende Community, insbesondere durch Flutter.
|
|
||||||
- fpdart ist aktiv entwickelt und erweitert die Möglichkeiten von Dart in Richtung funktionaler Programmierung.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Bezug zum Lambda-Kalkül**
|
|
||||||
|
|
||||||
**1. Was ist das Lambda-Kalkül?**
|
|
||||||
|
|
||||||
- **Lambda-Kalkül** ist ein formales System aus der mathematischen Logik zur Untersuchung von Funktionen und deren Anwendung.
|
|
||||||
- Es bildet die theoretische Grundlage für die funktionale Programmierung.
|
|
||||||
- Zentral sind anonyme Funktionen (Lambdas) und die Auswertung durch Funktionsanwendung.
|
|
||||||
|
|
||||||
**2. Anwendung in Go und Dart**
|
|
||||||
|
|
||||||
- **Anonyme Funktionen**:
|
|
||||||
|
|
||||||
- Beide Sprachen unterstützen anonyme Funktionen, die direkt aus dem Lambda-Kalkül abgeleitet sind.
|
|
||||||
- Diese ermöglichen Funktionen ohne Namen, die wie Variablen behandelt werden können.
|
|
||||||
|
|
||||||
- **Funktionen höherer Ordnung**:
|
|
||||||
|
|
||||||
- Funktionen, die andere Funktionen als Argumente nehmen oder zurückgeben.
|
|
||||||
- Wesentlich für die Ausdruckskraft des Lambda-Kalküls und in beiden Sprachen verfügbar.
|
|
||||||
|
|
||||||
**3. Erweiterte Konzepte mit fpdart**
|
|
||||||
|
|
||||||
- **Monaden und Funktoren**:
|
|
||||||
|
|
||||||
- Konzepte aus der Kategorie-Theorie, eng verwandt mit dem Lambda-Kalkül.
|
|
||||||
- Erlauben das Sequenzieren und Komponieren von Berechnungen auf abstrakte Weise.
|
|
||||||
- fpdart implementiert diese Konzepte in Dart und erweitert somit die Ausdruckskraft der Sprache im Sinne des Lambda-Kalküls.
|
|
||||||
|
|
||||||
**4. Relevanz**
|
|
||||||
|
|
||||||
- **Go**:
|
|
||||||
|
|
||||||
- Unterstützt grundlegende Konzepte des Lambda-Kalküls, aber ohne tiefe Integration.
|
|
||||||
- Eignet sich für pragmatische Anwendungen, bei denen funktionale Programmierung nicht im Vordergrund steht.
|
|
||||||
|
|
||||||
- **Dart (mit fpdart)**:
|
|
||||||
|
|
||||||
- Ermöglicht die Anwendung komplexerer Konzepte des Lambda-Kalküls.
|
|
||||||
- Bietet eine reichhaltigere Plattform für funktionale Programmierung.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Fazit**
|
|
||||||
|
|
||||||
- **Go** bietet grundlegende funktionale Programmiermöglichkeiten, aber der Schwerpunkt liegt auf imperativer und prozeduraler Programmierung.
|
|
||||||
- **Dart**, insbesondere mit der **fpdart**-Bibliothek, bietet erweiterte Unterstützung für funktionale Programmierung und ermöglicht die Nutzung fortgeschrittener Konzepte wie Monaden, Funktoren und unveränderliche Datenstrukturen.
|
|
||||||
- **Lambda-Kalkül** bildet die theoretische Basis für funktionale Programmierung und ist in beiden Sprachen durch anonyme Funktionen und Funktionen höherer Ordnung präsent. Mit fpdart wird Dart jedoch stärker an die Prinzipien des Lambda-Kalküls angelehnt.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Empfehlung**
|
|
||||||
|
|
||||||
Wenn Sie an funktionaler Programmierung interessiert sind und diese Konzepte in Ihrer Arbeit einsetzen möchten, ist **Dart mit fpdart** eine geeignete Wahl. Es bietet eine umfangreiche Bibliothek, um funktionale Paradigmen effektiv zu nutzen. **Go** ist hingegen ideal, wenn Sie eine einfache und performante Sprache für systemnahe Anwendungen benötigen, bei denen funktionale Programmierung nicht im Mittelpunkt steht.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Weiterführende Ressourcen**
|
|
||||||
|
|
||||||
- **fpdart GitHub-Repository**: [https://github.com/SandroMaglione/fpdart](https://github.com/SandroMaglione/fpdart)
|
|
||||||
- **Offizielle Go-Dokumentation**: [https://golang.org/doc/](https://golang.org/doc/)
|
|
||||||
- **Dart Programmierung**: [https://dart.dev/](https://dart.dev/)
|
|
||||||
- **Einführung in funktionale Programmierung und Lambda-Kalkül**:
|
|
||||||
- **Buch**: "Funktionale Programmierung in Scala" (auch für andere Sprachen hilfreich)
|
|
||||||
- **Online-Ressourcen**: Suchen Sie nach Tutorials zu funktionaler Programmierung und Lambda-Kalkül.
|
|
3
docs/presentation/fp_dart-demo/.gitignore
vendored
Normal file
3
docs/presentation/fp_dart-demo/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# https://dart.dev/guides/libraries/private-files
|
||||||
|
# Created by `dart pub`
|
||||||
|
.dart_tool/
|
1
docs/presentation/fp_dart-demo/CHANGELOG.md
Normal file
1
docs/presentation/fp_dart-demo/CHANGELOG.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
none
|
44
docs/presentation/fp_dart-demo/README.md
Normal file
44
docs/presentation/fp_dart-demo/README.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# **🚀 Demo-Projekt: AppError und Funktionale Programmierung mit fpdart**
|
||||||
|
|
||||||
|
Dieses Demo-Projekt begleitet die Zwischenpräsentation und verdeutlicht, wie funktionale Programmierung mit Dart und der Bibliothek `fpdart` umgesetzt werden kann. Es greift die zentralen Konzepte der Präsentation auf.
|
||||||
|
|
||||||
|
Das Projekt zeigt, wie durch funktionale Ansätze mit `fpdart`:
|
||||||
|
|
||||||
|
- ✅ Logik deklarativ ausgedrückt wird.
|
||||||
|
- 🛠️ Fehler elegant und strukturiert behandelt werden.
|
||||||
|
- 🔄 Erweiterbare, wartbare und typsichere Programme entstehen.
|
||||||
|
|
||||||
|
## **🔑 Zentrale Aspekte**
|
||||||
|
|
||||||
|
### **1. Monaden als Datenkonstrukte**
|
||||||
|
|
||||||
|
- 📦 Anwendung von **`Either`** für synchrone Fehler- und Erfolgsverarbeitung.
|
||||||
|
- ⏳ Verwendung von **`TaskEither`** zur Kombination von Lazy Evaluation mit asynchroner Verarbeitung und Fehlerbehandlung.
|
||||||
|
|
||||||
|
### **2. 🛡️ `AppError`: Einheitliche Fehlerstruktur**
|
||||||
|
|
||||||
|
- Einführung eines stark typisierten `AppError`, um Fehler systematisch zu kategorisieren (z. B. `ValidationError`, `DatabaseError`, `NetworkError`).
|
||||||
|
- Klare Trennung von:
|
||||||
|
- 📄 **Nachricht** (für Benutzer)
|
||||||
|
- ⚙️ **Typ** (zur Kategorisierung)
|
||||||
|
- 🔍 **Details** (für Debugging)
|
||||||
|
|
||||||
|
### **3. Praxisnahe Beispiele**
|
||||||
|
|
||||||
|
- 🔍 **Validierung**: Prüfung von Benutzereingaben mit `Either`.
|
||||||
|
- 🛠️ **Fehlerbehandlung**: Nutzung von `TaskEither` für Datenbank- und Netzwerkfehler.
|
||||||
|
- 🔗 **Verkettung von Funktionen**:
|
||||||
|
- Nahtlose Kombination von Validierung, Speicherung und weiteren Prozessen.
|
||||||
|
- Kein Abbruch bei Zwischenfehlern.
|
||||||
|
|
||||||
|
### **4. Verbindung zu funktionalen Konzepten**
|
||||||
|
|
||||||
|
- 🏛️ **Ursprung**: Konzepte aus Haskell und FP-TS.
|
||||||
|
- 🌀 **Monaden**: Praktische Anwendung zur sicheren Datenverarbeitung ohne Seiteneffekte.
|
||||||
|
- 🌐 **Anwendungsbezug**: Funktionale Programmierung als Werkzeug für robuste und skalierbare Software.
|
||||||
|
|
||||||
|
Das Projekt dient als praktische Grundlage, um die in der Präsentation behandelten Konzepte von funktionaler Programmierung und Fehlerbehandlung greifbar zu machen. Es zeigt, wie mit `fpdart`:
|
||||||
|
|
||||||
|
- Der Code sauber und wartbar bleibt.
|
||||||
|
- Funktionale Programmierung in Dart effektiv umgesetzt wird.
|
||||||
|
- Fehlermanagement nicht nur robust, sondern auch elegant sein kann.
|
30
docs/presentation/fp_dart-demo/analysis_options.yaml
Normal file
30
docs/presentation/fp_dart-demo/analysis_options.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# This file configures the static analysis results for your project (errors,
|
||||||
|
# warnings, and lints).
|
||||||
|
#
|
||||||
|
# This enables the 'recommended' set of lints from `package:lints`.
|
||||||
|
# This set helps identify many issues that may lead to problems when running
|
||||||
|
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
|
||||||
|
# style and format.
|
||||||
|
#
|
||||||
|
# If you want a smaller set of lints you can change this to specify
|
||||||
|
# 'package:lints/core.yaml'. These are just the most critical lints
|
||||||
|
# (the recommended set includes the core lints).
|
||||||
|
# The core lints are also what is used by pub.dev for scoring packages.
|
||||||
|
|
||||||
|
include: package:lints/recommended.yaml
|
||||||
|
|
||||||
|
# Uncomment the following section to specify additional rules.
|
||||||
|
|
||||||
|
# linter:
|
||||||
|
# rules:
|
||||||
|
# - camel_case_types
|
||||||
|
|
||||||
|
# analyzer:
|
||||||
|
# exclude:
|
||||||
|
# - path/to/excluded/files/**
|
||||||
|
|
||||||
|
# For more information about the core and recommended set of lints, see
|
||||||
|
# https://dart.dev/go/core-lints
|
||||||
|
|
||||||
|
# For additional information about configuring this file, see
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
46
docs/presentation/fp_dart-demo/lib/app_error.dart
Normal file
46
docs/presentation/fp_dart-demo/lib/app_error.dart
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
|
||||||
|
// Fehlerkategorien
|
||||||
|
enum AppErrorType {
|
||||||
|
ValidationError,
|
||||||
|
DatabaseError,
|
||||||
|
NetworkError,
|
||||||
|
UnknownError,
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppError {
|
||||||
|
final String message; // Benutzerfreundliche Fehlermeldung
|
||||||
|
final AppErrorType type; // Typisierte Fehlerkategorie
|
||||||
|
final Exception? exception; // Originale Exception (falls vorhanden)
|
||||||
|
|
||||||
|
AppError({
|
||||||
|
required this.message,
|
||||||
|
this.type = AppErrorType.UnknownError,
|
||||||
|
this.exception,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'AppError(message: $message, type: $type, exception: $exception)';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hilfsmethode zur einfachen Erstellung eines `Left`-Werts für `Either`
|
||||||
|
static Either<AppError, T> left<T>(
|
||||||
|
String message, {
|
||||||
|
AppErrorType? type,
|
||||||
|
Exception? exception,
|
||||||
|
}) {
|
||||||
|
return Either.left(AppError(
|
||||||
|
message: message,
|
||||||
|
type: type ?? AppErrorType.UnknownError,
|
||||||
|
exception: exception,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
return other is AppError && other.message == message && other.type == type;
|
||||||
|
}
|
||||||
|
}
|
68
docs/presentation/fp_dart-demo/lib/demo.dart
Normal file
68
docs/presentation/fp_dart-demo/lib/demo.dart
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import 'package:demo/app_error.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
|
||||||
|
// Mock-Datenbank
|
||||||
|
final existingEmails = ["existing@example.com"];
|
||||||
|
|
||||||
|
// Validierungsfunktionen
|
||||||
|
Either<AppError, String> validateName(String name) {
|
||||||
|
return name.isNotEmpty
|
||||||
|
? Either.right(name)
|
||||||
|
: AppError.left(
|
||||||
|
"Name cannot be empty",
|
||||||
|
type: AppErrorType.ValidationError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Either<AppError, String> validateEmail(String email) {
|
||||||
|
final emailRegex = RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
|
||||||
|
return emailRegex.hasMatch(email)
|
||||||
|
? Either.right(email)
|
||||||
|
: AppError.left(
|
||||||
|
"Invalid email format",
|
||||||
|
type: AppErrorType.ValidationError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asynchrone Überprüfung, ob die E-Mail bereits existiert
|
||||||
|
TaskEither<AppError, bool> checkEmailExists(String email) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async => existingEmails.contains(email),
|
||||||
|
(error, _) => AppError(
|
||||||
|
message: "Error checking email existence",
|
||||||
|
type: AppErrorType.DatabaseError,
|
||||||
|
exception: error as Exception?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benutzer in der Datenbank speichern (Dummy-Implementierung)
|
||||||
|
TaskEither<AppError, bool> saveUser(String name, String email) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
await Future.delayed(Duration(seconds: 1)); // Simulierte Latenz
|
||||||
|
print("User saved: $name, $email");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
(error, _) => AppError(
|
||||||
|
message: "Error saving user",
|
||||||
|
type: AppErrorType.DatabaseError,
|
||||||
|
exception: error as Exception?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: Begrüßungsnachricht senden
|
||||||
|
TaskEither<AppError, bool> sendWelcomeEmail(String email) {
|
||||||
|
return TaskEither.tryCatch(
|
||||||
|
() async {
|
||||||
|
print("Welcome email sent to $email");
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
(error, _) => AppError(
|
||||||
|
message: "Error sending welcome email",
|
||||||
|
type: AppErrorType.NetworkError,
|
||||||
|
exception: error as Exception?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
410
docs/presentation/fp_dart-demo/pubspec.lock
Normal file
410
docs/presentation/fp_dart-demo/pubspec.lock
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: "45cfa8471b89fb6643fe9bf51bd7931a76b8f5ec2d65de4fb176dba8d4f22c77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "73.0.0"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.3.2"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: "4959fec185fe70cce007c57e9ab6983101dbe593d2bf8bbfb4453aaec0cf470a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.8.0"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.12.0"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.19.1"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
coverage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: coverage
|
||||||
|
sha256: "4b03e11f6d5b8f6e5bb5e9f7889a56fe6c5cbe942da5378ea4d4d7f73ef9dfe5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.0"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.1"
|
||||||
|
fpdart:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: fpdart
|
||||||
|
sha256: "1b84ce64453974159f08046f5d05592020d1fcb2099d7fe6ec58da0e7337af77"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.1"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.1"
|
||||||
|
lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.2-main.4"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.16+1"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.16.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
node_preamble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_preamble
|
||||||
|
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
path:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.1"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.2"
|
||||||
|
shelf_packages_handler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_packages_handler
|
||||||
|
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.3"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.1"
|
||||||
|
source_map_stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_map_stack_trace
|
||||||
|
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
source_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_maps
|
||||||
|
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.12"
|
||||||
|
source_span:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.0"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.12.0"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "0bd04f5bb74fcd6ff0606a888a30e917af9bd52820b178eaa464beb11dca84b6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: test
|
||||||
|
sha256: f2a018e2baa6fce7c8daa55b8bdf4b3d7d165f82caac269e4cbe5edd666c0e4c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.25.9"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.4"
|
||||||
|
test_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_core
|
||||||
|
sha256: "60ff490bb383858015df7b7a0d883301a426edf9033989f55f091d91efb9dfaf"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.6"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "14.3.1"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.6"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.5.4 <4.0.0"
|
16
docs/presentation/fp_dart-demo/pubspec.yaml
Normal file
16
docs/presentation/fp_dart-demo/pubspec.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
name: demo
|
||||||
|
description: A sample command-line application.
|
||||||
|
version: 1.0.0
|
||||||
|
# repository: https://github.com/my_org/my_repo
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ^3.5.4
|
||||||
|
|
||||||
|
# Add regular dependencies here.
|
||||||
|
dependencies:
|
||||||
|
fpdart: ^1.1.1
|
||||||
|
# path: ^1.8.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^4.0.0
|
||||||
|
test: ^1.24.0
|
137
docs/presentation/fp_dart-demo/test/demo_test.dart
Normal file
137
docs/presentation/fp_dart-demo/test/demo_test.dart
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import 'package:demo/app_error.dart';
|
||||||
|
import 'package:demo/demo.dart';
|
||||||
|
import 'package:fpdart/fpdart.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group("User Registration Tests", () {
|
||||||
|
test("Valid name and email results in successful registration", () async {
|
||||||
|
final name = "John Doe";
|
||||||
|
final email = "newuser@example.com";
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Either<AppError, (String, String)>.right((name, email))
|
||||||
|
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||||
|
(validName) => validateEmail(userData.$2)
|
||||||
|
.map((validEmail) => (validName, validEmail))))
|
||||||
|
.toTaskEither()
|
||||||
|
.flatMap((validUser) => checkEmailExists(validUser.$2).flatMap(
|
||||||
|
(exists) => exists
|
||||||
|
? AppError.left("Email already exists",
|
||||||
|
type: AppErrorType.ValidationError)
|
||||||
|
.toTaskEither()
|
||||||
|
: saveUser(validUser.$1, validUser.$2)))
|
||||||
|
.flatMap((_) => sendWelcomeEmail(email))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(error) => fail("Test failed with error: ${error.message}"),
|
||||||
|
(success) => expect(success, equals(true)),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Invalid email format returns validation error", () async {
|
||||||
|
final name = "John Doe";
|
||||||
|
final email = "invalid-email";
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Either<AppError, (String, String)>.right((name, email))
|
||||||
|
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||||
|
(validName) => validateEmail(userData.$2)
|
||||||
|
.map((validEmail) => (validName, validEmail))))
|
||||||
|
.toTaskEither()
|
||||||
|
.run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(error) {
|
||||||
|
expect(error.message, equals("Invalid email format"));
|
||||||
|
expect(error.type, equals(AppErrorType.ValidationError));
|
||||||
|
},
|
||||||
|
(success) => fail("Test succeeded unexpectedly"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Existing email results in error", () async {
|
||||||
|
final name = "John Doe";
|
||||||
|
final email = "existing@example.com";
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Either<AppError, (String, String)>.right((name, email))
|
||||||
|
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||||
|
(validName) => validateEmail(userData.$2)
|
||||||
|
.map((validEmail) => (validName, validEmail))))
|
||||||
|
.toTaskEither()
|
||||||
|
.flatMap((validUser) => checkEmailExists(validUser.$2).flatMap(
|
||||||
|
(exists) => exists
|
||||||
|
? AppError.left("Email already exists",
|
||||||
|
type: AppErrorType.ValidationError)
|
||||||
|
.toTaskEither()
|
||||||
|
: saveUser(validUser.$1, validUser.$2)))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(error) => expect(error.message, equals("Email already exists")),
|
||||||
|
(success) => fail("Test succeeded unexpectedly"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Empty name returns validation error", () async {
|
||||||
|
final name = "";
|
||||||
|
final email = "newuser@example.com";
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Either<AppError, (String, String)>.right((name, email))
|
||||||
|
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||||
|
(validName) => validateEmail(userData.$2)
|
||||||
|
.map((validEmail) => (validName, validEmail))))
|
||||||
|
.toTaskEither()
|
||||||
|
.run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(error) => expect(
|
||||||
|
error,
|
||||||
|
equals(AppError(
|
||||||
|
message: "Name cannot be empty",
|
||||||
|
type: AppErrorType.ValidationError))),
|
||||||
|
(success) => fail("Test succeeded unexpectedly"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Error while sending welcome email is handled gracefully", () async {
|
||||||
|
final name = "John Doe";
|
||||||
|
final email = "newuser@example.com";
|
||||||
|
|
||||||
|
// Simuliere einen Fehler beim Senden der Begrüßungs-E-Mail
|
||||||
|
TaskEither<AppError, bool> sendWelcomeEmail(String email) {
|
||||||
|
return TaskEither.left(AppError(
|
||||||
|
message: "Error sending welcome email",
|
||||||
|
type: AppErrorType.NetworkError,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
final result =
|
||||||
|
await Either<AppError, (String, String)>.right((name, email))
|
||||||
|
.flatMap((userData) => validateName(userData.$1).flatMap(
|
||||||
|
(validName) => validateEmail(userData.$2)
|
||||||
|
.map((validEmail) => (validName, validEmail))))
|
||||||
|
.toTaskEither()
|
||||||
|
.flatMap((validUser) =>
|
||||||
|
checkEmailExists(validUser.$2).flatMap((exists) => exists
|
||||||
|
? AppError.left(
|
||||||
|
"Email already exists",
|
||||||
|
type: AppErrorType.ValidationError,
|
||||||
|
).toTaskEither()
|
||||||
|
: saveUser(validUser.$1, validUser.$2)))
|
||||||
|
.flatMap((_) => sendWelcomeEmail(email))
|
||||||
|
.run();
|
||||||
|
|
||||||
|
result.match(
|
||||||
|
(error) {
|
||||||
|
expect(error.message, equals("Error sending welcome email"));
|
||||||
|
expect(error.type, equals(AppErrorType.NetworkError));
|
||||||
|
},
|
||||||
|
(success) => fail("Test succeeded unexpectedly"),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user