killbill-memoizeit
Changes
payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java 29(+29 -0)
Details
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index 3acf35f..f4a0491 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -87,9 +87,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
@@ -241,17 +243,45 @@ public class PaymentProcessor extends ProcessorBase {
public Pagination<Payment> getPayments(final Long offset, final Long limit, final boolean withPluginInfo, final boolean withAttempts,
final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) {
- return getEntityPaginationFromPlugins(true,
- getAvailablePlugins(),
- offset,
- limit,
- new EntityPaginationBuilder<Payment, PaymentApiException>() {
- @Override
- public Pagination<Payment> build(final Long offset, final Long limit, final String pluginName) throws PaymentApiException {
- return getPayments(offset, limit, pluginName, withPluginInfo, withAttempts, properties, tenantContext, internalTenantContext);
- }
- }
- );
+ final Map<UUID, Optional<PaymentPluginApi>> paymentMethodIdToPaymentPluginApi = new HashMap<UUID, Optional<PaymentPluginApi>>();
+
+ try {
+ return getEntityPagination(limit,
+ new SourcePaginationBuilder<PaymentModelDao, PaymentApiException>() {
+ @Override
+ public Pagination<PaymentModelDao> build() {
+ // Find all payments for all accounts
+ return paymentDao.get(offset, limit, internalTenantContext);
+ }
+ },
+ new Function<PaymentModelDao, Payment>() {
+ @Override
+ public Payment apply(final PaymentModelDao paymentModelDao) {
+ final PaymentPluginApi pluginApi;
+ if (!withPluginInfo) {
+ pluginApi = null;
+ } else {
+ if (paymentMethodIdToPaymentPluginApi.get(paymentModelDao.getPaymentMethodId()) == null) {
+ try {
+ final PaymentPluginApi paymentProviderPlugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), internalTenantContext);
+ paymentMethodIdToPaymentPluginApi.put(paymentModelDao.getPaymentMethodId(), Optional.<PaymentPluginApi>of(paymentProviderPlugin));
+ } catch (final PaymentApiException e) {
+ log.warn("Unable to retrieve PaymentPluginApi for paymentMethodId='{}'", paymentModelDao.getPaymentMethodId(), e);
+ // We use Optional to avoid printing the log line for each result
+ paymentMethodIdToPaymentPluginApi.put(paymentModelDao.getPaymentMethodId(), Optional.<PaymentPluginApi>absent());
+ }
+ }
+ pluginApi = paymentMethodIdToPaymentPluginApi.get(paymentModelDao.getPaymentMethodId()).orNull();
+ }
+ final List<PaymentTransactionInfoPlugin> pluginInfo = getPaymentTransactionInfoPluginsIfNeeded(pluginApi, paymentModelDao, tenantContext);
+ return toPayment(paymentModelDao.getId(), pluginInfo, withAttempts, internalTenantContext);
+ }
+ }
+ );
+ } catch (final PaymentApiException e) {
+ log.warn("Unable to get payments", e);
+ return new DefaultPagination<Payment>(offset, limit, null, null, ImmutableSet.<Payment>of().iterator());
+ }
}
public Pagination<Payment> getPayments(final Long offset, final Long limit, final String pluginName, final boolean withPluginInfo, final boolean withAttempts, final Iterable<PluginProperty> properties, final TenantContext tenantContext, final InternalTenantContext internalTenantContext) throws PaymentApiException {
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
index 5ed95a9..7e010b7 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/sm/PaymentStateMachineHelper.java
@@ -78,6 +78,35 @@ public class PaymentStateMachineHelper {
private final StateMachineConfigCache stateMachineConfigCache;
+ public static final String[] STATE_NAMES = {AUTH_ERRORED,
+ AUTHORIZE_FAILED,
+ AUTHORIZE_PENDING,
+ AUTHORIZE_SUCCESS,
+ CAPTURE_ERRORED,
+ CAPTURE_FAILED,
+ CAPTURE_PENDING,
+ CAPTURE_SUCCESS,
+ CHARGEBACK_ERRORED,
+ CHARGEBACK_FAILED,
+ CHARGEBACK_PENDING,
+ CHARGEBACK_SUCCESS,
+ CREDIT_ERRORED,
+ CREDIT_FAILED,
+ CREDIT_PENDING,
+ CREDIT_SUCCESS,
+ PURCHASE_ERRORED,
+ PURCHASE_FAILED,
+ PURCHASE_PENDING,
+ PURCHASE_SUCCESS,
+ REFUND_ERRORED,
+ REFUND_FAILED,
+ REFUND_PENDING,
+ REFUND_SUCCESS,
+ VOID_ERRORED,
+ VOID_FAILED,
+ VOID_PENDING,
+ VOID_SUCCESS};
+
@Inject
public PaymentStateMachineHelper(final StateMachineConfigCache stateMachineConfigCache) {
this.stateMachineConfigCache = stateMachineConfigCache;
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
index 0e67704..bed7b5b 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/DefaultPaymentDao.java
@@ -19,16 +19,19 @@
package org.killbill.billing.payment.dao;
import java.math.BigDecimal;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
+import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTime;
+import org.killbill.billing.ErrorCode;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
@@ -38,10 +41,12 @@ import org.killbill.billing.payment.api.DefaultPaymentErrorEvent;
import org.killbill.billing.payment.api.DefaultPaymentInfoEvent;
import org.killbill.billing.payment.api.DefaultPaymentPluginErrorEvent;
import org.killbill.billing.payment.api.Payment;
+import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PaymentMethod;
import org.killbill.billing.payment.api.PaymentTransaction;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
import org.killbill.billing.util.cache.CacheControllerDispatcher;
import org.killbill.billing.util.callcontext.InternalCallContextFactory;
import org.killbill.billing.util.dao.NonEntityDao;
@@ -49,6 +54,7 @@ import org.killbill.billing.util.entity.Entity;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper;
import org.killbill.billing.util.entity.dao.DefaultPaginationSqlDaoHelper.PaginationIteratorBuilder;
+import org.killbill.billing.util.entity.dao.EntityDaoBase;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionWrapper;
import org.killbill.billing.util.entity.dao.EntitySqlDaoTransactionalJdbiWrapper;
import org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory;
@@ -66,11 +72,10 @@ import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-public class DefaultPaymentDao implements PaymentDao {
+public class DefaultPaymentDao extends EntityDaoBase<PaymentModelDao, Payment, PaymentApiException> implements PaymentDao {
private static final Logger log = LoggerFactory.getLogger(DefaultPaymentDao.class);
- private final EntitySqlDaoTransactionalJdbiWrapper transactionalSqlDao;
private final DefaultPaginationSqlDaoHelper paginationHelper;
private final PersistentBus eventBus;
private final Clock clock;
@@ -78,7 +83,7 @@ public class DefaultPaymentDao implements PaymentDao {
@Inject
public DefaultPaymentDao(final IDBI dbi, final Clock clock, final CacheControllerDispatcher cacheControllerDispatcher,
final NonEntityDao nonEntityDao, final InternalCallContextFactory internalCallContextFactory, final PersistentBus eventBus) {
- this.transactionalSqlDao = new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory);
+ super(new EntitySqlDaoTransactionalJdbiWrapper(dbi, clock, cacheControllerDispatcher, nonEntityDao, internalCallContextFactory), PaymentSqlDao.class);
this.paginationHelper = new DefaultPaginationSqlDaoHelper(transactionalSqlDao);
this.eventBus = eventBus;
this.clock = clock;
@@ -248,16 +253,20 @@ public class DefaultPaymentDao implements PaymentDao {
@Override
public Pagination<PaymentModelDao> searchPayments(final String searchKey, final Long offset, final Long limit, final InternalTenantContext context) {
+ // Optimization: if the search key looks like a state name (e.g. _ERRORED), assume the user is searching by state only
+ final List<String> paymentStates = shouldSearchByStateNameOnly(searchKey);
+
+ final String likeSearchKey = String.format("%%%s%%", searchKey);
return paginationHelper.getPagination(PaymentSqlDao.class,
new PaginationIteratorBuilder<PaymentModelDao, Payment, PaymentSqlDao>() {
@Override
public Long getCount(final PaymentSqlDao paymentSqlDao, final InternalTenantContext context) {
- return paymentSqlDao.getSearchCount(searchKey, String.format("%%%s%%", searchKey), context);
+ return !paymentStates.isEmpty() ? paymentSqlDao.getSearchByStateCount(paymentStates, context) : paymentSqlDao.getSearchCount(searchKey, likeSearchKey, context);
}
@Override
public Iterator<PaymentModelDao> build(final PaymentSqlDao paymentSqlDao, final Long limit, final InternalTenantContext context) {
- return paymentSqlDao.search(searchKey, String.format("%%%s%%", searchKey), offset, limit, context);
+ return !paymentStates.isEmpty() ? paymentSqlDao.searchByState(paymentStates, offset, limit, context) : paymentSqlDao.search(searchKey, likeSearchKey, offset, limit, context);
}
},
offset,
@@ -265,6 +274,20 @@ public class DefaultPaymentDao implements PaymentDao {
context);
}
+ private List<String> shouldSearchByStateNameOnly(final String searchKey) {
+ final Pattern pattern = Pattern.compile(".*" + searchKey + ".*");
+
+ // Note that technically, we should look at all of the available state names in the database instead since the state machine is configurable. The common use-case
+ // is to override transitions though, not to introduce new states, and since some of it is already hardcoded in PaymentStateMachineHelper anyways, it's probably good enough for now.
+ final List<String> stateNames = new ArrayList<String>();
+ for (final String stateName : PaymentStateMachineHelper.STATE_NAMES) {
+ if (pattern.matcher(stateName).matches()) {
+ stateNames.add(stateName);
+ }
+ }
+ return stateNames;
+ }
+
@Override
public PaymentModelDao insertPaymentWithFirstTransaction(final PaymentModelDao payment, final PaymentTransactionModelDao paymentTransaction, final InternalCallContext context) {
@@ -650,4 +673,9 @@ public class DefaultPaymentDao implements PaymentDao {
private InternalCallContext contextWithUpdatedDate(final InternalCallContext input) {
return new InternalCallContext(input, clock.getUTCNow());
}
+
+ @Override
+ protected PaymentApiException generateAlreadyExistsException(final PaymentModelDao entity, final InternalCallContext context) {
+ return new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, "Payment already exists");
+ }
}
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
index dc1f8f7..2c46e15 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentDao.java
@@ -24,11 +24,14 @@ import org.joda.time.DateTime;
import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
+import org.killbill.billing.payment.api.Payment;
+import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.entity.Pagination;
+import org.killbill.billing.util.entity.dao.EntityDao;
-public interface PaymentDao {
+public interface PaymentDao extends EntityDao<PaymentModelDao, Payment, PaymentApiException> {
public Pagination<PaymentTransactionModelDao> getByTransactionStatusAcrossTenants(final Iterable<TransactionStatus> transactionStatuses, DateTime createdBeforeDate, DateTime createdAfterDate, final Long offset, final Long limit);
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
index 0f5475b..23dcd3f 100644
--- a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentSqlDao.java
@@ -33,7 +33,6 @@ 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;
-import org.skife.jdbi.v2.sqlobject.customizers.Define;
@EntitySqlDaoStringTemplate
public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
@@ -69,6 +68,17 @@ public interface PaymentSqlDao extends EntitySqlDao<PaymentModelDao, Payment> {
@SqlQuery
@SmartFetchSize(shouldStream = true)
+ public Iterator<PaymentModelDao> searchByState(@PaymentStateCollectionBinder final Collection<String> paymentStates,
+ @Bind("offset") final Long offset,
+ @Bind("rowCount") final Long rowCount,
+ @BindBean final InternalTenantContext context);
+
+ @SqlQuery
+ public Long getSearchByStateCount(@PaymentStateCollectionBinder final Collection<String> paymentStates,
+ @BindBean final InternalTenantContext context);
+
+ @SqlQuery
+ @SmartFetchSize(shouldStream = true)
public Iterator<PaymentModelDao> getByPluginName(@Bind("pluginName") final String pluginName,
@Bind("offset") final Long offset,
@Bind("rowCount") final Long rowCount,
diff --git a/payment/src/main/java/org/killbill/billing/payment/dao/PaymentStateCollectionBinder.java b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentStateCollectionBinder.java
new file mode 100644
index 0000000..addde2a
--- /dev/null
+++ b/payment/src/main/java/org/killbill/billing/payment/dao/PaymentStateCollectionBinder.java
@@ -0,0 +1,57 @@
+/*
+ * 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
+ * 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.payment.dao;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collection;
+
+import org.killbill.billing.payment.dao.PaymentStateCollectionBinder.PaymentStateCollectionBinderFactory;
+import org.skife.jdbi.v2.SQLStatement;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+
+@BindingAnnotation(PaymentStateCollectionBinderFactory.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface PaymentStateCollectionBinder {
+
+ public static class PaymentStateCollectionBinderFactory implements BinderFactory {
+
+ @Override
+ public Binder build(final Annotation annotation) {
+ return new Binder<PaymentStateCollectionBinder, Collection<String>>() {
+
+ @Override
+ public void bind(final SQLStatement<?> query, final PaymentStateCollectionBinder bind, final Collection<String> allPaymentState) {
+ query.define("states", allPaymentState);
+
+ int idx = 0;
+ for (final String paymentState : allPaymentState) {
+ query.bind("state_" + idx, paymentState);
+ idx++;
+ }
+ }
+ };
+ }
+ }
+}
diff --git a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
index 6b110e9..bf30477 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
+++ b/payment/src/main/resources/org/killbill/billing/payment/dao/PaymentSqlDao.sql.stg
@@ -80,7 +80,33 @@ searchQuery(prefix) ::= <<
or <prefix>account_id = :searchKey
or <prefix>payment_method_id = :searchKey
or <prefix>external_key like :likeSearchKey
- or <prefix>state_name like :likeSearchKey
+>>
+
+searchByState(states) ::= <<
+select
+<allTableFields("t.")>
+from <tableName()> t
+join (
+ select <recordIdField()>
+ from <tableName()>
+ where state_name in (<states: {state | :state_<i0>}; separator="," >)
+ <AND_CHECK_TENANT()>
+ <andCheckSoftDeletionWithComma()>
+ order by <recordIdField()>
+ limit :rowCount offset :offset
+) optimization on <recordIdField("optimization.")> = <recordIdField("t.")>
+order by <recordIdField("t.")>
+;
+>>
+
+getSearchByStateCount(states) ::= <<
+select
+ count(1) as count
+from <tableName()> t
+where t.state_name in (<states: {state | :state_<i0>}; separator="," >)
+<andCheckSoftDeletionWithComma("t.")>
+<AND_CHECK_TENANT("t.")>
+;
>>
getByPluginName() ::= <<
diff --git a/payment/src/main/resources/org/killbill/billing/payment/ddl.sql b/payment/src/main/resources/org/killbill/billing/payment/ddl.sql
index 019e3cf..e994fa9 100644
--- a/payment/src/main/resources/org/killbill/billing/payment/ddl.sql
+++ b/payment/src/main/resources/org/killbill/billing/payment/ddl.sql
@@ -122,6 +122,7 @@ CREATE UNIQUE INDEX payments_id ON payments(id);
CREATE UNIQUE INDEX payments_key ON payments(external_key, tenant_record_id);
CREATE INDEX payments_accnt ON payments(account_id);
CREATE INDEX payments_tenant_account_record_id ON payments(tenant_record_id, account_record_id);
+CREATE INDEX payments_tenant_record_id_state_name ON payments(tenant_record_id, state_name);
DROP TABLE IF EXISTS payment_history;
diff --git a/payment/src/main/resources/org/killbill/billing/payment/migration/V20170123023324__add_payments_tenant_record_id_state_name_index.sql b/payment/src/main/resources/org/killbill/billing/payment/migration/V20170123023324__add_payments_tenant_record_id_state_name_index.sql
new file mode 100644
index 0000000..11ba386
--- /dev/null
+++ b/payment/src/main/resources/org/killbill/billing/payment/migration/V20170123023324__add_payments_tenant_record_id_state_name_index.sql
@@ -0,0 +1 @@
+alter table payments add index payments_tenant_record_id_state_name(tenant_record_id, state_name);
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
index 0798535..12ce2be 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/MockPaymentDao.java
@@ -34,16 +34,19 @@ import org.killbill.billing.callcontext.InternalCallContext;
import org.killbill.billing.callcontext.InternalTenantContext;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.dao.MockNonEntityDao;
+import org.killbill.billing.payment.api.Payment;
+import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
import org.killbill.billing.util.entity.DefaultPagination;
import org.killbill.billing.util.entity.Pagination;
+import org.killbill.billing.util.entity.dao.MockEntityDaoBase;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
-public class MockPaymentDao implements PaymentDao {
+public class MockPaymentDao extends MockEntityDaoBase<PaymentModelDao, Payment, PaymentApiException> implements PaymentDao {
private final Map<UUID, PaymentModelDao> payments = new HashMap<UUID, PaymentModelDao>();
private final Map<UUID, PaymentTransactionModelDao> transactions = new HashMap<UUID, PaymentTransactionModelDao>();
diff --git a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
index 4d6a938..35d2c42 100644
--- a/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
+++ b/payment/src/test/java/org/killbill/billing/payment/dao/TestDefaultPaymentDao.java
@@ -27,6 +27,7 @@ import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.payment.PaymentTestSuiteWithEmbeddedDB;
import org.killbill.billing.payment.api.TransactionStatus;
import org.killbill.billing.payment.api.TransactionType;
+import org.killbill.billing.payment.core.sm.PaymentStateMachineHelper;
import org.testng.Assert;
import org.testng.annotations.Test;
@@ -37,11 +38,11 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
@Test(groups = "slow")
public void testPaymentCRUD() throws Exception {
for (int i = 0; i < 3; i++) {
- testPaymentCRUDForAccount();
+ testPaymentCRUDForAccount(i + 1);
}
}
- public void testPaymentCRUDForAccount() throws Exception {
+ private void testPaymentCRUDForAccount(final int runNb) throws Exception {
final Account account = testHelper.createTestAccount(UUID.randomUUID().toString(), true);
final UUID accountId = account.getId();
@@ -68,8 +69,8 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
specifiedSecondPaymentTransactionModelDao.getAttemptId(),
specifiedSecondPaymentTransactionModelDao.getPaymentId(),
specifiedFirstPaymentTransactionModelDao.getTransactionType(),
- "SOME_ERRORED_STATE",
- "SOME_ERRORED_STATE",
+ PaymentStateMachineHelper.STATE_NAMES[0],
+ PaymentStateMachineHelper.STATE_NAMES[0],
specifiedSecondPaymentTransactionModelDao.getId(),
TransactionStatus.PAYMENT_FAILURE,
processedAmount,
@@ -99,6 +100,7 @@ public class TestDefaultPaymentDao extends PaymentTestSuiteWithEmbeddedDB {
// Verify search APIs
Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments(accountId.toString(), 0L, 100L, internalCallContext).iterator()).size(), 4);
+ Assert.assertEquals(ImmutableList.<PaymentModelDao>copyOf(paymentDao.searchPayments("_ERRORED", 0L, 100L, internalCallContext).iterator()).size(), runNb);
}
private void verifyPaymentAndTransactions(final InternalCallContext accountCallContext, final PaymentModelDao specifiedFirstPaymentModelDao, final PaymentTransactionModelDao... specifiedFirstPaymentTransactionModelDaos) {
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 d05e54e..6f35450 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
@@ -151,10 +151,15 @@ get(offset, rowCount, orderBy) ::= <<
select
<allTableFields("t.")>
from <tableName()> t
-where <CHECK_TENANT("t.")>
-<andCheckSoftDeletionWithComma("t.")>
+join (
+ select <recordIdField()>
+ from <tableName()>
+ where <CHECK_TENANT()>
+ <andCheckSoftDeletionWithComma()>
+ order by <orderBy>
+ limit :rowCount offset :offset
+) optimization on <recordIdField("optimization.")> = <recordIdField("t.")>
order by t.<orderBy>
-limit :rowCount offset :offset
;
>>
diff --git a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
index 7f1627c..cc50c48 100644
--- a/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
+++ b/util/src/test/java/org/killbill/billing/util/dao/TestStringTemplateInheritance.java
@@ -123,9 +123,14 @@ public class TestStringTemplateInheritance extends UtilTestSuiteNoDB {
", t.account_record_id\r?\n" +
", t.tenant_record_id\r?\n" +
"from kombucha t\r?\n" +
- "where t.tenant_record_id = :tenantRecordId\r?\n" +
+ "join \\(\r?\n" +
+ " select record_id\r?\n" +
+ " from kombucha\r?\n" +
+ " where tenant_record_id = :tenantRecordId\r?\n" +
+ " order by record_id\r?\n" +
+ " limit :rowCount offset :offset\r?\n" +
+ "\\) optimization on optimization.record_id = t.record_id\r?\n" +
"order by t.record_id\r?\n" +
- "limit :rowCount offset :offset\r?\n" +
";");
assertPattern(kombucha.getInstanceOf("test").toString(), "select\r?\n" +
" t.record_id\r?\n" +