Skip to content

Commit

Permalink
fixed different handling of for delete methods, added docs
Browse files Browse the repository at this point in the history
  • Loading branch information
musketyr committed May 28, 2024
1 parent e0ddc7c commit b565e3a
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 27 deletions.
1 change: 1 addition & 0 deletions docs/guide/src/docs/asciidoc/dynamodb.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,7 @@ include::{root-dir}/subprojects/micronaut-amazon-awssdk-dynamodb/src/test/groovy
<8> You can combine `@SortKey` and `@Filter` annotations to specify the sort key condition
<9> Only`EQ`, `LE`, `LT`, `GE`, `GT`, `BETWEEN` and `BEGINS_WITH` operators are supported
<10> You can also use `@Filter` annotation to specify the sort key name
<11> If you use any customization annotations on delete method, then the method will be used as batch delete method

TIP: The operator `EQ` is used by default if `@Filter` annotation is not present. This makes it special and the service introduction tries to find the appropriate operation based on the actual value. For collections or arrays, `inList` operation is actually used. If the actual value is `null` then `isNull` operation is used. For other types, `eq` operation is used. For sort keys, `eq` operation is always used.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
Expand All @@ -62,6 +63,11 @@ public class ServiceIntroduction implements MethodInterceptor<Object, Object> {
private static final String HASH = "hash";
private static final String RANGE = "range";

private static class ItemArgument {
Argument<?> argument;
boolean single;
}

private static class FilterArgument {
Argument<?> firstArgument;
Argument<?> secondArgument;
Expand Down Expand Up @@ -156,7 +162,7 @@ private <T> Object doIntercept(MethodInvocationContext<Object, Object> context,
private <T> Object doIntercept(MethodInvocationContext<Object, Object> context, DynamoDbService<T> service) {
String methodName = context.getMethodName();
if (methodName.startsWith("save")) {
return handleSave(service, context);
return handleSave(service, context, findItemArgument(service, context));
}

if (methodName.startsWith("get") || methodName.startsWith("load")) {
Expand Down Expand Up @@ -210,6 +216,13 @@ private <T> Object doIntercept(MethodInvocationContext<Object, Object> context,
return service.update(criteria);
}

if (methodName.startsWith("delete")) {
Optional<ItemArgument> maybeItemArgument = findItemArgument(service, context);
if (maybeItemArgument.isPresent()) {
return handleDelete(service, context, maybeItemArgument);
}
}

if (methodName.startsWith("query") || methodName.startsWith("findAll") || methodName.startsWith("list") || methodName.startsWith("count") || methodName.startsWith("delete")) {
String index = context.getTargetMethod().isAnnotationPresent(Index.class) ? context.getTargetMethod().getAnnotation(Index.class).value() : null;
boolean consistent = context.getTargetMethod().isAnnotationPresent(Consistent.class) && context.getTargetMethod().getAnnotation(Consistent.class).value();
Expand All @@ -226,10 +239,11 @@ private <T> Object doIntercept(MethodInvocationContext<Object, Object> context,
}

if (methodName.startsWith("delete")) {
Optional<ItemArgument> maybeItemArgument = findItemArgument(service, context);
if (customized) {
return service.deleteAll(service.query(generateQuery(context, partitionAndSort, index, consistent, descending)));
}
return handleDelete(service, context);
return handleDelete(service, context, maybeItemArgument);
}

if (customized) {
Expand All @@ -252,41 +266,35 @@ private Object publisherOrIterable(Publisher<?> result, Class<?> type) {
return Flux.from(result).collectList().blockOptional().orElse(Collections.emptyList());
}

private <T> Object handleSave(DynamoDbService<T> service, MethodInvocationContext<Object, Object> context) {
@SuppressWarnings("unchecked")
private <T> Object handleSave(DynamoDbService<T> service, MethodInvocationContext<Object, Object> context, Optional<ItemArgument> maybeItemArgument) {
Map<String, MutableArgumentValue<?>> params = context.getParameters();
Argument<?>[] args = context.getArguments();

if (args.length != 1) {
throw new UnsupportedOperationException("Method expects 1 parameter - item, iterable of items or array of items");
}

Argument<?> itemArgument = args[0];
Publisher<T> items = toPublisher(service.getItemType(), itemArgument, params);

if (itemArgument.getType().isArray() || Iterable.class.isAssignableFrom(itemArgument.getType()) || Publisher.class.isAssignableFrom(itemArgument.getType())) {
if (maybeItemArgument.isPresent()) {
ItemArgument itemArgument = maybeItemArgument.get();
Publisher<T> items = toPublisher(service.getItemType(), itemArgument.argument, params);
if (itemArgument.single) {
return service.save((T) params.get(itemArgument.argument.getName()).getValue());
}
return publisherOrIterable(service.saveAll(items), context.getReturnType().getType());
} else {
throw new UnsupportedOperationException("Method expects 1 parameter - item, iterable of items or array of items");
}

return service.save((T) params.get(itemArgument.getName()).getValue());
}

private <T> Object handleDelete(DynamoDbService<T> service, MethodInvocationContext<Object, Object> context) {
private <T> Object handleDelete(DynamoDbService<T> service, MethodInvocationContext<Object, Object> context, Optional<ItemArgument> maybeItemArgument) {
Map<String, MutableArgumentValue<?>> params = context.getParameters();
Argument<?>[] args = context.getArguments();

if (args.length == 1) {
Argument<?> itemArgument = args[0];
Publisher<T> items = toPublisher(service.getItemType(), itemArgument, params);

if (itemArgument.getType().isArray() || Iterable.class.isAssignableFrom(itemArgument.getType()) || Publisher.class.isAssignableFrom(itemArgument.getType())) {
return service.deleteAll(items);
}

if (service.getItemType().isAssignableFrom(itemArgument.getType())) {
if (maybeItemArgument.isPresent()) {
ItemArgument itemArgument = maybeItemArgument.get();
Publisher<T> items = toPublisher(service.getItemType(), itemArgument.argument, params);
if (itemArgument.single) {
return service.delete(Flux.from(items).blockFirst());
}
return service.deleteAll(items);
}

Argument<?>[] args = context.getArguments();
if (args.length > 2) {
throw new UnsupportedOperationException("Method expects at most 2 parameters - partition key and sort key, an item or items");
}
Expand Down Expand Up @@ -323,6 +331,30 @@ private <T> Object handleGet(DynamoDbService<T> service, MethodInvocationContext
return service.get(partitionValue, partitionAndSort.getSortValue(params));
}

private <T> Optional<ItemArgument> findItemArgument(DynamoDbService<T> service, MethodInvocationContext<Object, Object> context) {
Map<String, MutableArgumentValue<?>> params = context.getParameters();
Argument<?>[] args = context.getArguments();

if (args.length == 1) {
Argument<?> itemArgument = args[0];
if (itemArgument.getType().isArray() || Iterable.class.isAssignableFrom(itemArgument.getType()) || Publisher.class.isAssignableFrom(itemArgument.getType())) {
ItemArgument item = new ItemArgument();
item.argument = itemArgument;
item.single = false;
return Optional.of(item);
}

if (service.getItemType().isAssignableFrom(itemArgument.getType())) {
ItemArgument item = new ItemArgument();
item.argument = itemArgument;
item.single = true;
return Optional.of(item);
}
}

return Optional.empty();
}

private QueryArguments findHashAndRange(Argument<?>[] arguments, DynamoDbService<?> table) {
QueryArguments names = new QueryArguments();
for (Argument<?> argument : arguments) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class DefaultDynamoDBServiceSpec extends Specification {
}
// end::setup[]

@SuppressWarnings('LineLength')
void 'unsupported methods throws meaningful messages'() {
when:
unknownMethodsService.doSomething()
Expand All @@ -87,8 +88,8 @@ class DefaultDynamoDBServiceSpec extends Specification {
when:
unknownMethodsService.delete('1', '1', '1')
then:
UnsupportedOperationException e3 = thrown(UnsupportedOperationException)
e3.message == 'Method expects at most 2 parameters - partition key and sort key, an item or items'
IllegalArgumentException e3 = thrown(IllegalArgumentException)
e3.message == '''Unknown property somethingElse for DynamoDBEntity{parentId='null', id='null', rangeIndex='null', date=null, number=0, mapProperty={}}'''

when:
unknownMethodsService.get('1', '1', '1')
Expand Down

0 comments on commit b565e3a

Please sign in to comment.