package org.rakam.analysis.abtesting;
import com.google.common.collect.ImmutableList;
import com.google.inject.name.Named;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.rakam.analysis.JDBCPoolDataSource;
import org.rakam.analysis.abtesting.ABTestingReport.Goal;
import org.rakam.analysis.abtesting.ABTestingReport.Variant;
import org.rakam.util.JsonHelper;
import org.rakam.util.RakamException;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.exceptions.UnableToExecuteStatementException;
import org.skife.jdbi.v2.tweak.ResultSetMapper;
import javax.inject.Inject;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
public class ABTestingMetastore {
private final DBI dbi;
private ResultSetMapper<ABTestingReport> mapper = (index, r, ctx) -> {
List<Variant> variants = Arrays.asList(JsonHelper.read(r.getString(4), Variant[].class));
Goal goals = Arrays.asList(JsonHelper.read(r.getString(7), Goal[].class)).get(0);
return new ABTestingReport(r.getInt(1), r.getString(3),
variants, r.getString(5), r.getString(6), goals, JsonHelper.read(r.getString(8)));
};
@Inject
public ABTestingMetastore(@Named("report.metadata.store.jdbc") JDBCPoolDataSource dataSource) {
dbi = new DBI(dataSource);
setup();
}
public void setup() {
try(Handle handle = dbi.open()) {
handle.createStatement("CREATE TABLE IF NOT EXISTS ab_testing (" +
" id SERIAL NOT NULL," +
" project VARCHAR(255) NOT NULL," +
" name VARCHAR(255) NOT NULL," +
" collection_name VARCHAR(255) NOT NULL," +
" connector_field VARCHAR(255) NOT NULL," +
" variants TEXT NOT NULL," +
" goals TEXT NOT NULL," +
" options TEXT," +
" PRIMARY KEY (id)" +
" )")
.execute();
}
}
public List<ABTestingReport> getReports(String project) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT id, name, variants, collection_name, connector_field, goals, options FROM " +
"public.ab_testing WHERE project = :project")
.bind("project", project).map(mapper).list();
}
}
public void delete(String project, int id) {
try(Handle handle = dbi.open()) {
handle.createStatement("DELETE FROM reports WHERE project = :project AND id = :id")
.bind("project", project).bind("id", id).execute();
}
}
public void save(String project, ABTestingReport report) {
if(report.id != -1) {
throw new RakamException("Report already has an id.", HttpResponseStatus.BAD_REQUEST);
}
try(Handle handle = dbi.open()) {
handle.createStatement("INSERT INTO ab_testing (project, name, variants, collection_name, connector_field, goals, options)" +
" VALUES (:project, :name, :variants, :collection_name, :goals, :options)")
.bind("project", project)
.bind("name", report.name)
.bind("collection_name", report.collectionName)
.bind("variants", JsonHelper.encode(report.variants))
.bind("goals", JsonHelper.encode(ImmutableList.of(report.goal)))
.bind("options", JsonHelper.encode(report.options, false))
.execute();
} catch (UnableToExecuteStatementException e) {
if(e.getCause() instanceof SQLException && ((SQLException) e.getCause()).getSQLState().equals("23505")) {
// TODO: replace
throw new RakamException("Report already exists", HttpResponseStatus.BAD_REQUEST);
}
}
}
public ABTestingReport get(String project, int id) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT id, name, variants, collection_name, connector_field, goals, options " +
"FROM ab_testing WHERE project = :project AND id = :id")
.bind("project", project)
.bind("id", id).map(mapper).first();
}
}
public ABTestingReport update(String project, ABTestingReport report) {
if(report.id == 1) {
throw new RakamException("Report doesn't have an id.", HttpResponseStatus.BAD_REQUEST);
}
try(Handle handle = dbi.open()) {
int execute = handle.createStatement("UPDATE reports SET name = :name, variants = :variants, collection_name = :collection_name, connector_field = :connector_field, goals = :goals, options = :options WHERE project = :project AND id = :id")
.bind("project", project)
.bind("id", report.id)
.bind("variants", report.variants)
.bind("connector_field", report.connectorField)
.bind("collection_name", report.collectionName)
.bind("goals", JsonHelper.encode(ImmutableList.of(report.goal)))
.bind("options", JsonHelper.encode(report.options, false))
.execute();
if(execute == 0) {
throw new RakamException("Report does not exist", HttpResponseStatus.BAD_REQUEST);
}
}
return report;
}
}