Modddels
HomeGithubPub.dev
v0.2
v0.2
  • Motivation
  • Setup
  • Generalities
    • Modddels Overview
    • Validations & Validation steps
    • Structure of a Modddel
    • Member parameters & Dependency parameters
    • Usage
      • Data equality & toString
      • Pattern matching
      • Reading the fields
      • Reading the failures
      • CopyWith
  • ValueObjects
    • ValueObjects Overview
    • Creating a ValueObject
  • Entities
    • Entities Overview
    • ContentValidation & ContentFailure
    • ValidationSteps in Entities
    • SimpleEntity
      • Creating a SimpleEntity
      • Special Cases
    • IterableEntity & Iterable2Entity
      • IterableEntity / Iterable2Entity kinds
      • The Type Template
      • Creating an IterableEntity / Iterable2Entity
      • InvalidMembers Description
      • Special Cases
      • Creating your own IterableEntity / Iterable2Entity kind
  • Advanced Notions
    • The NullFailure Annotation
    • Using multiple parameters annotations
    • Class Hierarchy of ValueObjects
    • Class Hierarchy of Entities
    • Models that are always valid / invalid
  • Union of Modddels
    • Union of Modddels Overview
    • Basic Usage
    • Case-modddels pattern matching
    • Default Factory Constructor
    • Shared Properties
    • The Validate Methods
    • CopyWith
  • Unit-Testing Of Modddels
    • Unit-Testing Overview
    • Available Tests
    • Customizing Tests
  • Additional Information
    • Using type aliases
    • Re-running the generator
    • All Available Modddels
    • VsCode Snippets
Powered by GitBook
On this page
  1. Generalities
  2. Usage

Pattern matching

PreviousData equality & toStringNextReading the fields

Let's take this Username modddel again as an example :

The 'form' validationStep contains two validations : 'length' validation and 'characters' validation. The 'availability' validationStep contains only one validation : 'reserved' validation.

There are multiple pattern matching methods generated by the modddels generator.

/// Use the [map] method to do pattern matching between all the concrete
/// union-cases : the valid union-case + the invalid-step union-cases
///
String message1 = username.map(
    valid: (ValidUsername validUsername) => 'The username is valid',
    invalidForm: (InvalidUsernameForm invalidUsernameForm) => 
        'The username has an invalid form',
    invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) =>
        'The username is not available');

/// Use the [maybeMap] method when you only want to handle a few cases. It
/// returns the result of [orElse] for unhandled cases.
///
bool isAvailable = username.maybeMap(
  invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) => false,
  orElse: () => true,
);

/// Use the [mapOrNull] method when you only want to handle a few cases. It
/// returns null for unhandled cases.
///
String? message2 = username.mapOrNull(
  invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) =>
      'The username is not available',
);

/// Use the [mapValidity] method to do pattern matching between the valid
/// union-case and the abstract invalid union-case
///
username.mapValidity(
  valid: (ValidUsername validUsername) {
    print('Valid username');
  },
  invalid: (InvalidUsername invalidUsername) {
    print('Invalid username');
  },
);

/// The [maybeMapValidity] method is similar to the [maybeMap] method,
/// but :
/// - The [valid] callback parameter is required
/// - The [orElse] callback parameter is required too and has [invalid] as a
/// parameter.
///
String message3 = username.maybeMapValidity(
  valid: (ValidUsername validUsername) => 'Valid',
  invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) => 
      'Not available',
  orElse: (InvalidUsername invalidUsername) => 'Invalid for some other reason',
);

For the abstract invalid union-case (in this example it's InvalidUsername), there are other pattern matching methods you can use to map between the different invalid-step union-cases.

username.mapValidity(
  valid: (ValidUsername validUsername) {},
  invalid: (InvalidUsername invalidUsername) {
    /// Use the [mapInvalid] method to do pattern matching between all the
    /// invalid-step union-cases.
    ///
    String message1 = invalidUsername.mapInvalid(
        invalidForm: (InvalidUsernameForm invalidUsernameForm) => 
            'The username has an invalid form',
        invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) =>
            'The username is not available');

    /// Use the [maybeMapInvalid] method when you don't want to handle all
    /// invalid cases separately. The [orElse] callback parameter is required.
    ///
    invalidUsername.maybeMapInvalid(
      invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) => 
          print('Unavailable'),
      orElse: () => print('Invalid'),
    );

    /// The [mapOrNullInvalid] method is similar to [maybeMapInvalid], but it
    /// returns null for unhandled cases.
    ///
    String? message2 = invalidUsername.mapOrNullInvalid(
      invalidAvailability: (InvalidUsernameAvailability invalidUsernameAvailability) => 
          'Unavailable',
    );

    /// [whenInvalid], [maybeWhenInvalid], and [whenOrNullInvalid] give you a
    /// direct access to the failures of each invalid-step union-case.
    ///
    invalidUsername.whenInvalid(
      formFailures: (lengthFailure, charactersFailure) {},
      availabilityFailures: (reservedFailure) {},
    );

    invalidUsername.maybeWhenInvalid(
      availabilityFailures: (reservedFailure) {},
      orElse: () {},
    );

    invalidUsername.whenOrNullInvalid(
      availabilityFailures: (reservedFailure) {},
    );
  },
);