mirror of
https://github.com/valitydev/liminator.git
synced 2024-11-06 01:15:21 +00:00
modify calculation limit total value (#23)
* modify calculation limit total value * review * review(2) * review (3) * review (4)
This commit is contained in:
parent
db4d2ae383
commit
b201b272a9
@ -1,35 +0,0 @@
|
|||||||
package com.empayre.liminator.converter;
|
|
||||||
|
|
||||||
import com.empayre.liminator.model.LimitValue;
|
|
||||||
import dev.vality.liminator.LimitResponse;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class CurrentLimitValuesToLimitResponseConverter implements Converter<List<LimitValue>, List<LimitResponse>> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<LimitResponse> convert(List<LimitValue> values) {
|
|
||||||
if (values == null) {
|
|
||||||
log.info("Received LimitValues array is empty");
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
return values.stream()
|
|
||||||
.map(limitValue -> new LimitResponse(
|
|
||||||
limitValue.getLimitName(),
|
|
||||||
limitValue.getCommitValue(),
|
|
||||||
getTotalValue(limitValue))
|
|
||||||
.setLimitId(limitValue.getLimitId())
|
|
||||||
)
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static long getTotalValue(LimitValue limitValue) {
|
|
||||||
return limitValue.getHoldValue() + limitValue.getCommitValue() - limitValue.getRollbackValue();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.empayre.liminator.converter;
|
||||||
|
|
||||||
|
import com.empayre.liminator.model.LimitValue;
|
||||||
|
import dev.vality.liminator.LimitResponse;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class LimitValuesByLimitNameToLimitResponseConverter
|
||||||
|
implements Converter<Map.Entry<String, List<LimitValue>>, LimitResponse> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimitResponse convert(Map.Entry<String, List<LimitValue>> source) {
|
||||||
|
LimitResponse limitResponse = new LimitResponse();
|
||||||
|
limitResponse.setLimitName(source.getKey());
|
||||||
|
limitResponse.setLimitId(source.getValue().get(0).getLimitId());
|
||||||
|
long commitValue = 0L;
|
||||||
|
long totalValue = 0L;
|
||||||
|
for (LimitValue limitValue : source.getValue()) {
|
||||||
|
switch (limitValue.getState()) {
|
||||||
|
case HOLD -> totalValue = totalValue + limitValue.getOperationValue();
|
||||||
|
case COMMIT -> {
|
||||||
|
commitValue = commitValue + limitValue.getOperationValue();
|
||||||
|
totalValue = totalValue - limitValue.getOperationValue();
|
||||||
|
}
|
||||||
|
case ROLLBACK -> totalValue = totalValue - limitValue.getOperationValue();
|
||||||
|
default -> throw new IllegalStateException("Unexpected value: " + limitValue.getState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
limitResponse.setCommitValue(commitValue);
|
||||||
|
limitResponse.setTotalValue(totalValue);
|
||||||
|
return limitResponse;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.empayre.liminator.converter;
|
||||||
|
|
||||||
|
import com.empayre.liminator.model.LimitValue;
|
||||||
|
import dev.vality.liminator.LimitResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.core.convert.converter.Converter;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class LimitValuesToLimitResponsesConverter implements Converter<List<LimitValue>, List<LimitResponse>> {
|
||||||
|
|
||||||
|
private final Converter<Map.Entry<String, List<LimitValue>>, LimitResponse> limitResponseConverter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<LimitResponse> convert(List<LimitValue> values) {
|
||||||
|
if (CollectionUtils.isEmpty(values)) {
|
||||||
|
log.info("Received LimitValues array is empty");
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
Map<String, List<LimitValue>> valuesPerLimitName = values.stream()
|
||||||
|
.collect(groupingBy(LimitValue::getLimitName));
|
||||||
|
return valuesPerLimitName.entrySet().stream()
|
||||||
|
.map(limitResponseConverter::convert)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
@ -11,9 +11,9 @@ public interface OperationStateHistoryDao extends CommonDao<OperationStateHistor
|
|||||||
|
|
||||||
int[] saveBatch(List<OperationStateHistory> historyList);
|
int[] saveBatch(List<OperationStateHistory> historyList);
|
||||||
|
|
||||||
List<LimitValue> getCurrentLimitValue(List<String> limitNames);
|
List<LimitValue> getLimitHistory(List<String> limitNames);
|
||||||
|
|
||||||
List<LimitValue> getCurrentLimitValue(List<String> limitNames, String operationId);
|
List<LimitValue> getLimitHistory(List<String> limitNames, String operationId);
|
||||||
|
|
||||||
List<OperationStateHistory> get(String operationId, Collection<Long> limitIds, List<OperationState> states);
|
List<OperationStateHistory> get(String operationId, Collection<Long> limitIds, List<OperationState> states);
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,23 @@ import com.empayre.liminator.domain.tables.pojos.OperationStateHistory;
|
|||||||
import com.empayre.liminator.model.LimitValue;
|
import com.empayre.liminator.model.LimitValue;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jooq.DSLContext;
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.RecordMapper;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
|
import static com.empayre.liminator.domain.Tables.LIMIT_DATA;
|
||||||
import static com.empayre.liminator.domain.Tables.OPERATION_STATE_HISTORY;
|
import static com.empayre.liminator.domain.Tables.OPERATION_STATE_HISTORY;
|
||||||
import static org.jooq.impl.DSL.raw;
|
import static org.jooq.impl.DSL.select;
|
||||||
import static org.jooq.impl.DSL.val;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class OperationStateHistoryDaoImpl implements OperationStateHistoryDao {
|
public class OperationStateHistoryDaoImpl implements OperationStateHistoryDao {
|
||||||
|
|
||||||
private static final String DELIMITER = " ,";
|
|
||||||
|
|
||||||
private final DSLContext dslContext;
|
private final DSLContext dslContext;
|
||||||
|
private final RecordMapper<Record, LimitValue> recordMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long save(OperationStateHistory history) {
|
public Long save(OperationStateHistory history) {
|
||||||
@ -45,88 +45,32 @@ public class OperationStateHistoryDaoImpl implements OperationStateHistoryDao {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<LimitValue> getCurrentLimitValue(List<String> limitNames) {
|
public List<LimitValue> getLimitHistory(List<String> limitNames) {
|
||||||
String sql = """
|
|
||||||
with hold_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as hold_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.state = 'HOLD'
|
|
||||||
where ld.name in ({0})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
), commit_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as commit_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.state = 'COMMIT'
|
|
||||||
where ld.name in ({0})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
), rollback_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as rollback_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.state = 'ROLLBACK'
|
|
||||||
where ld.name in ({0})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
)
|
|
||||||
|
|
||||||
select cd.limit_id, cd.name as limit_name, cd.commit_value, hd.hold_value, rd.rollback_value
|
|
||||||
from commit_data as cd
|
|
||||||
join hold_data as hd on cd.id = hd.id
|
|
||||||
join rollback_data as rd on cd.id = rd.id;
|
|
||||||
""";
|
|
||||||
return dslContext
|
return dslContext
|
||||||
.resultQuery(sql, raw(arrayToString(limitNames)))
|
.select()
|
||||||
.fetchInto(LimitValue.class);
|
.from(OPERATION_STATE_HISTORY.join(LIMIT_DATA)
|
||||||
|
.on(OPERATION_STATE_HISTORY.LIMIT_DATA_ID.eq(LIMIT_DATA.ID))
|
||||||
|
.and(LIMIT_DATA.NAME.in(limitNames)))
|
||||||
|
.fetch()
|
||||||
|
.map(recordMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<LimitValue> getCurrentLimitValue(List<String> limitNames, String operationId) {
|
public List<LimitValue> getLimitHistory(List<String> limitNames, String operationId) {
|
||||||
String sql = """
|
|
||||||
with operation_timestamp as (
|
|
||||||
select created_at
|
|
||||||
from lim.operation_state_history
|
|
||||||
where operation_id = {0}
|
|
||||||
), hold_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as hold_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.created_at <= (select created_at from operation_timestamp limit 1)
|
|
||||||
and ops.state = 'HOLD'
|
|
||||||
where ld.name in ({1})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
), commit_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as commit_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.created_at <= (select created_at from operation_timestamp limit 1)
|
|
||||||
and ops.state = 'COMMIT'
|
|
||||||
where ld.name in ({1})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
), rollback_data as (
|
|
||||||
select ld.id, ld.name, ld.limit_id, coalesce(sum(ops.operation_value), 0) as rollback_value
|
|
||||||
from lim.limit_data as ld
|
|
||||||
left join lim.operation_state_history as ops
|
|
||||||
on ops.limit_name = ld.name
|
|
||||||
and ops.created_at <= (select created_at from operation_timestamp limit 1)
|
|
||||||
and ops.state = 'ROLLBACK'
|
|
||||||
where ld.name in ({1})
|
|
||||||
group by ld.id, ld.name
|
|
||||||
)
|
|
||||||
|
|
||||||
select cd.limit_id, cd.name as limit_name, cd.commit_value, hd.hold_value, rd.rollback_value
|
|
||||||
from commit_data as cd
|
|
||||||
join hold_data as hd on cd.id = hd.id
|
|
||||||
join rollback_data as rd on cd.id = rd.id;
|
|
||||||
""";
|
|
||||||
return dslContext
|
return dslContext
|
||||||
.resultQuery(sql, val(operationId), raw(arrayToString(limitNames)))
|
.select()
|
||||||
.fetchInto(LimitValue.class);
|
.from(OPERATION_STATE_HISTORY.join(LIMIT_DATA)
|
||||||
|
.on(OPERATION_STATE_HISTORY.LIMIT_DATA_ID.eq(LIMIT_DATA.ID))
|
||||||
|
.and(LIMIT_DATA.NAME.in(limitNames)))
|
||||||
|
.where(OPERATION_STATE_HISTORY.CREATED_AT.le(
|
||||||
|
select(OPERATION_STATE_HISTORY.CREATED_AT)
|
||||||
|
.from(OPERATION_STATE_HISTORY)
|
||||||
|
.where(OPERATION_STATE_HISTORY.OPERATION_ID.eq(operationId))
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.fetch()
|
||||||
|
.map(recordMapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -134,16 +78,11 @@ public class OperationStateHistoryDaoImpl implements OperationStateHistoryDao {
|
|||||||
Collection<Long> limitIds,
|
Collection<Long> limitIds,
|
||||||
List<OperationState> states) {
|
List<OperationState> states) {
|
||||||
return dslContext
|
return dslContext
|
||||||
.selectFrom(OPERATION_STATE_HISTORY)
|
.select()
|
||||||
|
.from(OPERATION_STATE_HISTORY)
|
||||||
.where(OPERATION_STATE_HISTORY.OPERATION_ID.eq(operationId))
|
.where(OPERATION_STATE_HISTORY.OPERATION_ID.eq(operationId))
|
||||||
.and(OPERATION_STATE_HISTORY.LIMIT_DATA_ID.in(limitIds))
|
.and(OPERATION_STATE_HISTORY.LIMIT_DATA_ID.in(limitIds))
|
||||||
.and(OPERATION_STATE_HISTORY.STATE.in(states))
|
.and(OPERATION_STATE_HISTORY.STATE.in(states))
|
||||||
.fetchInto(OperationStateHistory.class);
|
.fetchInto(OperationStateHistory.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String arrayToString(List<String> strings) {
|
|
||||||
return strings.stream()
|
|
||||||
.map(limit -> "'%s'".formatted(limit))
|
|
||||||
.collect(Collectors.joining(DELIMITER));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.empayre.liminator.dao.mapper;
|
||||||
|
|
||||||
|
import com.empayre.liminator.domain.enums.OperationState;
|
||||||
|
import com.empayre.liminator.model.LimitValue;
|
||||||
|
import org.jooq.Record;
|
||||||
|
import org.jooq.RecordMapper;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import static com.empayre.liminator.domain.Tables.OPERATION_STATE_HISTORY;
|
||||||
|
import static com.empayre.liminator.domain.Tables.LIMIT_DATA;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class LimitValueMapper implements RecordMapper<Record, LimitValue> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LimitValue map(Record opsDataRecord) {
|
||||||
|
String limitId = opsDataRecord.get(LIMIT_DATA.LIMIT_ID);
|
||||||
|
String limitName = opsDataRecord.get(OPERATION_STATE_HISTORY.LIMIT_NAME);
|
||||||
|
Long operationValue = opsDataRecord.get(OPERATION_STATE_HISTORY.OPERATION_VALUE);
|
||||||
|
OperationState state = OperationState.valueOf(opsDataRecord.get("state", String.class));
|
||||||
|
return new LimitValue(limitId, limitName, state, operationValue);
|
||||||
|
}
|
||||||
|
}
|
@ -5,19 +5,20 @@ import com.empayre.liminator.domain.tables.pojos.LimitData;
|
|||||||
import com.empayre.liminator.handler.HoldOperationHandler;
|
import com.empayre.liminator.handler.HoldOperationHandler;
|
||||||
import com.empayre.liminator.service.LimitDataService;
|
import com.empayre.liminator.service.LimitDataService;
|
||||||
import com.empayre.liminator.service.LimitOperationsHistoryService;
|
import com.empayre.liminator.service.LimitOperationsHistoryService;
|
||||||
import dev.vality.liminator.DuplicateOperation;
|
|
||||||
import dev.vality.liminator.LimitChange;
|
import dev.vality.liminator.LimitChange;
|
||||||
import dev.vality.liminator.LimitRequest;
|
import dev.vality.liminator.LimitRequest;
|
||||||
import dev.vality.liminator.OperationAlreadyInFinalState;
|
import dev.vality.liminator.OperationAlreadyInFinalState;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.thrift.TException;
|
import org.apache.thrift.TException;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.empayre.liminator.model;
|
package com.empayre.liminator.model;
|
||||||
|
|
||||||
|
import com.empayre.liminator.domain.enums.OperationState;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@ -9,7 +10,6 @@ public class LimitValue {
|
|||||||
|
|
||||||
private String limitId;
|
private String limitId;
|
||||||
private String limitName;
|
private String limitName;
|
||||||
private Long commitValue;
|
private OperationState state;
|
||||||
private Long holdValue;
|
private Long operationValue;
|
||||||
private Long rollbackValue;
|
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,9 @@ public class LiminatorService implements LiminatorServiceSrv.Iface {
|
|||||||
throws LimitNotFound, LimitsValuesReadingException, TException {
|
throws LimitNotFound, LimitsValuesReadingException, TException {
|
||||||
try {
|
try {
|
||||||
log.info("Get limits with request: {}", request);
|
log.info("Get limits with request: {}", request);
|
||||||
return getLimitsValuesHandler.handle(request);
|
List<LimitResponse> limitResponses = getLimitsValuesHandler.handle(request);
|
||||||
|
log.info("Success get limit responses: {}", limitResponses);
|
||||||
|
return limitResponses;
|
||||||
} catch (DataAccessException ex) {
|
} catch (DataAccessException ex) {
|
||||||
log.error("[GET] Received DaoException for getting limits operation (request: {})", request, ex);
|
log.error("[GET] Received DaoException for getting limits operation (request: {})", request, ex);
|
||||||
throw new LimitsValuesReadingException();
|
throw new LimitsValuesReadingException();
|
||||||
@ -80,7 +82,9 @@ public class LiminatorService implements LiminatorServiceSrv.Iface {
|
|||||||
throws LimitNotFound, LimitsValuesReadingException, TException {
|
throws LimitNotFound, LimitsValuesReadingException, TException {
|
||||||
try {
|
try {
|
||||||
log.info("Get last limits for limits: {}", Arrays.toString(limitNames.toArray()));
|
log.info("Get last limits for limits: {}", Arrays.toString(limitNames.toArray()));
|
||||||
return getLastLimitsValuesHandler.handle(limitNames);
|
List<LimitResponse> limitResponses = getLastLimitsValuesHandler.handle(limitNames);
|
||||||
|
log.info("Success get last limits response: {}", limitResponses);
|
||||||
|
return limitResponses;
|
||||||
} catch (DataAccessException ex) {
|
} catch (DataAccessException ex) {
|
||||||
log.error("[GET] Received DaoException for getting last limits operation (limitNames: {})", limitNames, ex);
|
log.error("[GET] Received DaoException for getting last limits operation (limitNames: {})", limitNames, ex);
|
||||||
throw new LimitsValuesReadingException();
|
throw new LimitsValuesReadingException();
|
||||||
|
@ -34,11 +34,11 @@ public class LimitOperationsHistoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<LimitValue> getCurrentLimitValue(List<String> limitNames) {
|
public List<LimitValue> getCurrentLimitValue(List<String> limitNames) {
|
||||||
return operationStateHistoryDao.getCurrentLimitValue(limitNames);
|
return operationStateHistoryDao.getLimitHistory(limitNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<LimitValue> getCurrentLimitValue(List<String> limitNames, String operationId) {
|
public List<LimitValue> getCurrentLimitValue(List<String> limitNames, String operationId) {
|
||||||
return operationStateHistoryDao.getCurrentLimitValue(limitNames, operationId);
|
return operationStateHistoryDao.getLimitHistory(limitNames, operationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<OperationStateHistory> get(String operationId,
|
public List<OperationStateHistory> get(String operationId,
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
DROP INDEX operation_history_idx;
|
||||||
|
|
||||||
|
CREATE INDEX operation_history_idx ON lim.operation_state_history USING btree (limit_data_id, state, created_at, operation_id);
|
||||||
|
|
@ -7,15 +7,18 @@ import com.empayre.liminator.domain.tables.pojos.LimitData;
|
|||||||
import com.empayre.liminator.domain.tables.pojos.OperationStateHistory;
|
import com.empayre.liminator.domain.tables.pojos.OperationStateHistory;
|
||||||
import com.empayre.liminator.model.LimitValue;
|
import com.empayre.liminator.model.LimitValue;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@PostgresqlSpringBootITest
|
@PostgresqlSpringBootITest
|
||||||
@ -57,35 +60,40 @@ class DaoTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
void operationDaoHistoryTest() {
|
void operationDaoHistoryTest() {
|
||||||
List<String> limitNamesList = new ArrayList<>();
|
var limitsList = new ArrayList<Pair<String, Long>>();
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
String limitName = "Limit-odc-1-" + i;
|
String limitName = "Limit-odc-1-" + i;
|
||||||
String limitId = "Limit-id-odc-1-" + i;
|
String limitId = "Limit-id-odc-1-" + i;
|
||||||
limitDataDao.save(new LimitData(null, limitName, LocalDate.now(), LocalDateTime.now(), limitId));
|
Long id = limitDataDao.save(new LimitData(null, limitName, LocalDate.now(), LocalDateTime.now(), limitId));
|
||||||
limitNamesList.add(limitName);
|
limitsList.add(Pair.of(limitName, id));
|
||||||
}
|
}
|
||||||
List<OperationStateHistory> operations = new ArrayList<>();
|
List<OperationStateHistory> operations = new ArrayList<>();
|
||||||
String operationNameTemplate = "Operation-odc-1-%s";
|
String operationNameTemplate = "Operation-odc-1-%s";
|
||||||
for (String limitName : limitNamesList) {
|
for (Pair<String, Long> limit : limitsList) {
|
||||||
for (int i = 0; i < 5; i++) {
|
for (int i = 0; i < 5; i++) {
|
||||||
operations.add(createOperationHistory(limitName, operationNameTemplate.formatted(i)));
|
operations.add(
|
||||||
|
createOperationHistory(
|
||||||
|
limit.getKey(),
|
||||||
|
limit.getValue(),
|
||||||
|
operationNameTemplate.formatted(i))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
operationStateHistoryDao.saveBatch(operations);
|
operationStateHistoryDao.saveBatch(operations);
|
||||||
|
|
||||||
|
|
||||||
|
List<String> limitNames = limitsList.stream().map(Pair::getKey).toList();
|
||||||
|
List<LimitValue> currentLimitValue = operationStateHistoryDao.getLimitHistory(limitNames);
|
||||||
|
assertEquals(operations.size(), currentLimitValue.size());
|
||||||
|
currentLimitValue.forEach(value -> assertEquals(100, value.getOperationValue()));
|
||||||
|
|
||||||
operations.clear();
|
operations.clear();
|
||||||
|
var commitLimits = limitsList.subList(0, 3);
|
||||||
List<LimitValue> currentLimitValue = operationStateHistoryDao.getCurrentLimitValue(limitNamesList);
|
|
||||||
assertEquals(limitNamesList.size(), currentLimitValue.size());
|
|
||||||
currentLimitValue.forEach(value -> assertEquals(0, value.getCommitValue()));
|
|
||||||
currentLimitValue.forEach(value -> assertEquals(0, value.getRollbackValue()));
|
|
||||||
currentLimitValue.forEach(value -> assertNotEquals(0, value.getHoldValue()));
|
|
||||||
currentLimitValue.forEach(value -> assertNotEquals(0, getTotal(value)));
|
|
||||||
|
|
||||||
List<String> commitLimitNames = limitNamesList.subList(0, 3);
|
|
||||||
String finalizeOperationName = operationNameTemplate.formatted(1);
|
String finalizeOperationName = operationNameTemplate.formatted(1);
|
||||||
for (String limitName : commitLimitNames) {
|
for (Pair<String, Long> commitLimit : commitLimits) {
|
||||||
var operationHistory = createOperationHistory(
|
var operationHistory = createOperationHistory(
|
||||||
limitName,
|
commitLimit.getKey(),
|
||||||
|
commitLimit.getValue(),
|
||||||
finalizeOperationName,
|
finalizeOperationName,
|
||||||
LocalDateTime.now(),
|
LocalDateTime.now(),
|
||||||
OperationState.COMMIT);
|
OperationState.COMMIT);
|
||||||
@ -94,10 +102,11 @@ class DaoTests {
|
|||||||
operationStateHistoryDao.saveBatch(operations);
|
operationStateHistoryDao.saveBatch(operations);
|
||||||
operations.clear();
|
operations.clear();
|
||||||
|
|
||||||
List<String> rollbackLimitNames = limitNamesList.subList(4, 9);
|
var rollbackLimits = limitsList.subList(4, 9);
|
||||||
for (String limitName : rollbackLimitNames) {
|
for (Pair<String, Long> rollbackLimit : rollbackLimits) {
|
||||||
var operationHistory = createOperationHistory(
|
var operationHistory = createOperationHistory(
|
||||||
limitName,
|
rollbackLimit.getKey(),
|
||||||
|
rollbackLimit.getValue(),
|
||||||
finalizeOperationName,
|
finalizeOperationName,
|
||||||
LocalDateTime.now(),
|
LocalDateTime.now(),
|
||||||
OperationState.ROLLBACK);
|
OperationState.ROLLBACK);
|
||||||
@ -106,69 +115,36 @@ class DaoTests {
|
|||||||
operationStateHistoryDao.saveBatch(operations);
|
operationStateHistoryDao.saveBatch(operations);
|
||||||
operations.clear();
|
operations.clear();
|
||||||
|
|
||||||
List<LimitValue> limitValuesAfterChanges = operationStateHistoryDao.getCurrentLimitValue(limitNamesList);
|
List<LimitValue> limitValuesAfterChanges = operationStateHistoryDao.getLimitHistory(limitNames);
|
||||||
List<LimitValue> limitValuesWithCommitData = limitValuesAfterChanges.stream()
|
|
||||||
.filter(value -> value.getCommitValue() == 100
|
|
||||||
&& value.getHoldValue() == 500
|
|
||||||
&& value.getRollbackValue() == 0)
|
|
||||||
.toList();
|
|
||||||
assertEquals(3, limitValuesWithCommitData.size());
|
|
||||||
|
|
||||||
List<LimitValue> limitValuesAfterRollback = limitValuesAfterChanges.stream()
|
List<LimitValue> operationsWithCommitData = limitValuesAfterChanges.stream()
|
||||||
.filter(value -> value.getHoldValue() == 500
|
.filter(value -> value.getState() == OperationState.COMMIT)
|
||||||
&& value.getCommitValue() == 0
|
|
||||||
&& value.getRollbackValue() == 100)
|
|
||||||
.toList();
|
.toList();
|
||||||
assertEquals(5, limitValuesAfterRollback.size());
|
assertEquals(commitLimits.size(), operationsWithCommitData.size());
|
||||||
|
|
||||||
List<LimitValue> limitValuesWithoutChanges = limitValuesAfterChanges.stream()
|
List<LimitValue> operationsWithRollback = limitValuesAfterChanges.stream()
|
||||||
.filter(value -> value.getHoldValue() == 500
|
.filter(value -> value.getState() == OperationState.ROLLBACK)
|
||||||
&& value.getCommitValue() == 0
|
|
||||||
&& value.getRollbackValue() == 0)
|
|
||||||
.toList();
|
.toList();
|
||||||
assertEquals(2, limitValuesWithoutChanges.size());
|
assertEquals(rollbackLimits.size(), operationsWithRollback.size());
|
||||||
|
|
||||||
|
List<LimitValue> operationsWithHold = limitValuesAfterChanges.stream()
|
||||||
|
.filter(value -> value.getState() == OperationState.HOLD)
|
||||||
|
.toList();
|
||||||
|
assertEquals(currentLimitValue.size(), operationsWithHold.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private long getTotal(LimitValue value) {
|
private OperationStateHistory createOperationHistory(String limitName, Long id, String operationId) {
|
||||||
return value.getHoldValue() - value.getCommitValue() - value.getRollbackValue();
|
return createOperationHistory(limitName, id, operationId, LocalDateTime.now(), OperationState.HOLD);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void operationDaoCurrentLimitWithOperationIdTest() {
|
|
||||||
String limitName = "Limit-odc-2";
|
|
||||||
String limitId = "Limit-id-odc-2";
|
|
||||||
Long id = limitDataDao.save(new LimitData(null, limitName, LocalDate.now(), LocalDateTime.now(), limitId));
|
|
||||||
List<OperationStateHistory> operations = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
var operation = createOperationHistory(
|
|
||||||
limitName,
|
|
||||||
"Operation-odc-2-%s-%s".formatted(id, i),
|
|
||||||
LocalDateTime.now().minusMinutes(11L - i),
|
|
||||||
OperationState.HOLD);
|
|
||||||
operationStateHistoryDao.save(operation);
|
|
||||||
operations.add(operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LimitValue> valuesForFifthOperation =
|
|
||||||
operationStateHistoryDao.getCurrentLimitValue(List.of(limitName), operations.get(2).getOperationId());
|
|
||||||
LimitValue limitValue = valuesForFifthOperation.get(0);
|
|
||||||
assertEquals(300, getTotal(limitValue));
|
|
||||||
|
|
||||||
valuesForFifthOperation =
|
|
||||||
operationStateHistoryDao.getCurrentLimitValue(List.of(limitName), operations.get(5).getOperationId());
|
|
||||||
assertEquals(600, getTotal(valuesForFifthOperation.get(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private OperationStateHistory createOperationHistory(String limitName, String operationId) {
|
|
||||||
return createOperationHistory(limitName, operationId, LocalDateTime.now(), OperationState.HOLD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OperationStateHistory createOperationHistory(String limitName,
|
private OperationStateHistory createOperationHistory(String limitName,
|
||||||
|
Long id,
|
||||||
String operationId,
|
String operationId,
|
||||||
LocalDateTime createdAt,
|
LocalDateTime createdAt,
|
||||||
OperationState state) {
|
OperationState state) {
|
||||||
OperationStateHistory operation = new OperationStateHistory();
|
OperationStateHistory operation = new OperationStateHistory();
|
||||||
operation.setLimitName(limitName);
|
operation.setLimitName(limitName);
|
||||||
|
operation.setLimitDataId(id);
|
||||||
operation.setOperationId(operationId);
|
operation.setOperationId(operationId);
|
||||||
operation.setState(state);
|
operation.setState(state);
|
||||||
operation.setOperationValue(100L);
|
operation.setOperationValue(100L);
|
||||||
|
@ -35,6 +35,7 @@ class LiminatorServiceTest {
|
|||||||
);
|
);
|
||||||
|
|
||||||
List<LimitResponse> response = liminatorService.hold(request);
|
List<LimitResponse> response = liminatorService.hold(request);
|
||||||
|
|
||||||
assertEquals(limitName, response.get(0).getLimitName());
|
assertEquals(limitName, response.get(0).getLimitName());
|
||||||
assertEquals(limitId, response.get(0).getLimitId());
|
assertEquals(limitId, response.get(0).getLimitId());
|
||||||
assertEquals(holdValue, response.get(0).getTotalValue());
|
assertEquals(holdValue, response.get(0).getTotalValue());
|
||||||
@ -59,7 +60,7 @@ class LiminatorServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void limitNotFoundTest() {
|
void limitNotFoundTest() {
|
||||||
String limitName = "TestLimitCommit";
|
String limitName = "TestLimitCommit";
|
||||||
String operationId = "OpComit";
|
String operationId = "Op-123";
|
||||||
LimitRequest holdRequest = new LimitRequest()
|
LimitRequest holdRequest = new LimitRequest()
|
||||||
.setOperationId(operationId)
|
.setOperationId(operationId)
|
||||||
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
||||||
@ -70,7 +71,7 @@ class LiminatorServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void operationNotFoundWithNotExistHoldTest() throws TException {
|
void operationNotFoundWithNotExistHoldTest() throws TException {
|
||||||
String limitName = "TestLimitCommit";
|
String limitName = "TestLimitCommit";
|
||||||
String operationId = "OpComit";
|
String operationId = "Op-123";
|
||||||
LimitRequest holdRequest = new LimitRequest()
|
LimitRequest holdRequest = new LimitRequest()
|
||||||
.setOperationId(operationId)
|
.setOperationId(operationId)
|
||||||
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
||||||
@ -86,7 +87,7 @@ class LiminatorServiceTest {
|
|||||||
void operationNotFoundWithNotExpectedHoldCountTest() throws TException {
|
void operationNotFoundWithNotExpectedHoldCountTest() throws TException {
|
||||||
String firstLimitName = "TestLimit1";
|
String firstLimitName = "TestLimit1";
|
||||||
String secondLimitName = "TestLimit2";
|
String secondLimitName = "TestLimit2";
|
||||||
String operationId = "OpComit";
|
String operationId = "Op-123";
|
||||||
LimitRequest holdRequest = new LimitRequest()
|
LimitRequest holdRequest = new LimitRequest()
|
||||||
.setOperationId(operationId)
|
.setOperationId(operationId)
|
||||||
.setLimitChanges(List.of(
|
.setLimitChanges(List.of(
|
||||||
@ -165,21 +166,28 @@ class LiminatorServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void commitValueTest() throws TException {
|
void commitValueTest() throws TException {
|
||||||
String limitName = "TestLimitCommit";
|
String limitName = "TestLimitCommit";
|
||||||
String operationId = "OpComit";
|
String operationId = "Op-123";
|
||||||
String limitId = "limit_day_id";
|
String limitId = "limit_day_id";
|
||||||
LimitRequest holdRequest = new LimitRequest()
|
LimitRequest holdRequest = new LimitRequest()
|
||||||
.setOperationId(operationId)
|
.setOperationId(operationId)
|
||||||
.setLimitChanges(List.of(new LimitChange(limitName, 500L).setLimitId(limitId)));
|
.setLimitChanges(List.of(new LimitChange(limitName, 500L).setLimitId(limitId)));
|
||||||
liminatorService.hold(holdRequest);
|
|
||||||
|
List<LimitResponse> holdResponses = liminatorService.hold(holdRequest);
|
||||||
|
|
||||||
|
assertEquals(1, holdResponses.size());
|
||||||
|
assertEquals(500, holdResponses.get(0).getTotalValue());
|
||||||
|
assertEquals(0, holdResponses.get(0).getCommitValue());
|
||||||
|
assertEquals(limitName, holdResponses.get(0).getLimitName());
|
||||||
|
|
||||||
liminatorService.commit(holdRequest);
|
liminatorService.commit(holdRequest);
|
||||||
|
|
||||||
List<LimitResponse> limitResponses = liminatorService.getLastLimitsValues(List.of(limitName));
|
List<LimitResponse> commitResponses = liminatorService.getLastLimitsValues(List.of(limitName));
|
||||||
|
|
||||||
assertEquals(1, limitResponses.size());
|
assertEquals(1, commitResponses.size());
|
||||||
assertEquals(1000, limitResponses.get(0).getTotalValue());
|
assertEquals(0, commitResponses.get(0).getTotalValue());
|
||||||
assertEquals(500, limitResponses.get(0).getCommitValue());
|
assertEquals(500, commitResponses.get(0).getCommitValue());
|
||||||
assertEquals(limitName, limitResponses.get(0).getLimitName());
|
assertEquals(limitName, commitResponses.get(0).getLimitName());
|
||||||
assertEquals(limitId, limitResponses.get(0).getLimitId());
|
assertEquals(limitId, commitResponses.get(0).getLimitId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -189,20 +197,26 @@ class LiminatorServiceTest {
|
|||||||
LimitRequest holdRequest = new LimitRequest()
|
LimitRequest holdRequest = new LimitRequest()
|
||||||
.setOperationId(operationId)
|
.setOperationId(operationId)
|
||||||
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
.setLimitChanges(List.of(new LimitChange(limitName, 500L)));
|
||||||
liminatorService.hold(holdRequest);
|
List<LimitResponse> holdResponses = liminatorService.hold(holdRequest);
|
||||||
|
|
||||||
|
assertEquals(1, holdResponses.size());
|
||||||
|
assertEquals(500, holdResponses.get(0).getTotalValue());
|
||||||
|
assertEquals(0, holdResponses.get(0).getCommitValue());
|
||||||
|
assertEquals(limitName, holdResponses.get(0).getLimitName());
|
||||||
|
|
||||||
liminatorService.rollback(holdRequest);
|
liminatorService.rollback(holdRequest);
|
||||||
|
|
||||||
List<LimitResponse> limitResponses = liminatorService.getLastLimitsValues(List.of(limitName));
|
List<LimitResponse> rollbackResponses = liminatorService.getLastLimitsValues(List.of(limitName));
|
||||||
|
|
||||||
assertEquals(1, limitResponses.size());
|
assertEquals(1, rollbackResponses.size());
|
||||||
assertEquals(0, limitResponses.get(0).getTotalValue());
|
assertEquals(0, rollbackResponses.get(0).getTotalValue());
|
||||||
assertEquals(0, limitResponses.get(0).getCommitValue());
|
assertEquals(0, rollbackResponses.get(0).getCommitValue());
|
||||||
assertEquals(limitName, limitResponses.get(0).getLimitName());
|
assertEquals(limitName, rollbackResponses.get(0).getLimitName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void complexOperationsTest() throws TException {
|
void complexOperationsTest() throws TException {
|
||||||
String limitName = "TestLimitRollback";
|
String limitName = "TestLimitComplex";
|
||||||
String operationId = "Op-112-%s";
|
String operationId = "Op-112-%s";
|
||||||
LimitRequest firstHoldRequest = new LimitRequest()
|
LimitRequest firstHoldRequest = new LimitRequest()
|
||||||
.setOperationId(operationId.formatted(1))
|
.setOperationId(operationId.formatted(1))
|
||||||
@ -227,28 +241,28 @@ class LiminatorServiceTest {
|
|||||||
List<LimitResponse> limitResponseAfterFourthHold = liminatorService.hold(fourthHoldRequest);
|
List<LimitResponse> limitResponseAfterFourthHold = liminatorService.hold(fourthHoldRequest);
|
||||||
|
|
||||||
assertEquals(1, limitResponseAfterFourthHold.size());
|
assertEquals(1, limitResponseAfterFourthHold.size());
|
||||||
assertEquals(500, limitResponseAfterFourthHold.get(0).getTotalValue());
|
assertEquals(300, limitResponseAfterFourthHold.get(0).getTotalValue());
|
||||||
assertEquals(100, limitResponseAfterFourthHold.get(0).getCommitValue());
|
assertEquals(100, limitResponseAfterFourthHold.get(0).getCommitValue());
|
||||||
assertEquals(limitName, limitResponseAfterFourthHold.get(0).getLimitName());
|
assertEquals(limitName, limitResponseAfterFourthHold.get(0).getLimitName());
|
||||||
|
|
||||||
liminatorService.rollback(firstHoldRequest);
|
liminatorService.rollback(firstHoldRequest);
|
||||||
|
|
||||||
LimitRequest fifthHoldRequest = new LimitRequest()
|
LimitRequest fifthHoldRequest = new LimitRequest()
|
||||||
.setOperationId(operationId.formatted(4))
|
.setOperationId(operationId.formatted(5))
|
||||||
.setLimitChanges(List.of(new LimitChange(limitName, 100L)));
|
.setLimitChanges(List.of(new LimitChange(limitName, 100L)));
|
||||||
liminatorService.hold(fifthHoldRequest);
|
liminatorService.hold(fifthHoldRequest);
|
||||||
|
|
||||||
List<LimitResponse> limitResponses = liminatorService.hold(fifthHoldRequest);
|
List<LimitResponse> limitResponses = liminatorService.hold(fifthHoldRequest);
|
||||||
|
|
||||||
assertEquals(1, limitResponses.size());
|
assertEquals(1, limitResponses.size());
|
||||||
assertEquals(500, limitResponses.get(0).getTotalValue());
|
assertEquals(300, limitResponses.get(0).getTotalValue());
|
||||||
assertEquals(100, limitResponses.get(0).getCommitValue());
|
assertEquals(100, limitResponses.get(0).getCommitValue());
|
||||||
assertEquals(limitName, limitResponses.get(0).getLimitName());
|
assertEquals(limitName, limitResponses.get(0).getLimitName());
|
||||||
|
|
||||||
List<LimitResponse> limitResponseAfterAllForFourthHold = liminatorService.hold(fourthHoldRequest);
|
List<LimitResponse> limitResponseAfterAllForFourthHold = liminatorService.hold(fourthHoldRequest);
|
||||||
|
|
||||||
assertEquals(1, limitResponseAfterAllForFourthHold.size());
|
assertEquals(1, limitResponseAfterAllForFourthHold.size());
|
||||||
assertEquals(500, limitResponseAfterAllForFourthHold.get(0).getTotalValue());
|
assertEquals(300, limitResponseAfterAllForFourthHold.get(0).getTotalValue());
|
||||||
assertEquals(100, limitResponseAfterAllForFourthHold.get(0).getCommitValue());
|
assertEquals(100, limitResponseAfterAllForFourthHold.get(0).getCommitValue());
|
||||||
assertEquals(limitName, limitResponseAfterAllForFourthHold.get(0).getLimitName());
|
assertEquals(limitName, limitResponseAfterAllForFourthHold.get(0).getLimitName());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user