Skip to content

Commit

Permalink
Allow int/boolean in delete to indicate whether rows were deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim203 committed Sep 9, 2024
1 parent 4ac3a54 commit 185231e
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 36 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
/*
* Copyright (c) 2024 GeyserMC <https://geysermc.org>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* Copyright (c) 2024 GeyserMC
* Licensed under the MIT license
* @link https://github.com/GeyserMC/DatabaseUtils
*/
package org.geysermc.databaseutils.processor.action;
Expand All @@ -45,9 +26,11 @@ protected void addToSingle(RepositoryGenerator generator, QueryContext context,
@Override
protected boolean validateSingle(
EntityInfo info, CharSequence methodName, TypeMirror returnType, TypeUtils typeUtils) {
// todo does it also support saying how many items were deleted?
if (!typeUtils.isType(Void.class, returnType)) {
throw new InvalidRepositoryException("Expected Void as return type for %s, got %s", methodName, returnType);
if (!typeUtils.isType(Void.class, returnType)
&& !typeUtils.isType(Integer.class, returnType)
&& !typeUtils.isType(Boolean.class, returnType)) {
throw new InvalidRepositoryException(
"Expected Void, Integer or Boolean as return type for %s, got %s", methodName, returnType);
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,23 @@ public void addUpdate(QueryContext context, MethodSpec.Builder spec) {
@Override
public void addDelete(QueryContext context, MethodSpec.Builder spec) {
wrapInCompletableFuture(spec, context.returnInfo().async(), () -> {
boolean needsUpdatedCount = context.typeUtils().isType(Integer.class, context.returnType())
|| context.typeUtils().isType(Boolean.class, context.returnType());
if (needsUpdatedCount) {
spec.addStatement("int __count");
}

// for now, it's only either: delete a (list of) entities, or deleteByAAndB
if (context.parametersInfo().isSelf()) {
var filter = createFilter(context.entityInfo()
.keyColumnsAsFactors(
AndFactor.INSTANCE, context.parametersInfo().firstName()));
spec.addStatement("this.collection.deleteOne($L)", filter);

if (needsUpdatedCount) {
spec.addStatement("__count = this.collection.deleteOne($L).getDeletedCount()", filter);
} else {
spec.addStatement("this.collection.deleteOne($L)", filter);
}
} else if (context.parametersInfo().isSelfCollection()) {
spec.addStatement(
"var __bulkOperations = new $T<$T<$T>>()",
Expand All @@ -177,13 +188,31 @@ public void addDelete(QueryContext context, MethodSpec.Builder spec) {
createFilter(context.entityInfo().keyColumnsAsFactors(AndFactor.INSTANCE, "__entry")));
spec.endControlFlow();

spec.addStatement("this.collection.bulkWrite(__bulkOperations)");
if (needsUpdatedCount) {
spec.addStatement("__count = this.collection.bulkWrite(__bulkOperations).getDeletedCount()");
} else {
spec.addStatement("this.collection.bulkWrite(__bulkOperations)");
}
} else {
spec.addStatement("this.collection.deleteMany($L)", createFilter(context.bySectionFactors()));
if (needsUpdatedCount) {
spec.addStatement(
"__count = (int) this.collection.deleteMany($L).getDeletedCount()",
createFilter(context.bySectionFactors()));
} else {
//todo technically it can be a deleteOne if the factors contain all the key columns
spec.addStatement("this.collection.deleteMany($L)", createFilter(context.bySectionFactors()));
}
}

if (context.returnInfo().async()) {
if (context.returnInfo().async() && !needsUpdatedCount) {
spec.addStatement("return null");
return;
}

if (context.typeUtils().isType(Integer.class, context.returnType())) {
spec.addStatement("return __count");
} else if (context.typeUtils().isType(Boolean.class, context.returnType())) {
spec.addStatement("return __count > 0");
}
});
typeSpec.addMethod(spec.build());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import org.geysermc.databaseutils.processor.util.TypeUtils;

public final class SqlRepositoryGenerator extends RepositoryGenerator {
private static final int BATCH_SIZE = 250;
private static final int BATCH_SIZE = 500;

public SqlRepositoryGenerator() {
super(DatabaseCategory.SQL);
Expand Down Expand Up @@ -160,14 +160,26 @@ private void addExecuteQueryData(
private void addUpdateQueryData(MethodSpec.Builder spec, QueryContext context, QueryBuilder builder) {
addBySectionData(spec, context, builder, () -> {
if (!context.parametersInfo().isSelfCollection()) {
spec.addStatement("__statement.executeUpdate()");
if (context.typeUtils().isType(Integer.class, context.returnType())) {
spec.addStatement("return __statement.executeUpdate()");
return;
} else if (context.typeUtils().isType(Boolean.class, context.returnType())) {
spec.addStatement("return __statement.executeUpdate() > 0");
return;
} else {
spec.addStatement("__statement.executeUpdate()");
}
}

if (context.typeUtils().isType(Void.class, context.returnType())) {
spec.addStatement("return $L", context.returnInfo().async() ? "null" : "");
} else if (context.typeUtils().isType(context.entityType().asType(), context.returnType())) {
// todo support also creating an entity type from the given parameters
spec.addStatement("return $L", context.parametersInfo().firstName());
} else if (context.typeUtils().isType(Integer.class, context.returnType())) {
spec.addStatement("return __updateCount");
} else if (context.typeUtils().isType(Boolean.class, context.returnType())) {
spec.addStatement("return __updateCount > 0");
} else {
throw new InvalidRepositoryException(
"Return type can be either void or %s but got %s",
Expand All @@ -180,6 +192,11 @@ private void addBySectionData(
MethodSpec.Builder spec, QueryContext context, QueryBuilder builder, Runnable execute) {
wrapInCompletableFuture(spec, context.returnInfo().async(), () -> {
spec.beginControlFlow("try ($T __connection = this.dataSource.getConnection())", Connection.class);

if (context.parametersInfo().isSelfCollection()) {
spec.addStatement("__connection.setAutoCommit(false)");
}

spec.beginControlFlow(
"try ($T __statement = __connection.prepareStatement($S))",
PreparedStatement.class,
Expand All @@ -190,8 +207,14 @@ private void addBySectionData(
parameterName = context.parametersInfo().firstName();
}

boolean needsUpdatedCount = context.typeUtils().isType(Integer.class, context.returnType())
|| context.typeUtils().isType(Boolean.class, context.returnType());

if (context.parametersInfo().isSelfCollection()) {
spec.addStatement("int __count = 0");
if (needsUpdatedCount) {
spec.addStatement("int __updateCount = 0");
}
spec.beginControlFlow("for (var __element : $L)", parameterName);
parameterName = "__element";
}
Expand All @@ -216,12 +239,13 @@ private void addBySectionData(
if (context.parametersInfo().isSelfCollection()) {
spec.addStatement("__statement.addBatch()");

spec.beginControlFlow("if (__count % $L == 0)", BATCH_SIZE);
spec.addStatement("__statement.executeBatch()");
spec.beginControlFlow("if (++__count % $L == 0)", BATCH_SIZE);
executeBatchAndUpdateUpdateCount(spec, needsUpdatedCount);
spec.endControlFlow();

spec.endControlFlow();
spec.addStatement("__statement.executeBatch()");

executeBatchAndUpdateUpdateCount(spec, needsUpdatedCount);
spec.addStatement("__connection.commit()");
}

Expand All @@ -241,6 +265,23 @@ private void addBySectionData(
typeSpec.addMethod(spec.build());
}

private void executeBatchAndUpdateUpdateCount(MethodSpec.Builder spec, boolean needsUpdatedCount) {
if (!needsUpdatedCount) {
spec.addStatement("__statement.executeBatch()");
return;
}

// todo this can also be used to check which items were and weren't inserted etc.
spec.addStatement("int[] __affected = __statement.executeBatch()");
spec.beginControlFlow("for (int __updated : __affected)");

spec.beginControlFlow("if (__updated > 0)");
spec.addStatement("__updateCount += __updated");
spec.endControlFlow();

spec.endControlFlow();
}

private String createSetFor(QueryContext context, QueryBuilder builder) {
if (context.projection() != null && context.projection().columnName() != null) {
List<Factor> columns =
Expand Down
4 changes: 4 additions & 0 deletions ap/src/test/resources/test/advanced/AdvancedRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ public interface AdvancedRepository extends IRepository<TestEntity> {
CompletableFuture<Boolean> existsByAOrB(int a, String bb);

void updateCByBAndC(String newValue, String b, String c);

CompletableFuture<Boolean> deleteByAAndB(int a, String b);

Integer deleteByAAndC(int a, String c);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import java.lang.Boolean;
import java.lang.Integer;
import java.lang.Override;
import java.lang.String;
import java.util.UUID;
Expand Down Expand Up @@ -43,4 +44,20 @@ public CompletableFuture<Boolean> existsByAOrB(int a, String bb) {
public void updateCByBAndC(String newValue, String b, String c) {
this.collection.updateMany(Filters.and(Filters.eq("b", b), Filters.eq("c", c)), new Document("c", newValue));
}

@Override
public CompletableFuture<Boolean> deleteByAAndB(int a, String b) {
return CompletableFuture.supplyAsync(() -> {
int __count;
__count = (int) this.collection.deleteMany(Filters.and(Filters.eq("a", a), Filters.eq("b", b))).getDeletedCount();
return __count > 0;
} , this.database.executorService());
}

@Override
public Integer deleteByAAndC(int a, String c) {
int __count;
__count = (int) this.collection.deleteMany(Filters.and(Filters.eq("a", a), Filters.eq("c", c))).getDeletedCount();
return __count;
}
}
28 changes: 28 additions & 0 deletions ap/src/test/resources/test/advanced/AdvancedRepositorySqlImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,32 @@ public void updateCByBAndC(String newValue, String b, String c) {
throw new CompletionException("Unexpected error occurred", __exception);
}
}

@Override
public CompletableFuture<Boolean> deleteByAAndB(int a, String b) {
return CompletableFuture.supplyAsync(() -> {
try (Connection __connection = this.dataSource.getConnection()) {
try (PreparedStatement __statement = __connection.prepareStatement("delete from hello where a=? and b=?")) {
__statement.setInt(1, a);
__statement.setString(2, b);
return __statement.executeUpdate() > 0;
}
} catch (SQLException __exception) {
throw new CompletionException("Unexpected error occurred", __exception);
}
} , this.database.executorService());
}

@Override
public Integer deleteByAAndC(int a, String c) {
try (Connection __connection = this.dataSource.getConnection()) {
try (PreparedStatement __statement = __connection.prepareStatement("delete from hello where a=? and c=?")) {
__statement.setInt(1, a);
__statement.setString(2, c);
return __statement.executeUpdate();
}
} catch (SQLException __exception) {
throw new CompletionException("Unexpected error occurred", __exception);
}
}
}
9 changes: 6 additions & 3 deletions ap/src/test/resources/test/basic/BasicRepositorySqlImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ public CompletableFuture<Boolean> existsByB(String b) {
@Override
public void update(List<TestEntity> entity) {
try (Connection __connection = this.dataSource.getConnection()) {
__connection.setAutoCommit(false);
try (PreparedStatement __statement = __connection.prepareStatement("update hello set c=?,d=? where a=? and b=?")) {
int __count = 0;
for (var __element : entity) {
Expand All @@ -120,7 +121,7 @@ public void update(List<TestEntity> entity) {
__statement.setInt(3, __element.a());
__statement.setString(4, __element.b());
__statement.addBatch();
if (__count % 250 == 0) {
if (++__count % 500 == 0) {
__statement.executeBatch();
}
}
Expand Down Expand Up @@ -173,6 +174,7 @@ public CompletableFuture<Void> insert(TestEntity entity) {
@Override
public void insert(List<TestEntity> entities) {
try (Connection __connection = this.dataSource.getConnection()) {
__connection.setAutoCommit(false);
try (PreparedStatement __statement = __connection.prepareStatement("insert into hello (a,b,c,d) values (?,?,?,?)")) {
int __count = 0;
for (var __element : entities) {
Expand All @@ -181,7 +183,7 @@ public void insert(List<TestEntity> entities) {
__statement.setString(3, __element.c());
__statement.setBytes(4, this.__d.encode(__element.d()));
__statement.addBatch();
if (__count % 250 == 0) {
if (++__count % 500 == 0) {
__statement.executeBatch();
}
}
Expand Down Expand Up @@ -216,13 +218,14 @@ public CompletableFuture<Void> delete(TestEntity entity) {
@Override
public void delete(List<TestEntity> entities) {
try (Connection __connection = this.dataSource.getConnection()) {
__connection.setAutoCommit(false);
try (PreparedStatement __statement = __connection.prepareStatement("delete from hello where a=? and b=?")) {
int __count = 0;
for (var __element : entities) {
__statement.setInt(1, __element.a());
__statement.setString(2, __element.b());
__statement.addBatch();
if (__count % 250 == 0) {
if (++__count % 500 == 0) {
__statement.executeBatch();
}
}
Expand Down

0 comments on commit 185231e

Please sign in to comment.