You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
8.2 KiB
193 lines
8.2 KiB
// Author: Gockner, Simon
|
|
// Created: 2020-02-12
|
|
// Copyright(c) 2020 SimonG. All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using GBase.DataHandling.Cache.Factories;
|
|
using GBase.DataHandling.Factories;
|
|
using GBase.Helpers;
|
|
using GBase.Interfaces;
|
|
using GBase.Interfaces.DataHandling;
|
|
using GBase.Interfaces.DataHandling.Xml;
|
|
using GBase.Interfaces.DataHandling.Xml.Cache;
|
|
|
|
namespace GBase.DataHandling
|
|
{
|
|
//TODO: access cache asynchronously?
|
|
|
|
/// <summary>
|
|
/// A <see cref="IDataHandler"/> that handles its data in an xml file
|
|
/// </summary>
|
|
public class XmlDataHandler : IXmlDataHandler
|
|
{
|
|
/// <summary>
|
|
/// The element name of the value element
|
|
/// </summary>
|
|
public const string VALUE_ELEMENT_NAME = "Value";
|
|
|
|
/// <summary>
|
|
/// The attribute name of the value <see cref="Type"/> attribute
|
|
/// </summary>
|
|
public const string VALUE_TYPE_ATTRIBUTE_NAME = "type";
|
|
|
|
private readonly IXmlDataReader _xmlDataReader;
|
|
private readonly IXmlDataWriter _xmlDataWriter;
|
|
|
|
private readonly IXmlDataHandlerCache _cache;
|
|
|
|
private bool _isInitialized;
|
|
private bool _overwrite;
|
|
|
|
/// <summary>
|
|
/// A <see cref="IDataHandler"/> that handles its data in an xml file
|
|
/// </summary>
|
|
/// <param name="path">The path to the xml file</param>
|
|
/// <param name="xmlDataReaderFactory">The <see cref="IXmlDataReader"/> factory</param>
|
|
/// <param name="xmlDataWriterFactory">The <see cref="IXmlDataWriter"/> factory</param>
|
|
/// <param name="xmlDataHandlerCacheFactory">The <see cref="IXmlDataHandlerCache"/> factory</param>
|
|
public XmlDataHandler(IXmlDataReaderFactory xmlDataReaderFactory,
|
|
IXmlDataWriterFactory xmlDataWriterFactory,
|
|
IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory)
|
|
{
|
|
_xmlDataWriter = xmlDataWriterFactory.Create();
|
|
_xmlDataReader = xmlDataReaderFactory.Create();
|
|
|
|
_cache = xmlDataHandlerCacheFactory.Create(_xmlDataReader);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the <see cref="XmlDataHandler"/>
|
|
/// </summary>
|
|
/// <param name="overwrite">If true an existing value is overwritten, if false an additional value is added</param>
|
|
/// <returns>Returns true if successful, false if not</returns>
|
|
public bool Init(bool overwrite)
|
|
{
|
|
if (_isInitialized)
|
|
return false;
|
|
|
|
_overwrite = overwrite;
|
|
|
|
_isInitialized = true;
|
|
return true;
|
|
}
|
|
|
|
public async Task<bool> AddEntry<T>(T entry, IGBaseTable table, FileStream entryFile, CancellationToken cancellationToken)
|
|
{
|
|
if (!await _xmlDataWriter.InitFile(entryFile, table.Type.Name, cancellationToken))
|
|
return false;
|
|
|
|
foreach (var column in table.Columns)
|
|
{
|
|
//TODO: Set value for each column
|
|
PropertyInfo property = entry.GetType().GetProperty(column.Name);
|
|
if (property == null)
|
|
continue; //TODO: What to do in this case? (Shouldn't really happen...)
|
|
|
|
string valueString;
|
|
if (property.PropertyType != typeof(string) && property.GetValue(entry) is IEnumerable enumerable)
|
|
valueString = enumerable.ToGBaseString();
|
|
else
|
|
valueString = property.GetValue(entry).ToString();
|
|
|
|
await _xmlDataWriter.Write<T>(entryFile, property.Name, valueString, property.PropertyType, _overwrite, cancellationToken);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public Task<bool> RemoveEntry<T>(T entry)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set the value for the given property
|
|
/// </summary>
|
|
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
|
|
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
|
|
/// <param name="entryFile"></param>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <param name="value">The value to set</param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns>A <see cref="Task"/> to await</returns>
|
|
public async Task SetValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken)
|
|
{
|
|
if (value == null)
|
|
return;
|
|
|
|
string valueString;
|
|
if (typeof(TProperty) != typeof(string) && value is IEnumerable enumerable)
|
|
valueString = enumerable.ToGBaseString();
|
|
else
|
|
valueString = value.ToString();
|
|
|
|
await _cache.SetValue<T, TProperty>(propertyName, value, _overwrite);
|
|
await _xmlDataWriter.Write<T, TProperty>(entryFile, propertyName, valueString, _overwrite, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Remove the value for the given property
|
|
/// </summary>
|
|
/// <typeparam name="T">The <see cref="Type"/> of the property</typeparam>
|
|
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
|
|
/// <param name="entryFile"></param>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <param name="value">The value to set</param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns>A <see cref="Task"/> to await</returns>
|
|
public async Task RemoveValue<T, TProperty>(FileStream entryFile, string propertyName, TProperty value, CancellationToken cancellationToken)
|
|
{
|
|
if (value == null)
|
|
return;
|
|
|
|
string valueString;
|
|
if (typeof(TProperty) != typeof(string) && value is IEnumerable enumerable)
|
|
valueString = enumerable.ToGBaseString();
|
|
else
|
|
valueString = value.ToString();
|
|
|
|
await _cache.TryRemoveValue<T, TProperty>(propertyName, value);
|
|
await _xmlDataWriter.Remove<T, TProperty>(entryFile, propertyName, valueString, cancellationToken);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the value for the given property, if multiple values are set the first is returned
|
|
/// </summary>
|
|
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
|
|
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
|
|
/// <param name="file"></param>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns>The value for the given property</returns>
|
|
public async Task<TProperty> GetValue<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
|
|
{
|
|
IEnumerable<TProperty> enumerable = await GetValues<T, TProperty>(file, propertyName, cancellationToken);
|
|
return enumerable == null ? default : enumerable.FirstOrDefault();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all the values that are set for the given property
|
|
/// </summary>
|
|
/// <typeparam name="T">The <see cref="Type"/> that implements the property</typeparam>
|
|
/// <typeparam name="TProperty">The <see cref="Type"/> of the property</typeparam>
|
|
/// <param name="file"></param>
|
|
/// <param name="propertyName">The name of the property</param>
|
|
/// <param name="cancellationToken"></param>
|
|
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
|
|
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(FileStream file, string propertyName, CancellationToken cancellationToken)
|
|
{
|
|
IEnumerable<TProperty> cachedValues = await _cache.TryGetValues<T, TProperty>(file, propertyName, cancellationToken);
|
|
if (cachedValues != null)
|
|
return cachedValues;
|
|
|
|
return await _xmlDataReader.Read<T, TProperty>(file, propertyName, cancellationToken);
|
|
}
|
|
}
|
|
} |