Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validation support on consuming data objects #11

Open
navibyte opened this issue Aug 10, 2021 · 1 comment
Open

Add validation support on consuming data objects #11

navibyte opened this issue Aug 10, 2021 · 1 comment
Labels
enhancement New feature or request 🗒️ attributes Related to the code package "attributes"

Comments

@navibyte
Copy link
Collaborator

Easier input data validation when consuming external data (like JSON) via DataObject and DataArray classes on domain model classes.

Also some validation helper functions.

Consider also relation to value conversion functions like toIntValue() currently available.

@navibyte navibyte added 🗒️ attributes Related to the code package "attributes" enhancement New feature or request labels Aug 10, 2021
@navispatial
Copy link
Member

Now getters are like:

String getString(String key);
String? tryString(String key);

int getInt(String key, {int? min, int? max});
int? tryInt(String key, {int? min, int? max});

Getting String using getString or tryString just accesses a field and converts to String as possible.

For integers getInt or tryInt the optional params {int? min, int? max} already functions as some kind of validators

  • docs: "If provided [min] and [max] are used to clamp the returned value."
  • getters ensures that the result is between if min and max if it's possible to read an integer at first place
  • however if out of range defined by these params, this implementation does not throw some kind of validation exception as some might expect

The default impl in ValueAccessorMixin:

  @override
  String getString(K key) => toStringValue(this[key]);

  @override
  int getInt(K key, {int? min, int? max}) =>
      toIntValue(this[key], min: min, max: max);

  @override
  String? tryString(K key) {
    try {
      return getString(key);
    } on Exception {
      return null;
    }
  }

  @override
  int? tryInt(K key, {int? min, int? max}) {
    try {
      return getInt(key, min: min, max: max);
    } on Exception {
      return null;
    }
  }

And functions used above are defined as:

String toStringValue(Object? data) {
  if (data == null) throw const NullValueException();
  if (data is String) return data;
  return data.toString();
}

/// Converts [data] to `int` or throws FormatException if cannot convert.
///
/// If provided [min] and [max] are used to clamp the returned value.
int toIntValue(Object? data, {int? min, int? max}) {
  if (data == null) throw const NullValueException();
  int result;
  if (data is num) {
    result = data.round();
  } else if (data is BigInt) {
    result = data.toInt();
  } else if (data is String) {
    result = _stringToInt(data);
  } else if (data is bool) {
    result = data ? 1 : 0;
  } else {
    throw ConversionException(target: int, data: data);
  }
  if (min != null && result < min) {
    result = min;
  }
  if (max != null && result > max) {
    result = max;
  }
  return result;
}

int _stringToInt(String value) =>
    int.tryParse(value) ?? double.parse(value).round();

Solutions choices to implement custom validation / conversions:

  1. Define typedefs like typedef StringConverter = String Function(Object data) that could be given as an optional param in "getXXX" and "tryXXX" methods. These optional converts would convert raw data + also validate as necessary.
  2. Define typedefs like typedef StringValidator = String Function(String value) that could be given as an optional param in "getXXX" and "tryXXX" methods. These optional validators would validate a converter value, and throw ValidationException (extending FormatException) if a value is not allowed by domain specific rules.
  3. Keep "getXXX" and "tryXXX" methods as they are, no validation by default on DataObject and DataArray, but those classes could be extended for some custom domain case to bind validation logic of some kind.

Of course there could be other alternatives too...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request 🗒️ attributes Related to the code package "attributes"
Projects
None yet
Development

No branches or pull requests

1 participant