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.
                
             The newest version!
        
        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.getInsertOnDuplicateUpdate(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