// Path: src/main/java/org/cri/redmetrics/dao/PlayerDao.java
// public class PlayerDao extends EntityDao<Player> {
//     
//     @Inject
//     public PlayerDao(ConnectionSource connectionSource) throws SQLException {
//         super(connectionSource, Player.class);
//     }
// 
//     public Player findByEmail(String email) {
//         try {
//             if (email == null) return null;
//             List<Player> players = orm.queryForEq("email", email);
//             assert players.size() <= 1; // email should be unique
//             if (players.isEmpty()) return null;
//             else return players.get(0);
//         } catch (SQLException e) {
//             throw new DbException(e);
//         }
//     }
// 
// }
// 
// Path: src/main/java/org/cri/redmetrics/model/Snapshot.java
// @Data
// @DatabaseTable(tableName = "snapshots")
// @EqualsAndHashCode(callSuper = true)
// public class Snapshot extends ProgressData {
// 
// }


import au.com.bytecode.opencsv.CSVWriter;
import com.google.inject.Inject;
import org.cri.redmetrics.dao.PlayerDao;
import org.cri.redmetrics.model.Snapshot;
import java.util.List;
import java.util.Map;
                "playerCountry",
                "playerGender",
                "playerExternalId",
                "playerCustomData",
                "type",
                "section"
        };

        CsvHelper.UnpackedCustomData unpackedCustomData = CsvHelper.unpackCustomData(models);

        String[] customDataColumnNames = unpackedCustomData.columnNames.toArray(new String[0]);
        String[] allColumnNames = CsvHelper.concatenateArrays(staticColumnNames, customDataColumnNames);

        csvWriter.writeNext(allColumnNames);

        // Write out rows
        for(int i = 0; i < models.size(); i++) {
            Snapshot model = models.get(i);

            // We need to include additional fields of the player
            // OPT: does this force a new request each time? if so we should join automatically
            playerDao.refresh(model.getPlayer());

            String[] staticRowValues = {
                    model.getId().toString(),
                    CsvHelper.formatDate(model.getServerTime()),
                    CsvHelper.formatDate(model.getUserTime()),
                    model.getGameVersion().getId().toString(),
                    model.getPlayer().getId().toString(),
                    CsvHelper.formatDate(model.getPlayer().getBirthDate()),
// Path: src/main/java/org/cri/redmetrics/dao/PlayerDao.java
// public class PlayerDao extends EntityDao<Player> {
//     
//     @Inject
//     public PlayerDao(ConnectionSource connectionSource) throws SQLException {
//         super(connectionSource, Player.class);
//     }
// 
//     public Player findByEmail(String email) {
//         try {
//             if (email == null) return null;
//             List<Player> players = orm.queryForEq("email", email);
//             assert players.size() <= 1; // email should be unique
//             if (players.isEmpty()) return null;
//             else return players.get(0);
//         } catch (SQLException e) {
//             throw new DbException(e);
//         }
//     }
// 
// }
// 
// Path: src/main/java/org/cri/redmetrics/model/Snapshot.java
// @Data
// @DatabaseTable(tableName = "snapshots")
// @EqualsAndHashCode(callSuper = true)
// public class Snapshot extends ProgressData {
// 
// }


// Path: src/main/java/org/cri/redmetrics/csv/SnapshotCsvEntityConverter.java
import au.com.bytecode.opencsv.CSVWriter;
import com.google.inject.Inject;
import org.cri.redmetrics.dao.PlayerDao;
import org.cri.redmetrics.model.Snapshot;
import java.util.List;
import java.util.Map;

                "playerCountry",
                "playerGender",
                "playerExternalId",
                "playerCustomData",
                "type",
                "section"
        };

        CsvHelper.UnpackedCustomData unpackedCustomData = CsvHelper.unpackCustomData(models);

        String[] customDataColumnNames = unpackedCustomData.columnNames.toArray(new String[0]);
        String[] allColumnNames = CsvHelper.concatenateArrays(staticColumnNames, customDataColumnNames);

        csvWriter.writeNext(allColumnNames);

        // Write out rows
        for(int i = 0; i < models.size(); i++) {
            Snapshot model = models.get(i);

            // We need to include additional fields of the player
            // OPT: does this force a new request each time? if so we should join automatically
            playerDao.refresh(model.getPlayer());

            String[] staticRowValues = {
                    model.getId().toString(),
                    CsvHelper.formatDate(model.getServerTime()),
                    CsvHelper.formatDate(model.getUserTime()),
                    model.getGameVersion().getId().toString(),
                    model.getPlayer().getId().toString(),
                    CsvHelper.formatDate(model.getPlayer().getBirthDate()),
                    model.getPlayer().getRegion(),