using System;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using Pfz.Collections;
using Pfz.Databasing.Filtering;
namespace Pfz.Databasing.Managers
{
/// <summary>
/// This interface is responsible for managing all transitions from
/// Databases to Objects, and is also the point where you can "start"
/// your business logic, as all the actions (select, insert, update and
/// delete) pass throght this object.
/// </summary>
public interface IDatabaseManager
{
/// <summary>
/// Creates a new connection.
/// The server can use the name param to select the appropriate connection string or, if it only uses
/// one database, can ignore it.
/// </summary>
/// <param name="name">The name of the connection.</param>
/// <returns>A connection object.</returns>
IDatabaseConnection CreateConnection(string name = "Default");
/// <summary>
/// Tries to load a record by it's primary key.
/// Returns null if it is not found.
/// </summary>
/// <typeparam name="T">The type of the record to load.</typeparam>
/// <param name="connection">The connection and transaction to use for loading.</param>
/// <param name="primaryKeyValue">The value of the key.</param>
/// <returns>The loaded record or null.</returns>
T TryLoadByPrimaryKey<T>(IDatabaseConnection connection, object primaryKeyValue)
where
T: class, IRecord;
/// <summary>
/// Creates a new (insert) record of the given type.
/// </summary>
/// <typeparam name="T">The type of the record. Must be a persisted one.</typeparam>
/// <param name="connection">A connection if they are needed
/// during object initialization.</param>
/// <returns>The new created record, or throws an exception.</returns>
T Create<T>(IDatabaseConnection connection)
where
T: class, IRecord;
/// <summary>
/// Applies the given record to the database.
/// Returns a new record which any modifications done to fully apply the
/// record, like auto-numbering. This can be the original record or a clone of it.
/// </summary>
T Apply<T>(IDatabaseConnection connection, T record)
where
T: class, IRecord;
/// <summary>
/// Gets a value indicating if the cloning is necessary before apply.
/// For example, when calling it remotelly the object on the remote side is already a clone,
/// so no clonning is needed.
/// </summary>
bool MustCloneBeforeApply { get; }
/// <summary>
/// Executes a select for the given record type.
/// The automatic created part of the select includes all fields, the from and the tablename.
/// You can add the where clause or even some join. An order by is not indicated,
/// as if child classes exist, they will be loaded after the main class, ignoring
/// the order by.
/// </summary>
/// <typeparam name="T">The type of the record to build the select field list.</typeparam>
/// <param name="connection">The connection to use for reading.</param>
/// <param name="sql">The partialSql. You have two options of special parameters:<br/>
/// [CSharpPropertyName] - This is converted into the database field name, if it is different;<br/>
/// {CSharpPropertyName} - This will create a parameter with the right type for the given
/// CSharpPropertyName. In this case, you need to give a parameterValue for it.
/// </param>
/// <param name="parameterValues">The values, in order, for each C#
/// parameter declared in the sql clause using the {}.</param>
/// <returns>An enumerable collection of read-only records.</returns>
IFastEnumerator<T> FastLoadByPartialSql<T>(IDatabaseConnection connection, string sql, params object[] parameterValues)
where
T: class, IRecord;
/// <summary>
/// Loads records using the given filter group.
/// Joins must by created implicity if other records are referenced.
/// </summary>
IFastEnumerator<T> FastLoadByFilter<T>(IDatabaseConnection connection, Filter filter, ReadOnlyCollection<OrderByIndex> orderByIndexes = null)
where
T: class, IRecord;
/// <summary>
/// Count the number of records of the given type that matches the filter.
/// </summary>
/// <typeparam name="T">The type of the record to count.</typeparam>
/// <param name="connection">The connection to use.</param>
/// <param name="filter">A filter group, or null to count all records.</param>
/// <returns>The number of found records.</returns>
int CountRecordsByFilter<T>(IDatabaseConnection connection, Filter filter)
where
T: class, IRecord;
/// <summary>
/// Gets an enumerator that selects the property values of the given
/// properties/propertypaths. Utilizes the initialRecordType to know where
/// the select begins.
/// </summary>
/// <param name="connection">The connection used to load.</param>
/// <param name="parameters">The parameters used for this advanced load call.</param>
/// <returns>An enumerable collection of value arrays.</returns>
IFastEnumerator<object[]> AdvancedLoad(IDatabaseConnection connection, AdvancedLoadParameters parameters);
/// <summary>
/// Gets the type of the implemented class for the given
/// record type.
/// </summary>
Type GetImplementedTypeFor(Type recordInterfaceType);
/// <summary>
/// Deletes records using the given search expression.
/// Returns the number of records actually deleted.
/// </summary>
/// <param name="databaseConnection"></param>
/// <param name="expression"></param>
/// <returns>The number of records deleted.</returns>
int Delete<T>(IDatabaseConnection databaseConnection, Expression<Func<T, bool>> expression)
where
T: class, IRecord;
/// <summary>
/// Updates 0 to many records at once, using the given expressions.
/// </summary>
/// <typeparam name="T">The type of the record to update.</typeparam>
/// <param name="databaseConnection">The connection to use.</param>
/// <param name="setExpression">Fake "boolean" expression. Use == as the "receives" sign, and && to add other field to be set.</param>
/// <param name="whereExpression">The expression to use to find records.</param>
/// <returns>The number of updated records.</returns>
int Update<T>(IDatabaseConnection databaseConnection, Expression<Func<T, bool>> setExpression, Expression<Func<T, bool>> whereExpression)
where
T: class, IRecord;
}
}