aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--yt/yt/core/ytree/unittests/yson_struct_update_ut.cpp31
-rw-r--r--yt/yt/core/ytree/yson_struct_update-inl.h69
-rw-r--r--yt/yt/core/ytree/yson_struct_update.h34
3 files changed, 128 insertions, 6 deletions
diff --git a/yt/yt/core/ytree/unittests/yson_struct_update_ut.cpp b/yt/yt/core/ytree/unittests/yson_struct_update_ut.cpp
index 0fb160fdcd..fd82265dd7 100644
--- a/yt/yt/core/ytree/unittests/yson_struct_update_ut.cpp
+++ b/yt/yt/core/ytree/unittests/yson_struct_update_ut.cpp
@@ -176,5 +176,36 @@ TEST(TUpdateYsonStructTest, Nested)
EXPECT_EQ(updatedCommand, "sort");
}
+TEST(TUpdateYsonStructTest, Validate)
+{
+ auto oldSpec = ConvertTo<TSpecWithPoolPtr>(TYsonString(TString("{pool=pool;}")));
+ auto longPoolSpec = ConvertTo<TSpecWithPoolPtr>(TYsonString(TString("{pool=new_pool;}")));
+ auto shortPoolSpec = ConvertTo<TSpecWithPoolPtr>(TYsonString(TString("{pool=p;}")));
+
+ std::string updatedPool;
+
+ auto configurator = TConfigurator<TSpecWithPool>();
+ configurator.Field("pool", &TSpecWithPool::Pool)
+ .Validator(BIND([&] (const std::string& newPool) {
+ THROW_ERROR_EXCEPTION_IF(
+ newPool.size() > 4,
+ "Pool name too long");
+ }))
+ .Updater(BIND([&] (const std::string& newPool) {
+ updatedPool = newPool;
+ }));
+
+ auto sealed = std::move(configurator).Seal();
+
+ EXPECT_THROW_WITH_SUBSTRING(
+ sealed.Validate(oldSpec, longPoolSpec),
+ "Pool name too long");
+
+ sealed.Validate(oldSpec, shortPoolSpec);
+ sealed.Update(oldSpec, shortPoolSpec);
+
+ EXPECT_EQ(updatedPool, "p");
+}
+
} // namespace
} // namespace NYT::NYTree
diff --git a/yt/yt/core/ytree/yson_struct_update-inl.h b/yt/yt/core/ytree/yson_struct_update-inl.h
index 3ba88ec853..c6ae5f1ead 100644
--- a/yt/yt/core/ytree/yson_struct_update-inl.h
+++ b/yt/yt/core/ytree/yson_struct_update-inl.h
@@ -49,9 +49,27 @@ struct TUnwrapYsonStructIntrusivePtr<TIntrusivePtr<T>>
////////////////////////////////////////////////////////////////////////////////
template <class TValue>
+TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::Validator(TCallback<void(const TValue&, const TValue&)> validator)
+{
+ VerifyEmptyValidator();
+ Validator_ = validator;
+ return *this;
+}
+
+template <class TValue>
+TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::Validator(TCallback<void(const TValue&)> validator)
+{
+ VerifyEmptyValidator();
+ Validator_ = BIND_NO_PROPAGATE([validator = std::move(validator)] (const TValue& /*oldValue*/, const TValue& newValue) {
+ validator(std::move(newValue));
+ });
+ return *this;
+}
+
+template <class TValue>
TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::Updater(TCallback<void(const TValue&, const TValue&)> updater)
{
- VerifyEmpty();
+ VerifyEmptyUpdater();
Updater_ = updater;
return *this;
}
@@ -59,7 +77,7 @@ TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::Updater(TCallback<void(const T
template <class TValue>
TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::Updater(TCallback<void(const TValue&)> updater)
{
- VerifyEmpty();
+ VerifyEmptyUpdater();
Updater_ = BIND_NO_PROPAGATE([updater = std::move(updater)] (const TValue& /*oldValue*/, const TValue& newValue) {
updater(std::move(newValue));
});
@@ -90,7 +108,7 @@ TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::NestedUpdater(
TUnwrappedValue,
typename NDetail::TUnwrapYsonStructIntrusivePtr<TValue>::TStruct>);
- VerifyEmpty();
+ VerifyEmptyUpdater();
auto configurator = configureCallback();
Updater_ = BIND_NO_PROPAGATE([configurator = std::move(configurator)] (const TValue& oldValue, const TValue& newValue) {
configurator.Update(oldValue, newValue);
@@ -99,6 +117,23 @@ TFieldRegistrar<TValue>& TFieldRegistrar<TValue>::NestedUpdater(
}
template <class TValue>
+void TFieldRegistrar<TValue>::DoValidate(
+ IYsonStructParameterPtr parameter,
+ TYsonStructBase* oldStruct,
+ TYsonStructBase* newStruct) const
+{
+ if (!Validator_) {
+ return;
+ }
+
+ auto typedParameter = DynamicPointerCast<TYsonStructParameter<TValue>>(parameter);
+ YT_VERIFY(typedParameter);
+ Validator_(
+ typedParameter->GetValue(oldStruct),
+ typedParameter->GetValue(newStruct));
+}
+
+template <class TValue>
void TFieldRegistrar<TValue>::DoUpdate(
IYsonStructParameterPtr parameter,
TYsonStructBase* oldStruct,
@@ -116,7 +151,13 @@ void TFieldRegistrar<TValue>::DoUpdate(
}
template <class TValue>
-void TFieldRegistrar<TValue>::VerifyEmpty() const
+void TFieldRegistrar<TValue>::VerifyEmptyValidator() const
+{
+ YT_VERIFY(!Validator_);
+}
+
+template <class TValue>
+void TFieldRegistrar<TValue>::VerifyEmptyUpdater() const
{
YT_VERIFY(!Updater_);
}
@@ -169,6 +210,7 @@ TSealedConfigurator<TStruct> TConfigurator<TStruct>::Seal() &&
{
return std::move(*this);
}
+
////////////////////////////////////////////////////////////////////////////////
template <CYsonStructDerived TStruct>
@@ -177,10 +219,27 @@ TSealedConfigurator<TStruct>::TSealedConfigurator(TConfigurator<TStruct> configu
{ }
template <CYsonStructDerived TStruct>
+void TSealedConfigurator<TStruct>::Validate(
+ TIntrusivePtr<TStruct> oldStruct,
+ TIntrusivePtr<TStruct> newStruct) const
+{
+ Do(oldStruct, newStruct, &NDetail::IFieldRegistrar::DoValidate);
+}
+
+template <CYsonStructDerived TStruct>
void TSealedConfigurator<TStruct>::Update(
TIntrusivePtr<TStruct> oldStruct,
TIntrusivePtr<TStruct> newStruct) const
{
+ Do(oldStruct, newStruct, &NDetail::IFieldRegistrar::DoUpdate);
+}
+
+template <CYsonStructDerived TStruct>
+void TSealedConfigurator<TStruct>::Do(
+ TIntrusivePtr<TStruct> oldStruct,
+ TIntrusivePtr<TStruct> newStruct,
+ TFieldRegistrarMethod fieldMethod) const
+{
const auto* meta = oldStruct->GetMeta();
YT_VERIFY(meta == newStruct->GetMeta());
const auto& parameterToFieldRegistrar = RegisteredFields_->ParameterToFieldRegistrar;
@@ -194,7 +253,7 @@ void TSealedConfigurator<TStruct>::Update(
if (fieldDescIter == parameterToFieldRegistrar.end()) {
THROW_ERROR_EXCEPTION("Field %Qv is not marked as updatable, but was changed", name);
} else {
- fieldDescIter->second->DoUpdate(parameter, oldStruct.Get(), newStruct.Get());
+ (*(fieldDescIter->second).*fieldMethod)(parameter, oldStruct.Get(), newStruct.Get());
}
}
}
diff --git a/yt/yt/core/ytree/yson_struct_update.h b/yt/yt/core/ytree/yson_struct_update.h
index 4b472021d1..7a517d6f57 100644
--- a/yt/yt/core/ytree/yson_struct_update.h
+++ b/yt/yt/core/ytree/yson_struct_update.h
@@ -26,6 +26,11 @@ DECLARE_REFCOUNTED_STRUCT(TRegisteredFieldDirectory);
struct IFieldRegistrar
: public TRefCounted
{
+ virtual void DoValidate(
+ IYsonStructParameterPtr parameter,
+ TYsonStructBase* oldStruct,
+ TYsonStructBase* newStruct) const = 0;
+
virtual void DoUpdate(
IYsonStructParameterPtr parameter,
TYsonStructBase* oldStruct,
@@ -42,6 +47,12 @@ class TFieldRegistrar
: public IFieldRegistrar
{
public:
+ // Registers validator that accepts old and new values as arguments.
+ TFieldRegistrar& Validator(TCallback<void(const TValue&, const TValue&)> validator);
+
+ // Registers validator that accepts only new value as an argument.
+ TFieldRegistrar& Validator(TCallback<void(const TValue&)> validator);
+
// Registers updater that accepts old and new values as arguments.
TFieldRegistrar& Updater(TCallback<void(const TValue&, const TValue&)> updater);
@@ -58,10 +69,17 @@ public:
TYsonStructBase* oldStruct,
TYsonStructBase* newStruct) const override;
+ void DoValidate(
+ IYsonStructParameterPtr parameter,
+ TYsonStructBase* oldStruct,
+ TYsonStructBase* newStruct) const override;
+
private:
- void VerifyEmpty() const;
+ void VerifyEmptyUpdater() const;
+ void VerifyEmptyValidator() const;
TCallback<void(const TValue&, const TValue&)> Updater_;
+ TCallback<void(const TValue&, const TValue&)> Validator_;
};
////////////////////////////////////////////////////////////////////////////////
@@ -114,11 +132,25 @@ class TSealedConfigurator
public:
TSealedConfigurator(TConfigurator<TStruct> configurator);
+ void Validate(
+ TIntrusivePtr<TStruct> oldStruct,
+ TIntrusivePtr<TStruct> newStruct) const;
+
void Update(
TIntrusivePtr<TStruct> oldStruct,
TIntrusivePtr<TStruct> newStruct) const;
private:
+ using TFieldRegistrarMethod = void(NDetail::IFieldRegistrar::*)(
+ IYsonStructParameterPtr parameter,
+ TYsonStructBase* oldStruct,
+ TYsonStructBase* newStruct) const;
+
+ void Do(
+ TIntrusivePtr<TStruct> oldStruct,
+ TIntrusivePtr<TStruct> newStruct,
+ TFieldRegistrarMethod fieldMethod) const;
+
NDetail::TRegisteredFieldDirectoryPtr RegisteredFields_;
};