/*
* Licensed 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.rakam.ui.customreport;
import com.google.inject.name.Named;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.rakam.util.AlreadyExistsException;
import org.rakam.analysis.JDBCPoolDataSource;
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.util.StringMapper;
import javax.inject.Inject;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class JDBCCustomReportMetadata implements CustomReportMetadata {
private final DBI dbi;
@Inject
public JDBCCustomReportMetadata(@Named("ui.metadata.jdbc") JDBCPoolDataSource dataSource) {
dbi = new DBI(dataSource);
createIndexIfNotExists();
}
private void createIndexIfNotExists() {
try(Handle handle = dbi.open()) {
handle.createStatement("CREATE INDEX report_type_idx ON custom_reports(report_type, project)")
.execute();
} catch (UnableToExecuteStatementException e) {
// IF NOT EXIST feature is not supported by majority of RDBMSs.
// Since this INDEX is optional, swallow exception
// since the exception is probably about duplicate indexes.
}
}
@Override
public void save(Integer user, int project, CustomReport report) {
try(Handle handle = dbi.open()) {
handle.createStatement("INSERT INTO custom_reports (report_type, project_id, name, data, user_id) VALUES (:reportType, :project, :name, :data, :user)")
.bind("reportType", report.reportType)
.bind("project", project)
.bind("name", report.name)
.bind("user", user)
.bind("data", JsonHelper.encode(report.data)).execute();
} catch (Exception e) {
// TODO move it to transaction
if (get(report.reportType, project, report.name) != null) {
throw new AlreadyExistsException("Custom report", HttpResponseStatus.BAD_REQUEST);
}
throw e;
}
}
@Override
public CustomReport get(String reportType, int project, String name) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT data FROM custom_reports WHERE report_type = :reportType AND project_id = :project AND name = :name")
.bind("reportType", reportType)
.bind("project", project)
.bind("name", name)
.map((i, resultSet, statementContext) -> {
return new CustomReport(reportType, name, JsonHelper.read(resultSet.getString(1)));
}).first();
}
}
@Override
public List<CustomReport> list(String reportType, int project) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT name, data, user_id FROM custom_reports WHERE report_type = :reportType AND project_id = :project")
.bind("reportType", reportType)
.bind("project", project)
.map((i, resultSet, statementContext) -> {
return new CustomReport(reportType, resultSet.getString(1), resultSet.getInt(3), JsonHelper.read(resultSet.getString(2)));
}).list();
}
}
@Override
public Map<String, List<CustomReport>> list(int project) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT report_type, name, data, user_id FROM custom_reports WHERE project_id = :project")
.bind("project", project)
.map((i, resultSet, statementContext) -> {
return new CustomReport(resultSet.getString(1), resultSet.getString(2), resultSet.getInt(4), JsonHelper.read(resultSet.getString(3)));
}).list().stream().collect(Collectors.groupingBy(customReport -> customReport.reportType));
}
}
@Override
public void delete(String reportType, int project, String name) {
try(Handle handle = dbi.open()) {
handle.createStatement("DELETE FROM custom_reports WHERE report_type = :reportType AND project_id = :project AND name = :name")
.bind("reportType", reportType)
.bind("project", project)
.bind("name", name).execute();
}
}
@Override
public void update(int project, CustomReport report) {
int execute;
try(Handle handle = dbi.open()) {
execute = handle.createStatement("UPDATE custom_reports SET data = :data WHERE report_type = :reportType AND name = :name AND project_id = :project")
.bind("reportType", report.reportType)
.bind("project", project)
.bind("name", report.name)
.bind("data", JsonHelper.encode(report.data)).execute();
}
if(execute == 0) {
throw new RakamException("Report does not exist.", HttpResponseStatus.BAD_REQUEST);
}
}
@Override
public List<String> types(int project) {
try(Handle handle = dbi.open()) {
return handle.createQuery("SELECT DISTINCT report_type FROM custom_reports WHERE project_id = :project")
.bind("project", project)
.map(StringMapper.FIRST).list();
}
}
}