/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.masterdb.position;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalTime;
import org.threeten.bp.OffsetTime;
import org.threeten.bp.ZoneOffset;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.opengamma.DataNotFoundException;
import com.opengamma.elsql.ElSqlBundle;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.ExternalIdSearch;
import com.opengamma.id.IdUtils;
import com.opengamma.id.ObjectId;
import com.opengamma.id.ObjectIdentifiable;
import com.opengamma.id.UniqueId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.AbstractHistoryRequest;
import com.opengamma.master.AbstractHistoryResult;
import com.opengamma.master.position.ManageablePosition;
import com.opengamma.master.position.ManageableTrade;
import com.opengamma.master.position.PositionDocument;
import com.opengamma.master.position.PositionHistoryRequest;
import com.opengamma.master.position.PositionHistoryResult;
import com.opengamma.master.position.PositionMaster;
import com.opengamma.master.position.PositionSearchRequest;
import com.opengamma.master.position.PositionSearchResult;
import com.opengamma.masterdb.AbstractDocumentDbMaster;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.db.DbConnector;
import com.opengamma.util.db.DbDateUtils;
import com.opengamma.util.db.DbMapSqlParameterSource;
import com.opengamma.util.money.Currency;
import com.opengamma.util.paging.Paging;
import com.opengamma.util.tuple.Pair;
/**
* A position master implementation using a database for persistence.
* <p>
* This is a full implementation of the position master using an SQL database. Full details of the API are in {@link PositionMaster}.
* <p>
* The SQL is stored externally in {@code DbPositionMaster.elsql}. Alternate databases or specific SQL requirements can be handled using database specific overrides, such as
* {@code DbPositionMaster-MySpecialDB.elsql}.
* <p>
* This class is mutable but must be treated as immutable after configuration.
*/
public class DbPositionMaster extends AbstractDocumentDbMaster<PositionDocument> implements PositionMaster {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(DbPositionMaster.class);
/**
* The default scheme for unique identifiers.
*/
public static final String IDENTIFIER_SCHEME_DEFAULT = "DbPos";
// -----------------------------------------------------------------
// TIMERS FOR METRICS GATHERING
// By default these do nothing. Registration will replace them
// so that they actually do something.
// -----------------------------------------------------------------
private Timer _insertTimer = new Timer();
/**
* Creates an instance.
*
* @param dbConnector the database connector, not null
*/
public DbPositionMaster(final DbConnector dbConnector) {
super(dbConnector, IDENTIFIER_SCHEME_DEFAULT);
setElSqlBundle(ElSqlBundle.of(dbConnector.getDialect().getElSqlConfig(), DbPositionMaster.class));
}
@Override
public void registerMetrics(MetricRegistry summaryRegistry, MetricRegistry detailedRegistry, String namePrefix) {
super.registerMetrics(summaryRegistry, detailedRegistry, namePrefix);
_insertTimer = summaryRegistry.timer(namePrefix + ".insert");
}
//-------------------------------------------------------------------------
@Override
public PositionSearchResult search(final PositionSearchRequest request) {
ArgumentChecker.notNull(request, "request");
ArgumentChecker.notNull(request.getPagingRequest(), "request.pagingRequest");
ArgumentChecker.notNull(request.getVersionCorrection(), "request.versionCorrection");
s_logger.debug("search {}", request);
final VersionCorrection vc = request.getVersionCorrection().withLatestFixed(now());
final PositionSearchResult result = new PositionSearchResult(vc);
final ExternalIdSearch securityIdSearch = request.getSecurityIdSearch();
final Collection<ObjectId> positionObjectIds = request.getPositionObjectIds();
final Collection<ObjectId> tradeObjectIds = request.getTradeObjectIds();
if ((positionObjectIds != null && positionObjectIds.size() == 0) ||
(tradeObjectIds != null && tradeObjectIds.size() == 0) ||
(ExternalIdSearch.canMatch(securityIdSearch) == false)) {
result.setPaging(Paging.of(request.getPagingRequest(), 0));
return result;
}
final DbMapSqlParameterSource args = new DbMapSqlParameterSource().addTimestamp("version_as_of_instant", vc.getVersionAsOf()).addTimestamp("corrected_to_instant", vc.getCorrectedTo())
.addValueNullIgnored("min_quantity", request.getMinQuantity()).addValueNullIgnored("max_quantity", request.getMaxQuantity())
.addValueNullIgnored("security_id_value", getDialect().sqlWildcardAdjustValue(request.getSecurityIdValue()));
if (request.getPositionProviderId() != null) {
args.addValue("pos_provider_scheme", request.getPositionProviderId().getScheme().getName());
args.addValue("pos_provider_value", request.getPositionProviderId().getValue());
}
if (request.getTradeProviderId() != null) {
args.addValue("trade_provider_scheme", request.getTradeProviderId().getScheme().getName());
args.addValue("trade_provider_value", request.getTradeProviderId().getValue());
}
if (securityIdSearch != null && securityIdSearch.alwaysMatches() == false) {
int i = 0;
for (final ExternalId id : securityIdSearch) {
args.addValue("key_scheme" + i, id.getScheme().getName());
args.addValue("key_value" + i, id.getValue());
i++;
}
args.addValue("sql_search_security_ids_type", securityIdSearch.getSearchType());
args.addValue("sql_search_security_ids", sqlSelectIdKeys(securityIdSearch));
args.addValue("security_id_search_size", securityIdSearch.getExternalIds().size());
}
if (positionObjectIds != null) {
final StringBuilder buf = new StringBuilder(positionObjectIds.size() * 10);
for (final ObjectId objectId : positionObjectIds) {
checkScheme(objectId);
buf.append(extractOid(objectId)).append(", ");
}
buf.setLength(buf.length() - 2);
args.addValue("sql_search_position_ids", buf.toString());
}
if (tradeObjectIds != null) {
final StringBuilder buf = new StringBuilder(tradeObjectIds.size() * 10);
for (final ObjectId objectId : tradeObjectIds) {
checkScheme(objectId);
buf.append(extractOid(objectId)).append(", ");
}
buf.setLength(buf.length() - 2);
args.addValue("sql_search_trade_ids", buf.toString());
}
args.addValue("paging_offset", request.getPagingRequest().getFirstItem());
args.addValue("paging_fetch", request.getPagingRequest().getPagingSize());
final String[] sql = {getElSqlBundle().getSql("Search", args), getElSqlBundle().getSql("SearchCount", args) };
doSearch(request.getPagingRequest(), sql, args, new PositionDocumentExtractor(), result);
return result;
}
/**
* Gets the SQL to find all the ids for a single bundle.
* <p>
* This is too complex for the elsql mechanism.
*
* @param idSearch the identifier search, not null
* @return the SQL, not null
*/
protected String sqlSelectIdKeys(final ExternalIdSearch idSearch) {
final List<String> list = new ArrayList<String>();
for (int i = 0; i < idSearch.size(); i++) {
list.add("(key_scheme = :key_scheme" + i + " AND key_value = :key_value" + i + ") ");
}
return StringUtils.join(list, "OR ");
}
//-------------------------------------------------------------------------
@Override
public PositionDocument get(final UniqueId uniqueId) {
return doGet(uniqueId, new PositionDocumentExtractor(), "Position");
}
//-------------------------------------------------------------------------
@Override
public PositionDocument get(final ObjectIdentifiable objectId, final VersionCorrection versionCorrection) {
return doGetByOidInstants(objectId, versionCorrection, new PositionDocumentExtractor(), "Position");
}
//-------------------------------------------------------------------------
@Override
public PositionHistoryResult history(final PositionHistoryRequest request) {
return doHistory(request, new PositionHistoryResult(), new PositionDocumentExtractor());
}
//-------------------------------------------------------------------------
/**
* Inserts a new document.
*
* @param document the document, not null
* @return the new document, not null
*/
@Override
protected PositionDocument insert(final PositionDocument document) {
ArgumentChecker.notNull(document.getPosition(), "document.position");
ArgumentChecker.notNull(document.getPosition().getQuantity(), "document.position.quantity");
for (final ManageableTrade trade : document.getPosition().getTrades()) {
ArgumentChecker.notNull(trade.getQuantity(), "position.trade.quantity");
ArgumentChecker.notNull(trade.getCounterpartyExternalId(), "position.trade.counterpartyexternalid");
ArgumentChecker.notNull(trade.getTradeDate(), "position.trade.tradedate");
}
try (Timer.Context context = _insertTimer.time()) {
final long positionId = nextId("pos_master_seq");
final long positionOid = (document.getUniqueId() != null ? extractOid(document.getUniqueId()) : positionId);
final UniqueId positionUid = createUniqueId(positionOid, positionId);
final ManageablePosition position = document.getPosition();
// the arguments for inserting into the position table
final DbMapSqlParameterSource docArgs = new DbMapSqlParameterSource().addValue("position_id", positionId).addValue("position_oid", positionOid)
.addTimestamp("ver_from_instant", document.getVersionFromInstant()).addTimestampNullFuture("ver_to_instant", document.getVersionToInstant())
.addTimestamp("corr_from_instant", document.getCorrectionFromInstant())
.addTimestampNullFuture("corr_to_instant", document.getCorrectionToInstant())
.addValue("quantity", position.getQuantity(), Types.DECIMAL)
.addValue("provider_scheme",
position.getProviderId() != null ? position.getProviderId().getScheme().getName() : null, Types.VARCHAR)
.addValue("provider_value",
position.getProviderId() != null ? position.getProviderId().getValue() : null, Types.VARCHAR);
// the arguments for inserting into the pos_attribute table
final List<DbMapSqlParameterSource> posAttrList = Lists.newArrayList();
for (final Entry<String, String> entry : position.getAttributes().entrySet()) {
final long posAttrId = nextId("pos_trade_attr_seq");
final DbMapSqlParameterSource posAttrArgs = new DbMapSqlParameterSource().addValue("attr_id", posAttrId)
.addValue("pos_id", positionId)
.addValue("pos_oid", positionOid)
.addValue("key", entry.getKey())
.addValue("value", entry.getValue());
posAttrList.add(posAttrArgs);
}
// the arguments for inserting into the idkey tables
final List<DbMapSqlParameterSource> posAssocList = new ArrayList<DbMapSqlParameterSource>();
final Set<Pair<String, String>> schemeValueSet = Sets.newHashSet();
for (final ExternalId id : position.getSecurityLink().getAllExternalIds()) {
final DbMapSqlParameterSource assocArgs = new DbMapSqlParameterSource().addValue("position_id", positionId)
.addValue("key_scheme", id.getScheme().getName())
.addValue("key_value", id.getValue());
posAssocList.add(assocArgs);
schemeValueSet.add(Pair.of(id.getScheme().getName(), id.getValue()));
}
// the arguments for inserting into the trade table
final List<DbMapSqlParameterSource> tradeList = Lists.newArrayList();
final List<DbMapSqlParameterSource> tradeAssocList = Lists.newArrayList();
final List<DbMapSqlParameterSource> tradeAttributeList = Lists.newArrayList();
for (final ManageableTrade trade : position.getTrades()) {
final long tradeId = nextId("pos_master_seq");
final long tradeOid = (trade.getUniqueId() != null ? extractOid(trade.getUniqueId()) : tradeId);
final ExternalId counterpartyId = trade.getCounterpartyExternalId();
final DbMapSqlParameterSource tradeArgs = new DbMapSqlParameterSource().addValue("trade_id", tradeId)
.addValue("trade_oid", tradeOid)
.addValue("position_id", positionId)
.addValue("position_oid", positionOid)
.addValue("quantity", trade.getQuantity())
.addDate("trade_date", trade.getTradeDate())
.addTimeAllowNull("trade_time", trade.getTradeTime() != null ? trade.getTradeTime().toLocalTime() : null)
.addValue("zone_offset",
trade.getTradeTime() != null ? trade.getTradeTime().getOffset().getTotalSeconds() : null, Types.INTEGER)
.addValue("cparty_scheme", counterpartyId.getScheme().getName())
.addValue("cparty_value", counterpartyId.getValue())
.addValue("provider_scheme",
position.getProviderId() != null ? position.getProviderId().getScheme().getName() : null, Types.VARCHAR)
.addValue("provider_value",
position.getProviderId() != null ? position.getProviderId().getValue() : null, Types.VARCHAR)
.addValue("premium_value", trade.getPremium(), Types.DOUBLE)
.addValue("premium_currency",
trade.getPremiumCurrency() != null ? trade.getPremiumCurrency().getCode() : null, Types.VARCHAR)
.addDateAllowNull("premium_date", trade.getPremiumDate())
.addTimeAllowNull("premium_time", (trade.getPremiumTime() != null ? trade.getPremiumTime().toLocalTime() : null))
.addValue("premium_zone_offset",
trade.getPremiumTime() != null ? trade.getPremiumTime().getOffset().getTotalSeconds() : null, Types.INTEGER);
tradeList.add(tradeArgs);
// trade attributes
final Map<String, String> attributes = new HashMap<String, String>(trade.getAttributes());
for (final Entry<String, String> entry : attributes.entrySet()) {
final long tradeAttrId = nextId("pos_trade_attr_seq");
final DbMapSqlParameterSource tradeAttributeArgs = new DbMapSqlParameterSource().addValue("attr_id", tradeAttrId)
.addValue("trade_id", tradeId)
.addValue("trade_oid", tradeOid)
.addValue("key", entry.getKey())
.addValue("value", entry.getValue());
tradeAttributeList.add(tradeAttributeArgs);
}
// set the trade uniqueId
final UniqueId tradeUid = createUniqueId(tradeOid, tradeId);
IdUtils.setInto(trade, tradeUid);
trade.setParentPositionId(positionUid);
for (final ExternalId id : trade.getSecurityLink().getAllExternalIds()) {
final DbMapSqlParameterSource assocArgs = new DbMapSqlParameterSource().addValue("trade_id", tradeId)
.addValue("key_scheme", id.getScheme().getName())
.addValue("key_value", id.getValue());
tradeAssocList.add(assocArgs);
schemeValueSet.add(Pair.of(id.getScheme().getName(), id.getValue()));
}
}
final List<DbMapSqlParameterSource> idKeyList = new ArrayList<DbMapSqlParameterSource>();
final String sqlSelectIdKey = getElSqlBundle().getSql("SelectIdKey");
for (final Pair<String, String> pair : schemeValueSet) {
final DbMapSqlParameterSource idkeyArgs = new DbMapSqlParameterSource().addValue("key_scheme", pair.getFirst())
.addValue("key_value", pair.getSecond());
if (getJdbcTemplate().queryForList(sqlSelectIdKey, idkeyArgs).isEmpty()) {
// select avoids creating unecessary id, but id may still not be used
final long idKeyId = nextId("pos_idkey_seq");
idkeyArgs.addValue("idkey_id", idKeyId);
idKeyList.add(idkeyArgs);
}
}
final String sqlDoc = getElSqlBundle().getSql("Insert", docArgs);
final String sqlIdKey = getElSqlBundle().getSql("InsertIdKey");
final String sqlPosition2IdKey = getElSqlBundle().getSql("InsertPosition2IdKey");
final String sqlTrade = getElSqlBundle().getSql("InsertTrade");
final String sqlTrade2IdKey = getElSqlBundle().getSql("InsertTrade2IdKey");
final String sqlPositionAttributes = getElSqlBundle().getSql("InsertPositionAttributes");
final String sqlTradeAttributes = getElSqlBundle().getSql("InsertTradeAttributes");
getJdbcTemplate().update(sqlDoc, docArgs);
getJdbcTemplate().batchUpdate(sqlIdKey, idKeyList.toArray(new DbMapSqlParameterSource[idKeyList.size()]));
getJdbcTemplate().batchUpdate(sqlPosition2IdKey, posAssocList.toArray(new DbMapSqlParameterSource[posAssocList.size()]));
getJdbcTemplate().batchUpdate(sqlTrade, tradeList.toArray(new DbMapSqlParameterSource[tradeList.size()]));
getJdbcTemplate().batchUpdate(sqlTrade2IdKey, tradeAssocList.toArray(new DbMapSqlParameterSource[tradeAssocList.size()]));
getJdbcTemplate().batchUpdate(sqlPositionAttributes, posAttrList.toArray(new DbMapSqlParameterSource[posAttrList.size()]));
getJdbcTemplate().batchUpdate(sqlTradeAttributes, tradeAttributeList.toArray(new DbMapSqlParameterSource[tradeAttributeList.size()]));
// set the uniqueId
position.setUniqueId(positionUid);
document.setUniqueId(positionUid);
return document;
}
}
//-------------------------------------------------------------------------
@Override
public ManageableTrade getTrade(final UniqueId uniqueId) {
ArgumentChecker.notNull(uniqueId, "uniqueId");
checkScheme(uniqueId);
if (uniqueId.isVersioned()) {
return getTradeById(uniqueId);
} else {
return getTradeByInstants(uniqueId, null, null);
}
}
/**
* Gets a trade by searching for the latest version of an object identifier.
*
* @param uniqueId the unique identifier, not null
* @param versionAsOf the instant to fetch, not null
* @param correctedTo the instant to fetch, not null
* @return the trade, null if not found
*/
protected ManageableTrade getTradeByInstants(final UniqueId uniqueId, final Instant versionAsOf, final Instant correctedTo) {
s_logger.debug("getTradeByLatest {}", uniqueId);
final Instant now = now();
final DbMapSqlParameterSource args = new DbMapSqlParameterSource().addValue("trade_oid", extractOid(uniqueId))
.addTimestamp("version_as_of_instant", Objects.firstNonNull(versionAsOf, now))
.addTimestamp("corrected_to_instant", Objects.firstNonNull(correctedTo, now));
final PositionDocumentExtractor extractor = new PositionDocumentExtractor();
final NamedParameterJdbcOperations namedJdbc = getDbConnector().getJdbcTemplate();
final String sql = getElSqlBundle().getSql("GetTradeByOidInstants", args);
final List<PositionDocument> docs = namedJdbc.query(sql, args, extractor);
if (docs.isEmpty()) {
throw new DataNotFoundException("Trade not found: " + uniqueId);
}
return docs.get(0).getPosition().getTrades().get(0); // SQL loads desired trade as only trade
}
/**
* Gets a trade by identifier.
*
* @param uniqueId the unique identifier, not null
* @return the trade, null if not found
*/
protected ManageableTrade getTradeById(final UniqueId uniqueId) {
s_logger.debug("getTradeById {}", uniqueId);
final DbMapSqlParameterSource args = new DbMapSqlParameterSource().addValue("trade_id", extractRowId(uniqueId));
final PositionDocumentExtractor extractor = new PositionDocumentExtractor();
final NamedParameterJdbcOperations namedJdbc = getDbConnector().getJdbcTemplate();
final String sql = getElSqlBundle().getSql("GetTradeById", args);
final List<PositionDocument> docs = namedJdbc.query(sql, args, extractor);
if (docs.isEmpty()) {
throw new DataNotFoundException("Trade not found: " + uniqueId);
}
return docs.get(0).getPosition().getTrades().get(0); // SQL loads desired trade as only trade
}
//-------------------------------------------------------------------------
@Override
protected AbstractHistoryResult<PositionDocument> historyByVersionsCorrections(final AbstractHistoryRequest request) {
final PositionHistoryRequest historyRequest = new PositionHistoryRequest();
historyRequest.setCorrectionsFromInstant(request.getCorrectionsFromInstant());
historyRequest.setCorrectionsToInstant(request.getCorrectionsToInstant());
historyRequest.setVersionsFromInstant(request.getVersionsFromInstant());
historyRequest.setVersionsToInstant(request.getVersionsToInstant());
historyRequest.setObjectId(request.getObjectId());
return history(historyRequest);
}
//-------------------------------------------------------------------------
/**
* Mapper from SQL rows to a PositionDocument.
*/
protected final class PositionDocumentExtractor implements ResultSetExtractor<List<PositionDocument>> {
private long _lastPositionId = -1;
private long _lastTradeId = -1;
private ManageablePosition _position;
private ManageableTrade _trade;
private final List<PositionDocument> _documents = new ArrayList<PositionDocument>();
@Override
public List<PositionDocument> extractData(final ResultSet rs) throws SQLException, DataAccessException {
while (rs.next()) {
final long positionId = rs.getLong("POSITION_ID");
if (_lastPositionId != positionId) {
_lastPositionId = positionId;
buildPosition(rs, positionId);
}
final String posIdScheme = rs.getString("POS_KEY_SCHEME");
final String posIdValue = rs.getString("POS_KEY_VALUE");
if (posIdScheme != null && posIdValue != null) {
if (posIdScheme.equals(ObjectId.EXTERNAL_SCHEME.getName())) {
final ObjectId oid = ObjectId.parse(posIdValue);
_position.getSecurityLink().setObjectId(oid);
} else {
final ExternalId id = ExternalId.of(posIdScheme, posIdValue);
_position.getSecurityLink().addExternalId(id);
}
}
final String posAttrKey = rs.getString("POS_ATTR_KEY");
final String posAttrValue = rs.getString("POS_ATTR_VALUE");
if (posAttrKey != null && posAttrValue != null) {
_position.addAttribute(posAttrKey, posAttrValue);
}
final long tradeId = rs.getLong("TRADE_ID");
if (_lastTradeId != tradeId && tradeId != 0) {
buildTrade(rs, tradeId);
}
final String tradeIdScheme = rs.getString("TRADE_KEY_SCHEME");
final String tradeIdValue = rs.getString("TRADE_KEY_VALUE");
if (tradeIdScheme != null && tradeIdValue != null) {
if (tradeIdScheme.equals(ObjectId.EXTERNAL_SCHEME.getName())) {
final ObjectId oid = ObjectId.parse(tradeIdValue);
_trade.getSecurityLink().setObjectId(oid);
} else {
final ExternalId id = ExternalId.of(tradeIdScheme, tradeIdValue);
_trade.getSecurityLink().addExternalId(id);
}
}
final String tradeAttrKey = rs.getString("TRADE_ATTR_KEY");
final String tradeAttrValue = rs.getString("TRADE_ATTR_VALUE");
if (tradeAttrKey != null && tradeAttrValue != null) {
_trade.addAttribute(tradeAttrKey, tradeAttrValue);
}
}
return _documents;
}
private void buildPosition(final ResultSet rs, final long positionId) throws SQLException {
final long positionOid = rs.getLong("POSITION_OID");
final BigDecimal quantity = extractBigDecimal(rs, "POS_QUANTITY");
final Timestamp versionFrom = rs.getTimestamp("VER_FROM_INSTANT");
final Timestamp versionTo = rs.getTimestamp("VER_TO_INSTANT");
final Timestamp correctionFrom = rs.getTimestamp("CORR_FROM_INSTANT");
final Timestamp correctionTo = rs.getTimestamp("CORR_TO_INSTANT");
final String providerScheme = rs.getString("POS_PROVIDER_SCHEME");
final String providerValue = rs.getString("POS_PROVIDER_VALUE");
_position = new ManageablePosition(quantity, ExternalIdBundle.EMPTY);
_position.setUniqueId(createUniqueId(positionOid, positionId));
if (providerScheme != null && providerValue != null) {
_position.setProviderId(ExternalId.of(providerScheme, providerValue));
}
final PositionDocument doc = new PositionDocument(_position);
doc.setVersionFromInstant(DbDateUtils.fromSqlTimestamp(versionFrom));
doc.setVersionToInstant(DbDateUtils.fromSqlTimestampNullFarFuture(versionTo));
doc.setCorrectionFromInstant(DbDateUtils.fromSqlTimestamp(correctionFrom));
doc.setCorrectionToInstant(DbDateUtils.fromSqlTimestampNullFarFuture(correctionTo));
doc.setUniqueId(createUniqueId(positionOid, positionId));
_documents.add(doc);
}
private void buildTrade(final ResultSet rs, final long tradeId) throws SQLException {
_lastTradeId = tradeId;
final long tradeOid = rs.getLong("TRADE_OID");
final BigDecimal tradeQuantity = extractBigDecimal(rs, "TRADE_QUANTITY");
final LocalDate tradeDate = DbDateUtils.fromSqlDate(rs.getDate("TRADE_DATE"));
final LocalTime tradeTime = rs.getTimestamp("TRADE_TIME") != null ? DbDateUtils.fromSqlTime(rs.getTimestamp("TRADE_TIME")) : null;
final int zoneOffset = rs.getInt("ZONE_OFFSET");
final String cpartyScheme = rs.getString("CPARTY_SCHEME");
final String cpartyValue = rs.getString("CPARTY_VALUE");
final String providerScheme = rs.getString("TRADE_PROVIDER_SCHEME");
final String providerValue = rs.getString("TRADE_PROVIDER_VALUE");
OffsetTime tradeOffsetTime = null;
if (tradeTime != null) {
tradeOffsetTime = OffsetTime.of(tradeTime, ZoneOffset.ofTotalSeconds(zoneOffset));
}
ExternalId counterpartyId = null;
if (cpartyScheme != null && cpartyValue != null) {
counterpartyId = ExternalId.of(cpartyScheme, cpartyValue);
}
_trade = new ManageableTrade(tradeQuantity, ExternalIdBundle.EMPTY, tradeDate, tradeOffsetTime, counterpartyId);
_trade.setUniqueId(createUniqueId(tradeOid, tradeId));
if (providerScheme != null && providerValue != null) {
_trade.setProviderId(ExternalId.of(providerScheme, providerValue));
}
//set premium
final Object premiumValue = rs.getObject("PREMIUM_VALUE");
if (premiumValue != null) {
_trade.setPremium((Double) premiumValue);
}
final String currencyCode = rs.getString("PREMIUM_CURRENCY");
if (currencyCode != null) {
_trade.setPremiumCurrency(Currency.of(currencyCode));
}
final Date premiumDate = rs.getDate("PREMIUM_DATE");
if (premiumDate != null) {
_trade.setPremiumDate(DbDateUtils.fromSqlDate(premiumDate));
}
_trade.setParentPositionId(_position.getUniqueId());
final LocalTime premiumTime = rs.getTimestamp("PREMIUM_TIME") != null ? DbDateUtils.fromSqlTime(rs.getTimestamp("PREMIUM_TIME")) : null;
final int premiumZoneOffset = rs.getInt("PREMIUM_ZONE_OFFSET");
if (premiumTime != null) {
_trade.setPremiumTime(OffsetTime.of(premiumTime, ZoneOffset.ofTotalSeconds(premiumZoneOffset)));
}
_position.getTrades().add(_trade);
}
}
}