Skip to content

Commit ee361e6

Browse files
committed
Started working on a more flexible section reader
Much still has to be done, like: - making sure all actions support both the by section variant and the non-by section variant - Adding stuff like limit and offset - Support returning collections
1 parent df935f1 commit ee361e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1696
-644
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ currently examples can be found in the tests of the AP module and the tests of t
66

77
# What's left to do?
88
- 'complex' updates like `updateCByAAndB` which would update every row's C to the specified value where A and B match the specified value
9+
- add distinct and things like limit and offset
910
- make 'simple' actions like `insert` more flexible
1011
- allow it to return something else than void, e.g. ~~the input entity~~ or whether there was a row added
1112
- support adding every variable of the entity as parameter

ap/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ dependencies {
1010
annotationProcessor(libs.auto.service)
1111

1212
testImplementation(libs.compile.testing)
13-
testImplementation(libs.junit.api)
13+
testImplementation(libs.bundles.junit)
1414
testRuntimeOnly(libs.junit.engine)
1515
}
1616

ap/src/main/java/org/geysermc/databaseutils/processor/EntityManager.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
package org.geysermc.databaseutils.processor;
2626

2727
import static org.geysermc.databaseutils.processor.util.AnnotationUtils.hasAnnotation;
28-
import static org.geysermc.databaseutils.processor.util.TypeUtils.toBoxedTypeElement;
2928

3029
import java.util.ArrayList;
3130
import java.util.Arrays;
@@ -39,18 +38,18 @@
3938
import javax.lang.model.element.Modifier;
4039
import javax.lang.model.element.TypeElement;
4140
import javax.lang.model.element.VariableElement;
42-
import javax.lang.model.util.Types;
4341
import org.geysermc.databaseutils.meta.Entity;
4442
import org.geysermc.databaseutils.meta.Key;
4543
import org.geysermc.databaseutils.processor.info.ColumnInfo;
4644
import org.geysermc.databaseutils.processor.info.EntityInfo;
4745
import org.geysermc.databaseutils.processor.info.IndexInfo;
46+
import org.geysermc.databaseutils.processor.util.TypeUtils;
4847

