DocSpace-client/common/ASC.Data.Backup.Core/Tasks/Modules/ModuleSpecificsBase.cs

295 lines
10 KiB
C#
Raw Normal View History

2022-03-15 18:00:53 +00:00
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Data.Backup.Tasks.Modules;
public abstract class ModuleSpecificsBase : IModuleSpecifics
2020-05-20 15:14:44 +00:00
{
public abstract ModuleName ModuleName { get; }
public abstract IEnumerable<TableInfo> Tables { get; }
public abstract IEnumerable<RelationInfo> TableRelations { get; }
public virtual string ConnectionStringName
=> _connectionStringName ??= ModuleName.ToString().ToLower();
private string _connectionStringName;
2022-04-14 19:42:15 +00:00
private readonly Helpers _helpers;
protected ModuleSpecificsBase(Helpers helpers)
2020-05-20 15:14:44 +00:00
{
_helpers = helpers;
}
public IEnumerable<TableInfo> GetTablesOrdered()
{
var notOrderedTables = new List<TableInfo>(Tables);
2022-02-09 18:33:50 +00:00
var totalTablesCount = notOrderedTables.Count;
var orderedTablesCount = 0;
while (orderedTablesCount < totalTablesCount)
2020-05-20 15:14:44 +00:00
{
var orderedTablesCountBeforeIter = orderedTablesCount; // ensure we not in infinite loop...
2020-05-20 15:14:44 +00:00
var i = 0;
while (i < notOrderedTables.Count)
2020-05-20 15:14:44 +00:00
{
var table = notOrderedTables[i];
2020-05-20 15:14:44 +00:00
var parentTables = TableRelations
.Where(x => x.FitsForTable(table.Name) && !x.IsExternal() && !x.IsSelfRelation() && x.Importance != RelationImportance.Low)
.Select(x => x.ParentTable);
if (parentTables.All(x => notOrderedTables.All(y => !string.Equals(y.Name, x, StringComparison.InvariantCultureIgnoreCase))))
2020-05-20 15:14:44 +00:00
{
notOrderedTables.RemoveAt(i);
orderedTablesCount++;
2020-05-20 15:14:44 +00:00
yield return table;
}
else
2022-02-09 18:33:50 +00:00
{
i++;
2022-02-09 18:33:50 +00:00
}
2020-05-20 15:14:44 +00:00
}
if (orderedTablesCountBeforeIter == orderedTablesCount) // ensure we not in infinite loop...
2022-02-09 16:46:09 +00:00
{
throw ThrowHelper.CantOrderTables(notOrderedTables.Select(x => x.Name));
2022-02-09 16:46:09 +00:00
}
}
}
2020-05-20 15:14:44 +00:00
public DbCommand CreateSelectCommand(DbConnection connection, int tenantId, TableInfo table, int limit, int offset)
{
var command = connection.CreateCommand();
command.CommandText = string.Format("select t.* from {0} as t {1} limit {2},{3};", table.Name, GetSelectCommandConditionText(tenantId, table), offset, limit);
2020-05-20 15:14:44 +00:00
return command;
}
2020-05-20 15:14:44 +00:00
public DbCommand CreateDeleteCommand(DbConnection connection, int tenantId, TableInfo table)
{
2022-04-14 19:42:15 +00:00
var command = connection.CreateCommand();
command.CommandText = $"delete t.* from {table.Name} as t {GetDeleteCommandConditionText(tenantId, table)};";
2022-02-09 18:33:50 +00:00
return command;
}
2022-02-09 18:33:50 +00:00
public DbCommand CreateInsertCommand(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row)
{
if (table.InsertMethod == InsertMethod.None)
{
return null;
2020-05-20 15:14:44 +00:00
}
2022-02-09 18:33:50 +00:00
if (!TryPrepareRow(dump, connection, columnMapper, table, row, out var valuesForInsert))
2020-05-26 08:52:47 +00:00
{
return null;
}
2020-05-20 15:14:44 +00:00
2022-04-14 19:42:15 +00:00
var columns = valuesForInsert.Keys.Intersect(table.Columns).ToArray();
var insert = table.InsertMethod != InsertMethod.Ignore
? table.InsertMethod.ToString().ToLower()
: "insert ignore";
var insertCommantText = $"{insert} into {table.Name}({string.Join(",", columns)}) values({string.Join(",", columns.Select(c => "@" + c))});";
2022-02-09 18:33:50 +00:00
var command = connection.CreateCommand();
command.CommandText = insertCommantText;
foreach (var parameter in valuesForInsert)
{
AddParameter(command, parameter.Key, parameter.Value);
2020-05-26 08:52:47 +00:00
}
return command;
}
public DbCommand AddParameter(DbCommand command, string name, object value)
{
var p = command.CreateParameter();
if (!string.IsNullOrEmpty(name))
2022-04-14 19:42:15 +00:00
{
p.ParameterName = name.StartsWith('@') ? name : "@" + name;
}
2020-05-26 08:52:47 +00:00
p.Value = GetParameterValue(value);
2020-05-26 08:52:47 +00:00
command.Parameters.Add(p);
2022-02-09 18:33:50 +00:00
return command;
}
2022-02-09 18:33:50 +00:00
public object GetParameterValue(object value)
{
if (value == null)
2020-05-20 15:14:44 +00:00
{
return DBNull.Value;
2020-05-20 15:14:44 +00:00
}
if (value is Enum @enum)
2022-02-09 18:33:50 +00:00
{
return @enum.ToString("d");
2022-02-09 18:33:50 +00:00
}
if (value is DateTime d)
2022-02-09 18:33:50 +00:00
{
return new DateTime(d.Year, d.Month, d.Day, d.Hour, d.Minute, d.Second, DateTimeKind.Unspecified);
2022-02-09 18:33:50 +00:00
}
return value;
}
2020-05-20 15:14:44 +00:00
public virtual bool TryAdjustFilePath(bool dump, ColumnMapper columnMapper, ref string filePath)
{
return true;
}
public virtual void PrepareData(DataTable data)
{
// nothing to do
}
public virtual Stream PrepareData(string key, Stream stream, ColumnMapper columnMapper)
{
return stream;
}
2020-05-20 15:14:44 +00:00
protected virtual string GetSelectCommandConditionText(int tenantId, TableInfo table)
{
if (!table.HasTenantColumn())
2020-05-20 15:14:44 +00:00
{
throw ThrowHelper.CantDetectTenant(table.Name);
2020-05-20 15:14:44 +00:00
}
return string.Format("where t.{0} = {1}", table.TenantColumn, tenantId);
}
2020-05-20 15:14:44 +00:00
protected virtual string GetDeleteCommandConditionText(int tenantId, TableInfo table)
{
return GetSelectCommandConditionText(tenantId, table);
}
protected virtual bool TryPrepareRow(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, DataRowInfo row, out Dictionary<string, object> preparedRow)
{
preparedRow = new Dictionary<string, object>();
2020-05-20 15:14:44 +00:00
var parentRelations = TableRelations
.Where(x => x.FitsForRow(row) && x.Importance != RelationImportance.Low)
.GroupBy(x => x.ChildColumn)
.ToDictionary(x => x.Key);
foreach (var columnName in row.ColumnNames)
{
if (table.IdType == IdType.Autoincrement && columnName.Equals(table.IdColumn, StringComparison.OrdinalIgnoreCase))
2020-05-20 15:14:44 +00:00
{
continue;
}
2020-05-20 15:14:44 +00:00
var val = row[columnName];
if (!parentRelations.ContainsKey(columnName))
{
if (!TryPrepareValue(connection, columnMapper, table, columnName, ref val))
2020-05-20 15:14:44 +00:00
{
return false;
2020-05-20 15:14:44 +00:00
}
}
else
{
if (!TryPrepareValue(dump, connection, columnMapper, table, columnName, parentRelations[columnName], ref val))
2020-05-20 15:14:44 +00:00
{
return false;
2020-05-20 15:14:44 +00:00
}
if (!table.HasIdColumn() && !table.HasTenantColumn() && val == row[columnName])
2022-02-09 16:46:09 +00:00
{
2020-05-20 15:14:44 +00:00
return false;
2022-02-09 16:46:09 +00:00
}
}
2022-02-09 16:46:09 +00:00
preparedRow.Add(columnName, val);
}
2022-02-09 18:33:50 +00:00
return true;
}
2020-05-20 15:14:44 +00:00
protected virtual bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, ref object value)
{
if (columnName.Equals(table.TenantColumn, StringComparison.OrdinalIgnoreCase))
{
var tenantMapping = columnMapper.GetTenantMapping();
if (tenantMapping < 1)
2020-05-20 15:14:44 +00:00
{
return false;
}
2022-02-09 16:46:09 +00:00
value = tenantMapping;
2022-02-09 18:33:50 +00:00
return true;
}
2020-05-20 15:14:44 +00:00
if (table.UserIDColumns.Any(x => columnName.Equals(x, StringComparison.OrdinalIgnoreCase)))
{
var strVal = Convert.ToString(value);
var userMapping = columnMapper.GetUserMapping(strVal);
if (userMapping == null)
2022-02-09 16:46:09 +00:00
{
return _helpers.IsEmptyOrSystemUser(strVal);
2022-02-09 16:46:09 +00:00
}
2020-05-20 15:14:44 +00:00
value = userMapping;
2020-05-20 15:14:44 +00:00
return true;
}
var mapping = columnMapper.GetMapping(table.Name, columnName, value);
if (mapping != null)
2020-05-20 15:14:44 +00:00
{
value = mapping;
2020-05-20 15:14:44 +00:00
}
return true;
}
2022-02-09 18:33:50 +00:00
protected virtual bool TryPrepareValue(bool dump, DbConnection connection, ColumnMapper columnMapper, TableInfo table, string columnName, IEnumerable<RelationInfo> relations, ref object value)
{
return TryPrepareValue(connection, columnMapper, relations.Single(), ref value);
}
2021-08-31 09:40:28 +00:00
protected virtual bool TryPrepareValue(DbConnection connection, ColumnMapper columnMapper, RelationInfo relation, ref object value)
{
var mappedValue = columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, value);
if (mappedValue != null)
{
value = mappedValue;
return true;
2020-05-20 15:14:44 +00:00
}
return value == null ||
Guid.TryParse(Convert.ToString(value), out _) ||
int.TryParse(Convert.ToString(value), out _);
2020-05-20 15:14:44 +00:00
}
}