use of io.requery.meta.Attribute in project requery by requery.
the class UpsertMergeGenerator method write.
@Override
public void write(Output output, Map<Expression<?>, Object> values) {
QueryBuilder qb = output.builder();
// TODO only supporting 1 type for now
Type<?> type = null;
for (Expression<?> expression : values.keySet()) {
if (expression.getExpressionType() == ExpressionType.ATTRIBUTE) {
Attribute attribute = (Attribute) expression;
type = attribute.getDeclaringType();
break;
}
}
if (type == null) {
throw new IllegalStateException();
}
qb.keyword(MERGE).keyword(INTO).tableName(type.getName()).keyword(USING);
appendUsing(output, values);
qb.keyword(ON).openParenthesis();
int count = 0;
Set<? extends Attribute<?, ?>> attributes = type.getKeyAttributes();
if (attributes.isEmpty()) {
attributes = type.getAttributes();
}
for (Attribute<?, ?> attribute : attributes) {
if (count > 0) {
qb.keyword(Keyword.AND);
}
qb.aliasAttribute(type.getName(), attribute);
qb.append(" = ");
qb.aliasAttribute(alias, attribute);
count++;
}
qb.closeParenthesis().space();
// update fragment
LinkedHashSet<Attribute<?, ?>> updates = new LinkedHashSet<>();
for (Expression<?> expression : values.keySet()) {
if (expression.getExpressionType() == ExpressionType.ATTRIBUTE) {
Attribute attribute = (Attribute) expression;
if (!attribute.isKey()) {
updates.add(attribute);
}
}
}
qb.keyword(WHEN, MATCHED, THEN, UPDATE, SET).commaSeparated(updates, new QueryBuilder.Appender<Attribute<?, ?>>() {
@Override
public void append(QueryBuilder qb, Attribute<?, ?> value) {
qb.attribute(value);
qb.append(" = " + alias + "." + value.getName());
}
}).space();
// insert fragment
qb.keyword(WHEN, NOT, MATCHED, THEN, INSERT).openParenthesis().commaSeparatedExpressions(values.keySet()).closeParenthesis().space().keyword(VALUES).openParenthesis().commaSeparated(values.keySet(), new QueryBuilder.Appender<Expression<?>>() {
@Override
public void append(QueryBuilder qb, Expression<?> value) {
qb.aliasAttribute(alias, (Attribute) value);
}
}).closeParenthesis();
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityGenerator method generateMembers.
private void generateMembers(TypeSpec.Builder builder) {
// generate property states
if (!entity.isStateless()) {
entity.attributes().stream().filter(attribute -> !attribute.isTransient()).forEach(attribute -> {
TypeName stateType = ClassName.get(PropertyState.class);
builder.addField(FieldSpec.builder(stateType, propertyStateFieldName(attribute), generatedMemberModifiers()).build());
});
}
if (entity.isEmbedded() && !(entity.isImmutable() || entity.isUnimplementable())) {
entity.attributes().stream().filter(attribute -> !attribute.isTransient()).forEach(attribute -> {
ParameterizedTypeName attributeType = ParameterizedTypeName.get(ClassName.get(Attribute.class), nameResolver.typeNameOf(parent), resolveAttributeType(attribute));
builder.addField(FieldSpec.builder(attributeType, attributeFieldName(attribute), generatedMemberModifiers(Modifier.FINAL)).build());
});
}
// only generate for interfaces or if the entity is immutable but has no builder
boolean generateMembers = typeElement.getKind().isInterface() || !entity.builderType().isPresent();
Set<String> existingFieldNames = entity.attributes().stream().map(AttributeDescriptor::element).filter(it -> it.getKind() == ElementKind.FIELD).map(it -> it.getSimpleName().toString()).collect(Collectors.toSet());
if (generateMembers) {
for (AttributeDescriptor attribute : entity.attributes()) {
Element element = attribute.element();
if (element.getKind() == ElementKind.METHOD) {
ExecutableElement methodElement = (ExecutableElement) element;
TypeMirror typeMirror = methodElement.getReturnType();
TypeName fieldName;
if (attribute.isIterable()) {
fieldName = parameterizedCollectionName(typeMirror);
} else if (attribute.isOptional()) {
typeMirror = tryFirstTypeArgument(attribute.typeMirror());
fieldName = TypeName.get(typeMirror);
} else {
fieldName = nameResolver.tryGeneratedTypeName(typeMirror);
}
if (entity.isImmutable() || !existingFieldNames.contains(attribute.fieldName())) {
builder.addField(FieldSpec.builder(fieldName, attribute.fieldName(), generatedMemberModifiers()).build());
}
}
}
}
if (entity.isImmutable()) {
generateBuilder(builder, entity, "builder");
entity.attributes().stream().filter(AttributeDescriptor::isEmbedded).forEach(attribute -> graph.embeddedDescriptorOf(attribute).ifPresent(embedded -> embedded.builderType().ifPresent(type -> {
String fieldName = attribute.fieldName() + "Builder";
generateBuilder(builder, embedded, fieldName);
})));
}
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityGenerator method generateProxyMethods.
private void generateProxyMethods(TypeSpec.Builder builder) {
// add proxy field
TypeName entityType = entity.isEmbedded() ? nameResolver.typeNameOf(parent) : typeName;
TypeName proxyName = parameterizedTypeName(EntityProxy.class, entityType);
FieldSpec.Builder proxyField = FieldSpec.builder(proxyName, PROXY_NAME, generatedMemberModifiers(Modifier.FINAL, Modifier.TRANSIENT));
if (!entity.isEmbedded()) {
proxyField.initializer("new $T(this, $L)", proxyName, TYPE_NAME);
}
builder.addField(proxyField.build());
for (AttributeDescriptor attribute : entity.attributes()) {
boolean useField = attribute.isTransient() || attribute.isEmbedded();
TypeMirror typeMirror = attribute.typeMirror();
TypeName unboxedTypeName;
if (attribute.isIterable()) {
unboxedTypeName = parameterizedCollectionName(typeMirror);
} else if (attribute.isOptional()) {
unboxedTypeName = TypeName.get(tryFirstTypeArgument(attribute.typeMirror()));
} else if (attribute.isEmbedded()) {
EntityDescriptor embedded = graph.embeddedDescriptorOf(attribute).orElseThrow(IllegalStateException::new);
unboxedTypeName = nameResolver.embeddedTypeNameOf(embedded, entity);
} else {
unboxedTypeName = nameResolver.tryGeneratedTypeName(typeMirror);
}
String attributeName = attribute.fieldName();
String getterName = attribute.getterName();
String fieldName = Names.upperCaseUnderscore(Names.removeMemberPrefixes(attributeName));
if (entity.isEmbedded()) {
fieldName = attributeFieldName(attribute);
}
// getter
MethodSpec.Builder getter = MethodSpec.methodBuilder(getterName).addModifiers(Modifier.PUBLIC).returns(attribute.isOptional() ? TypeName.get(typeMirror) : unboxedTypeName);
if (Mirrors.overridesMethod(types, typeElement, getterName)) {
getter.addAnnotation(Override.class);
}
memberExtensions.forEach(extension -> extension.addToGetter(attribute, getter));
if (useField) {
if (attribute.isEmbedded()) {
// have to cast to embedded type
getter.addStatement("return ($T)this.$L", unboxedTypeName, attributeName);
} else {
getter.addStatement("return this.$L", attributeName);
}
} else if (attribute.isOptional()) {
String ofNullable = "ofNullable";
if ("com.google.common.base.Optional".equals(attribute.optionalClass())) {
ofNullable = "fromNullable";
}
getter.addStatement("return $T.$L($L.get($L))", ClassName.bestGuess(attribute.optionalClass()), ofNullable, PROXY_NAME, fieldName);
} else {
getter.addStatement("return $L.get($L)", PROXY_NAME, fieldName);
}
builder.addMethod(getter.build());
// setter
String setterName = attribute.setterName();
// if read only don't generate a public setter
boolean readOnly = entity.isReadOnly() || attribute.isReadOnly();
// edge case check if it's interface and we need to implement the setter
if (entity.element().getKind().isInterface() && ElementFilter.methodsIn(entity.element().getEnclosedElements()).stream().anyMatch(element -> element.getSimpleName().toString().equals(setterName))) {
readOnly = false;
}
if (!readOnly) {
TypeName setTypeName = unboxedTypeName;
boolean castType = false;
// use wildcard generic collection type if necessary
if (setTypeName instanceof ParameterizedTypeName) {
ParameterizedTypeName parameterizedName = (ParameterizedTypeName) setTypeName;
List<TypeName> arguments = parameterizedName.typeArguments;
List<TypeName> wildcards = new ArrayList<>();
for (TypeName argument : arguments) {
if (!(argument instanceof WildcardTypeName)) {
Elements elements = processingEnv.getElementUtils();
TypeElement element = elements.getTypeElement(argument.toString());
if (element != null && element.getKind() == ElementKind.INTERFACE) {
wildcards.add(WildcardTypeName.subtypeOf(argument));
} else {
wildcards.add(argument);
}
} else {
wildcards.add(argument);
}
}
TypeName[] array = new TypeName[wildcards.size()];
setTypeName = ParameterizedTypeName.get(parameterizedName.rawType, wildcards.toArray(array));
castType = true;
}
String paramName = Names.lowerCaseFirst(Names.removeMemberPrefixes(attributeName));
MethodSpec.Builder setter = MethodSpec.methodBuilder(setterName).addModifiers(Modifier.PUBLIC).addParameter(setTypeName, paramName);
if (useField) {
setter.addStatement("this.$L = $L", attributeName, paramName);
} else {
if (castType) {
setter.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "unchecked").build());
setter.addStatement("$L.set($L, ($T)$L)", PROXY_NAME, fieldName, unboxedTypeName, paramName);
} else {
setter.addStatement("$L.set($L, $L)", PROXY_NAME, fieldName, paramName);
}
}
memberExtensions.forEach(extension -> extension.addToSetter(attribute, setter));
PropertyNameStyle style = entity.propertyNameStyle();
if (style == PropertyNameStyle.FLUENT || style == PropertyNameStyle.FLUENT_BEAN) {
setter.addStatement("return this");
setter.returns(typeName);
}
builder.addMethod(setter.build());
}
}
MethodSpec.Builder constructor = MethodSpec.constructorBuilder().addModifiers(Modifier.PUBLIC);
if (entity.isEmbedded()) {
constructor.addParameter(ParameterSpec.builder(proxyName, "proxy").build());
constructor.addStatement("this.$L = proxy", PROXY_NAME);
entity.attributes().stream().filter(attribute -> !attribute.isTransient()).forEach(attribute -> {
ParameterizedTypeName attributeType = ParameterizedTypeName.get(ClassName.get(Attribute.class), nameResolver.typeNameOf(parent), resolveAttributeType(attribute));
constructor.addParameter(ParameterSpec.builder(attributeType, attribute.name()).build());
constructor.addStatement("this.$L = $L", attributeFieldName(attribute), attribute.name());
});
}
generateListeners(constructor);
// initialize the generated embedded entities
entity.attributes().stream().filter(AttributeDescriptor::isEmbedded).forEach(attribute -> graph.embeddedDescriptorOf(attribute).ifPresent(embedded -> {
ClassName embeddedName = nameResolver.embeddedTypeNameOf(embedded, entity);
String format = embedded.attributes().stream().map(attr -> Names.upperCaseUnderscore(embeddedAttributeName(attribute, attr))).collect(Collectors.joining(", ", "$L = new $T($L, ", ")"));
constructor.addStatement(format, attribute.fieldName(), embeddedName, PROXY_NAME);
}));
builder.addMethod(constructor.build());
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityMetaGenerator method generate.
void generate(TypeSpec.Builder builder) {
boolean metadataOnly = entity.isImmutable() || entity.isUnimplementable();
TypeName targetName = metadataOnly ? ClassName.get(entity.element()) : typeName;
List<QualifiedName> generatedEmbeddedTypes = new LinkedList<>();
entity.attributes().stream().filter(attribute -> !attribute.isTransient()).forEach(attribute -> {
String fieldName = upperCaseUnderscoreRemovePrefixes(attribute.fieldName());
if (attribute.isForeignKey() && attribute.cardinality() != null) {
// generate a foreign key attribute for use in queries but not stored in the type
graph.referencingEntity(attribute).flatMap(entity -> graph.referencingAttribute(attribute, entity)).ifPresent(foreignKey -> {
String name = fieldName + "_ID";
TypeMirror mirror = foreignKey.typeMirror();
builder.addField(generateAttribute(attribute, null, targetName, name, mirror, true));
expressionNames.add(name);
});
}
if (attribute.isEmbedded()) {
graph.embeddedDescriptorOf(attribute).ifPresent(embedded -> {
generateEmbeddedAttributes(attribute, embedded, builder, targetName);
if (!generatedEmbeddedTypes.contains(embedded.typeName())) {
generatedEmbeddedTypes.add(embedded.typeName());
generateEmbeddedEntity(embedded);
}
});
} else {
TypeMirror mirror = attribute.typeMirror();
builder.addField(generateAttribute(attribute, null, targetName, fieldName, mirror, false));
attributeNames.add(fieldName);
}
});
generateType(builder, targetName);
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityMetaGenerator method generateAttribute.
private FieldSpec generateAttribute(AttributeDescriptor attribute, AttributeDescriptor parent, TypeName targetName, String fieldName, TypeMirror mirror, boolean expression) {
TypeMirror typeMirror = mirror;
TypeName typeName;
if (attribute.isIterable()) {
typeMirror = tryFirstTypeArgument(typeMirror);
typeName = parameterizedCollectionName(attribute.typeMirror());
} else if (attribute.isOptional()) {
typeMirror = tryFirstTypeArgument(typeMirror);
typeName = TypeName.get(typeMirror);
} else {
typeName = nameResolver.generatedTypeNameOf(typeMirror).orElse(null);
}
if (typeName == null) {
typeName = boxedTypeName(typeMirror);
}
ParameterizedTypeName type;
ClassName attributeType = null;
boolean useKotlinDelegate = false;
if (expression) {
type = parameterizedTypeName(QueryExpression.class, typeName);
} else {
// if it's an association don't make it available as a query attribute
boolean isQueryable = attribute.cardinality() == null || attribute.isForeignKey();
if (isQueryable) {
Class<?> attributeClass;
String kotlinDelegate;
switch(attribute.getType()) {
case STRING:
attributeClass = StringAttribute.class;
kotlinDelegate = "StringAttributeDelegate";
break;
case NUMERIC:
attributeClass = NumericAttribute.class;
kotlinDelegate = "NumericAttributeDelegate";
break;
default:
case DEFAULT:
attributeClass = QueryAttribute.class;
kotlinDelegate = "AttributeDelegate";
break;
}
attributeType = ClassName.get(attributeClass);
// check if the kotlin delegate is available, if so use that
TypeElement delegateType = elements.getTypeElement("io.requery.meta." + kotlinDelegate);
if (delegateType != null) {
attributeType = ClassName.get(delegateType);
useKotlinDelegate = true;
}
} else {
attributeType = ClassName.get(Attribute.class);
}
type = ParameterizedTypeName.get(attributeType, targetName, typeName);
}
CodeBlock.Builder builder = CodeBlock.builder();
String attributeName = attribute.name();
if (parent != null && parent.isEmbedded()) {
attributeName = embeddedAttributeName(parent, attribute);
}
if (attribute.isIterable()) {
typeMirror = tryFirstTypeArgument(typeMirror);
TypeName name = nameResolver.tryGeneratedTypeName(typeMirror);
TypeElement collection = (TypeElement) types.asElement(attribute.typeMirror());
ParameterizedTypeName builderName = parameterizedTypeName(attribute.builderClass(), targetName, typeName, name);
builder.add("\nnew $T($S, $T.class, $T.class)\n", builderName, attributeName, ClassName.get(collection), name);
} else if (attribute.isMap() && attribute.cardinality() != null) {
List<TypeMirror> parameters = Mirrors.listGenericTypeArguments(typeMirror);
// key type
TypeName keyName = TypeName.get(parameters.get(0));
// value type
typeMirror = parameters.get(1);
TypeName valueName = nameResolver.tryGeneratedTypeName(typeMirror);
TypeElement valueElement = (TypeElement) types.asElement(attribute.typeMirror());
ParameterizedTypeName builderName = parameterizedTypeName(attribute.builderClass(), targetName, typeName, keyName, valueName);
builder.add("\nnew $T($S, $T.class, $T.class, $T.class)\n", builderName, attributeName, ClassName.get(valueElement), keyName, valueName);
} else {
ParameterizedTypeName builderName = parameterizedTypeName(attribute.builderClass(), targetName, typeName);
TypeName classType = typeName;
if (typeMirror.getKind().isPrimitive()) {
// if primitive just use the primitive class not the boxed version
classType = TypeName.get(typeMirror);
}
String statement;
if (Mirrors.listGenericTypeArguments(typeMirror).size() > 0) {
// use the erased type and cast to class
classType = TypeName.get(types.erasure(typeMirror));
statement = "\nnew $T($S, (Class)$T.class)\n";
} else {
statement = "\nnew $T($S, $T.class)\n";
}
builder.add(statement, builderName, attributeName, classType);
}
if (!expression) {
generateProperties(attribute, parent, typeMirror, targetName, typeName, builder);
}
// attribute builder properties
if (attribute.isKey()) {
builder.add(".setKey(true)\n");
}
builder.add(".setGenerated($L)\n", attribute.isGenerated());
builder.add(".setReadOnly($L)\n", attribute.isReadOnly());
builder.add(".setLazy($L)\n", attribute.isLazy());
builder.add(".setNullable($L)\n", attribute.isNullable());
builder.add(".setUnique($L)\n", attribute.isUnique());
if (!Names.isEmpty(attribute.defaultValue())) {
builder.add(".setDefaultValue($S)\n", attribute.defaultValue());
}
if (!Names.isEmpty(attribute.collate())) {
builder.add(".setCollate($S)\n", attribute.collate());
}
if (attribute.columnLength() != null) {
builder.add(".setLength($L)\n", attribute.columnLength());
}
if (!Names.isEmpty(attribute.definition())) {
builder.add(".setDefinition($S)\n", attribute.definition());
}
if (attribute.isVersion()) {
builder.add(".setVersion($L)\n", attribute.isVersion());
}
if (attribute.converterName() != null) {
builder.add(".setConverter(new $L())\n", attribute.converterName());
}
if (attribute.isForeignKey()) {
builder.add(".setForeignKey($L)\n", attribute.isForeignKey());
Optional<EntityDescriptor> referencedType = graph.referencingEntity(attribute);
referencedType.ifPresent(referenced -> {
builder.add(".setReferencedClass($T.class)\n", referenced.isImmutable() ? TypeName.get(referenced.element().asType()) : nameResolver.typeNameOf(referenced));
graph.referencingAttribute(attribute, referenced).ifPresent(referencedAttribute -> {
String name = upperCaseUnderscoreRemovePrefixes(referencedAttribute.fieldName());
TypeSpec provider = CodeGeneration.createAnonymousSupplier(ClassName.get(Attribute.class), CodeBlock.builder().addStatement("return $T.$L", nameResolver.typeNameOf(referenced), name).build());
builder.add(".setReferencedAttribute($L)\n", provider);
});
});
}
if (attribute.isIndexed()) {
builder.add(".setIndexed($L)\n", attribute.isIndexed());
if (!attribute.indexNames().isEmpty()) {
StringJoiner joiner = new StringJoiner(",");
attribute.indexNames().forEach(name -> joiner.add("$S"));
builder.add(".setIndexNames(" + joiner + ")\n", attribute.indexNames().toArray());
}
}
if (attribute.deleteAction() != null) {
builder.add(".setDeleteAction($T.$L)\n", ClassName.get(ReferentialAction.class), attribute.deleteAction());
}
if (attribute.updateAction() != null) {
builder.add(".setUpdateAction($T.$L)\n", ClassName.get(ReferentialAction.class), attribute.updateAction());
}
if (!attribute.cascadeActions().isEmpty()) {
StringJoiner joiner = new StringJoiner(",");
attribute.cascadeActions().forEach(action -> joiner.add("$T.$L"));
int index = 0;
ClassName cascadeClass = ClassName.get(CascadeAction.class);
Object[] args = new Object[attribute.cascadeActions().size() * 2];
for (CascadeAction action : attribute.cascadeActions()) {
args[index++] = cascadeClass;
args[index++] = action;
}
builder.add(".setCascadeAction(" + joiner + ")\n", args);
}
if (attribute.cardinality() != null) {
if (!expression) {
builder.add(".setCardinality($T.$L)\n", ClassName.get(Cardinality.class), attribute.cardinality());
}
graph.referencingEntity(attribute).ifPresent(referenced -> {
Set<AttributeDescriptor> mappings = graph.mappedAttributes(entity, attribute, referenced);
if (attribute.cardinality() == Cardinality.MANY_TO_MANY) {
generateJunctionType(attribute, referenced, mappings).ifPresent(name -> builder.add(".setReferencedClass($T.class)\n", name));
}
if (mappings.size() == 1) {
AttributeDescriptor mapped = mappings.iterator().next();
String staticMemberName = upperCaseUnderscoreRemovePrefixes(mapped.fieldName());
TypeSpec provider = CodeGeneration.createAnonymousSupplier(ClassName.get(Attribute.class), CodeBlock.builder().addStatement("return $T.$L", nameResolver.typeNameOf(referenced), staticMemberName).build());
builder.add(".setMappedAttribute($L)\n", provider);
}
if (attribute.orderBy() != null) {
referenced.attributes().stream().filter(entry -> entry.name().equals(attribute.orderBy())).findFirst().ifPresent(orderBy -> {
String staticMemberName = upperCaseUnderscoreRemovePrefixes(orderBy.fieldName());
TypeSpec provider = CodeGeneration.createAnonymousSupplier(ClassName.get(Attribute.class), CodeBlock.builder().addStatement("return $T.$L", nameResolver.typeNameOf(referenced), staticMemberName).build());
builder.add(".setOrderByAttribute($L)\n", provider);
builder.add(".setOrderByDirection($T.$L)\n", ClassName.get(Order.class), attribute.orderByDirection());
});
}
});
}
switch(attribute.getType()) {
case DEFAULT:
builder.add(".build()");
break;
case STRING:
builder.add(".buildString()");
break;
case NUMERIC:
builder.add(".buildNumeric()");
break;
}
FieldSpec.Builder field = FieldSpec.builder(type, fieldName, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
if (useKotlinDelegate) {
return field.initializer("new $T($L)", attributeType, builder.build()).build();
} else {
return field.initializer("$L", builder.build()).build();
}
}
Aggregations