<commit_before>/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 * 
 * 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 monasca.api.infrastructure.persistence.influxdb;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;
import javax.inject.Named;

import org.influxdb.InfluxDB;
import org.influxdb.dto.Serie;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.Query;
import org.skife.jdbi.v2.util.StringMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.google.inject.Inject;
import monasca.api.MonApiConfiguration;
import monasca.common.model.alarm.AlarmState;
import monasca.common.model.metric.MetricDefinition;
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistory;
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepository;
import monasca.api.infrastructure.persistence.DimensionQueries;
import monasca.api.infrastructure.persistence.SubAlarmQueries;

public class AlarmStateHistoryInfluxDbRepositoryImpl implements AlarmStateHistoryRepository {
  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  private static final TypeReference<List<MetricDefinition>> METRICS_TYPE =
      new TypeReference<List<MetricDefinition>>() {};
  private static final Logger logger = LoggerFactory
      .getLogger(AlarmStateHistoryInfluxDbRepositoryImpl.class);
  private static final String FIND_ALARMS_SQL =
      "select distinct ad.id from alarm_definition as ad "
          + "join sub_alarm_definition sad on ad.id = sad.alarm_definition_id "
          + "left outer join sub_alarm_definition_dimension dim on sad.id = dim.sub_alarm_definition_id%s "
          + "where ad.tenant_id = :tenantId and ad.deleted_at is NULL";

  private final MonApiConfiguration config;
  private final InfluxDB influxDB;
  private final DBI mysql;

  static {
    OBJECT_MAPPER
        .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
  }

  @Inject
  public AlarmStateHistoryInfluxDbRepositoryImpl(@Named("mysql") DBI mysql,
      MonApiConfiguration config, InfluxDB influxDB) {
    this.mysql = mysql;
    this.config = config;
    this.influxDB = influxDB;
  }

  @Override
  public List<AlarmStateHistory> findById(String tenantId, String alarmId) throws Exception {
    // InfluxDB orders queries by time stamp desc by default.
    String query = buildQueryForFindById(tenantId, alarmId);
    return queryInfluxDBForAlarmStateHistory(query);
  }

  String buildQueryForFindById(String tenantId, String alarmId) throws Exception {
    return String.format("select alarm_id, metrics, old_state, new_state, reason, reason_data "
        + "from alarm_state_history where tenant_id = '%1$s' and alarm_id = '%2$s'",
        Utils.SQLSanitizer.sanitize(tenantId), Utils.SQLSanitizer.sanitize(alarmId));
  }

  @Override
  public Collection<AlarmStateHistory> find(String tenantId, Map<String, String> dimensions,
      DateTime startTime, @Nullable DateTime endTime) throws Exception {

    List<String> alarmIds = null;
    // Find alarm Ids for dimensions
    try (Handle h = mysql.open()) {
      String sql = String.format(FIND_ALARMS_SQL, SubAlarmQueries.buildJoinClauseFor(dimensions));
      Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
      DimensionQueries.bindDimensionsToQuery(query, dimensions);
      alarmIds = query.map(StringMapper.FIRST).list();
    }

    if (alarmIds == null || alarmIds.isEmpty()) {
      return Collections.emptyList();
    }

    String timePart = buildTimePart(startTime, endTime);
    String alarmsPart = buildAlarmsPart(alarmIds);

    String query = buildQueryForFind(tenantId, timePart, alarmsPart);

    return queryInfluxDBForAlarmStateHistory(query);

  }

  String buildTimePart(DateTime startTime, DateTime endTime) {
    return Utils.WhereClauseBuilder.buildTimePart(startTime, endTime);
  }

