Skip to content

Commit

Permalink
feature: initial proposal of 'is not null'
Browse files Browse the repository at this point in the history
  • Loading branch information
wellgenio committed Nov 18, 2024
1 parent 619be13 commit 3695c0d
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 12 deletions.
28 changes: 27 additions & 1 deletion lib/src/lucid_validation_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,14 @@ abstract class LucidValidationBuilder<TProp, Entity> {
final List<RuleFunc<Entity>> _rules = [];
var _mode = CascadeMode.continueExecution;
LucidValidator<TProp>? _nestedValidator;
LucidValidator _lucid;

bool Function(Entity entity)? _condition;

/// Creates a [LucidValidationBuilder] instance with an optional [key].
///
/// The [key] can be used to identify this specific validation in a larger validation context.
LucidValidationBuilder(this.key, this.label, this._selector);
LucidValidationBuilder(this.key, this.label, this._selector, this._lucid);

String? Function([String?]) nestedByField(Entity entity, String key) {
if (_nestedValidator == null) {
Expand Down Expand Up @@ -154,6 +155,26 @@ abstract class LucidValidationBuilder<TProp, Entity> {
return this;
}

LucidValidationBuilder<T, Entity> useNotNull<T extends Object>(
ValidationException? Function(TProp value, Entity entity) rule) {
_rules.add((entity) => rule(_selector(entity), entity));

final builder =
_LucidValidationBuilder<T, Entity>(key, label, (Entity entity) {
final value = _selector(entity) as T;
return value;
}, _lucid);

this._mode = CascadeMode.stopOnFirstFailure;

_lucid.addBuilder(builder);
return builder;
}

CascadeMode getMode() {
return this._mode;
}

/// Sets the [CascadeMode] for the validation rules associated with this property.
///
/// The [cascade] method allows you to control the behavior of rule execution when a validation failure occurs.
Expand Down Expand Up @@ -261,3 +282,8 @@ abstract class LucidValidationBuilder<TProp, Entity> {
return exceptions;
}
}

class _LucidValidationBuilder<TProp, Entity>
extends LucidValidationBuilder<TProp, Entity> {
_LucidValidationBuilder(super.key, super.label, super.selector, super.lucid);
}
20 changes: 14 additions & 6 deletions lib/src/lucid_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import '../lucid_validation.dart';
abstract class LucidValidator<E> {
final List<LucidValidationBuilder<dynamic, E>> _builders = [];

addBuilder(LucidValidationBuilder<dynamic, E> builder) {
this._builders.add(builder);
}

/// Registers a validation rule for a specific property of the entity.
///
/// [func] is a function that selects the property from the entity [E].
Expand All @@ -22,7 +26,7 @@ abstract class LucidValidator<E> {
TProp Function(E entity) selector,
{required String key,
String label = ''}) {
final builder = _LucidValidationBuilder<TProp, E>(key, label, selector);
final builder = _LucidValidationBuilder<TProp, E>(key, label, selector, this);
_builders.add(builder);

return builder;
Expand Down Expand Up @@ -89,10 +93,14 @@ abstract class LucidValidator<E> {
/// }
/// ```
ValidationResult validate(E entity) {
final exceptions =
_builders.fold(<ValidationException>[], (previousErrors, builder) {
return previousErrors..addAll(builder.executeRules(entity));
});
final List<ValidationException> exceptions = [];

for (var builder in _builders) {
exceptions.addAll(builder.executeRules(entity));
if(builder.getMode() == CascadeMode.stopOnFirstFailure && exceptions.isNotEmpty) {
break;
}
}

return ValidationResult(
isValid: exceptions.isEmpty,
Expand All @@ -103,5 +111,5 @@ abstract class LucidValidator<E> {

class _LucidValidationBuilder<TProp, Entity>
extends LucidValidationBuilder<TProp, Entity> {
_LucidValidationBuilder(super.key, super.label, super.selector);
_LucidValidationBuilder(super.key, super.label, super.selector, super.lucid);
}
4 changes: 2 additions & 2 deletions lib/src/validations/is_not_null_validation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ extension IsNotNullValidation<T> on SimpleValidationBuilder<T?> {
/// String format args:
/// - **{PropertyName}**: The name of the property.
///
SimpleValidationBuilder<T?> isNotNull({String? message, String? code}) {
return use(
SimpleValidationBuilder<String> isNotNull({String? message, String? code}) {
return useNotNull(
(value, entity) {
if (value != null) return null;

Expand Down
3 changes: 2 additions & 1 deletion test/mocks/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class UserModel {
String? description;
int age = 0;
String phone = '';
String cpf = '';
String? cpf = '';
}

class UserValidator extends LucidValidator<UserModel> {
Expand All @@ -27,6 +27,7 @@ class UserValidator extends LucidValidator<UserModel> {
.customValidPhone('Phone invalid format');

ruleFor((user) => user.cpf, key: 'cpf') //
.isNotNull()
.notEmpty()
.validCPF();
}
Expand Down
6 changes: 4 additions & 2 deletions test/src/validations/valid_cpf_validation_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ void main() {

validator
.ruleFor((e) => e.cpf, key: 'cpf') //
.isNotNull()
.notEmpty()
.validCPF();

final user = UserModel()..cpf = '1';
final user = UserModel()..cpf = null;

final result = validator.validate(user);

Expand All @@ -21,6 +23,6 @@ void main() {

final error = result.exceptions.first;

expect(error.message, "'cpf' is not a valid CPF.");
expect(error.message, "'cpf' must not be null.");
});
}

0 comments on commit 3695c0d

Please sign in to comment.