4948
final class EntityManager {
5049
private final Map<CharSequence, EntityInfo> entityInfoByClassName = new HashMap<>();
51-
private final Types typeUtils;
50+
private final TypeUtils typeUtils;
5251

53-
EntityManager(final Types typeUtils) {
52+
EntityManager(final TypeUtils typeUtils) {
5453
this.typeUtils = Objects.requireNonNull(typeUtils);
5554
}
5655

@@ -100,7 +99,7 @@ EntityInfo processEntity(TypeElement type) {
10099
continue;
101100
}
102101

103-
TypeElement typeElement = toBoxedTypeElement(field.asType(), typeUtils);
102+
TypeElement typeElement = typeUtils.toBoxedTypeElement(field.asType());
104103
columns.add(new ColumnInfo(field.getSimpleName(), typeElement.getQualifiedName()));
105104

106105
if (hasAnnotation(field, Key.class)) {
@@ -122,8 +121,8 @@ EntityInfo processEntity(TypeElement type) {
122121
}
123122

124123
for (int i = 0; i < parameters.size(); i++) {
125-
var parameterType = toBoxedTypeElement(parameters.get(i).asType(), typeUtils)
126-
.getQualifiedName();
124+
var parameterType =
125+
typeUtils.toBoxedTypeElement(parameters.get(i).asType()).getQualifiedName();
127126
if (!columns.get(i).typeName().equals(parameterType)) {
128127
continue constructors;
129128
}

ap/src/main/java/org/geysermc/databaseutils/processor/RepositoryProcessor.java

+15-13
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,29 @@
4646
import javax.lang.model.element.ExecutableElement;
4747
import javax.lang.model.element.TypeElement;
4848
import javax.lang.model.type.TypeMirror;
49-
import javax.lang.model.util.Types;
5049
import javax.tools.Diagnostic;
5150
import org.geysermc.databaseutils.IRepository;
5251
import org.geysermc.databaseutils.meta.Repository;
5352
import org.geysermc.databaseutils.processor.action.ActionRegistry;
53+
import org.geysermc.databaseutils.processor.query.KeywordsReader;
54+
import org.geysermc.databaseutils.processor.query.QueryInfoCreator;
5455
import org.geysermc.databaseutils.processor.type.RepositoryGenerator;
5556
import org.geysermc.databaseutils.processor.util.InvalidRepositoryException;
5657
import org.geysermc.databaseutils.processor.util.TypeUtils;
5758

5859
@AutoService(Processor.class)
5960
public final class RepositoryProcessor extends AbstractProcessor {
61+
private TypeUtils typeUtils;
6062
private EntityManager entityManager;
6163
private Filer filer;
62-
private Types typeUtils;
6364
private Messager messager;
6465

6566
@Override
6667
public synchronized void init(ProcessingEnvironment processingEnv) {
6768
super.init(processingEnv);
68-
this.entityManager = new EntityManager(processingEnv.getTypeUtils());
69+
this.typeUtils = new TypeUtils(processingEnv.getTypeUtils(), processingEnv.getElementUtils());
70+
this.entityManager = new EntityManager(typeUtils);
6971
this.filer = processingEnv.getFiler();
70-
this.typeUtils = processingEnv.getTypeUtils();
7172
this.messager = processingEnv.getMessager();
7273
}
7374

@@ -169,7 +170,7 @@ private void writeGeneratedTypes(List<GeneratedType> generatedTypes) {
169170
private List<RepositoryGenerator> processRepository(TypeElement repository) {
170171
TypeMirror entityType = null;
171172
for (TypeMirror mirror : repository.getInterfaces()) {
172-
if (TypeUtils.isTypeOf(IRepository.class, MoreTypes.asTypeElement(mirror))) {
173+
if (TypeUtils.isType(IRepository.class, MoreTypes.asTypeElement(mirror))) {
173174
entityType = MoreTypes.asDeclared(mirror).getTypeArguments().get(0);
174175
}
175176
}
@@ -198,22 +199,23 @@ private List<RepositoryGenerator> processRepository(TypeElement repository) {
198199
boolean async = false;
199200
if (MoreTypes.isTypeOf(CompletableFuture.class, element.getReturnType())) {
200201
async = true;
201-
returnType = TypeUtils.toBoxedTypeElement(
202-
MoreTypes.asDeclared(element.getReturnType())
203-
.getTypeArguments()
204-
.get(0),
205-
typeUtils);
202+
returnType = typeUtils.toBoxedTypeElement(MoreTypes.asDeclared(element.getReturnType())
203+
.getTypeArguments()
204+
.get(0));
206205
} else {
207-
returnType = TypeUtils.toBoxedTypeElement(element.getReturnType(), typeUtils);
206+
returnType = typeUtils.toBoxedTypeElement(element.getReturnType());
208207
}
209208

210209
var name = element.getSimpleName().toString();
211210

212-
var action = ActionRegistry.actionMatching(name);
211+
var result = new KeywordsReader(name, entity).read();
212+
var action = ActionRegistry.actionMatching(result);
213213
if (action == null) {
214214
throw new InvalidRepositoryException("No available actions for %s", name);
215215
}
216-
action.addTo(generators, name, element, returnType, entity, typeUtils, async);
216+
var queryInfo = new QueryInfoCreator(result, element, entity, typeUtils).create();
217+
218+
action.addTo(generators, queryInfo, returnType, async, typeUtils);
217219
}
218220

219221
return generators;

ap/src/main/java/org/geysermc/databaseutils/processor/action/Action.java

+75-15
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,97 @@
2424
*/
2525
package org.geysermc.databaseutils.processor.action;
2626

27+
import com.squareup.javapoet.MethodSpec;
28+
import java.util.Collection;
2729
import java.util.List;
28-
import java.util.regex.Pattern;
29-
import javax.lang.model.element.ExecutableElement;
3030
import javax.lang.model.element.TypeElement;
31-
import javax.lang.model.util.Types;
32-
import org.geysermc.databaseutils.processor.info.EntityInfo;
31+
import org.geysermc.databaseutils.processor.query.QueryInfo;
3332
import org.geysermc.databaseutils.processor.type.RepositoryGenerator;
33+
import org.geysermc.databaseutils.processor.util.InvalidRepositoryException;
34+
import org.geysermc.databaseutils.processor.util.TypeUtils;
3435

3536
public abstract class Action {
3637
private final String actionType;
37-
private final Pattern actionPattern;
38+
private final boolean supportsFilter;
3839

39-
protected Action(String actionType, String actionRegex) {
40+
protected Action(String actionType) {
41+
this(actionType, true);
42+
}
43+
44+
protected Action(String actionType, boolean supportsFilter) {
4045
this.actionType = actionType;
41-
this.actionPattern = Pattern.compile(actionRegex);
46+
this.supportsFilter = supportsFilter;
4247
}
4348

4449
public String actionType() {
4550
return actionType;
4651
}
4752

48-
public Pattern actionPattern() {
49-
return actionPattern;
53+
public boolean supportsFilter() {
54+
return supportsFilter;
5055
}
5156

52-
public abstract void addTo(
53-
List<RepositoryGenerator> generators,
54-
String fullName,
55-
ExecutableElement element,
57+
protected abstract void addToSingle(
58+
RepositoryGenerator generator,
59+
QueryInfo info,
60+
MethodSpec.Builder spec,
5661
TypeElement returnType,
57-
EntityInfo info,
58-
Types typeUtils,
5962
boolean async);
63+
64+
protected boolean validateSingle(QueryInfo info, TypeElement returnType, TypeUtils typeUtils) {
65+
return TypeUtils.isType(Void.class, returnType) || TypeUtils.isWholeNumberType(returnType);
66+
}
67+
68+
protected boolean validateCollection(QueryInfo info, TypeElement elementType, TypeUtils typeUtils) {
69+
return false;
70+
}
71+
72+
protected boolean validateEither(QueryInfo info, TypeElement elementType, boolean collection, TypeUtils typeUtils) {
73+
return false;
74+
}
75+
76+
protected void validate(QueryInfo info, TypeElement returnType, TypeUtils typeUtils) {
77+
var elementType = returnType;
78+
if (typeUtils.isAssignable(Collection.class, returnType.asType())) {
79+
elementType = (TypeElement) returnType.getTypeParameters().get(0);
80+
81+
if (!supportsFilter) {
82+
throw new InvalidRepositoryException("%s does not support a By section", actionType);
83+
}
84+
85+
if (validateCollection(info, elementType, typeUtils)
86+
|| validateEither(info, elementType, true, typeUtils)) {
87+
return;
88+
}
89+
} else {
90+
if (validateEither(info, elementType, false, typeUtils)) {
91+
return;
92+
}
93+
if (validateSingle(info, returnType, typeUtils)) {
94+
return;
95+
}
96+
}
97+
98+
if (!typeUtils.isAssignable(info.entityType(), elementType.asType())) {
99+
throw new InvalidRepositoryException(
100+
"Unsupported return type %s for %s",
101+
returnType.getSimpleName(), info.element().getSimpleName());
102+
}
103+
}
104+
105+
public void addTo(
106+
List<RepositoryGenerator> generators,
107+
QueryInfo info,
108+
TypeElement returnType,
109+
boolean async,
110+
TypeUtils typeUtils) {
111+
if (!info.hasBySection() && info.element().getParameters().size() != 1) {
112+
throw new InvalidRepositoryException("Expected one parameter with type %s", info.entityType());
113+
}
114+
validate(info, returnType, typeUtils);
115+
116+
for (RepositoryGenerator generator : generators) {
117+
addToSingle(generator, info, MethodSpec.overriding(info.element()), returnType, async);
118+
}
119+
}
60120
}

ap/src/main/java/org/geysermc/databaseutils/processor/action/ActionRegistry.java

+9-9
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@
2525
package org.geysermc.databaseutils.processor.action;
2626

2727
import java.util.Set;
28+
import org.geysermc.databaseutils.processor.query.KeywordsReadResult;
2829

2930
public final class ActionRegistry {
30-
private static final Set<Action> REGISTERED_ACTIONS = Set.of(
31-
new FindByAction(),
32-
new ExistsByAction(),
33-
new DeleteByAction(),
34-
new InsertAction(),
35-
new UpdateAction(),
36-
new DeleteAction());
31+
private static final Set<Action> REGISTERED_ACTIONS =
32+
Set.of(new FindAction(), new ExistsAction(), new InsertAction(), new UpdateAction(), new DeleteAction());
3733

38-
public static Action actionMatching(String name) {
34+
public static Action actionMatching(KeywordsReadResult result) {
3935
for (Action action : REGISTERED_ACTIONS) {
40-
if (action.actionPattern().matcher(name).matches()) {
36+
var hasFilter = result.bySection() != null;
37+
if (result.actionName().equals(action.actionType())) {
38+
if (hasFilter && !action.supportsFilter()) {
39+
continue;
40+
}
4141
return action;
4242
}
4343
}

ap/src/main/java/org/geysermc/databaseutils/processor/action/ByAction.java

-75
This file was deleted.

0 commit comments

Comments
 (0)