Commit 3349625
Changed files (2)
lib
model
export_import
lib/model/export_import/csv_converter.dart
@@ -28,6 +28,7 @@ class CsvConverter {
(column) => column.encode(record)
).toList()
).toList();
+ table.insert(0, columns.map((c) => c.csvTitle).toList());
final csvCreator = ListToCsvConverter(
fieldDelimiter: settings.fieldDelimiter,
@@ -55,7 +56,7 @@ class CsvConverter {
if (csvLines.length < 2) return converter.convert(csvString, eol: '\n');
return csvLines;
}();
- if (lines.length < 2) return RecordParsingResult.err(RecordParsingErrorType.emptyFile);
+ if (lines.length < 2) return RecordParsingResult.err(RecordParsingErrorEmptyFile());
// Get and validate columns from csv title.
final List<ExportColumn> columns = [];
@@ -64,26 +65,27 @@ class CsvConverter {
final column = availableColumns.firstWhere(
(c) => c.csvTitle == titleText
&& c.restoreAbleType != null);
- if (column == null) return RecordParsingResult.err(RecordParsingErrorType.unknownColumn);
+ if (column == null) return RecordParsingResult.err(RecordParsingErrorUnknownColumn(titleText));
columns.add(column);
}
if (columns.where((e) => e.restoreAbleType == RowDataFieldType.timestamp).isEmpty) {
- return RecordParsingResult.err(RecordParsingErrorType.timeNotRestoreable);
+ return RecordParsingResult.err(RecordParsingErrorTimeNotRestoreable());
}
// Convert data to records.
final List<BloodPressureRecord> records = [];
+ int currentLineNumber = 1;
for (final currentLine in lines) {
if (currentLine.length < columns.length) {
- return RecordParsingResult.err(RecordParsingErrorType.expectedMoreFields);
+ return RecordParsingResult.err(RecordParsingErrorExpectedMoreFields(currentLineNumber));
}
final List<(RowDataFieldType, dynamic)> recordPieces = [];
- for (int idx = 0; idx < columns.length; idx++) {
- assert(currentLine[idx] is String);
- final piece = columns[idx].decode(currentLine[idx]);
- if (piece?.$1 != columns[idx].restoreAbleType) { // validation
- return RecordParsingResult.err(RecordParsingErrorType.unparsableField);
+ for (int fieldIndex = 0; fieldIndex < columns.length; fieldIndex++) {
+ assert(currentLine[fieldIndex] is String);
+ final piece = columns[fieldIndex].decode(currentLine[fieldIndex]);
+ if (piece?.$1 != columns[fieldIndex].restoreAbleType) { // validation
+ return RecordParsingResult.err(RecordParsingErrorUnparsableField(currentLineNumber, currentLine[fieldIndex]));
}
if (piece != null) recordPieces.add(piece);
}
@@ -107,6 +109,7 @@ class CsvConverter {
}
records.add(BloodPressureRecord(timestamp, sys, dia, pul, note, needlePin: needlePin));
+ currentLineNumber++;
}
assert(records.length == lines.length, 'every line should have been parse'); // first line got removed
lib/model/export_import/record_parsing_result.dart
@@ -6,15 +6,15 @@ class RecordParsingResult {
RecordParsingResult._create(this._result, this._error);
final List<BloodPressureRecord>? _result;
- final RecordParsingErrorType? _error;
+ final RecordParsingError? _error;
/// Pass a valid record list and indicate success.
factory RecordParsingResult.ok(List<BloodPressureRecord> result)=>
RecordParsingResult._create(result, null);
/// Indicate a parsing failure.
- factory RecordParsingResult.err(RecordParsingErrorType type)=>
- RecordParsingResult._create(null, type);
+ factory RecordParsingResult.err(RecordParsingError error)=>
+ RecordParsingResult._create(null, error);
/// Returns if there is an error present.
///
@@ -24,7 +24,7 @@ class RecordParsingResult {
/// Returns the passed list on success or the result of [errorHandler] in case a error is present.
///
/// When [errorHandler] returns null a empty list is passed.
- List<BloodPressureRecord> getOr(List<BloodPressureRecord>? Function(RecordParsingErrorType error) errorHandler) {
+ List<BloodPressureRecord> getOr(List<BloodPressureRecord>? Function(RecordParsingError error) errorHandler) {
if (_result != null) {
assert(_error == null);
return _result!;
@@ -34,22 +34,38 @@ class RecordParsingResult {
}
}
-// TODO: consider converting to sealed class to allow passing error details.
/// Indicates what type error occurred while trying to decode a csv data.
-enum RecordParsingErrorType {
- /// There are not enough lines in the csv file to parse the record.
- emptyFile,
+sealed class RecordParsingError {}
- /// There is no column with this csv title that can be reversed.
- unknownColumn,
+/// There are not enough lines in the csv file to parse the record.
+class RecordParsingErrorEmptyFile implements RecordParsingError {}
- /// The current line has less fields than the first line.
- expectedMoreFields,
+/// There is no column that allows restoring a timestamp.
+class RecordParsingErrorTimeNotRestoreable implements RecordParsingError {}
- /// There is no column that allows restoring a timestamp.
- timeNotRestoreable,
+/// There is no column with this csv title that can be reversed.
+class RecordParsingErrorUnknownColumn implements RecordParsingError {
+ RecordParsingErrorUnknownColumn(this.title);
+
+ /// CSV title of the column no equivalent was found for.
+ final String title;
+}
+
+/// The current line has less fields than the first line.
+class RecordParsingErrorExpectedMoreFields implements RecordParsingError {
+ RecordParsingErrorExpectedMoreFields(this.lineNumber);
+
+ /// Line in which this error occurred.
+ final int lineNumber;
+}
+
+/// The corresponding column couldn't decode a specific field in the csv file.
+class RecordParsingErrorUnparsableField implements RecordParsingError {
+ RecordParsingErrorUnparsableField(this.lineNumber, this.fieldContents);
- /// The corresponding column couldn't decode a specific field in the csv file.
- unparsableField,
- // TODO ...
+ /// Line in which this error occurred.
+ final int lineNumber;
+
+ /// Text in the csv string that failed to parse.
+ final String fieldContents;
}
\ No newline at end of file