public static TBuilder SetPropertyDisplayName <TBuilder, TProperty>(
            this PropertyValidationBuilderBase <TBuilder, TProperty> builder, string propertyDisplayName)
        {
            builder.PropertyValidator.SetPropertyDisplayName(propertyDisplayName);

            return(builder.Builder);
        }
        public static TBuilder WithCode <TBuilder, TProperty>(
            this PropertyValidationBuilderBase <TBuilder, TProperty> builder, string code)
        {
            builder.PropertyValidator.Rules.LastOrDefault()?.OverrideErrorCode(code);

            return(builder.Builder);
        }
        public static TBuilder IsNotNullOrWhiteSpace <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder)
        {
            var          message   = "Value cannot be null or whitespace";
            const string errorCode = "NOT_NULL_OR_WHITE_SPACE";

            builder.PropertyValidator.AddRule <string>(x => !string.IsNullOrWhiteSpace(x), message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsNotNullOrEmpty <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder)
        {
            var          message   = "Value cannot be null or empty string";
            const string errorCode = "NOT_NULL_OR_EMPTY";

            builder.PropertyValidator.AddRule <string>(x => !string.IsNullOrEmpty(x), message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsNull <TBuilder, TProperty>(this PropertyValidationBuilderBase <TBuilder, TProperty> builder)
        {
            var          message   = "Value must be null";
            const string errorCode = "NULL";

            builder.PropertyValidator.AddRule <TProperty>(x => x == null, message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsEqual <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder,
                                                  string value, StringComparison stringComparison = StringComparison.CurrentCulture)
        {
            var          message   = "Values are not equal";
            const string errorCode = "STR_EQUALITY";

            builder.PropertyValidator.AddRule <string>(x => x.Equals(value, stringComparison), message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsGreaterThan <TBuilder, TNumber>(
            this PropertyValidationBuilderBase <TBuilder, TNumber> builder, TNumber value)
            where TNumber : IComparable <TNumber>
        {
            var          message   = $"Value must be greater than {value}";
            const string errorCode = "NUM_GREATER_THAN";

            builder.PropertyValidator.AddRule <TNumber>(x => x.CompareTo(value) > 0, message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsLessThanOrEqualTo <TBuilder, TNumber>(
            this PropertyValidationBuilderBase <TBuilder, TNumber> builder, TNumber value)
            where TNumber : IComparable <TNumber>
        {
            var          message   = $"Value must be less than or equal to {value}";
            const string errorCode = "NUM_LESS_THAN_OR_EQUAL_TO";

            builder.PropertyValidator.AddRule <TNumber>(x => x.CompareTo(value) <= 0, message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder IsEmailAddress <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder)
        {
            var          message   = "Has invalid email format";
            const string errorCode = "STR_INVALID_EMAIL";

            var emailRegex = @"\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z";

            builder.PropertyValidator.AddRule <string>(x => Regex.IsMatch(x, emailRegex, RegexOptions.IgnoreCase),
                                                       message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder StopValidationAfterFailure <TBuilder, TProperty>(
            this PropertyValidationBuilderBase <TBuilder, TProperty> builder)
        {
            var propertyValidator = builder.PropertyValidator;
            var lastRule          = propertyValidator.Rules.LastOrDefault();

            if (lastRule != null)
            {
                lastRule.StopValidationAfterFailure = true;
            }

            return(builder.Builder);
        }
        public static TBuilder HasMaxLength <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder,
                                                       int maxLength)
        {
            if (maxLength < 0)
            {
                throw new ArgumentException($"'{nameof(maxLength)}' must be >= 0");
            }

            var          message   = $"Has length greater than {maxLength}";
            const string errorCode = "STR_MAX_LENGTH";

            builder.PropertyValidator.AddRule <string>(x => x?.Length <= maxLength, message, errorCode);

            return(builder.Builder);
        }
        public static TBuilder MatchesRegex <TBuilder>(this PropertyValidationBuilderBase <TBuilder, string> builder, string regex)
        {
            try
            {
                Regex.Match("", regex);
            }
            catch (ArgumentException)
            {
                throw new ArgumentException($"'{nameof(regex)}' represents invalid regex");
            }

            var          message   = "Is not matching to regex";
            const string errorCode = "STR_NOT_MATCHING_TO_REGEX";

            builder.PropertyValidator.AddRule <string>(x => Regex.IsMatch(x, regex),
                                                       message, errorCode);

            return(builder.Builder);
        }