package org.javers.repository.sql.finders; import java.util.Optional; import org.javers.common.collections.Lists; import org.javers.common.collections.Pair; import org.javers.common.collections.Sets; import org.javers.core.json.CdoSnapshotSerialized; import org.javers.core.json.JsonConverter; import org.javers.core.metamodel.object.CdoSnapshot; import org.javers.core.metamodel.object.GlobalId; import org.javers.core.metamodel.type.EntityType; import org.javers.core.metamodel.type.ManagedType; import org.javers.repository.api.QueryParams; import org.javers.repository.api.QueryParamsBuilder; import org.javers.repository.api.SnapshotIdentifier; import org.javers.repository.sql.repositories.GlobalIdRepository; import org.javers.repository.sql.schema.TableNameProvider; import org.polyjdbc.core.PolyJDBC; import org.polyjdbc.core.query.Order; import org.polyjdbc.core.query.SelectQuery; import java.util.*; import static org.javers.repository.sql.PolyUtil.queryForOptionalLong; import static org.javers.repository.sql.schema.FixedSchemaFactory.*; public class CdoSnapshotFinder { private final PolyJDBC polyJDBC; private final GlobalIdRepository globalIdRepository; private final CommitPropertyFinder commitPropertyFinder; private final CdoSnapshotMapper cdoSnapshotMapper; private final CdoSnapshotsEnricher cdoSnapshotsEnricher = new CdoSnapshotsEnricher(); private JsonConverter jsonConverter; private final TableNameProvider tableNameProvider; public CdoSnapshotFinder(PolyJDBC polyJDBC, GlobalIdRepository globalIdRepository, CommitPropertyFinder commitPropertyFinder, TableNameProvider tableNameProvider) { this.polyJDBC = polyJDBC; this.globalIdRepository = globalIdRepository; this.commitPropertyFinder = commitPropertyFinder; this.cdoSnapshotMapper = new CdoSnapshotMapper(); this.tableNameProvider = tableNameProvider; } public Optional<CdoSnapshot> getLatest(GlobalId globalId) { Optional<Long> globalIdPk = globalIdRepository.findGlobalIdPk(globalId); if (!globalIdPk.isPresent()){ return Optional.empty(); } return selectMaxSnapshotPrimaryKey(globalIdPk.get()).map(maxSnapshot -> { QueryParams oneItemLimit = QueryParamsBuilder.withLimit(1).build(); return fetchCdoSnapshots(new SnapshotIdFilter(tableNameProvider, maxSnapshot), Optional.of(oneItemLimit)).get(0); }); } public List<CdoSnapshot> getSnapshots(QueryParams queryParams) { return fetchCdoSnapshots(new AnySnapshotFilter(tableNameProvider), Optional.of(queryParams)); } public List<CdoSnapshot> getSnapshots(Collection<SnapshotIdentifier> snapshotIdentifiers) { return fetchCdoSnapshots(new SnapshotIdentifiersFilter(tableNameProvider, globalIdRepository, snapshotIdentifiers), Optional.<QueryParams>empty()); } public List<CdoSnapshot> getStateHistory(Set<ManagedType> managedTypes, QueryParams queryParams) { Set<String> managedTypeNames = Sets.transform(managedTypes, managedType -> managedType.getName()); ManagedClassFilter classFilter = new ManagedClassFilter(tableNameProvider, managedTypeNames, queryParams.isAggregate()); return fetchCdoSnapshots(classFilter, Optional.of(queryParams)); } public List<CdoSnapshot> getVOStateHistory(EntityType ownerEntity, String fragment, QueryParams queryParams) { VoOwnerEntityFilter voOwnerFilter = new VoOwnerEntityFilter(tableNameProvider, ownerEntity.getName(), fragment); return fetchCdoSnapshots(voOwnerFilter, Optional.of(queryParams)); } public List<CdoSnapshot> getStateHistory(GlobalId globalId, QueryParams queryParams) { Optional<Long> globalIdPk = globalIdRepository.findGlobalIdPk(globalId); return globalIdPk.map(id -> fetchCdoSnapshots(new GlobalIdFilter(tableNameProvider, id, queryParams.isAggregate()), Optional.of(queryParams))) .orElse(Collections.emptyList()); } private List<CdoSnapshot> fetchCdoSnapshots(SnapshotFilter snapshotFilter, Optional<QueryParams> queryParams) { List<Pair<CdoSnapshotSerialized,Long>> serializedSnapshots = queryForCdoSnapshotDTOs(snapshotFilter, queryParams); List<CommitPropertyDTO> commitPropertyDTOs = commitPropertyFinder.findCommitPropertiesOfSnaphots(Pair.collectRightAsSet(serializedSnapshots)); cdoSnapshotsEnricher.enrichWithCommitProperties(serializedSnapshots, commitPropertyDTOs); return Lists.transform(serializedSnapshots, serializedSnapshot -> jsonConverter.fromSerializedSnapshot(serializedSnapshot.left())); } private List<Pair<CdoSnapshotSerialized,Long>> queryForCdoSnapshotDTOs(SnapshotFilter snapshotFilter, Optional<QueryParams> queryParams) { SelectQuery query = polyJDBC.query().select(snapshotFilter.select()); snapshotFilter.addFrom(query); snapshotFilter.addWhere(query); if (queryParams.isPresent()) { snapshotFilter.applyQueryParams(query, queryParams.get()); } query.orderBy(SNAPSHOT_PK, Order.DESC); return polyJDBC.queryRunner().queryList(query, cdoSnapshotMapper); } private Optional<Long> selectMaxSnapshotPrimaryKey(long globalIdPk) { SelectQuery query = polyJDBC.query() .select("MAX(" + SNAPSHOT_PK + ")") .from(tableNameProvider.getSnapshotTableNameWithSchema()) .where(SNAPSHOT_GLOBAL_ID_FK + " = :globalIdPk") .withArgument("globalIdPk", globalIdPk); Optional<Long> result = queryForOptionalLong(query, polyJDBC); if (result.isPresent() && result.get() == 0){ return Optional.empty(); } return result; } public void setJsonConverter(JsonConverter jsonConverter) { this.jsonConverter = jsonConverter; } }