Skip to content

Commit

Permalink
Merge branch 'main' into feature/cli
Browse files Browse the repository at this point in the history
  • Loading branch information
RohitM-IN committed Mar 5, 2024
2 parents 9fc05b6 + 5ab5dc1 commit e959180
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 217 deletions.
58 changes: 58 additions & 0 deletions src/Comparer/PropertyEqualityComparer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Reflection;

namespace DbSyncKit.DB.Comparer
{
/// <summary>
/// Compares instances of data contracts based on specified properties, which can be either key or comparable properties.
/// </summary>
public class PropertyEqualityComparer<T> : IEqualityComparer<T>
{
/// <summary>
/// Gets the array of <see cref="PropertyInfo"/> objects representing properties used for equality comparison.
/// These properties can serve as either key or comparable properties.
/// </summary>
public readonly PropertyInfo[] properties;

/// <summary>
/// Initializes a new instance of the <see cref="PropertyEqualityComparer{T}"/> class.
/// </summary>
/// <param name="Properties">An array of <see cref="PropertyInfo"/> objects representing properties used for equality comparison. These can be either key or comparable properties.</param>
public PropertyEqualityComparer(PropertyInfo[] Properties)
{
properties = Properties;
}

/// <summary>
/// Determines whether two instances of the data contract are equal based on the specified properties.
/// </summary>
/// <param name="x">The first instance to compare.</param>
/// <param name="y">The second instance to compare.</param>
/// <returns><c>true</c> if the instances are equal; otherwise, <c>false</c>.</returns>
public bool Equals(T? x, T? y)
{
return properties.All(prop => Equals(prop.GetValue(x), prop.GetValue(y)));
}

/// <summary>
/// Returns a hash code for the specified instance of the data contract based on the specified properties.
/// </summary>
/// <param name="obj">The instance for which to get the hash code.</param>
/// <returns>A hash code for the specified instance.</returns>
public int GetHashCode(T obj)
{
unchecked
{
int hash = 17;

foreach (var prop in properties)
{
var value = prop.GetValue(obj);
hash = hash ^ ((value?.GetHashCode() ?? 0) + 23);
}

return hash;
}
}
}

}
2 changes: 1 addition & 1 deletion src/DatabaseManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public DatabaseManager(T databaseProvider)
/// <param name="query">The SQL query to execute.</param>
/// <param name="tableName">The name of the table associated with the query.</param>
/// <returns>A list of results of type <typeparamref name="TItem"/>.</returns>
public List<TItem> ExecuteQuery<TItem>(string query, string tableName) where TItem : IDataContract
public List<TItem> ExecuteQuery<TItem>(string query, string tableName)
{
List<TItem> result = new List<TItem>();

Expand Down
10 changes: 7 additions & 3 deletions src/DbSyncKit.DB.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<AssemblyVersion>1.2.0.0</AssemblyVersion>
<FileVersion>1.2.0.0</FileVersion>
<Version>1.2.0.0</Version>
<AssemblyVersion>1.3.0.0</AssemblyVersion>
<FileVersion>1.3.0.0</FileVersion>
<Version>1.3.0.0</Version>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://dbsynckit.rohit-mahajan.in/</RepositoryUrl>
<PackageProjectUrl>https://github.com/RohitM-IN/DbSyncKit</PackageProjectUrl>
Expand All @@ -31,4 +31,8 @@
</None>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\DbSyncKit.Templates\src\DbSyncKit.Templates.csproj" />
</ItemGroup>

</Project>
3 changes: 0 additions & 3 deletions src/Extensions/DataRowExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ public static class DataRowExtensions
/// <param name="row">The DataRow from which to retrieve the value.</param>
/// <param name="columnName">The name of the column.</param>
/// <returns>The value of the specified column, converted to the specified type.</returns>
/// <remarks>
/// This extension method is intended for use with classes that inherit from <see cref="IDataContract"/>.
/// </remarks>
public static T GetValue<T>(this DataRow row, string columnName)
{
// Check if the DataRow is null
Expand Down
1 change: 1 addition & 0 deletions src/Factory/QueryGeneratorFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using DbSyncKit.DB.Enum;
using DbSyncKit.DB.Interface;
using DbSyncKit.Templates.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
144 changes: 144 additions & 0 deletions src/Fetcher/DataContractFetcher.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
using DbSyncKit.DB.Comparer;
using DbSyncKit.DB.Factory;
using DbSyncKit.DB.Interface;
using DbSyncKit.Templates;
using DbSyncKit.Templates.Interface;

namespace DbSyncKit.DB.Fetcher
{
/// <summary>
/// Represents a callback function for filtering a list of data entities of type T.
/// </summary>
/// <typeparam name="T">The type of data entities to filter.</typeparam>
/// <param name="data">The list of data entities to filter.</param>
/// <returns>A filtered list of data entities.</returns>
/// <remarks>
/// This delegate defines a callback function that takes a list of data entities as input,
/// performs filtering operations on the data, and returns the filtered list.
/// </remarks>
public delegate List<T> FilterCallback<T>(List<T> data);

/// <summary>
/// Utility class for fetching data from a database using data contracts.
/// </summary>
public class DataContractFetcher
{
#region Properties

/// <summary>
/// Gets the query generator factory instance used for creating query generators.
/// </summary>
private readonly QueryGeneratorFactory Factory;

/// <summary>
/// Gets or sets the QueryGenerationManager instance for generating queries for the destination database.
/// </summary>
/// <remarks>
/// This property is set by the <see cref="RetrieveDataFromDatabases{T}(IDatabase, IDatabase, string, List{string}, PropertyEqualityComparer{T}, FilterCallback{T}?, out HashSet{T}, out HashSet{T})"/> method.
/// It allows the reuse of the QueryGenerationManager instance when the source and destination databases share the same provider.
/// </remarks>
public IQueryGenerator? DestinationQueryGenerationManager { get; private set; }

#endregion

#region Constructor

/// <summary>
/// Initializes a new instance of the <see cref="DataContractFetcher"/> class with a custom query generator factory.
/// </summary>
/// <param name="factory">The custom query generator factory instance.</param>
public DataContractFetcher(QueryGeneratorFactory factory)
{
Factory = factory;
}

#endregion

#region Methods

/// <summary>
/// Retrieves data from source and destination databases for a specified table and column list, using a specified data contract type.
/// </summary>
/// <typeparam name="T">The type of data entities to retrieve.</typeparam>
/// <param name="source">The source database.</param>
/// <param name="destination">The destination database.</param>
/// <param name="tableName">The name of the table from which to retrieve data.</param>
/// <param name="ColumnList">A list of column names to retrieve from the table.</param>
/// <param name="ComparablePropertyEqualityComparer">An equality comparer for identifying properties used in data comparison.</param>
/// <param name="filterCallback">A callback function for filtering the retrieved data.</param>
/// <param name="sourceList">An output parameter that receives the retrieved data from the source database.</param>
/// <param name="destinationList">An output parameter that receives the retrieved data from the destination database.</param>
/// <remarks>
/// The method uses a QueryGenerationManager to generate queries for retrieving data based on the specified table and columns.
/// If the providers of the source and destination databases differ, a new QueryGenerationManager is created for the destination database.
/// The retrieved data can be optionally filtered using the provided filter callback function.
/// </remarks>
public void RetrieveDataFromDatabases<T>(
IDatabase source,
IDatabase destination,
string tableName,
List<string> ColumnList,
PropertyEqualityComparer<T> ComparablePropertyEqualityComparer,
FilterCallback<T>? filterCallback,
out HashSet<T> sourceList,
out HashSet<T> destinationList)
{
var sourceQueryGenerationManager = new QueryGenerationManager(Factory.GetQueryGenerator(source.Provider));
sourceList = GetDataFromDatabase<T>(tableName, source, sourceQueryGenerationManager, ColumnList, ComparablePropertyEqualityComparer, filterCallback);

if (source.Provider != destination.Provider)
{
sourceQueryGenerationManager.Dispose();
DestinationQueryGenerationManager = new QueryGenerationManager(Factory.GetQueryGenerator(destination.Provider));
}
else
{
DestinationQueryGenerationManager = sourceQueryGenerationManager;
}

destinationList = GetDataFromDatabase<T>(tableName, destination, DestinationQueryGenerationManager, ColumnList, ComparablePropertyEqualityComparer, filterCallback);
}

/// <summary>
/// Retrieves data from a database for a specified table, columns, and data contract type.
/// </summary>
/// <typeparam name="T">The type of data entities to retrieve.</typeparam>
/// <param name="tableName">The name of the table from which to retrieve data.</param>
/// <param name="connection">The database connection.</param>
/// <param name="manager">The query generation manager for creating the SELECT query.</param>
/// <param name="columns">A list of column names to retrieve from the table.</param>
/// <param name="ComparablePropertyEqualityComparer">An equality comparer for identifying properties used in data comparison.</param>
/// <param name="filterCallback">A callback function for filtering the retrieved data.</param>
/// <returns>
/// A HashSet of data entities of type T retrieved from the specified table and columns in the database.
/// </returns>
/// <remarks>
/// The method generates a SELECT query using the provided query generation manager and executes it using a DatabaseManager.
/// The resulting data is converted to a HashSet using the specified property equality comparer for data comparison.
/// The retrieved data can be optionally filtered using the provided filter callback function.
/// </remarks>
public HashSet<T> GetDataFromDatabase<T>(
string tableName,
IDatabase connection,
IQueryGenerator manager,
List<string> columns,
PropertyEqualityComparer<T> ComparablePropertyEqualityComparer,
FilterCallback<T>? filterCallback)
{
var query = manager.GenerateSelectQuery<T>(tableName, columns, string.Empty);

using var DBManager = new DatabaseManager<IDatabase>(connection);

var data = DBManager.ExecuteQuery<T>(query, tableName);

if (filterCallback != null)
{
data = filterCallback(data);
}

return data.ToHashSet(ComparablePropertyEqualityComparer);
}

#endregion
}
}
45 changes: 19 additions & 26 deletions src/Helper/QueryHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,29 @@ public class QueryHelper
/// <summary>
/// Gets the table name of a specified type, considering the TableNameAttribute if present.
/// </summary>
/// <typeparam name="T">The type for which to get the table name. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to get the table name.</typeparam>
/// <returns>The table name.</returns>
public string GetTableName<T>() where T : IDataContract
public string GetTableName<T>()
{
return CacheManager.GetTableName(typeof(T));
}

/// <summary>
/// Gets the table schema of a specified type, considering the TableSchemaAttribute if present.
/// </summary>
/// <typeparam name="T">The type for which to get the table schema. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to get the table schema.</typeparam>
/// <returns>The table schema name or null if not specified.</returns>
public string? GetTableSchema<T>() where T : IDataContract
public string? GetTableSchema<T>()
{
return CacheManager.GetTableSchema(typeof(T));
}

/// <summary>
/// Gets whether the type specifies to generate an INSERT query with ID, considering the GenerateInsertWithIDAttribute if present.
/// </summary>
/// <typeparam name="T">The type for which to determine the generation of INSERT query with ID. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to determine the generation of INSERT query with ID.</typeparam>
/// <returns>True if the INSERT query should include ID, otherwise false.</returns>
public bool GetInsertWithID<T>() where T : IDataContract
public bool GetInsertWithID<T>()
{
return CacheManager.GetInsertWithID(typeof(T));
}
Expand All @@ -44,80 +44,73 @@ public bool GetInsertWithID<T>() where T : IDataContract
/// during insert query generation, considering the GenerateInsertWithIDAttribute if present.
/// </summary>
/// <typeparam name="T">The type for which to determine the inclusion of identity insert statements.
/// Must implement <see cref="IDataContract"/>.</typeparam>
///</typeparam>
/// <returns><c>true</c> if identity insert statements should be included; otherwise, <c>false</c>.</returns>
public bool GetIncludeIdentityInsert<T>() where T : IDataContract
public bool GetIncludeIdentityInsert<T>()
{
return CacheManager.GetIncludeIdentityInsert(typeof(T));
}

/// <summary>
/// Gets the names of properties marked as key columns for a specified type.
/// </summary>
/// <typeparam name="T">The type for which to get the key columns. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to get the key columns.</typeparam>
/// <returns>A list of key column names.</returns>
/// <seealso cref="IDataContract"/>
public List<string> GetKeyColumns<T>() where T : IDataContract
public List<string> GetKeyColumns<T>()
{
return CacheManager.GetKeyColumns(typeof(T));
}

/// <summary>
/// Gets the names of properties marked as excluded properties for a specified type.
/// </summary>
/// <typeparam name="T">The type for which to get the excluded properties. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to get the excluded properties.</typeparam>
/// <returns>A list of excluded property names.</returns>
/// <seealso cref="IDataContract"/>
public List<string> GetExcludedColumns<T>() where T : IDataContract
public List<string> GetExcludedColumns<T>()
{
return CacheManager.GetExcludedColumns(typeof(T));
}

/// <summary>
/// Gets the names of all properties for a specified type.
/// </summary>
/// <typeparam name="T">The type for which to get all properties. Must implement <see cref="IDataContract"/>.</typeparam>
/// <typeparam name="T">The type for which to get all properties.</typeparam>
/// <returns>A list of all property names.</returns>
/// <seealso cref="IDataContract"/>
public List<string> GetAllColumns<T>() where T : IDataContract
public List<string> GetAllColumns<T>()
{
return CacheManager.GetAllColumns(typeof(T));
}

/// <summary>
/// Retrieves a list of identity columns for a specified data contract type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type implementing the IDataContract interface.</typeparam>
/// <returns>A list containing the names of identity columns for the specified data contract type <typeparamref name="T"/>.</returns>
/// <remarks>
/// This method uses reflection to analyze the properties of the specified type <typeparamref name="T"/> and retrieves properties marked with a [Key] attribute, indicating identity columns.
/// </remarks>
/// <seealso cref="IDataContract"/>
public List<string> GetIdentityColumns<T>() where T : IDataContract
public List<string> GetIdentityColumns<T>()
{
return CacheManager.GetIdentityColumns(typeof(T));
}

/// <summary>
/// Retrieves an array of <see cref="PropertyInfo"/> objects representing the properties that are used for data comparison
/// in objects of type <typeparamref name="T"/>. These properties are determined based on the implementation of the
/// <see cref="IDataContract"/> interface.
/// in objects of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of objects for which to retrieve comparable properties.</typeparam>
/// <returns>An array of <see cref="PropertyInfo"/> objects representing the comparable properties of type <typeparamref name="T"/>.</returns>
public PropertyInfo[] GetComparableProperties<T>() where T: IDataContract
public PropertyInfo[] GetComparableProperties<T>()
{
return CacheManager.GetComparableProperties(typeof(T));
}

/// <summary>
/// Retrieves an array of <see cref="PropertyInfo"/> objects representing the properties that are used as key properties
/// for uniquely identifying objects of type <typeparamref name="T"/>. These key properties are determined based on the
/// implementation of the <see cref="IDataContract"/> interface.
/// for uniquely identifying objects of type <typeparamref name="T"/>.
/// </summary>
/// <typeparam name="T">The type of objects for which to retrieve key properties.</typeparam>
/// <returns>An array of <see cref="PropertyInfo"/> objects representing the key properties of type <typeparamref name="T"/>.</returns>
public PropertyInfo[] GetKeyProperties<T>() where T : IDataContract
public PropertyInfo[] GetKeyProperties<T>()
{
return CacheManager.GetKeyProperties(typeof(T));
}
Expand Down
12 changes: 0 additions & 12 deletions src/Interface/IDataContract.cs

This file was deleted.

Loading

0 comments on commit e959180

Please sign in to comment.