Add queryable store with SQLite implementation

This adds the new "queryable store" API, that allows complex
queries and is backed by SQLite. This new API can be used
for entities annotated with the new QueryableType annotation.
This commit is contained in:
Rene Pfeuffer
2025-04-01 16:18:04 +02:00
parent d5362d634b
commit ada575d871
235 changed files with 10154 additions and 252 deletions

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import java.util.Map;
import java.util.Optional;
class AnnotationHelper {
public Optional<? extends AnnotationValue> findAnnotationValue(AnnotationMirror annotationMirror, String name) {
return annotationMirror.getElementValues()
.entrySet()
.stream()
.filter(entry -> entry.getKey().getSimpleName().toString().equals(name))
.map(Map.Entry::getValue)
.findFirst();
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import java.util.Optional;
class AnnotationProcessor {
Optional<? extends AnnotationMirror> findAnnotation(Element element, Class<?> annotationClass) {
return element.getAnnotationMirrors()
.stream()
.filter(annotationMirror -> annotationMirror.getAnnotationType().toString().equals(annotationClass.getCanonicalName()))
.findFirst();
}
}

View File

@@ -0,0 +1,280 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import jakarta.inject.Inject;
import sonia.scm.ModelObject;
import sonia.scm.store.QueryableStoreFactory;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.function.BiConsumer;
import java.util.function.Function;
class FactoryClassCreator {
private static final String STORE_PACKAGE_NAME = "sonia.scm.store";
private static final String QUERYABLE_MUTABLE_STORE_CLASS_NAME = "QueryableMutableStore";
private static final String QUERYABLE_STORE_CLASS_NAME = "QueryableStore";
private final ProcessingEnvironment processingEnv;
FactoryClassCreator(ProcessingEnvironment processingEnv) {
this.processingEnv = processingEnv;
}
void createFactoryClass(Element element, String packageName, TypeElement dataClassTypeElement) throws IOException {
TypeName typeNameOfDataClass = TypeName.get(dataClassTypeElement.asType());
TypeSpec.Builder builder =
TypeSpec
.classBuilder(element.getSimpleName() + "StoreFactory")
.addModifiers(Modifier.PUBLIC)
.addJavadoc("Generated queryable store factory for type {@link $T}.\nTo create conditions in queries, use the static fields in the class {@link $TQueryFields}.\n", typeNameOfDataClass, typeNameOfDataClass);
createStoreFactoryField(builder);
createConstructor(builder);
List<ParentSpec> parents = determineParentSpecs(dataClassTypeElement);
if (parents.isEmpty()) {
createGetterForDataTypeWithoutParent(builder, typeNameOfDataClass);
} else {
createOverallGetterForDataTypeWithParents(builder, typeNameOfDataClass);
createMutableGetterForDataTypeWithParents(typeNameOfDataClass, parents, builder);
createPartialGetterForDataTypeWithParents(builder, typeNameOfDataClass, parents);
}
JavaFile.builder(packageName, builder.build())
.build()
.writeTo(processingEnv.getFiler());
}
private void createMutableGetterForDataTypeWithParents(TypeName typeNameOfDataClass, List<ParentSpec> parents, TypeSpec.Builder builder) {
builder.addMethod(
createGetMutableMethodSpec(
typeNameOfDataClass,
"Returns a store to modify elements of the type {@link $T}.\nTo do so, an id has to be specified for each parent type.\n",
parents,
ParentSpec::buildParameterNameWithIdSuffix,
ParentSpec::appendParentAsIdStringArgument
)
);
if (isEveryParentModelObject(parents)) {
builder.addMethod(
createGetMutableMethodSpec(
typeNameOfDataClass,
"Returns a store to modify elements of the type {@link $T}.\nTo do so, an instance of each parent type has to be specified.\n",
parents,
ParentSpec::buildIdGetterWithParameterName,
ParentSpec::appendParentAsObjectArgument
)
);
}
}
private MethodSpec createGetMutableMethodSpec(TypeName typeNameOfDataClass,
String javaDoc,
List<ParentSpec> parents,
Function<ParentSpec, String> parentIdProcessor,
BiConsumer<MethodSpec.Builder, ParentSpec> parentArgumentProcessor) {
MethodSpec.Builder getMutableBuilder = MethodSpec
.methodBuilder("getMutable")
.addModifiers(Modifier.PUBLIC)
.addJavadoc(javaDoc, typeNameOfDataClass)
.returns(ParameterizedTypeName.get(ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_MUTABLE_STORE_CLASS_NAME), typeNameOfDataClass))
.addStatement(
"return storeFactory.getMutable($T.class, $L)",
typeNameOfDataClass,
parents.stream().map(parentIdProcessor).reduce((s1, s2) -> s1 + ", " + s2).orElseThrow()
);
parents.forEach(
parent -> parentArgumentProcessor.accept(getMutableBuilder, parent)
);
return getMutableBuilder.build();
}
private boolean isEveryParentModelObject(List<ParentSpec> parents) {
return parents.stream().allMatch(ParentSpec::isModelObject);
}
private void createPartialGetterForDataTypeWithParents(TypeSpec.Builder builder, TypeName typeNameOfDataClass, List<ParentSpec> parents) {
for (int i = 0; i < parents.size(); i++) {
String javaDocParentDescriptor;
if (i == 0) {
javaDocParentDescriptor = "only to the first parent";
} else if (i < parents.size() - 1) {
javaDocParentDescriptor = "only to the first " + (i + 1) + "parents";
} else {
javaDocParentDescriptor = "to all parents";
}
int currentParentLimit = i + 1;
builder.addMethod(
createPartialGetterMethodSpec(
typeNameOfDataClass,
"Returns a store to query elements of the type {@link $T} limited " + javaDocParentDescriptor + " specified by their ids.\n",
parents,
currentParentLimit,
ParentSpec::buildParameterNameWithIdSuffix,
ParentSpec::appendParentAsIdStringArgument
)
);
if (isEveryParentModelObject(parents)) {
builder.addMethod(
createPartialGetterMethodSpec(
typeNameOfDataClass,
"Returns a store to query elements of the type {@link $T} limited " + javaDocParentDescriptor + " specified as instances of the parent type.\n",
parents,
currentParentLimit,
ParentSpec::buildIdGetterWithParameterName,
ParentSpec::appendParentAsObjectArgument
)
);
}
}
}
private MethodSpec createPartialGetterMethodSpec(TypeName typeNameOfDataClass,
String javaDoc,
List<ParentSpec> parents,
int parentLimit,
Function<ParentSpec, String> parentIdProcessor,
BiConsumer<MethodSpec.Builder, ParentSpec> parentArgumentProcessor) {
MethodSpec.Builder getBuilder = MethodSpec
.methodBuilder(parentLimit == parents.size() ? "get" : "getOverlapping")
.addModifiers(Modifier.PUBLIC)
.returns(ParameterizedTypeName.get(ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME), typeNameOfDataClass))
.addJavadoc(javaDoc, typeNameOfDataClass)
.addStatement(
"return storeFactory.getReadOnly($T.class, $L)",
typeNameOfDataClass,
parents.stream()
.limit(parentLimit)
.map(parentIdProcessor)
.reduce((s1, s2) -> s1 + ", " + s2)
.orElseThrow()
);
parents.stream()
.limit(parentLimit)
.forEach(parent -> parentArgumentProcessor.accept(getBuilder, parent));
return getBuilder.build();
}
private void createOverallGetterForDataTypeWithParents(TypeSpec.Builder builder, TypeName typeNameOfDataClass) {
builder.addMethod(
MethodSpec.methodBuilder("getOverall")
.addModifiers(Modifier.PUBLIC)
.returns(ParameterizedTypeName.get(ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME), typeNameOfDataClass))
.addStatement("return storeFactory.getReadOnly($T.class)", typeNameOfDataClass)
.addJavadoc("Returns a store to overall query elements of the type {@link $T} independent of any parent.\n", typeNameOfDataClass)
.build());
}
private void createGetterForDataTypeWithoutParent(TypeSpec.Builder builder, TypeName typeNameOfDataClass) {
builder.addMethod(
MethodSpec.methodBuilder("get")
.addModifiers(Modifier.PUBLIC)
.returns(ParameterizedTypeName.get(ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME), typeNameOfDataClass))
.addStatement("return storeFactory.getReadOnly($T.class)", typeNameOfDataClass)
.addJavadoc("Returns a store to query elements of the type {@link $T}.\n", typeNameOfDataClass)
.build());
builder.addMethod(
MethodSpec.methodBuilder("getMutable")
.addModifiers(Modifier.PUBLIC)
.returns(ParameterizedTypeName.get(ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_MUTABLE_STORE_CLASS_NAME), typeNameOfDataClass))
.addStatement("return storeFactory.getMutable($T.class)", typeNameOfDataClass)
.addJavadoc("Returns a store to modify elements of the type {@link $T}.\n", typeNameOfDataClass)
.build());
}
private List<ParentSpec> determineParentSpecs(TypeElement typeElement) {
return new QueryableTypeParentProcessor().getQueryableTypeValues(typeElement)
.stream()
.map(queryableType -> {
String parentClassPackage = queryableType.substring(0, queryableType.lastIndexOf("."));
String parentClassName = queryableType.substring(queryableType.lastIndexOf(".") + 1);
String parameterName = lowercaseFirstLetter(parentClassName);
return new ParentSpec(parentClassPackage, parentClassName, parameterName, isParentModelObject(queryableType));
})
.toList();
}
private boolean isParentModelObject(String parentType) {
try {
Class<?> parentClass = Class.forName(parentType);
return Arrays.stream(parentClass.getInterfaces()).anyMatch(parentInterface -> parentInterface.getName().equals(ModelObject.class.getName()));
} catch (ClassNotFoundException e) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, String.format("Failed to find class of parent '%s'. Unable to determine whether this is a ModelObject or not. Will not generate factory methods for parent objects, only for ids.", parentType));
return false;
}
}
private String lowercaseFirstLetter(String parentClassName) {
return parentClassName.substring(0, 1).toLowerCase(Locale.ENGLISH) + parentClassName.substring(1);
}
private void createConstructor(TypeSpec.Builder builder) {
builder.addMethod(
MethodSpec
.constructorBuilder()
.addParameter(QueryableStoreFactory.class, "storeFactory")
.addStatement("this.storeFactory = storeFactory")
.addAnnotation(Inject.class)
.addJavadoc("Instances should not be created manually, but injected by dependency injection using {@link $T}.\n", Inject.class)
.build());
}
private void createStoreFactoryField(TypeSpec.Builder builder) {
builder.addField(QueryableStoreFactory.class, "storeFactory", Modifier.PRIVATE, Modifier.FINAL);
}
private record ParentSpec(String classPackage, String className, String parameterName, boolean isModelObject) {
String buildParameterNameWithIdSuffix() {
return parameterName + "Id";
}
String buildIdGetterWithParameterName() {
return parameterName + ".getId()";
}
static void appendParentAsIdStringArgument(MethodSpec.Builder builder, ParentSpec parent) {
builder.addParameter(String.class, parent.buildParameterNameWithIdSuffix());
}
static void appendParentAsObjectArgument(MethodSpec.Builder builder, ParentSpec parent) {
builder.addParameter(ClassName.get(parent.classPackage(), parent.className()), parent.parameterName());
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.squareup.javapoet.FieldSpec;
import javax.lang.model.element.TypeElement;
interface FieldInitializer {
void initialize(FieldSpec.Builder fieldBuilder, TypeElement element, String fieldClass, String fieldName);
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
class NumberQueryFieldHandler extends QueryFieldHandler {
public NumberQueryFieldHandler(String packageName, String className) {
this(packageName, className, null);
}
public NumberQueryFieldHandler(String packageName, String className, String suffix) {
super(
"NumberQueryField",
new TypeName[]{ClassName.get(packageName, className)},
(fieldBuilder, element, fieldClass, fieldName) -> fieldBuilder
.initializer(
"new $T<>($S)",
ClassName.get("sonia.scm.store", "QueryableStore").nestedClass(fieldClass),
fieldName
),
suffix
);
}
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.google.auto.common.MoreElements;
import com.google.auto.common.MoreTypes;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;
class QueryFieldClassCreator {
private static final String SIZE_SUFFIX = "SIZE";
private static final String STORE_PACKAGE_NAME = "sonia.scm.store";
private static final String QUERYABLE_STORE_CLASS_NAME = "QueryableStore";
private static final String ID_QUERY_FIELD_CLASS_NAME = "IdQueryField";
private static final FieldInitializer SIMPLE_INITIALIZER = (fieldBuilder, element, fieldClass, fieldName) -> fieldBuilder
.initializer(
"new $T<>($S)",
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME).nestedClass(fieldClass),
fieldName
);
private final ProcessingEnvironment processingEnv;
QueryFieldClassCreator(ProcessingEnvironment processingEnv) {
this.processingEnv = processingEnv;
}
void createQueryFieldClass(Element element, String packageName, TypeElement typeElement) throws IOException {
TypeSpec.Builder builder =
TypeSpec
.classBuilder(element.getSimpleName() + "QueryFields")
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addJavadoc("Generated query fields for type {@link $T}.\nTo create a queryable store for this, use an injected instance of the {@link $TStoreFactory}.\n", TypeName.get(typeElement.asType()), TypeName.get(typeElement.asType()));
createPrivateConstructor(builder);
processParents(typeElement, builder);
processId(typeElement, builder);
processFields(typeElement, builder);
JavaFile.builder(packageName, builder.build())
.build()
.writeTo(processingEnv.getFiler());
}
private void createPrivateConstructor(TypeSpec.Builder builder) {
builder.addMethod(
MethodSpec
.constructorBuilder()
.addModifiers(Modifier.PRIVATE)
.build());
}
private void processParents(TypeElement typeElement, TypeSpec.Builder builder) {
new QueryableTypeParentProcessor().getQueryableTypeValues(typeElement)
.forEach(queryableType -> {
String parentClassPackage = queryableType.substring(0, queryableType.lastIndexOf("."));
String parentClassName = queryableType.substring(queryableType.lastIndexOf(".") + 1);
builder.addField(
FieldSpec
.builder(
ParameterizedTypeName.get(
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME)
.nestedClass(ID_QUERY_FIELD_CLASS_NAME),
TypeName.get(typeElement.asType())),
parentClassName.toUpperCase(Locale.ENGLISH) + "_ID"
)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer(
"new $T<>($T.class)",
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME).nestedClass(ID_QUERY_FIELD_CLASS_NAME),
ClassName.get(parentClassPackage, parentClassName))
.build());
});
}
private void processId(TypeElement typeElement, TypeSpec.Builder builder) {
builder.addField(
FieldSpec
.builder(
ParameterizedTypeName.get(
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME)
.nestedClass(ID_QUERY_FIELD_CLASS_NAME),
TypeName.get(typeElement.asType())),
"INTERNAL_ID"
)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
.initializer(
"new $T<>()",
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME).nestedClass(ID_QUERY_FIELD_CLASS_NAME))
.build());
}
private void processFields(TypeElement typeElement, TypeSpec.Builder builder) {
processFields(typeElement, typeElement, builder);
}
@SuppressWarnings("UnstableApiUsage")
private void processFields(TypeElement typeElement, TypeElement superTypeElement, TypeSpec.Builder builder) {
processingEnv
.getElementUtils()
.getAllMembers(typeElement)
.stream()
.filter(member -> member.getKind() == ElementKind.FIELD)
.filter(member -> !member.getModifiers().contains(Modifier.STATIC))
.filter(member -> !member.getModifiers().contains(Modifier.TRANSIENT))
.flatMap(field ->
createFieldSpec(
superTypeElement,
MoreElements.asVariable(field))
)
.forEach(builder::addField);
TypeElement superclass = (TypeElement) processingEnv.getTypeUtils().asElement(typeElement.getSuperclass());
if (superclass != null && !superclass.getQualifiedName().toString().equals(Object.class.getCanonicalName())) {
processFields(superclass, typeElement, builder);
}
}
private Stream<FieldSpec> createFieldSpec(TypeElement element, VariableElement field) {
TypeMirror effectiveFieldType = determineFieldType(field);
return createFieldHandler(effectiveFieldType).stream()
.map(queryFieldHandler -> {
String fieldName = field.getSimpleName().toString();
String fieldClass = queryFieldHandler.getClazz();
TypeName[] furtherGenerics = queryFieldHandler.getGenerics();
TypeName[] generics = new TypeName[furtherGenerics.length + 1];
generics[0] = TypeName.get(element.asType());
System.arraycopy(furtherGenerics, 0, generics, 1, furtherGenerics.length);
FieldSpec.Builder fieldBuilder = FieldSpec
.builder(
ParameterizedTypeName.get(
ClassName
.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME)
.nestedClass(fieldClass),
generics),
determineFieldNameWithSuffix(fieldName, queryFieldHandler).toUpperCase(Locale.ENGLISH)
)
.addJavadoc("Generated query field to create conditions for field {@link $L#$L} of type {@link $L}.\n", TypeName.get(element.asType()), fieldName, effectiveFieldType)
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
queryFieldHandler.getInitializer().initialize(fieldBuilder, element, fieldClass, fieldName);
return fieldBuilder.build();
});
}
private TypeMirror determineFieldType(VariableElement field) {
return new AnnotationProcessor().findAnnotation(field, XmlJavaTypeAdapter.class)
.map(this::determineTypeFromAdapter)
.orElseGet(field::asType);
}
private TypeMirror determineTypeFromAdapter(AnnotationMirror annotationMirror) {
AnnotationValue value = new AnnotationHelper().findAnnotationValue(annotationMirror, "value").orElseThrow();
TypeMirror adapterType = (TypeMirror) value.getValue();
TypeMirror xmlAdapterType = processingEnv.getTypeUtils()
.directSupertypes(adapterType)
.stream()
.filter(typeMirror -> processingEnv.getTypeUtils()
.isAssignable(
processingEnv.getTypeUtils().erasure(typeMirror),
processingEnv.getElementUtils().getTypeElement(XmlAdapter.class.getCanonicalName()).asType()
))
.findFirst()
.orElseThrow(RuntimeException::new);
DeclaredType declaredType = MoreTypes.asDeclared(xmlAdapterType);
return declaredType.getTypeArguments().get(0);
}
private Collection<QueryFieldHandler> createFieldHandler(TypeMirror fieldType) {
TypeMirror collectionType = processingEnv.getElementUtils().getTypeElement(Collection.class.getCanonicalName()).asType();
TypeMirror erasure = processingEnv.getTypeUtils().erasure(fieldType);
if (processingEnv.getTypeUtils().isAssignable(erasure, collectionType)) {
return List.of(
new QueryFieldHandler(
"CollectionQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER
),
new QueryFieldHandler(
"CollectionSizeQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER,
SIZE_SUFFIX
)
);
}
TypeMirror mapType = processingEnv.getElementUtils().getTypeElement(Map.class.getCanonicalName()).asType();
if (processingEnv.getTypeUtils().isAssignable(erasure, mapType)) {
return List.of(
new QueryFieldHandler(
"MapQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER
),
new QueryFieldHandler(
"MapSizeQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER,
SIZE_SUFFIX
)
);
}
Element fieldAsElement = processingEnv.getTypeUtils().asElement(fieldType);
if (fieldAsElement != null && fieldAsElement.getKind() == ElementKind.ENUM) {
return List.of(new QueryFieldHandler(
"EnumQueryField",
new TypeName[]{TypeName.get(fieldAsElement.asType())},
(fieldBuilder, element, fieldClass, fieldName) -> fieldBuilder
.initializer(
"new $T<>($S)",
ClassName.get(STORE_PACKAGE_NAME, QUERYABLE_STORE_CLASS_NAME).nestedClass(fieldClass),
fieldName
)
));
}
return switch (fieldType.toString()) {
case "java.lang.String" -> List.of(
new QueryFieldHandler(
"StringQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER));
case "boolean", "java.lang.Boolean" -> List.of(
new QueryFieldHandler(
"BooleanQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER));
case "int", "java.lang.Integer" -> List.of(
new NumberQueryFieldHandler(
"java.lang",
"Integer"));
case "long", "java.lang.Long" -> List.of(
new NumberQueryFieldHandler(
"java.lang",
"Long"));
case "float", "java.lang.Float" -> List.of(
new NumberQueryFieldHandler(
"java.lang",
"Float"));
case "double", "java.lang.Double" -> List.of(
new NumberQueryFieldHandler(
"java.lang",
"Double"));
case "java.util.Date", "java.time.Instant" -> List.of(
new QueryFieldHandler(
"InstantQueryField",
new TypeName[]{},
SIMPLE_INITIALIZER));
default -> List.of();
};
}
private String determineFieldNameWithSuffix(String fieldName, QueryFieldHandler fieldHandler) {
return fieldHandler.getSuffix()
.map(suffix -> String.format("%s_%s", fieldName, suffix))
.orElse(fieldName);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.squareup.javapoet.TypeName;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Optional;
@Getter
@AllArgsConstructor
class QueryFieldHandler {
private final String clazz;
private final TypeName[] generics;
private final FieldInitializer initializer;
private final String suffix;
public QueryFieldHandler(String clazz, TypeName[] generics, FieldInitializer initializer) {
this(clazz, generics, initializer, null);
}
public Optional<String> getSuffix() {
return Optional.ofNullable(suffix);
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.google.auto.common.MoreElements;
import org.kohsuke.MetaInfServices;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import static java.util.Optional.empty;
import static java.util.Optional.of;
@SupportedAnnotationTypes("sonia.scm.store.QueryableType")
@MetaInfServices(Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_17)
public class QueryableTypeAnnotationProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
for (TypeElement annotation : annotations) {
log("Found annotation: " + annotation.getQualifiedName());
roundEnvironment.getElementsAnnotatedWith(annotation).forEach(element -> {
log("Found annotated element: " + element.getSimpleName());
tryToCreateQueryFieldClass(element);
tryToCreateFactoryClass(element);
});
}
return true;
}
@SuppressWarnings("UnstableApiUsage")
private void tryToCreateQueryFieldClass(Element element) {
TypeElement typeElement = MoreElements.asType(element);
getPackageName(typeElement)
.ifPresent(packageName -> {
try {
new QueryFieldClassCreator(processingEnv).createQueryFieldClass(element, packageName, typeElement);
} catch (IOException e) {
error("Failed to create query field class for type " + typeElement + ": " + e.getMessage());
}
});
}
@SuppressWarnings("UnstableApiUsage")
private void tryToCreateFactoryClass(Element element) {
TypeElement typeElement = MoreElements.asType(element);
getPackageName(typeElement)
.ifPresent(packageName -> {
try {
new FactoryClassCreator(processingEnv).createFactoryClass(element, packageName, typeElement);
} catch (IOException e) {
error("Failed to create factory class for type " + typeElement + ": " + e.getMessage());
}
});
}
@SuppressWarnings("UnstableApiUsage")
private Optional<String> getPackageName(TypeElement typeElement) {
Element enclosingElement = typeElement.getEnclosingElement();
try {
return of(MoreElements.asPackage(enclosingElement).getQualifiedName().toString());
} catch (IllegalArgumentException e) {
error("Could not determine package name for " + typeElement + ". QueryableType annotation does not support inner classes. Exception: " + e.getMessage());
return empty();
}
}
private void log(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
}
private void error(String message) {
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import sonia.scm.store.QueryableType;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.TypeElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
class QueryableTypeParentProcessor {
@SuppressWarnings("unchecked")
public List<String> getQueryableTypeValues(TypeElement typeElement) {
return new AnnotationProcessor().findAnnotation(typeElement, QueryableType.class)
.map(annotationMirror -> {
Optional<? extends AnnotationValue> value = new AnnotationHelper().findAnnotationValue(annotationMirror, "value");
if (value.isEmpty()) {
return new ArrayList<String>();
}
List<AnnotationValue> parentClassTypes = (List<AnnotationValue>) value.orElseThrow().getValue();
return parentClassTypes.stream()
.map(AnnotationValue::getValue)
.map(Object::toString)
.toList();
})
.orElseGet(List::of);
}
}

View File

@@ -0,0 +1 @@
sonia.scm.annotation.QueryableTypeAnnotationProcessor,isolating

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.annotation;
import com.google.common.truth.Truth;
import com.google.testing.compile.JavaFileObjects;
import com.google.testing.compile.JavaSourcesSubjectFactory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
import javax.tools.JavaFileObject;
import java.util.List;
@SuppressWarnings("java:S115") // we do not heed enum naming conventions for better readability in the test
class QueryableTypeAnnotationProcessorTest {
enum FieldScenario {
A("empty class"),
B("string query field"),
C("boolean query fields"),
D("number query fields"),
E("enum query field"),
F("collection query field"),
G("map query field"),
H("unknown field"),
I("instant field mapped to string"),
K("parent id field"),
L("unmapped instant field"),
M("unmapped java util date field"),
N("static field"),
O("transient field"),
BSub("fields from super class");
private final String description;
FieldScenario(String description) {
this.description = description;
}
@Override
public String toString() {
return description;
}
}
@ParameterizedTest(name = "should test field scenario for {0}")
@EnumSource(FieldScenario.class)
void shouldTest(FieldScenario scenario) {
JavaFileObject someObject = JavaFileObjects.forResource(String.format("sonia/scm/testing/%s.java", scenario.name()));
Truth.assert_()
.about(JavaSourcesSubjectFactory.javaSources())
.that(List.of(someObject))
.processedWith(new QueryableTypeAnnotationProcessor())
.compilesWithoutError()
.and()
.generatesSources(JavaFileObjects.forResource(String.format("sonia/scm/testing/%sQueryFields.java", scenario.name())));
}
enum FactoryScenario {
A("class without parent"),
OneParent("class with one parent"),
TwoParents("class with two parents"),
ThreeParents("class with three parents"),
OneNonModelObjectParent("class with one model object parent and one non model object parent");
private final String description;
FactoryScenario(String description) {
this.description = description;
}
@Override
public String toString() {
return description;
}
}
@ParameterizedTest(name = "should test factory scenario for {0}")
@EnumSource(FactoryScenario.class)
void shouldTest(FactoryScenario scenario) {
JavaFileObject someObject = JavaFileObjects.forResource(String.format("sonia/scm/testing/%s.java", scenario.name()));
Truth.assert_()
.about(JavaSourcesSubjectFactory.javaSources())
.that(List.of(someObject))
.processedWith(new QueryableTypeAnnotationProcessor())
.compilesWithoutError()
.and()
.generatesSources(JavaFileObjects.forResource(String.format("sonia/scm/testing/%sStoreFactory.java", scenario.name())));
}
@Test
void shouldHandleInnerClasses() {
JavaFileObject someObject = JavaFileObjects.forResource("sonia/scm/testing/InnerA.java");
Truth.assert_()
.about(JavaSourcesSubjectFactory.javaSources())
.that(List.of(someObject))
.processedWith(new QueryableTypeAnnotationProcessor())
.failsToCompile();
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class A {
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class AQueryFields {
public static final QueryableStore.IdQueryField<A> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
private AQueryFields() {
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.inject.Inject;
import sonia.scm.store.QueryableMutableStore;
import sonia.scm.store.QueryableStore;
import sonia.scm.store.QueryableStoreFactory;
public class AStoreFactory {
private final QueryableStoreFactory storeFactory;
@Inject
AStoreFactory(QueryableStoreFactory storeFactory) {
this.storeFactory = storeFactory;
}
public QueryableStore<A> get() {
return storeFactory.getReadOnly(A.class);
}
public QueryableMutableStore<A> getMutable() {
return storeFactory.getMutable(A.class);
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class B {
private String name;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class BQueryFields {
public static final QueryableStore.IdQueryField<B> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.StringQueryField<B> NAME =
new QueryableStore.StringQueryField<>("name");
private BQueryFields() {
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class BSub extends B {
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class BSubQueryFields {
public static final QueryableStore.IdQueryField<BSub> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.StringQueryField<BSub> NAME =
new QueryableStore.StringQueryField<>("name");
private BSubQueryFields() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class C {
private boolean active;
private Boolean enabled;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class CQueryFields {
public static final QueryableStore.IdQueryField<C> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.BooleanQueryField<C> ACTIVE =
new QueryableStore.BooleanQueryField<>("active");
public static final QueryableStore.BooleanQueryField<C> ENABLED =
new QueryableStore.BooleanQueryField<>("enabled");
private CQueryFields() {
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class D {
private int age;
private Integer weight;
private long creationTime;
private Long lastModified;
private float height;
private Float width;
private double price;
private Double margin;
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import java.lang.Double;
import java.lang.Float;
import java.lang.Integer;
import java.lang.Long;
import sonia.scm.store.QueryableStore;
public final class DQueryFields {
public static final QueryableStore.IdQueryField<D> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.NumberQueryField<D, Integer> AGE =
new QueryableStore.NumberQueryField<>("age");
public static final QueryableStore.NumberQueryField<D, Integer> WEIGHT =
new QueryableStore.NumberQueryField<>("weight");
public static final QueryableStore.NumberQueryField<D, Long> CREATIONTIME =
new QueryableStore.NumberQueryField<>("creationTime");
public static final QueryableStore.NumberQueryField<D, Long> LASTMODIFIED =
new QueryableStore.NumberQueryField<>("lastModified");
public static final QueryableStore.NumberQueryField<D, Float> HEIGHT =
new QueryableStore.NumberQueryField<>("height");
public static final QueryableStore.NumberQueryField<D, Float> WIDTH =
new QueryableStore.NumberQueryField<>("width");
public static final QueryableStore.NumberQueryField<D, Double> PRICE =
new QueryableStore.NumberQueryField<>("price");
public static final QueryableStore.NumberQueryField<D, Double> MARGIN =
new QueryableStore.NumberQueryField<>("margin");
private DQueryFields() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.Stage;
import sonia.scm.store.QueryableType;
@QueryableType
public class E {
private Stage stage;
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.Stage;
import sonia.scm.store.QueryableStore;
public final class EQueryFields {
public static final QueryableStore.IdQueryField<E> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.EnumQueryField<E, Stage> STAGE =
new QueryableStore.EnumQueryField<>("stage");
private EQueryFields() {
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.Stage;
import sonia.scm.store.QueryableType;
import java.util.List;
@QueryableType
public class F {
private List<String> names;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class FQueryFields {
public static final QueryableStore.IdQueryField<F> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.CollectionQueryField<F> NAMES =
new QueryableStore.CollectionQueryField<>("names");
public static final QueryableStore.CollectionSizeQueryField<F> NAMES_SIZE =
new QueryableStore.CollectionSizeQueryField<>("names");
private FQueryFields() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
import java.util.Map;
@QueryableType
public class G {
private Map<String, Object> dictionary;
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class GQueryFields {
public static final QueryableStore.IdQueryField<G> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.MapQueryField<G> DICTIONARY =
new QueryableStore.MapQueryField<>("dictionary");
public static final QueryableStore.MapSizeQueryField<G> DICTIONARY_SIZE =
new QueryableStore.MapSizeQueryField<>("dictionary");
private GQueryFields() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
import java.util.Map;
@QueryableType
public class H {
private Object somethingStrange;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class HQueryFields {
public static final QueryableStore.IdQueryField<H> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
private HQueryFields() {
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import sonia.scm.store.QueryableType;
import sonia.scm.xml.XmlInstantAdapter;
import java.time.Instant;
@QueryableType
public class I {
@XmlJavaTypeAdapter(XmlInstantAdapter.class)
private Instant birthday;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class IQueryFields {
public static final QueryableStore.IdQueryField<I> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.StringQueryField<I> BIRTHDAY =
new QueryableStore.StringQueryField<>("birthday");
private IQueryFields() {
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
public class InnerA {
@QueryableType
public static class A {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.Stage;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableType;
@QueryableType(Repository.class)
public class K {
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableStore;
public final class KQueryFields {
public static final QueryableStore.IdQueryField<K> REPOSITORY_ID =
new QueryableStore.IdQueryField<>(Repository.class);
public static final QueryableStore.IdQueryField<K> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
private KQueryFields() {
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import sonia.scm.store.QueryableType;
import sonia.scm.xml.XmlInstantAdapter;
import java.time.Instant;
@QueryableType
public class L {
private Instant birthday;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class LQueryFields {
public static final QueryableStore.IdQueryField<L> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.InstantQueryField<L> BIRTHDAY =
new QueryableStore.InstantQueryField<>("birthday");
private LQueryFields() {
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
import java.util.Date;
@QueryableType
public class M {
private Date birthday;
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class MQueryFields {
public static final QueryableStore.IdQueryField<M> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
public static final QueryableStore.InstantQueryField<M> BIRTHDAY =
new QueryableStore.InstantQueryField<>("birthday");
private MQueryFields() {
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class N {
private static String someField;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class NQueryFields {
public static final QueryableStore.IdQueryField<N> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
private NQueryFields() {
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableType;
@QueryableType
public class O {
private transient String transientField;
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.store.QueryableStore;
public final class OQueryFields {
public static final QueryableStore.IdQueryField<O> INTERNAL_ID =
new QueryableStore.IdQueryField<>();
private OQueryFields() {
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.repository.NamespaceAndName;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableType;
@QueryableType({NamespaceAndName.class, Repository.class})
public class OneNonModelObjectParent {
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.inject.Inject;
import java.lang.String;
import sonia.scm.store.QueryableMutableStore;
import sonia.scm.store.QueryableStore;
import sonia.scm.store.QueryableStoreFactory;
public class OneNonModelObjectParentStoreFactory {
private final QueryableStoreFactory storeFactory;
@Inject
OneNonModelObjectParentStoreFactory(QueryableStoreFactory storeFactory) {
this.storeFactory = storeFactory;
}
public QueryableStore<OneNonModelObjectParent> getOverall() {
return storeFactory.getReadOnly(OneNonModelObjectParent.class);
}
public QueryableMutableStore<OneNonModelObjectParent> getMutable(String namespaceAndNameId, String repositoryId) {
return storeFactory.getMutable(OneNonModelObjectParent.class, namespaceAndNameId, repositoryId);
}
public QueryableStore<OneNonModelObjectParent> getOverlapping(String namespaceAndNameId) {
return storeFactory.getReadOnly(OneNonModelObjectParent.class, namespaceAndNameId);
}
public QueryableStore<OneNonModelObjectParent> get(String namespaceAndNameId, String repositoryId) {
return storeFactory.getReadOnly(OneNonModelObjectParent.class, namespaceAndNameId, repositoryId);
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableType;
@QueryableType(Repository.class)
public class OneParent {
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.inject.Inject;
import java.lang.String;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableMutableStore;
import sonia.scm.store.QueryableStore;
import sonia.scm.store.QueryableStoreFactory;
public class OneParentStoreFactory {
private final QueryableStoreFactory storeFactory;
@Inject
OneParentStoreFactory(QueryableStoreFactory storeFactory) {
this.storeFactory = storeFactory;
}
public QueryableStore<OneParent> getOverall() {
return storeFactory.getReadOnly(OneParent.class);
}
public QueryableMutableStore<OneParent> getMutable(String repositoryId) {
return storeFactory.getMutable(OneParent.class, repositoryId);
}
public QueryableMutableStore<OneParent> getMutable(Repository repository) {
return storeFactory.getMutable(OneParent.class, repository.getId());
}
public QueryableStore<OneParent> get(String repositoryId) {
return storeFactory.getReadOnly(OneParent.class, repositoryId);
}
public QueryableStore<OneParent> get(Repository repository) {
return storeFactory.getReadOnly(OneParent.class, repository.getId());
}
}

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.group.Group;
import sonia.scm.repository.Repository;
import sonia.scm.user.User;
import sonia.scm.store.QueryableType;
@QueryableType({Repository.class, User.class, Group.class})
public class ThreeParents {
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.inject.Inject;
import java.lang.String;
import sonia.scm.group.Group;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableMutableStore;
import sonia.scm.store.QueryableStore;
import sonia.scm.store.QueryableStoreFactory;
import sonia.scm.user.User;
public class ThreeParentsStoreFactory {
private final QueryableStoreFactory storeFactory;
@Inject
ThreeParentsStoreFactory(QueryableStoreFactory storeFactory) {
this.storeFactory = storeFactory;
}
public QueryableStore<ThreeParents> getOverall() {
return storeFactory.getReadOnly(ThreeParents.class);
}
public QueryableMutableStore<ThreeParents> getMutable(String repositoryId, String userId, String groupId) {
return storeFactory.getMutable(ThreeParents.class, repositoryId, userId, groupId);
}
public QueryableMutableStore<ThreeParents> getMutable(Repository repository, User user, Group group) {
return storeFactory.getMutable(ThreeParents.class, repository.getId(), user.getId(), group.getId());
}
public QueryableStore<ThreeParents> getOverlapping(String repositoryId) {
return storeFactory.getReadOnly(ThreeParents.class, repositoryId);
}
public QueryableStore<ThreeParents> getOverlapping(Repository repository) {
return storeFactory.getReadOnly(ThreeParents.class, repository.getId());
}
public QueryableStore<ThreeParents> getOverlapping(String repositoryId, String userId) {
return storeFactory.getReadOnly(ThreeParents.class, repositoryId, userId);
}
public QueryableStore<ThreeParents> getOverlapping(Repository repository, User user) {
return storeFactory.getReadOnly(ThreeParents.class, repository.getId(), user.getId());
}
public QueryableStore<ThreeParents> get(String repositoryId, String userId, String groupId) {
return storeFactory.getReadOnly(ThreeParents.class, repositoryId, userId, groupId);
}
public QueryableStore<ThreeParents> get(Repository repository, User user, Group group) {
return storeFactory.getReadOnly(ThreeParents.class, repository.getId(), user.getId(), group.getId());
}
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import sonia.scm.repository.Repository;
import sonia.scm.user.User;
import sonia.scm.store.QueryableType;
@QueryableType({Repository.class, User.class})
public class TwoParents {
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
package sonia.scm.testing;
import jakarta.inject.Inject;
import java.lang.String;
import sonia.scm.repository.Repository;
import sonia.scm.store.QueryableMutableStore;
import sonia.scm.store.QueryableStore;
import sonia.scm.store.QueryableStoreFactory;
import sonia.scm.user.User;
public class TwoParentsStoreFactory {
private final QueryableStoreFactory storeFactory;
@Inject
TwoParentsStoreFactory(QueryableStoreFactory storeFactory) {
this.storeFactory = storeFactory;
}
public QueryableStore<TwoParents> getOverall() {
return storeFactory.getReadOnly(TwoParents.class);
}
public QueryableMutableStore<TwoParents> getMutable(String repositoryId, String userId) {
return storeFactory.getMutable(TwoParents.class, repositoryId, userId);
}
public QueryableMutableStore<TwoParents> getMutable(Repository repository, User user) {
return storeFactory.getMutable(TwoParents.class, repository.getId(), user.getId());
}
public QueryableStore<TwoParents> getOverlapping(String repositoryId) {
return storeFactory.getReadOnly(TwoParents.class, repositoryId);
}
public QueryableStore<TwoParents> getOverlapping(Repository repository) {
return storeFactory.getReadOnly(TwoParents.class, repository.getId());
}
public QueryableStore<TwoParents> get(String repositoryId, String userId) {
return storeFactory.getReadOnly(TwoParents.class, repositoryId, userId);
}
public QueryableStore<TwoParents> get(Repository repository, User user) {
return storeFactory.getReadOnly(TwoParents.class, repository.getId(), user.getId());
}
}