Skip to content

Commit

Permalink
add cascade delete to software tablesAdd toggle to finter direct and …
Browse files Browse the repository at this point in the history
…all involvements (including inherited)

- filter parent involvements that cannot be removed form edit screen
- fix arch unit test - command interface

#CTCTOWALTZ-2705
finos#6629
finos#6648
  • Loading branch information
jessica-woodland-scott-db committed Jun 22, 2023
2 parents 0e5edd5 + d79efba commit 28d68b5
Show file tree
Hide file tree
Showing 38 changed files with 13,078 additions and 424 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ public class MeasurableIdSelectorFactory implements IdSelectorFactory {
private final OrganisationalUnitIdSelectorFactory orgUnitIdSelectorFactory = new OrganisationalUnitIdSelectorFactory();


/**
* @param measurableId the identifier of the measurable to start from
* @return a selector which gives all measurable ids that belong to the same category as the given measurable id
*/
public static SelectConditionStep<Record1<Long>> allMeasurablesIdsInSameCategory(Long measurableId) {
return DSL
.select(MEASURABLE.ID)
.from(MEASURABLE)
.where(MEASURABLE.MEASURABLE_CATEGORY_ID.eq(DSL
.select(MEASURABLE.MEASURABLE_CATEGORY_ID)
.from(MEASURABLE)
.where(MEASURABLE.ID.eq(measurableId))));
}

@Override
public Select<Record1<Long>> apply(IdSelectionOptions options) {
switch (options.entityReference().kind()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class MeasurableCategoryDao {
.constrainingAssessmentDefinitionId(Optional.ofNullable(r.getConstrainingAssessmentDefinitionId()))
.icon(r.getIconName())
.position(r.getPosition())
.allowPrimaryRatings(r.getAllowPrimaryRatings())
.build();
};

Expand Down Expand Up @@ -127,6 +128,7 @@ public boolean save(MeasurableCategory measurableCategory, String username) {
record.setLastUpdatedAt(DateTimeUtilities.nowUtcTimestamp());
record.setLastUpdatedBy(username);
record.setRatingSchemeId(measurableCategory.ratingSchemeId());
record.setAllowPrimaryRatings(measurableCategory.allowPrimaryRatings());

record.changed(MEASURABLE_CATEGORY.ID, false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@
import org.finos.waltz.data.InlineSelectFieldFactory;
import org.finos.waltz.data.JooqUtilities;
import org.finos.waltz.data.SelectorUtilities;
import org.finos.waltz.model.*;
import org.finos.waltz.model.EntityKind;
import org.finos.waltz.model.EntityLifecycleStatus;
import org.finos.waltz.model.EntityReference;
import org.finos.waltz.model.IdSelectionOptions;
import org.finos.waltz.model.ImmutableEntityReference;
import org.finos.waltz.model.Operation;
import org.finos.waltz.model.Severity;
import org.finos.waltz.model.measurable_rating.ImmutableMeasurableRating;
import org.finos.waltz.model.measurable_rating.MeasurableRating;
import org.finos.waltz.model.measurable_rating.RemoveMeasurableRatingCommand;
Expand All @@ -32,8 +38,24 @@
import org.finos.waltz.model.tally.MeasurableRatingTally;
import org.finos.waltz.model.tally.Tally;
import org.finos.waltz.schema.Tables;
import org.finos.waltz.schema.tables.EntityHierarchy;
import org.finos.waltz.schema.tables.Measurable;
import org.finos.waltz.schema.tables.records.MeasurableRatingRecord;
import org.jooq.*;
import org.jooq.Condition;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record2;
import org.jooq.Record3;
import org.jooq.Record4;
import org.jooq.Record9;
import org.jooq.RecordMapper;
import org.jooq.Select;
import org.jooq.SelectConditionStep;
import org.jooq.SelectHavingStep;
import org.jooq.SelectJoinStep;
import org.jooq.SelectOrderByStep;
import org.jooq.impl.DSL;
import org.jooq.lambda.tuple.Tuple2;
import org.slf4j.Logger;
Expand All @@ -58,7 +80,12 @@
import static org.finos.waltz.common.SetUtilities.union;
import static org.finos.waltz.common.StringUtilities.firstChar;
import static org.finos.waltz.common.StringUtilities.notEmpty;
import static org.finos.waltz.schema.Tables.*;
import static org.finos.waltz.schema.Tables.ALLOCATION;
import static org.finos.waltz.schema.Tables.CHANGE_LOG;
import static org.finos.waltz.schema.Tables.ENTITY_HIERARCHY;
import static org.finos.waltz.schema.Tables.MEASURABLE_CATEGORY;
import static org.finos.waltz.schema.Tables.MEASURABLE_RATING_PLANNED_DECOMMISSION;
import static org.finos.waltz.schema.Tables.USER_ROLE;
import static org.finos.waltz.schema.tables.Application.APPLICATION;
import static org.finos.waltz.schema.tables.Measurable.MEASURABLE;
import static org.finos.waltz.schema.tables.MeasurableRating.MEASURABLE_RATING;
Expand Down Expand Up @@ -103,6 +130,7 @@ public class MeasurableRatingDao {
.lastUpdatedAt(toLocalDateTime(r.getLastUpdatedAt()))
.lastUpdatedBy(r.getLastUpdatedBy())
.isReadOnly(r.getIsReadonly())
.isPrimary(r.getIsPrimary())
.build();
};

Expand All @@ -129,6 +157,7 @@ public class MeasurableRatingDao {
record.setLastUpdatedAt(Timestamp.valueOf(command.lastUpdate().at()));
record.setLastUpdatedBy(command.lastUpdate().by());
record.setProvenance(command.provenance());
record.setIsPrimary(command.isPrimary());
return record;
};

Expand Down Expand Up @@ -157,6 +186,7 @@ public Operation save(SaveMeasurableRatingCommand command, boolean ignoreReadOnl
.set(MEASURABLE_RATING.LAST_UPDATED_BY, command.lastUpdate().by())
.set(MEASURABLE_RATING.LAST_UPDATED_AT, command.lastUpdate().atTimestamp())
.set(MEASURABLE_RATING.PROVENANCE, command.provenance())
.set(MEASURABLE_RATING.IS_PRIMARY, command.isPrimary())
.where(MEASURABLE_RATING.ENTITY_ID.eq(command.entityReference().id()))
.and(MEASURABLE_RATING.ENTITY_KIND.eq(command.entityReference().kind().name()))
.and(MEASURABLE_RATING.MEASURABLE_ID.eq(command.measurableId()))
Expand All @@ -169,15 +199,15 @@ public Operation save(SaveMeasurableRatingCommand command, boolean ignoreReadOnl
throw new NotFoundException(
"MR_SAVE_UPDATE_FAILED",
format("Could find writable associated record to update for rating: %s", command));
};
}
return Operation.UPDATE;
} else {
if (dsl.executeInsert(record) != 1) {
throw new NotFoundException(
"MR_SAVE_INSERT_FAILED",
format("Creation of record failed: %s", command));
}
;

return Operation.ADD;
}
}
Expand Down Expand Up @@ -268,11 +298,19 @@ public List<Tally<Long>> tallyByMeasurableCategoryId(long categoryId) {
}


public List<MeasurableRatingTally> statsByAppSelector(Select<Record1<Long>> selector) {
return dsl.select(MEASURABLE_RATING.MEASURABLE_ID, MEASURABLE_RATING.RATING, DSL.count())
public List<MeasurableRatingTally> statsByAppSelector(Select<Record1<Long>> selector,
boolean primaryOnly) {
Condition primaryCond = MEASURABLE_CATEGORY.ALLOW_PRIMARY_RATINGS.isFalse()
.or(MEASURABLE_RATING.IS_PRIMARY.eq(primaryOnly));

return dsl
.select(MEASURABLE_RATING.MEASURABLE_ID, MEASURABLE_RATING.RATING, DSL.count())
.from(MEASURABLE_RATING)
.innerJoin(MEASURABLE).on(MEASURABLE.ID.eq(MEASURABLE_RATING.MEASURABLE_ID))
.innerJoin(MEASURABLE_CATEGORY).on(MEASURABLE_CATEGORY.ID.eq(MEASURABLE.MEASURABLE_CATEGORY_ID))
.where(dsl.renderInlined(MEASURABLE_RATING.ENTITY_KIND.eq(EntityKind.APPLICATION.name())
.and(MEASURABLE_RATING.ENTITY_ID.in(selector))))
.and(MEASURABLE_RATING.ENTITY_ID.in(selector))))
.and(primaryCond)
.groupBy(MEASURABLE_RATING.MEASURABLE_ID, MEASURABLE_RATING.RATING)
.fetch(TO_TALLY_MAPPER);
}
Expand Down Expand Up @@ -323,6 +361,45 @@ public int removeForCategory(EntityReference ref, long categoryId) {
.execute();
}

/**
* Given a measurable and a selector, will determine if any other measurables are mapped by apps
* which map to this measurable. This is used to provide functionality for features like: "apps that
* do this function, also do these functions..."
*
* @param measurableId starting measurable
* @param selector set of apps to consider
* @return boolean indicating if there are implicitly related measurables
*/
public boolean hasImplicitlyRelatedMeasurables(long measurableId, Select<Record1<Long>> selector) {

org.finos.waltz.schema.tables.MeasurableRating mr1 = MEASURABLE_RATING.as("mr1");
org.finos.waltz.schema.tables.MeasurableRating mr2 = MEASURABLE_RATING.as("mr2");
Measurable m1 = MEASURABLE.as("m1");
Measurable m2 = MEASURABLE.as("m2");
EntityHierarchy eh = ENTITY_HIERARCHY.as("eh");

Condition appCondition = mr1.ENTITY_ID.in(selector)
.and(mr1.ENTITY_KIND.eq(DSL.val(EntityKind.APPLICATION.name())));

SelectConditionStep<Record> rawQry = DSL
.select()
.from(m1)
.innerJoin(eh).on(eh.ANCESTOR_ID.eq(m1.ID).and(eh.KIND.eq(EntityKind.MEASURABLE.name())))
.innerJoin(mr1).on(mr1.MEASURABLE_ID.eq(eh.ID))
.innerJoin(mr2).on(mr1.ENTITY_ID.eq(mr2.ENTITY_ID)
.and(mr1.ENTITY_KIND.eq(mr2.ENTITY_KIND))
.and(mr1.MEASURABLE_ID.ne(mr2.MEASURABLE_ID)))
.innerJoin(APPLICATION).on(mr1.ENTITY_ID.eq(APPLICATION.ID)
.and(APPLICATION.IS_REMOVED.isFalse())
.and(APPLICATION.ENTITY_LIFECYCLE_STATUS.ne(EntityLifecycleStatus.REMOVED.name())))
.innerJoin(m2).on(mr2.MEASURABLE_ID.eq(m2.ID)
.and(m2.ENTITY_LIFECYCLE_STATUS.ne(EntityLifecycleStatus.REMOVED.name())))
.where(m1.ID.eq(measurableId)
.and(appCondition));

return dsl.fetchExists(rawQry);
}


// --- utils

Expand All @@ -334,6 +411,7 @@ private SelectJoinStep<Record> mkBaseQuery() {
.from(MEASURABLE_RATING);
}


public Set<Operation> calculateAmendedRatingOperations(Set<Operation> operationsForEntityAssessment,
EntityReference entityReference,
long measurableId,
Expand Down Expand Up @@ -367,6 +445,7 @@ public Set<Operation> calculateAmendedRatingOperations(Set<Operation> operations
}
}


public Set<Operation> calculateAmendedAllocationOperations(Set<Operation> operationsForAllocation,
long categoryId,
String username) {
Expand All @@ -384,9 +463,9 @@ public Set<Operation> calculateAmendedAllocationOperations(Set<Operation> operat
} else {
return operationsForAllocation;
}

}


/**
* Takes a source measurable and will move all ratings, decommission dates, replacement applications and allocations to the target measurable where possible.
* If a value already exists on the target the migration is ignored, or in the case of allocations, aggregated.
Expand Down Expand Up @@ -564,7 +643,10 @@ public void migrateRatings(Long measurableId, Long targetId, String userId) {
targetId,
EntityKind.ALLOCATION,
Operation.UPDATE,
format("Removed %d ratings from measurable: %d where they could not be migrated due to an existing rating on the target", removedRatings, measurableId, targetId),
format("Removed %d ratings from measurable: %d where they could not be migrated due to an existing rating on the target (%d)",
removedRatings,
measurableId,
targetId),
userId);
}

Expand Down Expand Up @@ -605,13 +687,15 @@ private SelectOrderByStep<Record2<Long, String>> selectRatingsThatCanBeModified(
return migrations.except(targets);
}


private SelectConditionStep<Record2<Long, String>> mkEntitySelectForMeasurable(Long measurableId) {
return DSL
.select(Tables.MEASURABLE_RATING.ENTITY_ID, Tables.MEASURABLE_RATING.ENTITY_KIND)
.from(Tables.MEASURABLE_RATING)
.where(Tables.MEASURABLE_RATING.MEASURABLE_ID.eq(measurableId));
}


public int getSharedRatingsCount(Long measurableId, Long targetId) {

SelectConditionStep<Record2<Long, String>> targets = mkEntitySelectForMeasurable(targetId);
Expand All @@ -622,6 +706,7 @@ public int getSharedRatingsCount(Long measurableId, Long targetId) {
return dsl.fetchCount(sharedRatings);
}


public int getSharedDecommsCount(Long measurableId, Long targetId) {

SelectConditionStep<Record2<Long, String>> targets = mkEntitySelectForDecomm(targetId);
Expand Down Expand Up @@ -679,6 +764,7 @@ private SelectOrderByStep<Record3<Long, Long, String>> selectAllocsToBeSummed(Lo
return migrations.intersect(targets);
}


private SelectHavingStep<Record4<Long, Long, String, Integer>> selectAllocsToBeUpdated(Long measurableId, Long targetId) {

SelectOrderByStep<Record3<Long, Long, String>> valuesToBeSummed = selectAllocsToBeSummed(measurableId, targetId);
Expand All @@ -689,11 +775,44 @@ private SelectHavingStep<Record4<Long, Long, String, Integer>> selectAllocsToBeU
ALLOCATION.ENTITY_KIND,
DSL.cast(DSL.sum(ALLOCATION.ALLOCATION_PERCENTAGE), Integer.class).as("allocation_percentage"))
.from(ALLOCATION)
.innerJoin(valuesToBeSummed).on(ALLOCATION.ALLOCATION_SCHEME_ID.eq(valuesToBeSummed.field(ALLOCATION.ALLOCATION_SCHEME_ID))
.innerJoin(valuesToBeSummed)
.on(ALLOCATION.ALLOCATION_SCHEME_ID.eq(valuesToBeSummed.field(ALLOCATION.ALLOCATION_SCHEME_ID))
.and(ALLOCATION.ENTITY_KIND.eq(valuesToBeSummed.field(ALLOCATION.ENTITY_KIND))
.and(ALLOCATION.ENTITY_ID.eq(valuesToBeSummed.field(ALLOCATION.ENTITY_ID)))))
.where(ALLOCATION.MEASURABLE_ID.in(targetId, measurableId))
.groupBy(ALLOCATION.ALLOCATION_SCHEME_ID, ALLOCATION.ENTITY_ID, ALLOCATION.ENTITY_KIND);
}


public boolean saveRatingItem(EntityReference entityRef,
long measurableId,
String ratingCode,
String username) {
return MeasurableRatingHelper.saveRatingItem(
dsl,
entityRef,
measurableId,
ratingCode,
username);
}


public boolean saveRatingIsPrimary(EntityReference entityRef, long measurableId, boolean isPrimary, String username) {
return dsl.transactionResult(ctx -> MeasurableRatingHelper.saveRatingIsPrimary(
ctx.dsl(),
entityRef,
measurableId,
isPrimary,
username));
}


public boolean saveRatingDescription(EntityReference entityRef, long measurableId, String description, String username) {
return dsl.transactionResult(ctx -> MeasurableRatingHelper.saveRatingDescription(
ctx.dsl(),
entityRef,
measurableId,
description,
username));
}
}
Loading

0 comments on commit 28d68b5

Please sign in to comment.