com.kenshoo.pl.entity.internal.DbCommandsOutputGenerator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of persistence-layer Show documentation
Show all versions of persistence-layer Show documentation
A Java persistence layer based on JOOQ for high performance and business flow support.
package com.kenshoo.pl.entity.internal;
import com.google.common.base.Stopwatch;
import com.kenshoo.jooq.DataTable;
import com.kenshoo.pl.data.*;
import com.kenshoo.pl.entity.*;
import com.kenshoo.pl.entity.spi.OutputGenerator;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.jooq.ForeignKey;
import org.jooq.Record;
import org.jooq.TableField;
import org.jooq.lambda.Seq;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static com.kenshoo.pl.entity.ChangeOperation.CREATE;
import static com.kenshoo.pl.entity.ChangeOperation.UPDATE;
import static com.kenshoo.pl.entity.HierarchyKeyPopulator.autoInc;
import static com.kenshoo.pl.entity.HierarchyKeyPopulator.fromContext;
import static com.kenshoo.pl.entity.internal.SecondaryTableRelationExtractor.relationUsingTableFieldsOfPrimary;
import static com.kenshoo.pl.entity.internal.SecondaryTableRelationExtractor.relationUsingTableFieldsOfSecondary;
import static java.util.stream.Collectors.toList;
import static org.jooq.lambda.Seq.seq;
import static org.jooq.lambda.function.Functions.not;
public class DbCommandsOutputGenerator> implements OutputGenerator {
private final E entityType;
private final CommandsExecutor commandsExecutor;
public DbCommandsOutputGenerator(E entityType, PLContext plContext) {
this.entityType = entityType;
this.commandsExecutor = CommandsExecutor.of(plContext.dslContext());
}
@Override
public void generate(Collection extends EntityChange> entityChanges, ChangeOperation operator, ChangeContext changeContext) {
Stopwatch stopwatch = Stopwatch.createStarted();
if (operator == ChangeOperation.DELETE) {
generateForDelete(changeContext, entityChanges);
} else {
final ChangesContainer primaryTableCommands =
generateForCreateOrUpdate(entityChanges,
this::isOfPrimaryTable,
operator,
changeContext);
entityType.getPrimaryIdentityField().ifPresent(identityField -> {
if (operator == CREATE) {
populateGeneratedIdsToContext(identityField,
entityChanges,
changeContext,
primaryTableCommands);
//noinspection unchecked
new HierarchyKeyPopulator.Builder()
.with(changeContext.getHierarchy())
.whereParentFieldsAre(autoInc())
.gettingValues(fromContext(changeContext)).build()
.populateKeysToChildren((Collection extends ChangeEntityCommand>) entityChanges);
}
}
);
generateForCreateOrUpdate(entityChanges,
not(this::isOfPrimaryTable),
operator,
changeContext);
}
changeContext.getStats().addUpdateTime(stopwatch.elapsed(TimeUnit.MILLISECONDS));
}
private void populateGeneratedIdsToContext(final EntityField identityField,
Collection extends EntityChange> entityChanges,
ChangeContext changeContext,
ChangesContainer changesContainer) {
final TableField identityTableField = getFirstTableField(identityField);
seq(entityChanges)
.map(change -> ImmutablePair.of(change, changesContainer.getInsert(entityType.getPrimaryTable(), change)))
.filter(pair -> pair.getRight().isPresent())
.forEach(pair -> {
final CreateRecordCommand cmd = pair.getRight().get();
Object generatedValue = cmd.get(identityTableField);
changeContext.addEntity(pair.getLeft(), new EntityWithGeneratedId(identityField, generatedValue));
});
}
private TableField getFirstTableField(final EntityField entityField) {
return entityField.getDbAdapter().getTableFields()
.findFirst()
.orElseThrow(() -> new IllegalStateException("No table fields found for an entity field"));
}
private boolean isOfPrimaryTable(FieldChange f) {
return f.getField().getDbAdapter().getTable() == entityType.getPrimaryTable();
}
private void translateChange(EntityChange entityChange, FieldChange change, ChangesContainer changesContainer, ChangeOperation changeOperation, ChangeContext changeContext) {
EntityField entityField = change.getField();
if (!entityField.isVirtual()) {
translateChange(entityChange, change, entityField, changesContainer, changeOperation, changeContext);
}
}
private void translateChange(final EntityChange entityChange, final FieldChange change, final EntityField entityField, final ChangesContainer changesContainer, final ChangeOperation operator, final ChangeContext ctx) {
final DataTable fieldTable = entityField.getDbAdapter().getTable();
final DataTable primaryTable = entityType.getPrimaryTable();
AbstractRecordCommand recordCommand;
if (fieldTable == primaryTable) {
if (operator == CREATE) {
recordCommand = changesContainer.getInsert(primaryTable, entityChange, () -> newCreateRecord(entityChange));
} else {
recordCommand = changesContainer.getUpdate(primaryTable, entityChange, () -> new UpdateRecordCommand(primaryTable, getDatabaseId(entityChange)));
}
} else {
var foreignKeyValues = foreignKeyValues(entityChange, operator, ctx, fieldTable);
if (operator == CREATE || rowNotYetExistsInSecondary(fieldTable, ctx.getEntity(entityChange), ctx, foreignKeyValues)) {
recordCommand = changesContainer.getInsert(fieldTable, entityChange, () -> {
var createRecordCommand = new CreateRecordCommand(fieldTable);
populate(foreignKeyValues, createRecordCommand);
return createRecordCommand;
});
} else {
recordCommand = changesContainer.getUpdate(fieldTable, entityChange, () -> new UpdateRecordCommand(fieldTable, foreignKeyValues));
}
}
populateFieldChange(change, recordCommand);
}
private boolean rowNotYetExistsInSecondary(DataTable table, CurrentEntityState fetchedFields, ChangeContext ctx, DatabaseId fkToPrimary) {
var keyFieldFromSecondaryToPrimary = seq(ctx.getFetchRequests())
.map(FieldFetchRequest::getEntityField)
.filter(isTableFieldExistsIn(fkToPrimary))
.findFirst(field -> field.getDbAdapter().getTable() == table).get();
return fetchedFields.safeGet(keyFieldFromSecondaryToPrimary).isNullOrAbsent();
}
private Predicate> isTableFieldExistsIn(DatabaseId fkToPrimary) {
return field -> field.getDbAdapter().getTableFields().findFirst()
.map(tableField -> Seq.of(fkToPrimary.getTableFields()).contains(tableField))
.orElse(false);
}
private CreateRecordCommand newCreateRecord(EntityChange entityChange) {
CreateRecordCommand cmd = new CreateRecordCommand(entityType.getPrimaryTable());
populateParentKeys(entityChange, cmd);
return cmd;
}
private void populateFieldChange(FieldChange, T> change, AbstractRecordCommand recordCommand) {
T value = change.getValue();
Iterator> tableFields = change.getField().getDbAdapter().getTableFields().iterator();
Iterator
© 2015 - 2025 Weber Informatics LLC | Privacy Policy