validator.h 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #pragma once
  2. #include <jvalidate/detail/on_block_exit.h>
  3. #include <jvalidate/forward.h>
  4. #include <jvalidate/regex.h>
  5. #include <jvalidate/status.h>
  6. #include <jvalidate/validation_config.h>
  7. #include <jvalidate/validation_visitor.h>
  8. namespace jvalidate::detail {
  9. /**
  10. * @brief An implementation of an "Extension Constraint Visitor" plugin that
  11. * does nothing.
  12. */
  13. struct StubExtensionVisitor {};
  14. }
  15. namespace jvalidate {
  16. /**
  17. * @brief A validator is the tool by which a JSON object is actually validated
  18. * against a schema.
  19. *
  20. * @tparam RE A type that can be used to solve regular expressions
  21. */
  22. template <RegexEngine RE = JVALIDATE_IIF(JVALIDATE_HAS_ICU, ICURegexEngine, StdRegexEngine),
  23. typename ExtensionVisitor = detail::StubExtensionVisitor>
  24. class Validator {
  25. private:
  26. schema::Node const & schema_;
  27. ValidationConfig cfg_;
  28. ExtensionVisitor extension_;
  29. RE regex_;
  30. public:
  31. /**
  32. * @brief Construct a Validator
  33. *
  34. * @param schema The root schema being validated against. Must outlive this.
  35. *
  36. * @param cfg Any special (runtime) configuration rules being applied to the
  37. * validator.
  38. */
  39. Validator(schema::Node const & schema, ExtensionVisitor extension = {},
  40. ValidationConfig const & cfg = {})
  41. : schema_(schema), cfg_(cfg), extension_(extension) {}
  42. Validator(schema::Node const & schema, ValidationConfig const & cfg)
  43. : schema_(schema), cfg_(cfg) {}
  44. template <typename... Args> Validator(schema::Node &&, Args &&...) = delete;
  45. /**
  46. * @brief Run validation on the given JSON
  47. *
  48. * @tparam A Any Adapter type, in principle a subclass of adapter::Adapter.
  49. * Disallows mutation via ValidationConfig.construct_default_values
  50. *
  51. * @param json The value being validated
  52. *
  53. * @param result An optional out-param of detailed information about
  54. * validation failures. If result is not provided, then the validator will
  55. * terminate on the first error. Otherwise it will run through the entire
  56. * schema to provide a record of all of the failures.
  57. */
  58. template <Adapter A>
  59. requires(not MutableAdapter<A>)
  60. bool validate(A const & json, ValidationResult * result = nullptr) {
  61. EXPECT_M(not cfg_.construct_default_values,
  62. "Cannot perform mutations on an immutable JSON Adapter");
  63. detail::OnBlockExit _ = [&result, this]() { post_process(result); };
  64. return static_cast<bool>(
  65. ValidationVisitor(schema_, json, cfg_, regex_, extension_, result).validate(json));
  66. }
  67. /**
  68. * @brief Run validation on the given JSON
  69. *
  70. * @tparam A Any Adapter type that supports assignment, in principle a
  71. * subclass of adapter::Adapter.
  72. *
  73. * @param json The value being validated. Because A is a reference-wrapper,
  74. * the underlying value may be mutated.
  75. *
  76. * @param result An optional out-param of detailed information about
  77. * validation failures. If result is not provided, then the validator will
  78. * terminate on the first error. Otherwise it will run through the entire
  79. * schema to provide a record of all of the failures.
  80. */
  81. template <MutableAdapter A> bool validate(A const & json, ValidationResult * result = nullptr) {
  82. detail::OnBlockExit _ = [&result, this]() { post_process(result); };
  83. return static_cast<bool>(
  84. ValidationVisitor(schema_, json, cfg_, regex_, extension_, result).validate(json));
  85. }
  86. /**
  87. * @brief Run validation on the given JSON
  88. *
  89. * @tparam JSON A concrete JSON type. Will be turned into an Adapter, or a
  90. * MutableAdapter (if json is non-const and exists).
  91. *
  92. * @param json The value being validated.
  93. *
  94. * @param result An optional out-param of detailed information about
  95. * validation failures. If result is not provided, then the validator will
  96. * terminate on the first error. Otherwise it will run through the entire
  97. * schema to provide a record of all of the failures.
  98. */
  99. template <typename JSON>
  100. requires(not Adapter<JSON>)
  101. bool validate(JSON & json, ValidationResult * result = nullptr) {
  102. return validate(adapter::AdapterFor<JSON>(json), result);
  103. }
  104. private:
  105. void post_process(ValidationResult *& result) const {
  106. if (result == nullptr) {
  107. return;
  108. }
  109. if (cfg_.only_return_results_with_error) {
  110. *result = result->only_errors();
  111. }
  112. }
  113. };
  114. }