[BUG] Update and delete statements should return the number of affected rows
Which JNoSQL project the issue refers to?
JNoSQL (Core)
Bug description
The Jakarta Data spec says that update and delete statements should return the number of changed records to the client:
5.6.2. Update statements An update statement, with syntax given by update_statement, updates each record which satisfies the restriction imposed by the where clause, and returns the number of updated records to the client.
5.6.3. Delete statements A delete statement, with syntax given by delete_statement, deletes each record which satisfies the restriction imposed by the where clause, and returns the number of deleted records to the client.
(Emphasis mine.) However, trying this in current JNoSQL implementations gets me an UnsupportedOperationException.
JNoSQL Version
JNoSQL version 1.1.6
Steps To Reproduce
Running this program will exit with an exception:
package org.example;
import jakarta.data.repository.Insert;
import jakarta.data.repository.Param;
import jakarta.data.repository.Query;
import jakarta.data.repository.Repository;
import jakarta.enterprise.inject.se.SeContainer;
import jakarta.enterprise.inject.se.SeContainerInitializer;
import jakarta.nosql.Column;
import jakarta.nosql.Entity;
import jakarta.nosql.Id;
@Entity
public record Failure(
@Id String name,
@Column String value
) {
@Repository
public static interface Repo {
@Insert
Failure addRef(Failure f);
@Query("update Failure set value = :newValue where name = :name and value = :oldValue")
int updateRef(@Param("name") String name, @Param("oldValue") String oldValue, @Param("newValue") String newValue);
@Query("delete from Failure where name = :name and value = :value")
int deleteRef(@Param("name") String name, @Param("value") String value);
}
public static void main(String[] args) {
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
var repo = container.select(Repo.class).get();
var f = new Failure("test", "a");
System.out.println("inserted: "+(f = repo.addRef(f)));
try { System.out.println("inserted again: "+repo.addRef(f)); }
catch (Exception e) { System.out.println("duplicate insert fails: "+e); }
// The below fail with:
// Exception in thread "main" java.lang.UnsupportedOperationException: The return type must be Void when the query is not a SELECT operation, due to the nature of DELETE and UPDATE operations. The query: update Failure set value = :newValue where name = :name and value = :oldValu
System.out.println("refs updated: "+repo.updateRef(f.name(), "a", "b"));
System.out.println("refs updated: "+repo.updateRef(f.name(), "a", "c"));
System.out.println("refs deleted: "+repo.deleteRef(f.name(), "a"));
System.out.println("refs deleted: "+repo.deleteRef(f.name(), "b"));
}
}
}
Expected Results
The program should complete silently & successfully.
Code example, screenshot, or link to a repository
Attached is a minimal Docker Compose project that demonstrates the issue.
- Run
docker compose up --build -Vin the (unzipped) example directory. - The
app-1container will exit with an exception shortly after the database initialization. In the logs, this will look like:
app-1 | Mar 28, 2025 10:27:19 PM org.jboss.weld.environment.se.WeldContainer shutdown app-1 | INFO: WELD-ENV-002001: Weld SE container 75c5b4af-4099-400f-82fe-7e9db64e2122 shut down
app-1 | Exception in thread "main" java.lang.UnsupportedOperationException: The return type must be Void when the query is not a SELECT operation, due to the nature of DELETE and UPDATE operations. The query: delete from Failure where name = :name and value = :value
app-1 | at org.eclipse.jnosql.communication.semistructured.QueryType.checkValidReturn(QueryType.java:109)
app-1 | at org.eclipse.jnosql.mapping.semistructured.query.CustomRepositoryHandler.invoke(CustomRepositoryHandler.java:134)
app-1 | at jdk.proxy2/jdk.proxy2.$Proxy56.deleteRef(Unknown Source) app-1 | at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) app-1 | at java.base/java.lang.reflect.Method.invoke(Method.java:580) app-1 | at org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
app-1 | at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:109)
app-1 | at org.example.Failure$Repo$1121156340$Proxy$_$$_WeldClientProxy.deleteRef(Unknown Source)
app-1 | at org.example.Failure.main(Failure.java:42)
I will update the Jakarta NoSQL spec about this behavior and I will create a specialization for MongoDB once it does support this kind of capability
After a couple of discussions on the Jakarta NoSQL spec, due to the eventual persistence capability of NoSQL databases, we will not, by default, support returning numbers on delete.
The discussion is still open for more, however, for now I will close this one.