use of io.requery.meta.Attribute in project requery by requery.
the class SchemaUpdater method update.
public void update() {
SchemaModifier schema = new SchemaModifier(configuration);
schema.createTables(mode);
if (mode == TableCreationMode.DROP_CREATE) {
// don't need to check missing columns
return;
}
Function<String, String> columnTransformer = configuration.getColumnTransformer();
Function<String, String> tableTransformer = configuration.getTableTransformer();
// check for missing columns
List<Attribute> missingAttributes = new ArrayList<>();
for (Type<?> type : configuration.getModel().getTypes()) {
if (type.isView()) {
continue;
}
String tableName = type.getName();
if (tableTransformer != null) {
tableName = tableTransformer.apply(tableName);
}
Cursor cursor = queryFunction.apply("PRAGMA table_info(" + tableName + ")");
Map<String, Attribute> map = new LinkedHashMap<>();
for (Attribute attribute : type.getAttributes()) {
if (attribute.isAssociation() && !attribute.isForeignKey()) {
continue;
}
if (columnTransformer == null) {
map.put(attribute.getName(), attribute);
} else {
map.put(columnTransformer.apply(attribute.getName()), attribute);
}
}
if (cursor.getCount() > 0) {
int nameIndex = cursor.getColumnIndex("name");
while (cursor.moveToNext()) {
String name = cursor.getString(nameIndex);
map.remove(name);
}
}
cursor.close();
// whats left in the map are are the missing columns for this type
missingAttributes.addAll(map.values());
}
// foreign keys are created last
Collections.sort(missingAttributes, new Comparator<Attribute>() {
@Override
public int compare(Attribute lhs, Attribute rhs) {
if (lhs.isForeignKey() && rhs.isForeignKey()) {
return 0;
}
if (lhs.isForeignKey()) {
return 1;
}
return -1;
}
});
for (Attribute<?, ?> attribute : missingAttributes) {
schema.addColumn(attribute);
}
}
use of io.requery.meta.Attribute in project requery by requery.
the class SelectResult method iterator.
@Override
public CloseableIterator<E> iterator(int skip, int take) {
Statement statement = null;
try {
// connection held by the iterator if statement not reused
BoundParameters parameters = createQuery(skip, take);
statement = createStatement(!parameters.isEmpty());
statement.setFetchSize(limit == null ? 0 : limit);
StatementListener listener = configuration.getStatementListener();
listener.beforeExecuteQuery(statement, sql, parameters);
ResultSet results;
if (parameters.isEmpty()) {
results = statement.executeQuery(sql);
} else {
PreparedStatement preparedStatement = (PreparedStatement) statement;
Mapping mapping = configuration.getMapping();
for (int i = 0; i < parameters.count(); i++) {
Expression expression = parameters.expressionAt(i);
Object value = parameters.valueAt(i);
if (expression instanceof Attribute) {
// extract foreign key reference
Attribute attribute = (Attribute) expression;
if (attribute.isAssociation() && (attribute.isForeignKey() || attribute.isKey())) {
// get the referenced value
if (value != null && ((Expression<?>) expression).getClassType().isAssignableFrom(value.getClass())) {
value = Attributes.replaceKeyReference(value, attribute);
}
}
}
mapping.write(expression, preparedStatement, i + 1, value);
}
results = preparedStatement.executeQuery();
}
listener.afterExecuteQuery(statement);
return new ResultSetIterator<>(reader, results, selection, true, closeConnection);
} catch (Exception e) {
throw StatementExecutionException.closing(statement, e, sql);
}
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityMetaGenerator method generateType.
private void generateType(TypeSpec.Builder builder, TypeName targetName) {
CodeBlock.Builder block = CodeBlock.builder().add("new $T<$T>($T.class, $S)\n", TypeBuilder.class, targetName, targetName, entity.tableName());
block.add(".setBaseType($T.class)\n", ClassName.get(typeElement)).add(".setCacheable($L)\n", entity.isCacheable()).add(".setImmutable($L)\n", entity.isImmutable()).add(".setReadOnly($L)\n", entity.isReadOnly()).add(".setStateless($L)\n", entity.isStateless()).add(".setView($L)\n", entity.isView());
String factoryName = entity.classFactoryName();
if (!Names.isEmpty(factoryName)) {
block.add(".setFactory(new $L())\n", ClassName.bestGuess(factoryName));
} else if (entity.isImmutable()) {
// returns this class as the builder
TypeSpec.Builder supplier = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Supplier.class, typeName));
supplier.addMethod(CodeGeneration.overridePublicMethod("get").returns(typeName).addStatement("return new $T()", typeName).build());
block.add(".setBuilderFactory($L)\n", supplier.build());
MethodSpec.Builder applyMethod = CodeGeneration.overridePublicMethod("apply").addParameter(typeName, "value").returns(targetName);
// add embedded builder calls
entity.attributes().stream().filter(AttributeDescriptor::isEmbedded).forEach(attribute -> graph.embeddedDescriptorOf(attribute).ifPresent(embedded -> embedded.builderType().ifPresent(type -> {
String fieldName = attribute.fieldName() + "Builder";
String methodName = attribute.setterName();
applyMethod.addStatement("value.builder.$L(value.$L.build())", methodName, fieldName);
})));
applyMethod.addStatement(entity.builderType().isPresent() ? "return value.builder.build()" : "return value.build()");
TypeSpec.Builder buildFunction = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Function.class, typeName, targetName)).addMethod(applyMethod.build());
block.add(".setBuilderFunction($L)\n", buildFunction.build());
} else {
TypeSpec.Builder typeFactory = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Supplier.class, targetName)).addMethod(CodeGeneration.overridePublicMethod("get").addStatement("return new $T()", targetName).returns(targetName).build());
block.add(".setFactory($L)\n", typeFactory.build());
}
ParameterizedTypeName proxyType = parameterizedTypeName(EntityProxy.class, targetName);
TypeSpec.Builder proxyProvider = TypeSpec.anonymousClassBuilder("").addSuperinterface(parameterizedTypeName(Function.class, targetName, proxyType));
MethodSpec.Builder proxyFunction = CodeGeneration.overridePublicMethod("apply").addParameter(targetName, "entity").returns(proxyType);
if (entity.isImmutable() || entity.isUnimplementable()) {
proxyFunction.addStatement("return new $T(entity, $L)", proxyType, TYPE_NAME);
} else {
proxyFunction.addStatement("return entity.$L", PROXY_NAME);
}
proxyProvider.addMethod(proxyFunction.build());
block.add(".setProxyProvider($L)\n", proxyProvider.build());
if (entity.tableAttributes().length > 0) {
StringJoiner joiner = new StringJoiner(",", "new String[] {", "}");
for (String attribute : entity.tableAttributes()) {
joiner.add("\"" + attribute + "\"");
}
block.add(".setTableCreateAttributes($L)\n", joiner.toString());
}
if (entity.tableUniqueIndexes().length > 0) {
StringJoiner joiner = new StringJoiner(",", "new String[] {", "}");
for (String attribute : entity.tableUniqueIndexes()) {
joiner.add("\"" + attribute + "\"");
}
block.add(".setTableUniqueIndexes($L)\n", joiner.toString());
}
attributeNames.forEach(name -> block.add(".addAttribute($L)\n", name));
expressionNames.forEach(name -> block.add(".addExpression($L)\n", name));
block.add(".build()");
ParameterizedTypeName type = parameterizedTypeName(Type.class, targetName);
builder.addField(FieldSpec.builder(type, TYPE_NAME, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("$L", block.build()).build());
}
use of io.requery.meta.Attribute in project requery by requery.
the class FunctionalTest method testFindByCompositeKey.
@Test
public void testFindByCompositeKey() {
Group group = new Group();
group.setName("group");
group.setType(GroupType.PRIVATE);
Person person = randomPerson();
person.getGroups().add(group);
data.insert(person);
assertTrue(person.getId() > 0);
// create the composite key
Map<Attribute<Group_Person, Integer>, Integer> map = new LinkedHashMap<>();
map.put(Group_Person.GROUPS_ID, group.getId());
map.put(Group_Person.PERSON_ID, person.getId());
CompositeKey<Group_Person> compositeKey = new CompositeKey<>(map);
Group_Person joined = data.findByKey(Group_Person.class, compositeKey);
assertNotNull(joined);
}
use of io.requery.meta.Attribute in project requery by requery.
the class EntityWriter method updateAssociation.
@SuppressWarnings("unchecked")
private void updateAssociation(Cascade mode, E entity, EntityProxy<E> proxy, Attribute<E, ?> attribute) {
switch(attribute.getCardinality()) {
case ONE_TO_ONE:
S value = (S) proxy.get(attribute, false);
if (value != null) {
Attribute<S, Object> mapped = Attributes.get(attribute.getMappedAttribute());
EntityProxy<S> referred = context.proxyOf(value, true);
referred.set(mapped, entity, PropertyState.MODIFIED);
cascadeWrite(mode, value, referred);
} else if (!stateless) {
throw new PersistenceException("1-1 relationship can only be removed from the owning side");
}
break;
case ONE_TO_MANY:
Object relation = proxy.get(attribute, false);
if (relation instanceof ObservableCollection) {
ObservableCollection<S> collection = (ObservableCollection<S>) relation;
CollectionChanges<?, S> changes = (CollectionChanges<?, S>) collection.observer();
List<S> added = new ArrayList<>(changes.addedElements());
List<S> removed = new ArrayList<>(changes.removedElements());
changes.clear();
for (S element : added) {
updateMappedAssociation(mode, element, attribute, entity);
}
for (S element : removed) {
updateMappedAssociation(Cascade.UPDATE, element, attribute, null);
}
} else if (relation instanceof Iterable) {
Iterable<S> iterable = (Iterable<S>) relation;
for (S added : iterable) {
updateMappedAssociation(mode, added, attribute, entity);
}
} else {
throw new IllegalStateException("unsupported relation type " + relation);
}
break;
case MANY_TO_MANY:
final Class referencedClass = attribute.getReferencedClass();
if (referencedClass == null) {
throw new IllegalStateException("Invalid referenced class in " + attribute);
}
Type<?> referencedType = model.typeOf(referencedClass);
QueryAttribute<S, Object> tKey = null;
QueryAttribute<S, Object> uKey = null;
for (Attribute a : referencedType.getAttributes()) {
Class<?> referenced = a.getReferencedClass();
if (referenced != null) {
if (tKey == null && entityClass.isAssignableFrom(referenced)) {
tKey = Attributes.query(a);
} else if (attribute.getElementClass() != null && attribute.getElementClass().isAssignableFrom(referenced)) {
uKey = Attributes.query(a);
}
}
}
Objects.requireNotNull(tKey);
Objects.requireNotNull(uKey);
Attribute<E, Object> tRef = Attributes.get(tKey.getReferencedAttribute());
Attribute<S, Object> uRef = Attributes.get(uKey.getReferencedAttribute());
CollectionChanges<?, S> changes = null;
relation = proxy.get(attribute, false);
Iterable<S> addedElements = (Iterable<S>) relation;
boolean isObservable = relation instanceof ObservableCollection;
if (relation instanceof ObservableCollection) {
ObservableCollection<S> collection = (ObservableCollection<S>) relation;
changes = (CollectionChanges<?, S>) collection.observer();
if (changes != null) {
addedElements = changes.addedElements();
}
}
for (S added : addedElements) {
S junction = (S) referencedType.getFactory().get();
EntityProxy<S> junctionProxy = context.proxyOf(junction, false);
EntityProxy<S> uProxy = context.proxyOf(added, false);
if (attribute.getCascadeActions().contains(CascadeAction.SAVE)) {
cascadeWrite(mode, added, uProxy);
}
Object tValue = proxy.get(tRef, false);
Object uValue = uProxy.get(uRef, false);
junctionProxy.set(tKey, tValue, PropertyState.MODIFIED);
junctionProxy.set(uKey, uValue, PropertyState.MODIFIED);
Cascade cascade = isObservable && mode == Cascade.UPSERT ? Cascade.UPSERT : Cascade.INSERT;
cascadeWrite(cascade, junction, null);
}
if (changes != null) {
Object keyValue = proxy.get(tRef, false);
for (S removed : changes.removedElements()) {
Object otherValue = context.proxyOf(removed, false).get(uRef);
Class<? extends S> removeType = (Class<? extends S>) referencedType.getClassType();
Supplier<? extends Scalar<Integer>> query = queryable.delete(removeType).where(tKey.equal(keyValue)).and(uKey.equal(otherValue));
int count = query.get().value();
if (count != 1) {
throw new RowCountException(entity.getClass(), 1, count);
}
}
changes.clear();
}
break;
case MANY_TO_ONE:
default:
break;
}
context.read(type.getClassType()).refresh(entity, proxy, attribute);
}
Aggregations