Skip to content

Commit

Permalink
Started working on a more flexible section reader
Browse files Browse the repository at this point in the history
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
  • Loading branch information
Tim203 committed Jun 16, 2024
1 parent df935f1 commit ee361e6
Show file tree
Hide file tree
Showing 47 changed files with 1,696 additions and 644 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ currently examples can be found in the tests of the AP module and the tests of t

# What's left to do?
- 'complex' updates like `updateCByAAndB` which would update every row's C to the specified value where A and B match the specified value
- add distinct and things like limit and offset
- make 'simple' actions like `insert` more flexible
- allow it to return something else than void, e.g. ~~the input entity~~ or whether there was a row added
- support adding every variable of the entity as parameter
Expand Down
2 changes: 1 addition & 1 deletion ap/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dependencies {
annotationProcessor(libs.auto.service)

testImplementation(libs.compile.testing)
testImplementation(libs.junit.api)
testImplementation(libs.bundles.junit)
testRuntimeOnly(libs.junit.engine)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
package org.geysermc.databaseutils.processor;

import static org.geysermc.databaseutils.processor.util.AnnotationUtils.hasAnnotation;
import static org.geysermc.databaseutils.processor.util.TypeUtils.toBoxedTypeElement;

import java.util.ArrayList;
import java.util.Arrays;
Expand All @@ -39,18 +38,18 @@
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Types;
import org.geysermc.databaseutils.meta.Entity;
import org.geysermc.databaseutils.meta.Key;
import org.geysermc.databaseutils.processor.info.ColumnInfo;
import org.geysermc.databaseutils.processor.info.EntityInfo;
import org.geysermc.databaseutils.processor.info.IndexInfo;
import org.geysermc.databaseutils.processor.util.TypeUtils;

final class EntityManager {
private final Map<CharSequence, EntityInfo> entityInfoByClassName = new HashMap<>();
private final Types typeUtils;
private final TypeUtils typeUtils;

EntityManager(final Types typeUtils) {
EntityManager(final TypeUtils typeUtils) {
this.typeUtils = Objects.requireNonNull(typeUtils);
}

Expand Down Expand Up @@ -100,7 +99,7 @@ EntityInfo processEntity(TypeElement type) {
continue;
}

TypeElement typeElement = toBoxedTypeElement(field.asType(), typeUtils);
TypeElement typeElement = typeUtils.toBoxedTypeElement(field.asType());
columns.add(new ColumnInfo(field.getSimpleName(), typeElement.getQualifiedName()));

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

for (int i = 0; i < parameters.size(); i++) {
var parameterType = toBoxedTypeElement(parameters.get(i).asType(), typeUtils)
.getQualifiedName();
var parameterType =
typeUtils.toBoxedTypeElement(parameters.get(i).asType()).getQualifiedName();
if (!columns.get(i).typeName().equals(parameterType)) {
continue constructors;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,29 @@
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import org.geysermc.databaseutils.IRepository;
import org.geysermc.databaseutils.meta.Repository;
import org.geysermc.databaseutils.processor.action.ActionRegistry;
import org.geysermc.databaseutils.processor.query.KeywordsReader;
import org.geysermc.databaseutils.processor.query.QueryInfoCreator;
import org.geysermc.databaseutils.processor.type.RepositoryGenerator;
import org.geysermc.databaseutils.processor.util.InvalidRepositoryException;
import org.geysermc.databaseutils.processor.util.TypeUtils;

@AutoService(Processor.class)
public final class RepositoryProcessor extends AbstractProcessor {
private TypeUtils typeUtils;
private EntityManager entityManager;
private Filer filer;
private Types typeUtils;
private Messager messager;

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.entityManager = new EntityManager(processingEnv.getTypeUtils());
this.typeUtils = new TypeUtils(processingEnv.getTypeUtils(), processingEnv.getElementUtils());
this.entityManager = new EntityManager(typeUtils);
this.filer = processingEnv.getFiler();
this.typeUtils = processingEnv.getTypeUtils();
this.messager = processingEnv.getMessager();
}

Expand Down Expand Up @@ -169,7 +170,7 @@ private void writeGeneratedTypes(List<GeneratedType> generatedTypes) {
private List<RepositoryGenerator> processRepository(TypeElement repository) {
TypeMirror entityType = null;
for (TypeMirror mirror : repository.getInterfaces()) {
if (TypeUtils.isTypeOf(IRepository.class, MoreTypes.asTypeElement(mirror))) {
if (TypeUtils.isType(IRepository.class, MoreTypes.asTypeElement(mirror))) {
entityType = MoreTypes.asDeclared(mirror).getTypeArguments().get(0);
}
}
Expand Down Expand Up @@ -198,22 +199,23 @@ private List<RepositoryGenerator> processRepository(TypeElement repository) {
boolean async = false;
if (MoreTypes.isTypeOf(CompletableFuture.class, element.getReturnType())) {
async = true;
returnType = TypeUtils.toBoxedTypeElement(
MoreTypes.asDeclared(element.getReturnType())
.getTypeArguments()
.get(0),
typeUtils);
returnType = typeUtils.toBoxedTypeElement(MoreTypes.asDeclared(element.getReturnType())
.getTypeArguments()
.get(0));
} else {
returnType = TypeUtils.toBoxedTypeElement(element.getReturnType(), typeUtils);
returnType = typeUtils.toBoxedTypeElement(element.getReturnType());
}

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

var action = ActionRegistry.actionMatching(name);
var result = new KeywordsReader(name, entity).read();
var action = ActionRegistry.actionMatching(result);
if (action == null) {
throw new InvalidRepositoryException("No available actions for %s", name);
}
action.addTo(generators, name, element, returnType, entity, typeUtils, async);
var queryInfo = new QueryInfoCreator(result, element, entity, typeUtils).create();

action.addTo(generators, queryInfo, returnType, async, typeUtils);
}

return generators;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,37 +24,97 @@
*/
package org.geysermc.databaseutils.processor.action;

import com.squareup.javapoet.MethodSpec;
import java.util.Collection;
import java.util.List;
import java.util.regex.Pattern;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Types;
import org.geysermc.databaseutils.processor.info.EntityInfo;
import org.geysermc.databaseutils.processor.query.QueryInfo;
import org.geysermc.databaseutils.processor.type.RepositoryGenerator;
import org.geysermc.databaseutils.processor.util.InvalidRepositoryException;
import org.geysermc.databaseutils.processor.util.TypeUtils;

public abstract class Action {
private final String actionType;
private final Pattern actionPattern;
private final boolean supportsFilter;

protected Action(String actionType, String actionRegex) {
protected Action(String actionType) {
this(actionType, true);
}

protected Action(String actionType, boolean supportsFilter) {
this.actionType = actionType;
this.actionPattern = Pattern.compile(actionRegex);
this.supportsFilter = supportsFilter;
}

public String actionType() {
return actionType;
}

public Pattern actionPattern() {
return actionPattern;
public boolean supportsFilter() {
return supportsFilter;
}

public abstract void addTo(
List<RepositoryGenerator> generators,
String fullName,
ExecutableElement element,
protected abstract void addToSingle(
RepositoryGenerator generator,
QueryInfo info,
MethodSpec.Builder spec,
TypeElement returnType,
EntityInfo info,
Types typeUtils,
boolean async);

protected boolean validateSingle(QueryInfo info, TypeElement returnType, TypeUtils typeUtils) {
return TypeUtils.isType(Void.class, returnType) || TypeUtils.isWholeNumberType(returnType);
}

protected boolean validateCollection(QueryInfo info, TypeElement elementType, TypeUtils typeUtils) {
return false;
}

protected boolean validateEither(QueryInfo info, TypeElement elementType, boolean collection, TypeUtils typeUtils) {
return false;
}

protected void validate(QueryInfo info, TypeElement returnType, TypeUtils typeUtils) {
var elementType = returnType;
if (typeUtils.isAssignable(Collection.class, returnType.asType())) {
elementType = (TypeElement) returnType.getTypeParameters().get(0);

if (!supportsFilter) {
throw new InvalidRepositoryException("%s does not support a By section", actionType);
}

if (validateCollection(info, elementType, typeUtils)
|| validateEither(info, elementType, true, typeUtils)) {
return;
}
} else {
if (validateEither(info, elementType, false, typeUtils)) {
return;
}
if (validateSingle(info, returnType, typeUtils)) {
return;
}
}

if (!typeUtils.isAssignable(info.entityType(), elementType.asType())) {
throw new InvalidRepositoryException(
"Unsupported return type %s for %s",
returnType.getSimpleName(), info.element().getSimpleName());
}
}

public void addTo(
List<RepositoryGenerator> generators,
QueryInfo info,
TypeElement returnType,
boolean async,
TypeUtils typeUtils) {
if (!info.hasBySection() && info.element().getParameters().size() != 1) {
throw new InvalidRepositoryException("Expected one parameter with type %s", info.entityType());
}
validate(info, returnType, typeUtils);

for (RepositoryGenerator generator : generators) {
addToSingle(generator, info, MethodSpec.overriding(info.element()), returnType, async);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@
package org.geysermc.databaseutils.processor.action;

import java.util.Set;
import org.geysermc.databaseutils.processor.query.KeywordsReadResult;

public final class ActionRegistry {
private static final Set<Action> REGISTERED_ACTIONS = Set.of(
new FindByAction(),
new ExistsByAction(),
new DeleteByAction(),
new InsertAction(),
new UpdateAction(),
new DeleteAction());
private static final Set<Action> REGISTERED_ACTIONS =
Set.of(new FindAction(), new ExistsAction(), new InsertAction(), new UpdateAction(), new DeleteAction());

public static Action actionMatching(String name) {
public static Action actionMatching(KeywordsReadResult result) {
for (Action action : REGISTERED_ACTIONS) {
if (action.actionPattern().matcher(name).matches()) {
var hasFilter = result.bySection() != null;
if (result.actionName().equals(action.actionType())) {
if (hasFilter && !action.supportsFilter()) {
continue;
}
return action;
}
}
Expand Down

This file was deleted.

Loading

0 comments on commit ee361e6

Please sign in to comment.