killbill-memoizeit
Changes
analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountSqlDao.sql.stg 13(+13 -0)
Details
diff --git a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
index cbd652d..691eb33 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/api/user/DefaultAnalyticsUserApi.java
@@ -45,6 +45,11 @@ public class DefaultAnalyticsUserApi implements AnalyticsUserApi {
return analyticsDao.getAccountsCreatedOverTime();
}
+ @Override
+ public TimeSeriesData getSubscriptionsCreatedOverTime(final String productType, final String slug) {
+ return analyticsDao.getSubscriptionsCreatedOverTime(productType, slug);
+ }
+
// Note: the following is not exposed in api yet, as the models need to be extracted first
public BusinessAccount getAccountByKey(final String accountKey) {
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
index d4ae76e..165d087 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/AnalyticsDao.java
@@ -31,6 +31,8 @@ public interface AnalyticsDao {
TimeSeriesData getAccountsCreatedOverTime();
+ TimeSeriesData getSubscriptionsCreatedOverTime(final String productType, final String slug);
+
BusinessAccount getAccountByKey(final String accountKey);
List<BusinessSubscriptionTransition> getTransitionsByKey(final String externalKey);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountSqlDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountSqlDao.java
index d2c6d2e..b538d04 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountSqlDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/BusinessAccountSqlDao.java
@@ -36,6 +36,10 @@ public interface BusinessAccountSqlDao extends Transactional<BusinessAccountSqlD
List<TimeSeriesTuple> getAccountsCreatedOverTime();
@SqlQuery
+ List<TimeSeriesTuple> getSubscriptionsCreatedOverTime(@Bind("product_type") final String productType,
+ @Bind("slug") final String slug);
+
+ @SqlQuery
BusinessAccount getAccount(@Bind("account_id") final String accountId);
@SqlQuery
diff --git a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
index 0918673..fe4fe6e 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/dao/DefaultAnalyticsDao.java
@@ -63,6 +63,11 @@ public class DefaultAnalyticsDao implements AnalyticsDao {
}
@Override
+ public TimeSeriesData getSubscriptionsCreatedOverTime(final String productType, final String slug) {
+ return new DefaultTimeSeriesData(accountSqlDao.getSubscriptionsCreatedOverTime(productType, slug));
+ }
+
+ @Override
public BusinessAccount getAccountByKey(final String accountKey) {
return accountSqlDao.getAccountByKey(accountKey);
}
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscription.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscription.java
index 86b6244..18d85cc 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscription.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscription.java
@@ -41,6 +41,7 @@ import static com.ning.billing.entitlement.api.user.Subscription.SubscriptionSta
* Describe a subscription for Analytics purposes
*/
public class BusinessSubscription {
+
private static final Logger log = LoggerFactory.getLogger(BusinessSubscription.class);
private static final BigDecimal DAYS_IN_MONTH = BigDecimal.valueOf(30);
diff --git a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionEvent.java b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionEvent.java
index b529559..eac9c07 100644
--- a/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionEvent.java
+++ b/analytics/src/main/java/com/ning/billing/analytics/model/BusinessSubscriptionEvent.java
@@ -32,6 +32,7 @@ import static com.ning.billing.entitlement.api.user.Subscription.SubscriptionSta
* Describe an event associated with a transition between two BusinessSubscription
*/
public class BusinessSubscriptionEvent {
+
private static final Logger log = LoggerFactory.getLogger(BusinessSubscriptionEvent.class);
private static final String MISC = "MISC";
diff --git a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountSqlDao.sql.stg b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountSqlDao.sql.stg
index c6b9195..a253aea 100644
--- a/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountSqlDao.sql.stg
+++ b/analytics/src/main/resources/com/ning/billing/analytics/dao/BusinessAccountSqlDao.sql.stg
@@ -11,6 +11,19 @@ getAccountsCreatedOverTime() ::= <<
;
>>
+getSubscriptionsCreatedOverTime(product_type, slug) ::= <<
+ select
+ date(from_unixtime(requested_timestamp / 1000)) day
+ , count(record_id) count
+ from bst
+ where event in ('ADD_ADD_ON', 'ADD_BASE', 'ADD_STANDALONE')
+ and next_product_type = :product_type
+ and next_slug = :slug
+ group by 1
+ order by 1
+ ;
+>>
+
getAccount(account_id) ::= <<
select
account_id
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
index 1b7ef04..45ef9b9 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/user/TestDefaultAnalyticsUserApi.java
@@ -19,13 +19,18 @@ package com.ning.billing.analytics.api.user;
import java.math.BigDecimal;
import java.util.UUID;
+import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.mockito.Mockito;
import org.skife.jdbi.v2.IDBI;
import org.testng.Assert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import com.ning.billing.analytics.AnalyticsTestSuiteWithEmbeddedDB;
+import com.ning.billing.analytics.MockDuration;
+import com.ning.billing.analytics.MockPhase;
+import com.ning.billing.analytics.MockProduct;
import com.ning.billing.analytics.api.TimeSeriesData;
import com.ning.billing.analytics.dao.AnalyticsDao;
import com.ning.billing.analytics.dao.BusinessAccountSqlDao;
@@ -37,6 +42,18 @@ import com.ning.billing.analytics.dao.BusinessOverdueStatusSqlDao;
import com.ning.billing.analytics.dao.BusinessSubscriptionTransitionSqlDao;
import com.ning.billing.analytics.dao.DefaultAnalyticsDao;
import com.ning.billing.analytics.model.BusinessAccount;
+import com.ning.billing.analytics.model.BusinessSubscription;
+import com.ning.billing.analytics.model.BusinessSubscriptionEvent;
+import com.ning.billing.analytics.model.BusinessSubscriptionTransition;
+import com.ning.billing.catalog.api.Catalog;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.mock.MockPlan;
import com.ning.billing.util.clock.Clock;
import com.ning.billing.util.clock.ClockMock;
@@ -81,4 +98,38 @@ public class TestDefaultAnalyticsUserApi extends AnalyticsTestSuiteWithEmbeddedD
Assert.assertEquals(data.getValues().size(), 1);
Assert.assertEquals(data.getValues().get(0), (double) 1);
}
+
+ @Test(groups = "slow")
+ public void testSubscriptionsCreatedOverTime() throws Exception {
+ final String productType = "subscription";
+ final Product product = new MockProduct("platinum", productType, ProductCategory.BASE);
+ final Plan plan = new MockPlan("platinum-monthly", product);
+ final PlanPhase phase = new MockPhase(PhaseType.TRIAL, plan, MockDuration.UNLIMITED(), 25.95);
+ final Catalog catalog = Mockito.mock(Catalog.class);
+ Mockito.when(catalog.findPlan(Mockito.anyString(), Mockito.<DateTime>any(), Mockito.<DateTime>any())).thenReturn(plan);
+ Mockito.when(catalog.findPhase(Mockito.anyString(), Mockito.<DateTime>any(), Mockito.<DateTime>any())).thenReturn(phase);
+ final BusinessSubscriptionTransition transition = new BusinessSubscriptionTransition(
+ 3L,
+ UUID.randomUUID(),
+ UUID.randomUUID().toString(),
+ UUID.randomUUID(),
+ UUID.randomUUID().toString(),
+ UUID.randomUUID(),
+ clock.getUTCNow(),
+ BusinessSubscriptionEvent.subscriptionCreated(plan.getName(), catalog, clock.getUTCNow(), clock.getUTCNow()),
+ null,
+ new BusinessSubscription("DEFAULT", plan.getName(), phase.getName(), Currency.USD, clock.getUTCNow(), Subscription.SubscriptionState.ACTIVE, catalog)
+ );
+ subscriptionTransitionSqlDao.createTransition(transition);
+
+ final TimeSeriesData notFoundData = analyticsUserApi.getSubscriptionsCreatedOverTime(productType, UUID.randomUUID().toString());
+ Assert.assertEquals(notFoundData.getDates().size(), 0);
+ Assert.assertEquals(notFoundData.getValues().size(), 0);
+
+ final TimeSeriesData data = analyticsUserApi.getSubscriptionsCreatedOverTime(productType, phase.getName());
+ Assert.assertEquals(data.getDates().size(), 1);
+ Assert.assertEquals(data.getDates().get(0), new LocalDate());
+ Assert.assertEquals(data.getValues().size(), 1);
+ Assert.assertEquals(data.getValues().get(0), (double) 1);
+ }
}
diff --git a/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java b/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
index 26a2480..dc79d9a 100644
--- a/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
+++ b/api/src/main/java/com/ning/billing/analytics/api/user/AnalyticsUserApi.java
@@ -24,4 +24,11 @@ public interface AnalyticsUserApi {
* @return the number of accounts created per day
*/
public TimeSeriesData getAccountsCreatedOverTime();
+
+ /**
+ * @param productType catalog name
+ * @param slug plan phase name, as returned by PlanPhase#getName()
+ * @return the number of new subscriptions created per day (transfers not included)
+ */
+ public TimeSeriesData getSubscriptionsCreatedOverTime(final String productType, final String slug);
}
diff --git a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
index fbc3623..f0df8ac 100644
--- a/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
+++ b/jaxrs/src/main/java/com/ning/billing/jaxrs/resources/AnalyticsResource.java
@@ -20,6 +20,7 @@ import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -50,4 +51,14 @@ public class AnalyticsResource {
final TimeSeriesDataJson json = new TimeSeriesDataJson(data);
return Response.status(Status.OK).entity(json).build();
}
+
+ @GET
+ @Path("/subscriptionsCreatedOverTime")
+ @Produces(APPLICATION_JSON)
+ public Response getSubscriptionsCreatedOverTime(@QueryParam("productType") final String productType,
+ @QueryParam("slug") final String slug) {
+ final TimeSeriesData data = analyticsUserApi.getSubscriptionsCreatedOverTime(productType, slug);
+ final TimeSeriesDataJson json = new TimeSeriesDataJson(data);
+ return Response.status(Status.OK).entity(json).build();
+ }
}