  String buildQueryForFind(String tenantId, String timePart, String alarmsPart) throws Exception {
    return String.format("select alarm_id, metrics, old_state, new_state, reason, reason_data "
        + "from alarm_state_history where tenant_id = '%1$s' %2$s %3$s",
        Utils.SQLSanitizer.sanitize(tenantId), timePart, alarmsPart);
  }<commit_msg>Fix the query to get all the AlarmStateHistory objects<commit_after>/*
 * Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 * 
 * 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 monasca.api.infrastructure.persistence.influxdb;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;
import javax.inject.Named;

import org.influxdb.InfluxDB;
import org.influxdb.dto.Serie;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.skife.jdbi.v2.DBI;
import org.skife.jdbi.v2.Handle;
import org.skife.jdbi.v2.Query;
import org.skife.jdbi.v2.util.StringMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.google.inject.Inject;

import monasca.api.MonApiConfiguration;
import monasca.common.model.alarm.AlarmState;
import monasca.common.model.metric.MetricDefinition;
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistory;
import monasca.api.domain.model.alarmstatehistory.AlarmStateHistoryRepository;
import monasca.api.infrastructure.persistence.DimensionQueries;

public class AlarmStateHistoryInfluxDbRepositoryImpl implements AlarmStateHistoryRepository {
  private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
  private static final TypeReference<List<MetricDefinition>> METRICS_TYPE =
      new TypeReference<List<MetricDefinition>>() {};
  private static final Logger logger = LoggerFactory
      .getLogger(AlarmStateHistoryInfluxDbRepositoryImpl.class);
  private static final String FIND_ALARMS_SQL =
      "select distinct a.id from alarm as a "  +
      "join alarm_definition as ad on a.alarm_definition_id=ad.id " + 
      "%s " +
      "where ad.tenant_id = :tenantId and ad.deleted_at is NULL order by ad.created_at";
  private final MonApiConfiguration config;
  private final InfluxDB influxDB;
  private final DBI mysql;

  static {
    OBJECT_MAPPER
        .setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
  }

  @Inject
  public AlarmStateHistoryInfluxDbRepositoryImpl(@Named("mysql") DBI mysql,
      MonApiConfiguration config, InfluxDB influxDB) {
    this.mysql = mysql;
    this.config = config;
    this.influxDB = influxDB;
  }

  @Override
  public List<AlarmStateHistory> findById(String tenantId, String alarmId) throws Exception {
    // InfluxDB orders queries by time stamp desc by default.
    String query = buildQueryForFindById(tenantId, alarmId);
    return queryInfluxDBForAlarmStateHistory(query);
  }

  String buildQueryForFindById(String tenantId, String alarmId) throws Exception {
    return String.format("select alarm_id, metrics, old_state, new_state, reason, reason_data "
        + "from alarm_state_history where tenant_id = '%1$s' and alarm_id = '%2$s'",
        Utils.SQLSanitizer.sanitize(tenantId), Utils.SQLSanitizer.sanitize(alarmId));
  }

  @Override
  public Collection<AlarmStateHistory> find(String tenantId, Map<String, String> dimensions,
      DateTime startTime, @Nullable DateTime endTime) throws Exception {

    List<String> alarmIds = null;
    // Find alarm Ids for dimensions
    try (Handle h = mysql.open()) {
      final String sql =
          String.format(FIND_ALARMS_SQL, buildJoinClauseFor(dimensions));

      Query<Map<String, Object>> query = h.createQuery(sql).bind("tenantId", tenantId);
      logger.debug("AlarmStateHistory query '{}'", sql);
      DimensionQueries.bindDimensionsToQuery(query, dimensions);
      alarmIds = query.map(StringMapper.FIRST).list();
    }

    if (alarmIds == null || alarmIds.isEmpty()) {
      logger.debug("AlarmStateHistory no alarmIds");
      return Collections.emptyList();
    }

    logger.debug("AlarmStateHistory alarmIds {}", alarmIds);
    String timePart = buildTimePart(startTime, endTime);
    String alarmsPart = buildAlarmsPart(alarmIds);

    String query = buildQueryForFind(tenantId, timePart, alarmsPart);
    logger.debug("AlarmStateHistory query for influxdb '{}'", query);

    return queryInfluxDBForAlarmStateHistory(query);

  }

  private String buildJoinClauseFor(Map<String, String> dimensions) {
    if ((dimensions == null) || dimensions.isEmpty()) {
      return "";
    }
    final StringBuilder sbJoin = new StringBuilder("join alarm_metric as am on a.id=am.alarm_id ");
    sbJoin
        .append("join metric_definition_dimensions as mdd on am.metric_definition_dimensions_id=mdd.id ");
    for (int i = 0; i < dimensions.size(); i++) {
      final String tableAlias = "md" + i;
      sbJoin.append(" inner join metric_dimension ").append(tableAlias).append(" on ")
          .append(tableAlias).append(".name = :dname").append(i).append(" and ")
          .append(tableAlias).append(".value = :dvalue").append(i)
          .append(" and mdd.metric_dimension_set_id = ")
          .append(tableAlias).append(".dimension_set_id");
    }

    return sbJoin.toString();
  }

  String buildTimePart(DateTime startTime, DateTime endTime) {
    return Utils.WhereClauseBuilder.buildTimePart(startTime, endTime);
  }

  String buildQueryForFind(String tenantId, String timePart, String alarmsPart) throws Exception {
    return String.format("select alarm_id, metrics, old_state, new_state, reason, reason_data "
        + "from alarm_state_history where tenant_id = '%1$s' %2$s %3$s",
        Utils.SQLSanitizer.sanitize(tenantId), timePart, alarmsPart);
  }
{'fraction_non_alphanumeric': 0.09487315010570825, 'fraction_numerical': 0.003435517970401691, 'mean_word_length': 4.60641975308642, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4447300', 'n_tokens_mistral': 3429, 'n_tokens_neox': 3344, 'n_words': 831}