package org.gcube.accounting.analytics.persistence.postgresql; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.HashSet; import java.util.List; import java.util.Set; import org.gcube.accounting.analytics.Filter; import org.gcube.accounting.analytics.TemporalConstraint; import org.gcube.accounting.analytics.TemporalConstraint.AggregationMode; import org.gcube.accounting.analytics.TemporalConstraint.CalendarEnum; import org.gcube.accounting.datamodel.UsageRecord; import org.gcube.accounting.datamodel.aggregation.AggregatedServiceUsageRecord; import org.gcube.accounting.datamodel.aggregation.AggregatedStorageStatusRecord; import org.gcube.accounting.utility.postgresql.PostgreSQLQuery; import org.gcube.accounting.utility.postgresql.RecordToDBFields; import org.gcube.accounting.utility.postgresql.RecordToDBMapping; import org.gcube.documentstore.records.AggregatedRecord; public class Query extends PostgreSQLQuery { public static final String DATE_OF_TIMESERIES_AS_FIELD = AggregatedRecord.START_TIME; private Class> clz; private final RecordToDBFields recordToDBFields; private List requestedTableField; protected TemporalConstraint temporalConstraint; protected List filters; protected Set contexts; private String tableFieldToRequest; private String orderByField; private Integer limit; private String recordId; protected Set providersId; public Query(Class> clz) throws Exception { this.clz = clz; this.recordToDBFields = RecordToDBMapping.getRecordToDBFields(clz); } public List getRequestedTableField() { return requestedTableField; } public void setTemporalConstraint(TemporalConstraint temporalConstraint) { this.temporalConstraint = temporalConstraint; } public void setFilters(List filters) { this.filters = filters; } public void setContexts(Set contexts) { this.contexts = contexts; } public void setTableFieldToRequest(String tableFieldToRequest) { this.tableFieldToRequest = tableFieldToRequest; } public void setOrderByField(String orderByField) { this.orderByField = orderByField; } public void setLimit(Integer limit) { this.limit = limit; } public void addContext(String context) { if(this.contexts == null) { this.contexts = new HashSet<>(); } this.contexts.add(context); } public void setRecordId(String recordId) { this.recordId = recordId; } public void addProvidersId(String providerId) { if(providersId == null) { providersId = new HashSet<>(); } providersId.add(providerId); } public void setProvidersId(List providersId) { this.providersId = new HashSet<>(providersId); } public RecordToDBFields getRecordToDBMapper() { return recordToDBFields; } protected String getTableField(String fieldName) { return recordToDBFields.getTableField(fieldName); } protected void appendTableField(String fieldName) { stringBuffer.append(getTableField(fieldName)); } public static String getFormattedDate(Calendar calendar) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATETIME_PATTERN); String date = simpleDateFormat.format(calendar.getTime()); return date; } protected void addFilters() { if(filters!=null && filters.size()>0) { // The first filter if the time_bucket stringBuffer.append(" AND "); boolean first = true; for(Filter filter : filters) { if(first) { first = false; }else { stringBuffer.append(" AND "); } appendTableField(filter.getKey()); stringBuffer.append("="); appendValue(filter.getValue()); } } } protected void addContextFilter() { if(contexts!=null && contexts.size()>0) { // The first filter if the time_bucket stringBuffer.append(" AND ("); boolean first = true; for(String context : contexts) { if(first) { first = false; }else { stringBuffer.append(" OR "); } appendTableField(UsageRecord.SCOPE); stringBuffer.append("="); appendValue(context); } stringBuffer.append(")"); } } protected void addProvidersIdFilter() { if(providersId!=null && providersId.size()>0) { // The first filter if the time_bucket stringBuffer.append(" AND ("); boolean first = true; for(String providerId : providersId) { if(first) { first = false; }else { stringBuffer.append(" OR "); } appendTableField(AggregatedStorageStatusRecord.PROVIDER_ID); stringBuffer.append("="); appendValue(providerId); } stringBuffer.append(")"); } } protected void addEmittedFields() throws Exception { Set aggregatedField = clz.newInstance().getAggregatedFields(); for(String fieldName : aggregatedField) { String dbField = getTableField(fieldName); switch (fieldName) { case AggregatedRecord.START_TIME: case AggregatedRecord.END_TIME: case AggregatedRecord.AGGREGATED: continue; case AggregatedRecord.OPERATION_COUNT: stringBuffer.append(", SUM("); stringBuffer.append(dbField); stringBuffer.append(") AS "); break; // WEIGHTED AVERAGE case AggregatedServiceUsageRecord.DURATION: stringBuffer.append(", ROUND(SUM("); stringBuffer.append(dbField); stringBuffer.append("*"); appendTableField(AggregatedRecord.OPERATION_COUNT); stringBuffer.append(")/SUM("); appendTableField(AggregatedRecord.OPERATION_COUNT); stringBuffer.append(")) AS "); break; case AggregatedServiceUsageRecord.MAX_INVOCATION_TIME: stringBuffer.append(", MAX("); stringBuffer.append(dbField); stringBuffer.append(") AS "); break; case AggregatedServiceUsageRecord.MIN_INVOCATION_TIME: stringBuffer.append(", MIN("); stringBuffer.append(dbField); stringBuffer.append(") AS "); break; default: stringBuffer.append(", "); break; } stringBuffer.append(dbField); requestedTableField.add(dbField); } } protected String getTimeBucketCalendarInterval(AggregationMode aggregationMode) { CalendarEnum calendarEnum = CalendarEnum.values()[aggregationMode.ordinal()]; return calendarEnum.name().toLowerCase(); } protected void addRequestedDate() { stringBuffer.append("date_trunc('"); String calendarInterval = getTimeBucketCalendarInterval(temporalConstraint.getAggregationMode()); stringBuffer.append(calendarInterval); stringBuffer.append("', "); appendTableField(AggregatedRecord.START_TIME); stringBuffer.append(") "); stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD); requestedTableField.add(DATE_OF_TIMESERIES_AS_FIELD); } private void newQuery() { stringBuffer = new StringBuffer(); requestedTableField = new ArrayList<>(); stringBuffer.append("SELECT "); } protected void addTemporalConstraintToQuery() { stringBuffer.append(" WHERE "); String tableField = getTableField(AggregatedRecord.START_TIME); stringBuffer.append(tableField); stringBuffer.append(" > "); appendValue(temporalConstraint.getAlignedStartTime()); stringBuffer.append(" AND "); stringBuffer.append(tableField); stringBuffer.append(" < "); appendValue(temporalConstraint.getAlignedEndTime()); } protected void addDateGropuBy() { stringBuffer.append(" GROUP BY "); stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD); } protected void addDateOrderBy() { stringBuffer.append(" ORDER BY "); stringBuffer.append(DATE_OF_TIMESERIES_AS_FIELD); stringBuffer.append(" ASC"); } protected void addGroupAndOrderByForOrderByField() { stringBuffer.append(" GROUP BY "); String dbField = getTableField(tableFieldToRequest); stringBuffer.append(dbField); stringBuffer.append(" ORDER BY "); stringBuffer.append(orderByField); stringBuffer.append(" DESC"); } protected void addLimit() { stringBuffer.append(" LIMIT "); if(limit != null) { stringBuffer.append(limit.toString()); }else { stringBuffer.append(50); } } protected void addRequestedField() { String dbField = getTableField(tableFieldToRequest); stringBuffer.append(dbField); requestedTableField.add(dbField); stringBuffer.append(", SUM("); dbField = getTableField(orderByField); stringBuffer.append(dbField); requestedTableField.add(dbField); stringBuffer.append(") AS "); stringBuffer.append(orderByField); } public String getTimeSeriesQuery() throws Exception { newQuery(); addRequestedDate(); addEmittedFields(); stringBuffer.append(" FROM "); stringBuffer.append(recordToDBFields.getTableName()); addTemporalConstraintToQuery(); addFilters(); addContextFilter(); addDateGropuBy(); addDateOrderBy(); return stringBuffer.toString(); } public String getSpaceTimeSeries() { newQuery(); addRequestedDate(); stringBuffer.append(" FROM "); stringBuffer.append(recordToDBFields.getTableName()); addTemporalConstraintToQuery(); addFilters(); addProvidersIdFilter(); addDateGropuBy(); addDateOrderBy(); return stringBuffer.toString(); } public String getNextPossibleValueQuery() throws Exception { newQuery(); addRequestedField(); stringBuffer.append(" FROM "); stringBuffer.append(recordToDBFields.getTableName()); addTemporalConstraintToQuery(); addFilters(); addContextFilter(); addGroupAndOrderByForOrderByField(); addLimit(); return stringBuffer.toString(); } public String getRecordQuery(){ newQuery(); stringBuffer.append("* "); stringBuffer.append(" FROM "); stringBuffer.append(recordToDBFields.getTableName()); stringBuffer.append(" WHERE "); stringBuffer.append(" id="); appendString(recordId); return stringBuffer.toString(); } public String getDinstinctValuesQuery() { newQuery(); String dbField = getTableField(tableFieldToRequest); requestedTableField.add(dbField); stringBuffer.append("DISTINCT "); stringBuffer.append(dbField); stringBuffer.append(" FROM "); stringBuffer.append(recordToDBFields.getTableName()); return stringBuffer.toString(); } }