Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

!!! BUGFIX: Always unset node property, if set to null #4322

Merged
merged 25 commits into from
Feb 26, 2024

Conversation

mhsdesign
Copy link
Member

@mhsdesign mhsdesign commented Jun 9, 2023

Previously we made a distinction between unsetting a node property and setting it to null on the write side.

There was setting to null SerializedPropertyValues::fromArray(['tagName' => new SerializedPropertyValue(null, 'string')]) and unset SerializedPropertyValues::fromArray(['tagName' => null])

Unsetting a property would only be possible via php api by creating a custom SerializedPropertyValues.

The read site treats it the same and returns true in hasProperty only if there is a non null value in the database.

As discussed with @bwaidelich

I would recommend to not make a difference whether a property wasn't set initially or whether it was removed lateron.
While it might be useful to expose this information at some point, we should do so explicitly and not via the null-behavior of some adapter.

Previously if a property tagName was set to null

the NodePropertiesWereSet event would contain

"propertyValues":{"tagName":{"value":null,"type":"string"}}

and the properties of the node in the projection as well

"tagName":{"value":null,"type":"string"}

which this change the the NodePropertiesWereSet event would contain:

"propertyValues":{"tagName":null}

and the properties of the node in the projection would show no hint of this property.


Our logic to decide between unsetting properties and setting them to null was spread through a lot of classes and is a sheer wonder that it worked :D Now with the instruction of the UnsetPropertyValue, it is much more obvious how the behaviour works.

solves: #4467

Important

This change is breaking to your existing content repository data. To migrate your events please execute:

flow migrateevents:migratePropertiesToUnset
flow cr:projectionReplay contentGraph

otherwise you will face this error SerializedPropertyValue::__construct(): Argument #1 ($value) must be of type ArrayObject|array|string|int|float|bool, null given

mhsdesign added a commit to Flowpack/Flowpack.NodeTemplates that referenced this pull request Jun 10, 2023
@mhsdesign mhsdesign requested review from bwaidelich and nezaniel June 12, 2023 07:17
@bwaidelich
Copy link
Member

From the description and the code itself, I don't really understand this change. But I have the strong feeling that is should be backed by a test

@mhsdesign
Copy link
Member Author

Yes i see, sorry for being so spare about the details.

Id like to "quickly" chat with you about this to structure my mind - after that i could probably write it down more easily, and we could also discuss if my expectations are correct.

@bwaidelich
Copy link
Member

Id like to "quickly" chat with you about this to structure my mind

Those quotes around "quickly" make me suspicious :)
No, sure thing, let's talk about this sometimes next week!

@bwaidelich
Copy link
Member

I added some thoughts to #4304 (comment)

bwaidelich
bwaidelich previously approved these changes Jun 28, 2023
@mhsdesign mhsdesign marked this pull request as draft June 30, 2023 09:28
Copy link
Member

@skurfuerst skurfuerst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good :) wonder why the stuff before was done ;)

@mhsdesign
Copy link
Member Author

Now i only have to come up with a test for this ;) (Thats why its WIP - and also need to rebase it)

@mhsdesign mhsdesign linked an issue Sep 1, 2023 that may be closed by this pull request
@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch from 166c202 to e4ebdee Compare November 27, 2023 16:42
@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch from e4ebdee to 62ae5a4 Compare February 1, 2024 14:51
@mhsdesign mhsdesign marked this pull request as ready for review February 1, 2024 14:52
@mhsdesign
Copy link
Member Author

As we discussed previously it is an implementation detail of the adapter to save null values to the database or not, thats why its a bit hard to come up with a test? And as everything passes that seems proof enough this refactoring is correct?

@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch 2 times, most recently from 5eebe27 to 2e92b68 Compare February 2, 2024 23:38
Copy link
Member

@bwaidelich bwaidelich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for being complicated, but I dislike that one of the highest-level APIs now has this awkward withoutUnsets() method.
I am probably missing something but I expected SerializedProperties to be just that, a set of serialized properties. But that they would never contain any null-values.
I.e. that we would filter them out at write time.

I know, that we need it to unset previously existing properties, but I thought that we could put that logic into PropertyValuesToWrite rather than having something like Node->properties->serialized->withoutUnsets() which does not make sense to me on the read side at all

@mhsdesign
Copy link
Member Author

We discussed to introduce a PropertyNames dto and a new property in the SetSerializedProperties command / event $propertiesToUnset.

Additionally we briefly discussed that a property converter for the properties should probably never return null, as this would cause confusion about hasProperty seeminly not working.

@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch from 721fb45 to 7403660 Compare February 10, 2024 17:50
@mhsdesign
Copy link
Member Author

mhsdesign commented Feb 14, 2024

So i also just wrote a database migration that will update the events. Adding a php compatibility layer would just permanently introduce complexity and possibly bugs.

The following things have to be migrated:

  • NodePropertiesWereSet payload
  • SetSerializedNodeProperties in metadata
    example:
"propertyValues":{"tagName":{"value":null,"type":"string"}}
->
"propertyValues":[],"propertiesToUnset":["tagName"]

Here we just have to omit the null values because its a new node either way:

  • NodeAggregateWithNodeWasCreated payload
  • CreateNodeAggregateWithNodeAndSerializedProperties in metadata
"initialPropertyValues":{"title":{"value":"Blog","type":"string"},"titleOverride":{"value":null,"type":"string"},"uriPathSegment":{"value":"blog","type":"string"}}
->
"initialPropertyValues":{"title":{"value":"Blog","type":"string"},"uriPathSegment":{"value":"blog","type":"string"}}
  • CopyNodesRecursively in metadata
// somewhere deep recursive in $nodeTreeToInsert
"propertyValues":{"senderName":{"value":null,"type":"string"}}}
-> 
"propertyValues":{}

Also the basically impossible "initialPropertyValues":{"tagName":null} and "propertyValues":{"tagName":null will be migrated.

@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch 2 times, most recently from fc4299e to eb854f7 Compare February 14, 2024 20:56
@mhsdesign mhsdesign changed the title TASK: Always unset node property, if set to null !!! TASK: Always unset node property, if set to null Feb 14, 2024
@mhsdesign mhsdesign force-pushed the task/alwaysUnsetNodePropertyIfSetToNull branch from 295d0d2 to 81d53b6 Compare February 23, 2024 14:00
As discussed here #4322 (comment)
this _can_ likely happen when entity privileges are used.
Copy link
Member

@kitsunet kitsunet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, fine by me now, shall I hit merge?

@kitsunet
Copy link
Member

(I guess we agreed in the weekyl this is fine)

@kitsunet kitsunet merged commit 5ff329c into 9.0 Feb 26, 2024
10 checks passed
@kitsunet kitsunet deleted the task/alwaysUnsetNodePropertyIfSetToNull branch February 26, 2024 12:13
@mhsdesign
Copy link
Member Author

Yes i even did some additional testing that the command payload is also correctly migrated and a workspace with migrated changes can be merged.

Test cases:

  • unset node properties via set serialised properties
  • copy nodes which have explicitly unset properties which will also be added to the command
  • create node with initial unset property

Each of the scenarios worked when being published after switching the branch and applying the migrateevents:migratePropertiesToUnset migration.

@mhsdesign
Copy link
Member Author

Neos.Demo followup neos/Neos.Demo#191

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9.0 Node property is set to null instead of unset in database
5 participants