@Override
    public List<DataRecord> visit(StagingBlockKey stagingBlockKey) {
      FieldMetadata blockField =
          new SimpleTypeFieldMetadata(
              explicitProjection,
              false,
              false,
              false,
              "blockKey", //$NON-NLS-1$
              new SimpleTypeMetadata(XMLConstants.W3C_XML_SCHEMA_NS_URI, Types.STRING),
              Collections.<String>emptyList(),
              Collections.<String>emptyList(),
              Collections.<String>emptyList(),
              StringUtils.EMPTY);
      lastField = blockField;
      recordProjection.put(
          blockField,
          new ValueBuilder() {

            @Override
            public Object getValue(DataRecord record) {
              return record
                  .getRecordMetadata()
                  .getRecordProperties()
                  .get(StagingStorage.METADATA_STAGING_BLOCK_KEY);
            }
          });
      return records;
    }
    @Override
    public List<DataRecord> visit(final Distinct distinct) {
      distinct.getExpression().accept(this);
      final ValueBuilder builder = recordProjection.remove(lastField);
      aggregateProjection.put(
          lastField,
          new AggregateValueBuilder() {

            @Override
            public Collection<Object> getValues(List<DataRecord> records) {
              Set<Object> distinctObjects = new HashSet<Object>();
              for (DataRecord record : records) {
                distinctObjects.add(builder.getValue(record));
              }
              return distinctObjects;
            }
          });
      return records;
    }
    @Override
    public List<DataRecord> visit(Field field) {
      lastField = field.getFieldMetadata();
      recordProjection.put(
          lastField,
          new ValueBuilder() {

            @Override
            public Object getValue(DataRecord record) {
              return record.get(lastField);
            }
          });
      return records;
    }
 @Override
 public List<DataRecord> visit(Alias alias) {
   alias.getTypedExpression().accept(this);
   FieldMetadata aliasField =
       new SimpleTypeFieldMetadata(
           explicitProjection,
           false,
           lastField.isMany(),
           lastField.isMandatory(),
           alias.getAliasName(),
           lastField.getType(),
           Collections.<String>emptyList(),
           Collections.<String>emptyList(),
           Collections.<String>emptyList(),
           StringUtils.EMPTY);
   ValueBuilder previousValueBuilder = recordProjection.remove(lastField);
   if (previousValueBuilder == null) {
     AggregateValueBuilder previous = aggregateProjection.remove(lastField);
     aggregateProjection.put(aliasField, previous);
   } else {
     recordProjection.put(aliasField, previousValueBuilder);
   }
   return records;
 }
 @Override
 public List<DataRecord> visit(Select select) {
   if (!select.isProjection()) {
     return records;
   } else {
     List<DataRecord> filteredRecords = new LinkedList<DataRecord>();
     for (TypedExpression expression : select.getSelectedFields()) {
       expression.accept(this);
     }
     if (!aggregateProjection.isEmpty()) {
       for (FieldMetadata fieldMetadata : aggregateProjection.keySet()) {
         explicitProjection.addField(fieldMetadata);
       }
       for (Map.Entry<FieldMetadata, AggregateValueBuilder> entry :
           aggregateProjection.entrySet()) {
         Collection<Object> aggregateValues = entry.getValue().getValues(records);
         for (Object aggregateValue : aggregateValues) {
           DataRecord newRecord =
               new DataRecord(explicitProjection, UnsupportedDataRecordMetadata.INSTANCE);
           newRecord.set(entry.getKey(), aggregateValue);
           filteredRecords.add(newRecord);
         }
       }
     } else if (!recordProjection.isEmpty()) {
       ComplexTypeMetadata explicitProjection =
           new ComplexTypeMetadataImpl("", "ExplicitProjectionType", true);
       for (FieldMetadata fieldMetadata : recordProjection.keySet()) {
         explicitProjection.addField(fieldMetadata);
       }
       for (DataRecord inputReport : records) {
         DataRecord newRecord =
             new DataRecord(explicitProjection, UnsupportedDataRecordMetadata.INSTANCE);
         for (Map.Entry<FieldMetadata, ValueBuilder> entry : recordProjection.entrySet()) {
           newRecord.set(entry.getKey(), entry.getValue().getValue(inputReport));
         }
       }
     }
     return filteredRecords;
   }
 }