If no transactional boundaries were set by the user,
Spring Data Neo4j would create new transactions (default read/write)
for the underlying database operations.
In cases where multiple statements are required to execute
a SDN operation this would mean that multiple transaction
would have been created.
This commit fixes this problem and creates new transaction if no
transaction was defined around the invocation of those units-of-work.
The change will introduce a breaking change:
All pure read operations in SDN (like Neo4jTemplate#findAll) will
now happen in read-only transactions.
If they contain custom statements with write operations,
they need to get wrapped in an explicit write transaction.
Closes#2860
Co-authored-by: Michael Simons <michael@simons.ac>
Prior to this, an incomplete loaded entity, due to projection, was never
touched again to add missing properties loaded via a different relationship
and projection definition.
Closes#2858
If an entity has already been loaded by any relationship,
it gets marked as processed.
But this is not a valid state if there are multiple relationships
to this entity and it is loaded via different projections for each
relationship.
In those cases SDN will just stop to find other relationships.
This commit fixes this behaviour by also taking the relationship
the entity got loaded with into account.
For a lot of relationships on a self-referencing type (10k+),
the result will be in the format `n, collect(rel), collect(relNode)`.
This brings the whole bucket of `relNodes` every time as a mappable option
to the table.
Prior to this change, SDN would have to check this complete bucket for potential
matching nodes. Just to find out later that there is no relationship to map this one for.
Checking the relationship bucket first to find if there is a relationship at all
to find a target node for, improves the performance drastically.
Closes#2782
This orders reusable containers on wish and is meant for scenarios in which a CI does not allow "native" use of reusable test containers but will make sure to clean them up after CI ran. Export a variable `SDN_FORCE_REUSE_OF_CONTAINERS` as `true` and SDN tests won't close the container, regardless whether the underlying Testcontainers supports reuse or not.
Closes#2837
Works now with Neo4j 4.4 and 5.x.
Instead of having a unified return type (String) in the Cypher result,
SDN accepts now `Long` for id() and `String`.
The conversion will take place in the library code.
To switch between id() and elementId(), SDN will inspect the selected
CypherDSL dialect and select the needed identifier function accordingly.
Closes#2784
The separate reactive bookmark manager was introduced because Project Reactor and Blockhound have issues with the `ReentrantReadWriteLock` approach we have taken in the imperative approach.
The first approach was using a synchronized set, but as it was correctly noted by @seabamirum on #2769 this is not enough on the reading path:
> It is imperative that the user manually synchronize on the returned set when iterating over it:
(From the JavaDoc of `Collections.synchronizedSet`.
Using `ConcurrentHashMap.newKeySet` would solve that issue, but it would require a check for `null` values in the `usedBookmarks` argument for `updateBookmarks` AND it would also not solve the fact that removing the used bookmarks and adding the new ones is an atomic operation (such as it originally was in the imperative world).
So therefor it is just easier to use a standard set and synchronize over it.
This update makes sure that the `ReactiveDefaultBookmarkManager` returns an unmodifiable copy of its current bookmarks instead of returning a view of the bookmarks.
Without the string conversion Neo4j will either to an (element)id or
label seek instead of a full node scan.
Also: In some corner case adding labels to the generic cyclic query
can improve the performance of the query.
On the other hand it cannot make it worse.
Closes#2750
Using FluentQueryByExample/Predicate with a subset of properties,
the underlying fetching mechanics in the Neo4jTemplate was still
querying for everything if the domain has a potential circular dependency.
Closes#2748