From aa549f040e5eb0cd589d720df08970b81beebc1e Mon Sep 17 00:00:00 2001 From: Juraj Budai Date: Thu, 12 Feb 2026 15:22:51 +0100 Subject: [PATCH] tree data UPDATE support applying diff subtrees instead of full diff --- src/diff.c | 37 ++++++++++++++++++++++++++++++++++++- src/tree_data.h | 18 ++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/diff.c b/src/diff.c index 6fda6962b..0d422c87b 100644 --- a/src/diff.c +++ b/src/diff.c @@ -1763,7 +1763,7 @@ lyd_diff_apply_metadata(struct lyd_node *node, const struct lyd_node *diff_node) /** * @brief Apply diff subtree on data tree nodes, recursively. * - * @param[in,out] first_node First sibling of the data tree. + * @param[in,out] first_node First sibling of the subtree. * @param[in] parent_node Parent of the first sibling. * @param[in] diff_node Current diff node. * @param[in] diff_cb Optional diff callback. @@ -1949,6 +1949,41 @@ lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff) return lyd_diff_apply_module(data, diff, NULL, NULL, NULL); } +LIBYANG_API_DEF LY_ERR +lyd_diff_apply_node(struct lyd_node *data_parent, struct lyd_node **data_first, const struct lyd_node *diff_node) +{ + LY_ERR ret = LY_SUCCESS; + struct ly_ht *dup_inst = NULL; + + LY_CHECK_ARG_RET(NULL, data_parent || data_first, diff_node, LY_EINVAL); + + /* diff_node is top level node, data_parent must be NULL */ + if (!diff_node->parent && data_parent) { + LOGERR(LYD_CTX(diff_node), LY_EINVAL, "data_parent must be NULL when applying top-level diff_node."); + return LY_EINVAL; + } + + if (!data_first) { + data_first = lyd_node_child_p(data_parent); + } + + /* diff_node is top level node, data_first must be set */ + if (!diff_node->parent && !data_first) { + LOGERR(LYD_CTX(diff_node), LY_EINVAL, "data_first is not set, when working with top-level node."); + return LY_EINVAL; + } + + if (diff_node->parent && data_parent && (diff_node->parent->schema != data_parent->schema)) { + LOGERR(LYD_CTX(diff_node), LY_EINVAL, "Schemas of data_parent and diff_node do not match."); + return LY_EINVAL; + } + + ret = lyd_diff_apply_r(data_first, data_parent, diff_node, NULL, NULL, &dup_inst); + + lyd_dup_inst_free(dup_inst); + return ret; +} + /** * @brief Update operations on a diff node when the new operation is NONE. * diff --git a/src/tree_data.h b/src/tree_data.h index a35798485..281a1ce3d 100644 --- a/src/tree_data.h +++ b/src/tree_data.h @@ -2186,6 +2186,24 @@ LIBYANG_API_DECL LY_ERR lyd_diff_apply_module(struct lyd_node **data, const stru */ LIBYANG_API_DECL LY_ERR lyd_diff_apply_all(struct lyd_node **data, const struct lyd_node *diff); +/** + * @brief Apply the diff subtree on a data tree. + * + * Details are mentioned in ::lyd_diff_apply_module(). + * + * @param[in,out] data_parent Parent of data to apply the diff subtree on. + * If @p diff_node is a top-level node, this parameter must be NULL. + * If @p diff_node has a parent, its schema must match this parameter schema. + * @param[in,out] data_first First sibling of the subtree. + * If @p diff_node is a top-level node, this parameter must point to the first top-level sibling. + * Optional for nested data. + * @param[in] diff_node Diff subtree to apply on data. + * @return LY_SUCCESS on success, + * @return LY_ERR on error. + */ +LIBYANG_API_DECL LY_ERR lyd_diff_apply_node(struct lyd_node *data_parent, struct lyd_node **data_first, + const struct lyd_node *diff_node); + /** * @ingroup datatree * @defgroup diffmergeoptions Data diff merge options.