5ce9e51ae7
Microsoft Excel files can be used to import/export devices. Several import bugs were also fixed in the process.
222 lines
6.4 KiB
C#
222 lines
6.4 KiB
C#
using Disco.Models.Services.Devices.Importing;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
namespace Disco.Services.Devices.Importing
|
|
{
|
|
public class CsvDeviceImportDataReader : IDeviceImportDataReader
|
|
{
|
|
private static string[] TrueValues = { "true", "1", "yes", "-1", "on" };
|
|
private static string[] FalseValues = { "false", "0", "no", "off" };
|
|
|
|
private CsvDeviceImportContext context;
|
|
private List<string[]> rawData;
|
|
private int currentRowIndex;
|
|
private int rowOffset;
|
|
private string[] currentRow;
|
|
|
|
public int Index { get { return currentRowIndex; } }
|
|
|
|
public CsvDeviceImportDataReader(CsvDeviceImportContext Context, List<string[]> RawData, bool HasHeaderRow)
|
|
{
|
|
context = Context;
|
|
rawData = RawData;
|
|
currentRowIndex = 0;
|
|
rowOffset = HasHeaderRow ? 1 : 0;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
currentRowIndex = 0;
|
|
currentRow = null;
|
|
}
|
|
|
|
public bool Read()
|
|
{
|
|
if (++currentRowIndex >= rawData.Count)
|
|
{
|
|
currentRowIndex--;
|
|
return false;
|
|
}
|
|
|
|
currentRow = rawData[currentRowIndex];
|
|
return true;
|
|
}
|
|
|
|
public int GetRowNumber(int Index)
|
|
{
|
|
return Index + rowOffset;
|
|
}
|
|
|
|
public string GetString(int ColumnIndex)
|
|
{
|
|
if (currentRow == null)
|
|
throw new InvalidOperationException($"{nameof(CsvDeviceImportDataReader.Read)} must be called before retrieving values");
|
|
|
|
var value = currentRow[ColumnIndex];
|
|
|
|
if (value.Length == 0)
|
|
return null;
|
|
|
|
return value;
|
|
}
|
|
|
|
public IEnumerable<string> GetStrings(int ColumnIndex)
|
|
{
|
|
return rawData.Select(r => r[ColumnIndex]);
|
|
}
|
|
|
|
public bool TryGetNullableInt(int ColumnIndex, out int? value)
|
|
{
|
|
if (currentRow == null)
|
|
throw new InvalidOperationException($"{nameof(CsvDeviceImportDataReader.Read)} must be called before retrieving values");
|
|
|
|
return TryGetNullableInt(currentRow[ColumnIndex], out value);
|
|
}
|
|
|
|
public bool TryGetNullableBool(int ColumnIndex, out bool? value)
|
|
{
|
|
if (currentRow == null)
|
|
throw new InvalidOperationException($"{nameof(CsvDeviceImportDataReader.Read)} must be called before retrieving values");
|
|
|
|
return TryGetNullableBool(currentRow[ColumnIndex], out value);
|
|
}
|
|
|
|
public bool TryGetNullableDateTime(int ColumnIndex, out DateTime? value)
|
|
{
|
|
if (currentRow == null)
|
|
throw new InvalidOperationException($"{nameof(CsvDeviceImportDataReader.Read)} must be called before retrieving values");
|
|
|
|
return TryGetNullableDateTime(currentRow[ColumnIndex], out value);
|
|
}
|
|
|
|
public bool TestAllNotEmpty(int ColumnIndex)
|
|
{
|
|
return GetStrings(ColumnIndex).All(s => !string.IsNullOrWhiteSpace(s));
|
|
}
|
|
|
|
public bool TestAllNullableInt(int ColumnIndex)
|
|
{
|
|
return rawData.Select(r => r[ColumnIndex])
|
|
.All(c =>
|
|
{
|
|
int? value;
|
|
return TryGetNullableInt(c, out value);
|
|
});
|
|
}
|
|
|
|
public bool TestAllInt(int ColumnIndex)
|
|
{
|
|
return rawData.Select(r => r[ColumnIndex])
|
|
.All(c =>
|
|
{
|
|
int? value;
|
|
return TryGetNullableInt(c, out value) && value.HasValue;
|
|
});
|
|
}
|
|
|
|
public bool TestAllNullableBool(int ColumnIndex)
|
|
{
|
|
return rawData.Select(r => r[ColumnIndex])
|
|
.All(c =>
|
|
{
|
|
bool? value;
|
|
return TryGetNullableBool(c, out value);
|
|
});
|
|
}
|
|
|
|
public bool TestAllNullableDateTime(int ColumnIndex)
|
|
{
|
|
return rawData.Select(r => r[ColumnIndex])
|
|
.All(c =>
|
|
{
|
|
DateTime? value;
|
|
return TryGetNullableDateTime(c, out value);
|
|
});
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
// Nothing to dispose
|
|
}
|
|
|
|
private bool TryGetNullableDateTime(string content, out DateTime? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
value = null;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
content = content.Trim();
|
|
|
|
DateTime valueDateTime;
|
|
if (DateTime.TryParse(content, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out valueDateTime))
|
|
{
|
|
value = valueDateTime;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
value = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool TryGetNullableBool(string content, out bool? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
value = null;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
content = content.Trim();
|
|
|
|
if (TrueValues.Contains(content, StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
value = true;
|
|
return true;
|
|
}
|
|
else if (FalseValues.Contains(content, StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
value = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
value = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool TryGetNullableInt(string content, out int? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(content))
|
|
{
|
|
value = null;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
int intValue;
|
|
if (int.TryParse(content, out intValue))
|
|
{
|
|
value = intValue;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
value = null;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |