IFC-1197: Fix CoreNumberPool not allowing upsert#9214
Conversation
There was a problem hiding this comment.
No issues found across 3 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Shadow auto-approve: would require human review. This change modifies the core mutation guard logic for CoreNumberPool upsert, which involves loading existing data and comparing values, and could impact production behavior if bugs exist.
| new_node_value = data.get("node") and data.get("node").value | ||
| new_node_attr_value = data.get("node_attribute") and data.get("node_attribute").value | ||
| if new_node_value or new_node_attr_value: | ||
| existing = await NodeManager.find_object( |
There was a problem hiding this comment.
should this method be able to accept node and assume that it is the latest version of this CoreNumberPool? I don't think that is possible right now, but if a graphql mutation class inherits from CoreNumberPool in the future then it would be
| raise ValidationError(input_value="The fields 'node' or 'node_attribute' can't be changed.") | ||
|
|
||
| async with graphql_context.db.start_transaction() as dbt: | ||
| number_pool, result = await super().mutate_update( |
There was a problem hiding this comment.
it looks like exisiting, if it is retrieved, should be passed in to the node parameter here so that the parent class doesn't also need to retrieve the same object from the database. existing could probably also be called node to go with the current pattern.
There was a problem hiding this comment.
now it looks like existing and node are unnecessarily swapping places. is it possible to just use node all the way through? you might have to do find_object(..., kind="CoreNumberPool") for the typing to be right
| ) | ||
| if new_node_value and new_node_value != existing.node.value: # type: ignore[attr-defined] | ||
| raise ValidationError(input_value="The fields 'node' or 'node_attribute' can't be changed.") | ||
| if new_node_attr_value and new_node_attr_value != existing.node_attribute.value: # type: ignore[attr-defined] |
There was a problem hiding this comment.
could you use get_attribute() here to remove the typing exception?
| ) | ||
| assert not upsert_mutable.errors | ||
| assert upsert_mutable.data | ||
| assert upsert_mutable.data["CoreNumberPoolUpsert"]["object"]["id"] == pool_id |
There was a problem hiding this comment.
the test should assert that the end_range is correctly updated in the response and that the end range is correct on the object retrieved from the database
|
|
||
| async def test_number_pool_update_with_unchanged_node_fields( | ||
| db: InfrahubDatabase, default_branch: Branch, register_core_models_schema: SchemaBranch | ||
| ) -> None: |
There was a problem hiding this comment.
this looks like it tests the same thing as the test above, but maybe I am missing something
| ) | ||
|
|
||
|
|
||
| async def test_number_pool_upsert_identical_fields( |
There was a problem hiding this comment.
all these tests could be combined into class so that the schema only has to be loaded once and the data only has to be loaded when necessary
| raise ValidationError(input_value="The fields 'node' or 'node_attribute' can't be changed.") | ||
|
|
||
| async with graphql_context.db.start_transaction() as dbt: | ||
| number_pool, result = await super().mutate_update( |
There was a problem hiding this comment.
now it looks like existing and node are unnecessarily swapping places. is it possible to just use node all the way through? you might have to do find_object(..., kind="CoreNumberPool") for the typing to be right
|
|
||
| pool = await NodeManager.get_one(id=pool_id, db=db, branch=default_branch_scope_class) | ||
| assert pool is not None | ||
| assert pool.get_attribute("end_range").value == 30 # type: ignore[union-attr] |
There was a problem hiding this comment.
is the type ignore really required here? I would think value would have a type of Any
| }, | ||
| ) | ||
| assert not update_same_values.errors | ||
| assert update_same_values.data |
There was a problem hiding this comment.
should confirm the expected value is returned and that the update actually persists on a retrieved instance of the object
| if new_node_value and new_node_value != node.get_attribute("node").value: # type: ignore[union-attr] | ||
| raise ValidationError(input_value="The fields 'node' or 'node_attribute' can't be changed.") | ||
| if new_node_attr_value and new_node_attr_value != node.get_attribute("node_attribute").value: # type: ignore[union-attr] |
There was a problem hiding this comment.
I think you can remove these type: ignores
There was a problem hiding this comment.
0 issues found across 1 file (changes from recent commits).
Shadow auto-approve: would require human review. This change modifies core business logic in a GraphQL mutation by altering the validation guard from a simple presence check to a value-diff check, which has a non-trivial impact on data integrity and behavior, so it requires human review.
Re-trigger cubic
Why
This PR changes the guard from a presence check to a value-diff check: the mutation now loads the existing node and only rejects the request when the incoming value genuinely differs from the stored one.
Closes #5636
How to test
Checklist
changelog/5636.fixed.md)