class ElasticsearchQueryStore implements QueryStore {

    @Override
    @Timed
    public void save(String table, Document document) {
        table = ElasticsearchUtils.getValidTableName(table);
        Stopwatch stopwatch = Stopwatch.createStarted();
        String action = StringUtils.EMPTY;
        try {
            if(!tableMetadataManager.exists(table)) {
                throw FoxtrotExceptions.createBadRequestException(table, String.format(UNKNOWN_TABLE_ERROR_MESSAGE, table));
            }
            if(new DateTime().plusDays(1)
                       .minus(document.getTimestamp())
                       .getMillis() < 0) {
                return;
            }
            action = TABLE_META;
            stopwatch.reset()
                    .start();
            final Table tableMeta = tableMetadataManager.get(table);
            logger.debug("TableMetaGetTook:{}", stopwatch.elapsed(TimeUnit.MILLISECONDS));

            MetricUtil.getInstance()
                    .registerActionSuccess(action, table, stopwatch.elapsed(TimeUnit.MILLISECONDS));
            stopwatch.reset()
                    .start();

            action = DATA_STORE;
            final Document translatedDocument = dataStore.save(tableMeta, document);
            logger.debug("DataStoreTook:{}", stopwatch.elapsed(TimeUnit.MILLISECONDS));

            MetricUtil.getInstance()
                    .registerActionSuccess(action, table, stopwatch.elapsed(TimeUnit.MILLISECONDS));
            stopwatch.reset()
                    .start();

            action = QUERY_STORE;
            long timestamp = translatedDocument.getTimestamp();
            connection.getClient()
                    .prepareIndex()
                    .setIndex(ElasticsearchUtils.getCurrentIndex(table, timestamp))
                    .setType(ElasticsearchUtils.DOCUMENT_TYPE_NAME)
                    .setId(translatedDocument.getId())
                    .setSource(convert(table, translatedDocument))
                    .execute()
                    .get(2, TimeUnit.SECONDS);
            logger.debug("QueryStoreTook:{}", stopwatch.elapsed(TimeUnit.MILLISECONDS));

            MetricUtil.getInstance()
                    .registerActionSuccess(action, table, stopwatch.elapsed(TimeUnit.MILLISECONDS));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            MetricUtil.getInstance()
                    .registerActionFailure(action, table, stopwatch.elapsed(TimeUnit.MILLISECONDS));
            Thread.currentThread()
                    .interrupt();
            throw FoxtrotExceptions.createExecutionException(table, e);
        }
    }

    @Inject public  ElasticsearchQueryStore(TableMetadataManager tableMetadataManager,
                                   ElasticsearchConnection connection,
                                   DataStore dataStore,
                                   List<IndexerEventMutator> mutators,
                                   ObjectMapper mapper,
                                   CardinalityConfig cardinalityConfig);

}