Пример #1
0
/////////////////////////////////////////////////
// struct FixedSizeRecord
//
Record FixedSizeRecord::GetRecord() const
{
    Record r;

    r.AddField(Field(Field::STB,       std::string(stb)));
    r.AddField(Field(Field::TITLE,     std::string(title)));
    r.AddField(Field(Field::PROVIDER,  std::string(provider)));
    r.AddField(Field(Field::DATE,      std::string(date)));
    r.AddField(Field(Field::REV,       dollars, cents));
    r.AddField(Field(Field::VIEW_TIME, hours, mins));

    return r;
}
Пример #2
0
void GroupOperation::Run(std::vector<Record> &vRecords)
{
    if (m_sGroupParam.empty())
        throw std::runtime_error("Group parameter (-g) expects an argument");

    //Only one group parameter supported by -g
    if (Utility::Tokenize(m_sGroupParam, ",:").size() > 1)
        throw std::runtime_error("Group parameter (-g) must be a single field");

    //First collect the "-s" params
    std::vector<std::string> const vSelectTokens(Utility::Tokenize(m_sSelectFields, ","));
    if (vSelectTokens.empty())
        throw std::runtime_error("Group feature (-g) cannot be used without a SELECT list (-s)");

    //The field we want to group by must be on the SELECT list, and must not be associated with an aggregate
    if (std::find(vSelectTokens.begin(), vSelectTokens.end(), m_sGroupParam) == vSelectTokens.end())
        throw std::runtime_error("Group field (" + m_sGroupParam + ") must be on the SELECT list (-s) and cannot have aggregates");

    //Now find aggregates associated with each SELECT field
    for (std::string const &s : vSelectTokens) {
        std::vector<std::string> const vNameValue(Utility::Tokenize(s, ":"));
        assert(!vNameValue.empty());

        if (vNameValue.size() == 2)
            m_vFieldToAggregate.emplace_back(Field::ToEnum(vNameValue.front()), GetAggregate(vNameValue.back()));
        else if (vNameValue.size() == 1)
            m_vFieldToAggregate.emplace_back(Field::ToEnum(vNameValue.front()), Aggregate::NONE);
        else
            throw std::runtime_error("Invalid aggregate: \"" + s + "\"");
    }

    //Exactly one field must be in the SELECT list without aggregates
    if (std::count_if(m_vFieldToAggregate.begin(), m_vFieldToAggregate.end(),
                      [](std::pair<Field::Name, Aggregate> const &p) { return (p.second == Aggregate::NONE); }) != 1)
        throw std::runtime_error("Exactly one field must be in the SELECT list (-s) without aggregates");

    //Now let's do real work!
    //Step 1: Group records by the "group-by" field
    Field::Name const groupByField(Field::ToEnum(m_sGroupParam));
    std::map<std::string, std::vector<Record>> mapGroupedRecords;
    for (Record const &rec : vRecords)
        mapGroupedRecords[rec.GetFieldValue(groupByField)].push_back(rec);

    std::vector<Record> vOutputRecords;

    //For each group of records...
    for (auto const &group : mapGroupedRecords) {
        std::vector<Record> const &groupRecords(group.second);

        Record newRecord;

        //For each aggregate...
        for (auto const &aggregate : m_vFieldToAggregate) {
            Field::Name const &name(aggregate.first);
            Aggregate   const &aggr(aggregate.second);

            //Step 2: Aggregate field values across records in a group
            Field const newField(PerformAggregation(groupRecords, name, aggr));
            newRecord.AddField(newField);
        }

        vOutputRecords.emplace_back(newRecord);
    }

    vRecords.swap(vOutputRecords);
}