Files
2022-02-11 15:06:05 -08:00

271 lines
8.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.CompilerServices;
using ImpromptuInterface;
using Dynamitey;
namespace DotNetDBF.Enumerable
{
/// <summary>
/// Interface to get the contents of the DBF Wrapper
/// </summary>
public interface IDBFInterceptor
{
/// <summary>
/// Does field exist in row
/// </summary>
/// <returns></returns>
bool Exists(string fieldName);
/// <summary>
/// Gets the data row.
/// </summary>
/// <returns></returns>
object[] GetDataRow();
}
#pragma warning disable 618
public class DBFInterceptor : DBFIntercepter
#pragma warning restore 618
{
public DBFInterceptor(object[] wrappedObj, string[] fieldNames) : base(wrappedObj, fieldNames)
{
}
}
/// <summary>
/// DBF Dynamic Wrapper
/// </summary>
public abstract class BaseDBFInterceptor : Dynamitey.DynamicObjects.BaseObject, IDBFInterceptor
{
private readonly string[] _fieldNames;
private readonly object[] _wrappedArray;
protected BaseDBFInterceptor(object[] wrappedObj, string[] fieldNames)
{
_wrappedArray = wrappedObj;
_fieldNames = fieldNames;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return _fieldNames;
}
public bool Exists(string fieldName)
{
return _fieldNames.Contains(fieldName);
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
var tLookup = binder.Name;
var tIndex = Array.FindIndex(_fieldNames,
it => it.Equals(tLookup, StringComparison.InvariantCultureIgnoreCase));
if (tIndex < 0)
return false;
result = _wrappedArray[tIndex];
if (TryTypeForName(tLookup, out var outType))
{
result = Dynamic.CoerceConvert(result, outType);
}
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var tLookup = binder.Name;
var tIndex = Array.FindIndex(_fieldNames,
it => it.Equals(tLookup, StringComparison.InvariantCultureIgnoreCase));
if (tIndex < 0)
return false;
if (TryTypeForName(tLookup, out var outType))
{
value = Dynamic.CoerceConvert(value, outType);
}
_wrappedArray[tIndex] = value;
return true;
}
public object[] GetDataRow()
{
return _wrappedArray;
}
}
/// <summary>
/// Enumerable API
/// </summary>
public static partial class DBFEnumerable
{
/// <summary>
/// New Blank Row Dynamic object that matches writer;
/// </summary>
/// <param name="writer">The writer.</param>
/// <returns></returns>
public static dynamic NewBlankRow(this DBFWriter writer)
{
var fields = writer.Fields.Select(it => it.Name).ToArray();
var obj = new object[fields.Length];
return new Enumerable.DBFInterceptor(obj, fields);
}
public static void CopyRecordTo(this IDBFInterceptor original, IDBFInterceptor dest)
{
foreach (var fieldName in Dynamitey.Dynamic.GetMemberNames(dest, true))
{
try
{
var val = Dynamic.InvokeGet(original, fieldName);
Dynamic.InvokeSet(dest, fieldName, val);
}
catch
{
// ignored
}
}
}
/// <summary>
/// Writes the record.
/// </summary>
/// <param name="writer">The writer.</param>
/// <param name="value">The value.</param>
public static void WriteRecord(this DBFWriter writer, Enumerable.IDBFInterceptor value)
{
writer.WriteRecord(value.GetDataRow());
}
/// <summary>
/// Adds the record.
/// </summary>
/// <param name="writer">The writer.</param>
/// <param name="value">The value.</param>
public static void AddRecord(this DBFWriter writer, Enumerable.IDBFInterceptor value)
{
writer.AddRecord(value.GetDataRow());
}
/// <summary>
/// Return all the records. T should be interface with getter properties that match types and names of the database.
/// Optionally instead of T being and interface you can pass in an anonymous object with properties that match that
/// database and then you'll get an IEnumerable of that anonymous type with the data filled in.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader">The reader.</param>
/// <param name="prototype">The prototype. Anonymous class instance</param>
/// <param name="throwOnParsingError">Indicates if parsing error throws an exception. Default: true</param>
/// <returns></returns>
public static IEnumerable<T> AllRecords<T>(this DBFReader reader, T prototype = null, bool throwOnParsingError = true) where T : class
{
var tType = typeof(T);
var tProperties = tType.GetProperties()
.Where(
it =>
Array.FindIndex(reader.Fields,
f => f.Name.Equals(it.Name, StringComparison.InvariantCultureIgnoreCase)) >= 0)
.ToList();
var tProps = tProperties
.Select(
it =>
Array.FindIndex(reader.Fields,
jt => jt.Name.Equals(it.Name, StringComparison.InvariantCultureIgnoreCase)))
.Where(it => it >= 0)
.ToArray();
var tOrderedProps = tProps.OrderBy(it => it).ToArray();
var tReturn = new List<T>();
if (tType.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any())
{
var tAnon = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
while (tAnon != null)
{
tReturn.Add((T) Activator.CreateInstance(tType, tAnon));
tAnon = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
}
return tReturn;
}
var t = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
while (t != null)
{
var interceptor = new Enumerable.DBFInterceptor(t, tProperties.Select(it => it.Name).ToArray());
tReturn.Add(interceptor.ActLike<T>(typeof(Enumerable.IDBFInterceptor)));
t = reader.NextRecord(tProps, tOrderedProps, throwOnParsingError);
}
return tReturn;
}
/// <summary>
/// Returns a list of dynamic objects whose properties and types match up with that database name.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="whereColumn">The where column name.</param>
/// <param name="whereColumnEquals">What the were column should equal.</param>
/// <param name="throwOnParsingError">Indicates if parsing error throws an exception. Default: true</param>
/// <returns></returns>
public static IEnumerable<dynamic> DynamicAllRecords(this DBFReader reader, string whereColumn = null,
dynamic whereColumnEquals = null, bool throwOnParsingError = true)
{
var props = reader.GetSelectFields().Select(it => it.Name).ToArray();
int? whereColumnIndex = null;
if (!String.IsNullOrEmpty(whereColumn))
{
whereColumnIndex = Array.FindIndex(props,
it => it.Equals(whereColumn, StringComparison.InvariantCultureIgnoreCase));
}
var tReturn = new List<object>();
var t = reader.NextRecord(throwOnParsingError);
while (t != null)
{
if (whereColumnIndex is int i)
{
dynamic tO = t[i];
if (!tO.Equals(whereColumnEquals))
{
t = reader.NextRecord(throwOnParsingError);
continue;
}
}
var interceptor = new Enumerable.DBFInterceptor(t, props);
tReturn.Add(interceptor);
t = reader.NextRecord(throwOnParsingError);
}
return tReturn;
}
}
}