Details
diff --git a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
index 237b8f5..e8ea8f0 100644
--- a/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
+++ b/account/src/test/java/org/killbill/billing/account/dao/TestAccountDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -26,6 +26,7 @@ import org.joda.time.DateTimeZone;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.AccountTestSuiteWithEmbeddedDB;
+import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountData;
import org.killbill.billing.account.api.AccountEmail;
@@ -42,6 +43,7 @@ import org.killbill.billing.util.audit.AuditLog;
import org.killbill.billing.util.audit.ChangeType;
import org.killbill.billing.util.audit.DefaultAccountAuditLogs;
import org.killbill.billing.util.customfield.dao.CustomFieldModelDao;
+import org.killbill.billing.util.dao.EntityHistoryModelDao;
import org.killbill.billing.util.dao.TableName;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.tag.DescriptiveTag;
@@ -211,6 +213,18 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
public void testUpdate() throws Exception {
final AccountModelDao account = createTestAccount();
accountDao.create(account, internalCallContext);
+ final AccountModelDao createdAccount = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
+
+ final List<EntityHistoryModelDao<AccountModelDao, Account>> history1 = getAccountHistory(createdAccount.getRecordId());
+ Assert.assertEquals(history1.size(), 1);
+ Assert.assertEquals(history1.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history1.get(0).getEntity().getAccountRecordId(), createdAccount.getRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getTenantRecordId(), createdAccount.getTenantRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getExternalKey(), createdAccount.getExternalKey());
+ Assert.assertEquals(history1.get(0).getEntity().getMigrated(), createdAccount.getMigrated());
+ Assert.assertEquals(history1.get(0).getEntity().getIsNotifiedForInvoices(), createdAccount.getIsNotifiedForInvoices());
+ Assert.assertEquals(history1.get(0).getEntity().getTimeZone(), createdAccount.getTimeZone());
+ Assert.assertEquals(history1.get(0).getEntity().getLocale(), createdAccount.getLocale());
final AccountData accountData = new MockAccountBuilder(new DefaultAccount(account)).migrated(false)
.isNotifiedForInvoices(false)
@@ -222,6 +236,40 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
final AccountModelDao retrievedAccount = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
checkAccountsEqual(retrievedAccount, updatedAccount);
+
+ final List<EntityHistoryModelDao<AccountModelDao, Account>> history2 = getAccountHistory(createdAccount.getRecordId());
+ Assert.assertEquals(history2.size(), 2);
+ Assert.assertEquals(history2.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history2.get(1).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history2.get(1).getEntity().getAccountRecordId(), retrievedAccount.getRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getTenantRecordId(), retrievedAccount.getTenantRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getExternalKey(), retrievedAccount.getExternalKey());
+ Assert.assertEquals(history2.get(1).getEntity().getMigrated(), retrievedAccount.getMigrated());
+ Assert.assertEquals(history2.get(1).getEntity().getIsNotifiedForInvoices(), retrievedAccount.getIsNotifiedForInvoices());
+ Assert.assertEquals(history2.get(1).getEntity().getTimeZone(), retrievedAccount.getTimeZone());
+ Assert.assertEquals(history2.get(1).getEntity().getLocale(), retrievedAccount.getLocale());
+
+ final AccountData accountData2 = new MockAccountBuilder(new DefaultAccount(updatedAccount)).isNotifiedForInvoices(true)
+ .locale("en_US")
+ .build();
+ final AccountModelDao updatedAccount2 = new AccountModelDao(account.getId(), accountData2);
+ accountDao.update(updatedAccount2, internalCallContext);
+
+ final AccountModelDao retrievedAccount2 = accountDao.getAccountByKey(account.getExternalKey(), internalCallContext);
+ checkAccountsEqual(retrievedAccount2, updatedAccount2);
+
+ final List<EntityHistoryModelDao<AccountModelDao, Account>> history3 = getAccountHistory(createdAccount.getRecordId());
+ Assert.assertEquals(history3.size(), 3);
+ Assert.assertEquals(history3.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history3.get(1).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history3.get(2).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history3.get(2).getEntity().getAccountRecordId(), retrievedAccount2.getRecordId());
+ Assert.assertEquals(history3.get(2).getEntity().getTenantRecordId(), retrievedAccount2.getTenantRecordId());
+ Assert.assertEquals(history3.get(2).getEntity().getExternalKey(), retrievedAccount2.getExternalKey());
+ Assert.assertEquals(history3.get(2).getEntity().getMigrated(), retrievedAccount2.getMigrated());
+ Assert.assertEquals(history3.get(2).getEntity().getIsNotifiedForInvoices(), retrievedAccount2.getIsNotifiedForInvoices());
+ Assert.assertEquals(history3.get(2).getEntity().getTimeZone(), retrievedAccount2.getTimeZone());
+ Assert.assertEquals(history3.get(2).getEntity().getLocale(), retrievedAccount2.getLocale());
}
@Test(groups = "slow", description = "Test Account DAO: payment method update")
@@ -351,4 +399,10 @@ public class TestAccountDao extends AccountTestSuiteWithEmbeddedDB {
Assert.assertEquals(auditLogsForAccountEmail2.size(), 1);
Assert.assertEquals(auditLogsForAccountEmail2.get(0).getChangeType(), ChangeType.INSERT);
}
+
+ private List<EntityHistoryModelDao<AccountModelDao, Account>> getAccountHistory(final Long accountRecordId) {
+ // See https://github.com/killbill/killbill/issues/335
+ final AccountSqlDao accountSqlDao = dbi.onDemand(AccountSqlDao.class);
+ return accountSqlDao.getHistoryForTargetRecordId(accountRecordId, internalCallContext);
+ }
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorWithDB.java b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorWithDB.java
index 79f4b34..3912a51 100644
--- a/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorWithDB.java
+++ b/payment/src/test/java/org/killbill/billing/payment/core/TestPaymentMethodProcessorWithDB.java
@@ -1,6 +1,6 @@
/*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -17,12 +17,18 @@
package org.killbill.billing.payment.core;
+import java.util.List;
import java.util.UUID;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
import org.killbill.billing.payment.api.PaymentApiException;
+import org.killbill.billing.payment.api.PaymentMethod;
import org.killbill.billing.payment.api.PluginProperty;
+import org.killbill.billing.payment.dao.PaymentMethodModelDao;
+import org.killbill.billing.payment.dao.PaymentMethodSqlDao;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.dao.EntityHistoryModelDao;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -55,4 +61,43 @@ public class TestPaymentMethodProcessorWithDB extends PaymentTestSuiteWithEmbedd
final Account accountById = accountApi.getAccountById(account.getId(), internalCallContext);
Assert.assertEquals(accountById.getPaymentMethodId(), newPaymentMethod);
}
+
+ @Test(groups = "slow")
+ public void testDeletePaymentMethod() throws Exception {
+ final Account account = testHelper.createTestAccount("foo@bar.com", true);
+
+ final UUID paymentMethodId = paymentMethodProcessor.createOrGetExternalPaymentMethod("pmExternalKey", account, PLUGIN_PROPERTIES, callContext, internalCallContext);
+ final PaymentMethodModelDao paymentMethodModelDao = paymentDao.getPaymentMethod(paymentMethodId, internalCallContext);
+
+ final List<EntityHistoryModelDao<PaymentMethodModelDao, PaymentMethod>> history1 = getPaymentMethodHistory(paymentMethodModelDao.getRecordId());
+ Assert.assertEquals(history1.size(), 1);
+ Assert.assertEquals(history1.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history1.get(0).getEntity().getAccountRecordId(), paymentMethodModelDao.getAccountRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getTenantRecordId(), paymentMethodModelDao.getTenantRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getExternalKey(), paymentMethodModelDao.getExternalKey());
+ Assert.assertTrue(history1.get(0).getEntity().isActive());
+
+ paymentMethodProcessor.deletedPaymentMethod(account, paymentMethodId, true, true, ImmutableList.<PluginProperty>of(), callContext, internalCallContext);
+
+ final List<EntityHistoryModelDao<PaymentMethodModelDao, PaymentMethod>> history2 = getPaymentMethodHistory(paymentMethodModelDao.getRecordId());
+ Assert.assertEquals(history2.size(), 2);
+ Assert.assertEquals(history2.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history2.get(0).getEntity().getAccountRecordId(), paymentMethodModelDao.getAccountRecordId());
+ Assert.assertEquals(history2.get(0).getEntity().getTenantRecordId(), paymentMethodModelDao.getTenantRecordId());
+ Assert.assertEquals(history2.get(0).getEntity().getExternalKey(), paymentMethodModelDao.getExternalKey());
+ Assert.assertTrue(history2.get(0).getEntity().isActive());
+ // Note: it looks like we don't consider this as a DELETE, probably because we can un-delete such payment methods?
+ Assert.assertEquals(history2.get(1).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history2.get(1).getEntity().getAccountRecordId(), paymentMethodModelDao.getAccountRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getTenantRecordId(), paymentMethodModelDao.getTenantRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getExternalKey(), paymentMethodModelDao.getExternalKey());
+ // Note: upon deletion, the recorded state is the same as before the delete
+ Assert.assertTrue(history2.get(1).getEntity().isActive());
+ }
+
+ private List<EntityHistoryModelDao<PaymentMethodModelDao, PaymentMethod>> getPaymentMethodHistory(final Long paymentMethodRecordId) {
+ // See https://github.com/killbill/killbill/issues/335
+ final PaymentMethodSqlDao paymentMethodSqlDao = dbi.onDemand(PaymentMethodSqlDao.class);
+ return paymentMethodSqlDao.getHistoryForTargetRecordId(paymentMethodRecordId, internalCallContext);
+ }
}
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
index a195593..a23c0a0 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestPaymentDao.java
@@ -1,7 +1,7 @@
/*
* Copyright 2010-2013 Ning, Inc.
- * Copyright 2014-2016 Groupon, Inc
- * Copyright 2014-2016 The Billing Project, LLC
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
* The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
@@ -28,13 +28,14 @@ import org.joda.time.DateTime;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
+import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.dao.EntityHistoryModelDao;
import org.killbill.billing.util.entity.Pagination;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -95,7 +96,6 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testPaymentAndTransactions() {
-
final UUID paymentMethodId = UUID.randomUUID();
final UUID accountId = UUID.randomUUID();
final String externalKey = "hhhhooo";
@@ -117,6 +117,17 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(savedPayment.getPaymentMethodId(), paymentModelDao.getPaymentMethodId());
assertNull(savedPayment.getStateName());
+ final List<EntityHistoryModelDao<PaymentModelDao, Payment>> history1 = getPaymentHistory(savedPayment.getRecordId());
+ Assert.assertEquals(history1.size(), 1);
+ Assert.assertEquals(history1.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history1.get(0).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history1.get(0).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertEquals(history1.get(0).getEntity().getStateName(), savedPayment.getStateName());
+ Assert.assertEquals(history1.get(0).getEntity().getLastSuccessStateName(), savedPayment.getLastSuccessStateName());
+ Assert.assertNull(history1.get(0).getEntity().getStateName());
+ Assert.assertNull(history1.get(0).getEntity().getLastSuccessStateName());
+
final PaymentModelDao savedPayment2 = paymentDao.getPayment(savedPayment.getId(), internalCallContext);
assertEquals(savedPayment2.getId(), paymentModelDao.getId());
assertEquals(savedPayment2.getAccountId(), paymentModelDao.getAccountId());
@@ -162,6 +173,20 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(savedTransactionModelDao2.getAmount().compareTo(BigDecimal.TEN), 0);
assertEquals(savedTransactionModelDao2.getCurrency(), Currency.AED);
+ final List<EntityHistoryModelDao<PaymentModelDao, Payment>> history2 = getPaymentHistory(savedPayment.getRecordId());
+ Assert.assertEquals(history2.size(), 2);
+ Assert.assertEquals(history2.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history2.get(0).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history2.get(0).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history2.get(0).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertEquals(history2.get(1).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history2.get(1).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history2.get(1).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertTrue(history2.get(1).getEntity().getUpdatedDate().compareTo(history2.get(0).getEntity().getUpdatedDate()) >= 0);
+ Assert.assertNull(history2.get(1).getEntity().getStateName());
+ Assert.assertNull(history2.get(1).getEntity().getLastSuccessStateName());
+
final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(savedPayment.getId(), internalCallContext);
assertEquals(transactions.size(), 2);
@@ -176,6 +201,25 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
assertEquals(savedPayment4.getStateName(), "AUTH_ABORTED");
assertEquals(savedPayment4.getLastSuccessStateName(), "AUTH_SUCCESS");
+ final List<EntityHistoryModelDao<PaymentModelDao, Payment>> history3 = getPaymentHistory(savedPayment.getRecordId());
+ Assert.assertEquals(history3.size(), 3);
+ Assert.assertEquals(history3.get(0).getChangeType(), ChangeType.INSERT);
+ Assert.assertEquals(history3.get(0).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history3.get(0).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history3.get(0).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertEquals(history3.get(1).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history3.get(1).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history3.get(1).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history3.get(1).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertTrue(history3.get(1).getEntity().getUpdatedDate().compareTo(history3.get(0).getEntity().getUpdatedDate()) >= 0);
+ Assert.assertEquals(history3.get(2).getChangeType(), ChangeType.UPDATE);
+ Assert.assertEquals(history3.get(2).getEntity().getAccountRecordId(), savedPayment.getAccountRecordId());
+ Assert.assertEquals(history3.get(2).getEntity().getTenantRecordId(), savedPayment.getTenantRecordId());
+ Assert.assertEquals(history3.get(2).getEntity().getExternalKey(), savedPayment.getExternalKey());
+ Assert.assertTrue(history3.get(2).getEntity().getUpdatedDate().compareTo(history3.get(2).getEntity().getUpdatedDate()) >= 0);
+ Assert.assertEquals(history3.get(2).getEntity().getStateName(), savedPayment4.getStateName());
+ Assert.assertEquals(history3.get(2).getEntity().getLastSuccessStateName(), savedPayment4.getLastSuccessStateName());
+
final PaymentTransactionModelDao savedTransactionModelDao4 = paymentDao.getPaymentTransaction(savedTransactionModelDao2.getId(), internalCallContext);
assertEquals(savedTransactionModelDao4.getTransactionExternalKey(), transactionExternalKey2);
assertEquals(savedTransactionModelDao4.getPaymentId(), paymentModelDao.getId());
@@ -550,5 +594,11 @@ public class TestPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
}
}));
}
+
+ private List<EntityHistoryModelDao<PaymentModelDao, Payment>> getPaymentHistory(final Long paymentRecordId) {
+ // See https://github.com/killbill/killbill/issues/335
+ final PaymentSqlDao paymentSqlDao = dbi.onDemand(PaymentSqlDao.class);
+ return paymentSqlDao.getHistoryForTargetRecordId(paymentRecordId, internalCallContext);
+ }
}
diff --git a/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapper.java b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapper.java
new file mode 100644
index 0000000..5ff331d
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017 Groupon, Inc
+ * Copyright 2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.dao;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.killbill.billing.util.audit.ChangeType;
+import org.killbill.billing.util.entity.Entity;
+import org.killbill.billing.util.entity.dao.EntityModelDao;
+import org.killbill.billing.util.entity.dao.EntityModelDaoBase;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+public class EntityHistoryModelDaoMapper<M extends EntityModelDao<E>, E extends Entity> extends MapperBase implements ResultSetMapper<EntityHistoryModelDao<M, E>> {
+
+ private final ResultSetMapper<M> entityMapper;
+
+ public EntityHistoryModelDaoMapper(final ResultSetMapper<M> entityMapper) {
+ this.entityMapper = entityMapper;
+ }
+
+ @Override
+ public EntityHistoryModelDao<M, E> map(final int index, final ResultSet r, final StatementContext ctx) throws SQLException {
+ final UUID id = getUUID(r, "id");
+ final long targetRecordId = r.getLong("target_record_id");
+ final String changeType = r.getString("change_type");
+ final DateTime createdDate = getDateTime(r, "created_date");
+
+ final M entityModelDao = entityMapper.map(index, r, ctx);
+
+ // Hack -- remove the id as it is the history id, not the entity id
+ ((EntityModelDaoBase) entityModelDao).setId(null);
+ // Hack -- similarly, populate the right record_id
+ ((EntityModelDaoBase) entityModelDao).setRecordId(targetRecordId);
+ // Hack -- account is special
+ if (entityModelDao.getAccountRecordId() == null) {
+ ((EntityModelDaoBase) entityModelDao).setAccountRecordId(targetRecordId);
+ }
+
+ return new EntityHistoryModelDao(id, entityModelDao, targetRecordId, ChangeType.valueOf(changeType), createdDate);
+ }
+}
diff --git a/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapperFactory.java b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapperFactory.java
new file mode 100644
index 0000000..38cc98d
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/dao/EntityHistoryModelDaoMapperFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 Groupon, Inc
+ * Copyright 2017 The Billing Project, LLC
+ *
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.killbill.billing.util.dao;
+
+import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapper;
+import org.skife.jdbi.v2.ResultSetMapperFactory;
+import org.skife.jdbi.v2.StatementContext;
+import org.skife.jdbi.v2.tweak.ResultSetMapper;
+
+public class EntityHistoryModelDaoMapperFactory implements ResultSetMapperFactory {
+
+ private final Class<?> sqlObjectType;
+ private final Class<?> modelClazz;
+
+ public EntityHistoryModelDaoMapperFactory(final Class modelClazz, final Class<?> sqlObjectType) {
+ this.sqlObjectType = sqlObjectType;
+ this.modelClazz = modelClazz;
+ }
+
+ @Override
+ public boolean accepts(final Class type, final StatementContext ctx) {
+ return type.isAssignableFrom(EntityHistoryModelDao.class) && sqlObjectType.equals(ctx.getSqlObjectType());
+ }
+
+ @Override
+ public ResultSetMapper mapperFor(final Class type, final StatementContext ctx) {
+ return new EntityHistoryModelDaoMapper(new LowerToCamelBeanMapper(modelClazz));
+ }
+}
+
diff --git a/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java b/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
index c829280..1a748c1 100644
--- a/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
+++ b/util/src/main/java/org/killbill/billing/util/dao/HistorySqlDao.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2011 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -16,15 +18,22 @@
package org.killbill.billing.util.dao;
-import org.skife.jdbi.v2.sqlobject.BindBean;
-import org.skife.jdbi.v2.sqlobject.SqlUpdate;
+import java.util.List;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.util.entity.Entity;
import org.killbill.billing.util.entity.dao.EntityModelDao;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.BindBean;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
public interface HistorySqlDao<M extends EntityModelDao<E>, E extends Entity> {
+ @SqlQuery
+ public List<EntityHistoryModelDao<M, E>> getHistoryForTargetRecordId(@Bind("targetRecordId") final long targetRecordId,
+ @BindBean InternalCallContext context);
+
@SqlUpdate
public void addHistoryFromTransaction(@EntityHistoryBinder EntityHistoryModelDao<M, E> history,
@BindBean InternalCallContext context);
diff --git a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoStringTemplate.java b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
index 12d9517..ce2fd8d 100644
--- a/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
+++ b/util/src/main/java/org/killbill/billing/util/entity/dao/EntitySqlDaoStringTemplate.java
@@ -1,7 +1,9 @@
/*
- * Copyright 2010-2012 Ning, Inc.
+ * Copyright 2010-2013 Ning, Inc.
+ * Copyright 2014-2017 Groupon, Inc
+ * Copyright 2014-2017 The Billing Project, LLC
*
- * Ning licenses this file to you under the Apache License, version 2.0
+ * The Billing Project licenses this file to you under the Apache License, version 2.0
* (the "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
*
@@ -28,6 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
+import org.killbill.billing.util.dao.EntityHistoryModelDaoMapperFactory;
+import org.killbill.billing.util.entity.Entity;
import org.killbill.commons.jdbi.mapper.LowerToCamelBeanMapperFactory;
import org.skife.jdbi.v2.Query;
import org.skife.jdbi.v2.SQLStatement;
@@ -38,8 +42,6 @@ import org.skife.jdbi.v2.sqlobject.stringtemplate.StringTemplate3StatementLocato
import org.skife.jdbi.v2.sqlobject.stringtemplate.UseStringTemplate3StatementLocator;
import org.skife.jdbi.v2.tweak.StatementLocator;
-import org.killbill.billing.util.entity.Entity;
-
@SqlStatementCustomizingAnnotation(EntitySqlDaoStringTemplate.EntitySqlDaoLocatorFactory.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@@ -114,6 +116,7 @@ public @interface EntitySqlDaoStringTemplate {
final Class modelClazz = (Class) modelType;
if (Entity.class.isAssignableFrom(modelClazz)) {
query.registerMapper(new LowerToCamelBeanMapperFactory(modelClazz));
+ query.registerMapper(new EntityHistoryModelDaoMapperFactory(modelClazz, sqlObjectType));
}
}
}
diff --git a/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg b/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
index a79883d..2d96592 100644
--- a/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
+++ b/util/src/main/resources/org/killbill/billing/util/entity/dao/EntitySqlDao.sql.stg
@@ -336,6 +336,18 @@ auditTableValues() ::= <<
<if(tenantRecordIdField(""))>, <tenantRecordIdValue()><endif>
>>
+getHistoryForTargetRecordId() ::= <<
+select
+ <idField()>
+, <historyTableFields("t.")>
+<accountRecordIdFieldWithComma("t.")>
+<tenantRecordIdFieldWithComma("t.")>
+from <historyTableName()> t
+where <targetRecordIdField("t.")> = :targetRecordId
+<AND_CHECK_TENANT("t.")>
+order by <recordIdField("t.")> ASC
+;
+>>
addHistoryFromTransaction() ::= <<
insert into <historyTableName()> (