A database based on .net
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.

168 lines
6.8 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.Linq;
using System.Threading;
using System.Threading.Tasks;
using GBase.DataHandling.Cache.Factories;
using GBase.DataHandling.Factories;
using GBase.Helpers;
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="rootElementName">The root element name of 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(string path,
string rootElementName,
IXmlDataReaderFactory xmlDataReaderFactory,
IXmlDataWriterFactory xmlDataWriterFactory,
IXmlDataHandlerCacheFactory xmlDataHandlerCacheFactory)
{
_xmlDataWriter = xmlDataWriterFactory.Create(path, rootElementName);
_xmlDataReader = xmlDataReaderFactory.Create(path);
_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>
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the async operation</param>
/// <returns>Returns true if successful, false if not</returns>
public async Task<bool> Init(bool overwrite, CancellationToken cancellationToken)
{
if (_isInitialized)
return false;
_overwrite = overwrite;
if (!await _xmlDataWriter.Init(cancellationToken))
return false;
if (!await _xmlDataReader.Init(cancellationToken))
return false;
_isInitialized = true;
return true;
}
/// <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="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task SetValue<T, TProperty>(string propertyName, TProperty value)
{
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>(propertyName, valueString, _overwrite);
}
/// <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="propertyName">The name of the property</param>
/// <param name="value">The value to set</param>
/// <returns>A <see cref="Task"/> to await</returns>
public async Task RemoveValue<T, TProperty>(string propertyName, TProperty value)
{
if (value == null)
return;
await _cache.TryRemoveValue<T, TProperty>(propertyName, value);
await _xmlDataWriter.Remove<T, TProperty>(propertyName, value.ToString());
}
/// <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="propertyName">The name of the property</param>
/// <returns>The value for the given property</returns>
public async Task<TProperty> GetValue<T, TProperty>(string propertyName)
{
IEnumerable<TProperty> enumerable = await GetValues<T, TProperty>(propertyName);
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="propertyName">The name of the property</param>
/// <returns>An <see cref="IEnumerable{T}"/> with all the values for the property</returns>
public async Task<IEnumerable<TProperty>> GetValues<T, TProperty>(string propertyName)
{
IEnumerable<TProperty> cachedValues = await _cache.TryGetValues<T, TProperty>(propertyName);
if (cachedValues != null)
return cachedValues;
return await _xmlDataReader.Read<T, TProperty>(propertyName);
}
/// <summary>
/// Dispose used resources asynchronously
/// </summary>
/// <returns>A <see cref="ValueTask"/> to await</returns>
public async ValueTask DisposeAsync()
{
await _xmlDataReader.DisposeAsync();
await _xmlDataWriter.DisposeAsync();
}
}
}