Skip to content

Commit 6e504b1

Browse files
committed
validation: add minimal KV helpers (validate_kv + set fallback)
1 parent c8e8479 commit 6e504b1

1 file changed

Lines changed: 68 additions & 1 deletion

File tree

include/vix/validation/Form.hpp

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <string_view>
2121
#include <type_traits>
2222
#include <utility>
23+
#include <vector>
2324

2425
#include <vix/validation/Schema.hpp>
2526
#include <vix/validation/ValidationError.hpp>
@@ -94,6 +95,43 @@ namespace vix::validation
9495
{
9596
};
9697

98+
/**
99+
* @brief Detects: static bool set(Derived&, std::string_view, std::string_view).
100+
*
101+
* Optional ultra-minimal KV binder for examples and simple forms.
102+
*/
103+
template <typename Derived, typename = void>
104+
struct has_kv_set : std::false_type
105+
{
106+
};
107+
108+
template <typename Derived>
109+
struct has_kv_set<Derived, std::void_t<decltype(Derived::set(
110+
std::declval<Derived &>(),
111+
std::declval<std::string_view>(),
112+
std::declval<std::string_view>()))>> : std::true_type
113+
{
114+
};
115+
116+
template <typename Derived>
117+
inline constexpr bool has_kv_set_v = has_kv_set<Derived>::value;
118+
119+
/**
120+
* @brief Detect KV input type: std::vector<std::pair<std::string_view, std::string_view>>.
121+
*/
122+
template <typename Input>
123+
struct is_kv_input : std::false_type
124+
{
125+
};
126+
127+
template <>
128+
struct is_kv_input<std::vector<std::pair<std::string_view, std::string_view>>> : std::true_type
129+
{
130+
};
131+
132+
template <typename Input>
133+
inline constexpr bool is_kv_input_v = is_kv_input<std::remove_cv_t<Input>>::value;
134+
97135
template <typename Derived, typename Input>
98136
inline constexpr bool has_bind2_v = has_bind2<Derived, Input>::value;
99137

@@ -331,12 +369,27 @@ namespace vix::validation
331369
return FormResult<cleaned_type>(std::move(errors));
332370
}
333371
}
372+
else if constexpr (detail::is_kv_input_v<Input> && detail::has_kv_set_v<Derived>)
373+
{
374+
for (const auto &kv : in)
375+
{
376+
const bool ok = static_cast<bool>(Derived::set(form, kv.first, kv.second));
377+
if (!ok)
378+
{
379+
errors.add(detail::make_form_error(
380+
"unknown or invalid field: " + std::string(kv.first),
381+
ValidationErrorCode::Format));
382+
return FormResult<cleaned_type>(std::move(errors));
383+
}
384+
}
385+
}
334386
else
335387
{
336388
static_assert(vix::validation::detail::dependent_false_v<Input>,
337389
"Form::validate(Input): Derived must implement a compatible bind(). "
338390
"Expected: static bool bind(Derived&, const Input&, ValidationErrors&) "
339-
"or static bool bind(Derived&, const Input&).");
391+
"or static bool bind(Derived&, const Input&) "
392+
"or (KV input) static bool set(Derived&, std::string_view, std::string_view).");
340393
}
341394

342395
// 2) Validate using Schema<Derived>
@@ -366,6 +419,20 @@ namespace vix::validation
366419
}
367420
}
368421

422+
// helper KV input type used by validate_kv
423+
using kv_pair = std::pair<std::string_view, std::string_view>;
424+
using kv_list = std::initializer_list<kv_pair>;
425+
using kv_input = std::vector<kv_pair>;
426+
427+
[[nodiscard]] static FormResult<cleaned_type> validate_kv(kv_list kv)
428+
{
429+
kv_input in;
430+
in.reserve(kv.size());
431+
for (const auto &p : kv)
432+
in.push_back(p);
433+
return validate(in);
434+
}
435+
369436
/**
370437
* @brief Access the cached schema associated with this form type.
371438
*

0 commit comments

Comments
 (0)