/// Otherwise, this function will write the header to the file.
/// In order to write rows to opened file, the @c append function
/// should be called.
- void recreate();
+ virtual void recreate();
/// @brief Sets error message after row validation.
///
ASSERT_NO_THROW(csv->recreate());
ASSERT_TRUE(exists());
+ // We should have 3 defined columns
+ EXPECT_EQ(3, csv->getColumnCount());
+
+ // Number valid columns should match defined columns
+ EXPECT_EQ(3, csv->getValidColumnCount());
+
+ // Minium valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Upgrade flag should be false
+ EXPECT_EQ(false, csv->needsUpgrading());
+
+ // Schema versions for new files should always match
+ EXPECT_EQ("3.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("3.0", csv->getSchemaVersion());
+
// Make sure we can't add columns (even unique) when the file is open.
ASSERT_THROW(csv->addColumn("zoo", "3.0", ""), CSVFileError);
// Header should pass validation and allow the open to succeed.
ASSERT_NO_THROW(csv->open());
+ // We should have 2 defined columns
+ EXPECT_EQ(2, csv->getColumnCount());
+
+ // We should have found 1 valid column in the header
+ EXPECT_EQ(1, csv->getValidColumnCount());
+
+ // Minium valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Upgrade flag should be true
+ EXPECT_EQ(true, csv->needsUpgrading());
+
+ // Input schema should be 1.0, while our current schema should be 2.0
+ EXPECT_EQ("1.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("2.0", csv->getSchemaVersion());
+
// First row is correct.
CSVRow row;
ASSERT_TRUE(csv->next(row));
// Header should pass validation and allow the open to succeed
ASSERT_NO_THROW(csv->open());
- ASSERT_EQ(3, csv->getColumnCount());
+
+ // We should have 2 defined columns
+ EXPECT_EQ(3, csv->getColumnCount());
+
+ // We should have found 1 valid column in the header
+ EXPECT_EQ(1, csv->getValidColumnCount());
+
+ // Minium valid columns wasn't set. (Remember it's optional)
+ EXPECT_EQ(0, csv->getMinimumValidColumns());
+
+ // Upgrade flag should be true
+ EXPECT_EQ(true, csv->needsUpgrading());
+
+ // Make sure schema versions are accurate
+ EXPECT_EQ("1.0", csv->getInputSchemaVersion());
+ EXPECT_EQ("3.0", csv->getSchemaVersion());
// First row is correct.
ASSERT_TRUE(csv->next(row));
EXPECT_EQ("blue", row.readAt(1));
EXPECT_EQ("21", row.readAt(2));
- ASSERT_EQ(3, csv->getColumnCount());
-
// Fourth row is correct.
- if (!csv->next(row)) {
- std::cout << "row error is : " <<
- csv->getReadMsg() << std::endl;
-
- }
-
+ ASSERT_TRUE(csv->next(row));
EXPECT_EQ("bird", row.readAt(0));
EXPECT_EQ("yellow", row.readAt(1));
EXPECT_EQ("21", row.readAt(2));
}
size_t
-VersionedCSVFile::getMinimumValidColumns() {
+VersionedCSVFile::getMinimumValidColumns() const {
return (minimum_valid_columns_);
}
+size_t
+VersionedCSVFile::getValidColumnCount() const {
+ return (valid_column_count_);
+}
+
void
VersionedCSVFile::open(const bool seek_to_end) {
if (getColumnCount() == 0) {
isc_throw(VersionedCSVFileError,
- "no schema has been defined, cannot open file :"
+ "no schema has been defined, cannot open CSV file :"
<< getFilename());
}
CSVFile::open(seek_to_end);
}
+void
+VersionedCSVFile::recreate() {
+ if (getColumnCount() == 0) {
+ isc_throw(VersionedCSVFileError,
+ "no schema has been defined, cannot create CSV file :"
+ << getFilename());
+ }
+
+ CSVFile::recreate();
+ // For new files they always match.
+ valid_column_count_ = getColumnCount();
+}
+
+bool
+VersionedCSVFile::needsUpgrading() const {
+ return (getValidColumnCount() < getColumnCount());
+}
+
+std::string
+VersionedCSVFile::getInputSchemaVersion() const {
+ if (getValidColumnCount() > 0) {
+ return (getVersionedColumn(getValidColumnCount() - 1)->version_);
+ }
+
+ return ("undefined");
+}
+
+std::string
+VersionedCSVFile::getSchemaVersion() const {
+ if (getColumnCount() > 0) {
+ return (getVersionedColumn(getColumnCount() - 1)->version_);
+ }
+
+ return ("undefined");
+}
+
+const VersionedColumnPtr&
+VersionedCSVFile::getVersionedColumn(const size_t index) const {
+ if (index >= getColumnCount()) {
+ isc_throw(isc::OutOfRange, "versioned column index " << index
+ << " out of range; CSV file : " << getFilename()
+ << " only has " << getColumnCount() << " columns ");
+ }
+
+ return (columns_[index]);
+}
+
bool
VersionedCSVFile::next(CSVRow& row) {
+ // Use base class to physicall read the row, but skip its row
+ // validation
CSVFile::next(row, true);
if (row == CSVFile::EMPTY_ROW()) {
return(true);
// defined column count. If not they're the equal. Either way
// each data row must have valid_column_count_ values or its
// an invalid row.
- if (row.getValuesCount() < valid_column_count_) {
+ if (row.getValuesCount() < getValidColumnCount()) {
std::ostringstream s;
s << "the size of the row '" << row << "' has too few valid columns "
- << valid_column_count_ << "' of the CSV file '"
+ << getValidColumnCount() << "' of the CSV file '"
<< getFilename() << "'";
setReadMsg(s.str());
return (false);
/// @brief Returns the minimum number of columns which must be present
/// for the file to be considered valid.
- size_t getMinimumValidColumns();
+ size_t getMinimumValidColumns() const;
+
+ /// @brief Returns the number of valid columns found in the header
+ /// For newly created files this will always match the number of defined
+ /// columns (i.e. getColumnCount()). For existing files, this will be
+ /// the number of columns in the header that match the defined columnns.
+ /// When this number is less than getColumnCount() it means the input file
+ /// is from an earlier schema. This value is zero until the file has
+ /// been opened.
+ size_t getValidColumnCount() const;
/// @brief Opens existing file or creates a new one.
///
/// CSVFileError when IO operation fails, or header fails to validate.
virtual void open(const bool seek_to_end = false);
+ /// @brief Creates a new CSV file.
+ ///
+ /// The file creation will fail if there are no columns specified.
+ /// Otherwise, this function will write the header to the file.
+ /// In order to write rows to opened file, the @c append function
+ /// should be called.
+ ///
+ /// @throw VersionedCSVFileError if schema has not been defined
+ /// CSVFileError if an IO operation fails
+ virtual void recreate();
+
/// @brief Reads next row from the file file.
///
/// This function will return the @c CSVRow object representing a
/// failed.
bool next(CSVRow& row);
+ /// @brief Returns the schema version of the physical file
+ ///
+ /// @return text version of the schema found or string "undefined" if the
+ /// file has not been opened
+ std::string getInputSchemaVersion() const;
+
+ /// @brief text version of current schema supported by the file's metadata
+ ///
+ /// @return text version info assigned to the last column in the list of
+ /// defined column, or the string "undefined" if no columns have been
+ /// defined.
+ std::string getSchemaVersion() const;
+
+ /// @brief Fetch the column descriptor for a given index
+ ///
+ /// @param index index within the list of columns of the desired column
+ /// @return a pointer to the VersionedColumn at the given index
+ /// @trow OutOfRange exception if the index is invalid
+ const VersionedColumnPtr& getVersionedColumn(const size_t index) const;
+
+ /// @brief Returns true if the opened file is needs to be upgraded
+ ///
+ /// @return true if the file's valid column count is greater than 0 and
+ /// is less than the defined number of columns
+ bool needsUpgrading() const;
+
protected:
/// @brief Validates the header of a VersionedCSVFile