Rebase with github repository
This commit is contained in:
parent
e38eb7aa1c
commit
d7b0a471f0
@ -1,5 +1,6 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using Connected.Data.Schema.Sql;
|
||||
using Connected.Entities.Annotations;
|
||||
|
||||
@ -44,6 +45,7 @@ internal class ExistingColumn : ISchemaColumn, IExistingSchemaColumn
|
||||
public DateKind DateKind { get; set; } = DateKind.DateTime;
|
||||
public BinaryKind BinaryKind { get; set; } = BinaryKind.VarBinary;
|
||||
|
||||
public PropertyInfo Property { get; set; }
|
||||
public int DatePrecision { get; set; }
|
||||
|
||||
public ImmutableArray<string> QueryIndexColumns(string column)
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using Connected.Entities.Annotations;
|
||||
|
||||
namespace Connected.Data.Schema;
|
||||
@ -21,4 +22,6 @@ public interface ISchemaColumn
|
||||
DateKind DateKind { get; }
|
||||
BinaryKind BinaryKind { get; }
|
||||
int DatePrecision { get; }
|
||||
|
||||
PropertyInfo Property { get; }
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using Connected.Entities.Annotations;
|
||||
|
||||
namespace Connected.Data.Schema;
|
||||
|
||||
internal class SchemaColumn : IEquatable<ISchemaColumn>, ISchemaColumn
|
||||
{
|
||||
public SchemaColumn(ISchema schema)
|
||||
public SchemaColumn(ISchema schema, PropertyInfo property)
|
||||
{
|
||||
Schema = schema;
|
||||
Property = property;
|
||||
}
|
||||
private ISchema Schema { get; }
|
||||
|
||||
@ -30,6 +32,8 @@ internal class SchemaColumn : IEquatable<ISchemaColumn>, ISchemaColumn
|
||||
|
||||
public int Ordinal { get; set; }
|
||||
|
||||
public PropertyInfo Property { get; set; }
|
||||
|
||||
public bool Equals(ISchemaColumn? other)
|
||||
{
|
||||
if (other is null)
|
||||
|
@ -60,6 +60,7 @@ internal class SchemaService : ISchemaService
|
||||
await middleware.Synchronize(entity, schema);
|
||||
|
||||
synchronized = true;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* We should notify the environment that entity is no synchronized.
|
||||
@ -80,7 +81,7 @@ internal class SchemaService : ISchemaService
|
||||
{
|
||||
var persistence = entityType.GetCustomAttribute<PersistenceAttribute>();
|
||||
|
||||
return persistence is null || !persistence.Persistence.HasFlag(ColumnPersistence.Write);
|
||||
return persistence is null || persistence.Persistence.HasFlag(ColumnPersistence.Write);
|
||||
}
|
||||
|
||||
private static ISchema CreateSchema(Type type)
|
||||
@ -104,7 +105,7 @@ internal class SchemaService : ISchemaService
|
||||
if (property.FindAttribute<PersistenceAttribute>() is PersistenceAttribute pa && pa.IsVirtual)
|
||||
continue;
|
||||
|
||||
var column = new SchemaColumn(result)
|
||||
var column = new SchemaColumn(result, property)
|
||||
{
|
||||
Name = ResolveColumnName(property),
|
||||
DataType = DataExtensions.ToDbType(property)
|
||||
|
@ -4,8 +4,7 @@ using Connected.Entities.Annotations;
|
||||
namespace Connected.Data.Schema.Sql;
|
||||
|
||||
[Persistence(Persistence = ColumnPersistence.InMemory)]
|
||||
internal sealed class AdHocSchemaEntity : IEntity
|
||||
internal sealed record AdHocSchemaEntity : Entity
|
||||
{
|
||||
public State State { get; init; }
|
||||
public bool Result { get; init; }
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using Connected.Data.Sql;
|
||||
using System.Data;
|
||||
using Connected.Data.Sql;
|
||||
using Connected.Entities.Storage;
|
||||
using System.Data;
|
||||
|
||||
namespace Connected.Data.Schema.Sql;
|
||||
|
||||
@ -50,7 +50,7 @@ internal class SchemaExecutionContext
|
||||
|
||||
public async Task Execute(string commandText)
|
||||
{
|
||||
await Storage.Open<AdHocSchemaEntity>().Select(new SchemaStorageArgs(new StorageOperation { CommandText = commandText }, typeof(SqlDataConnection), ConnectionString));
|
||||
await Storage.Open<AdHocSchemaEntity>().Execute(new SchemaStorageArgs(new StorageOperation { CommandText = commandText }, typeof(SqlDataConnection), ConnectionString));
|
||||
}
|
||||
|
||||
public async Task<AdHocSchemaEntity?> Select(string commandText)
|
||||
@ -74,7 +74,7 @@ internal class SchemaExecutionContext
|
||||
Constraints.Add(type, existing);
|
||||
}
|
||||
|
||||
if (ConstraintNameExists(name))
|
||||
if (!ConstraintNameExists(name))
|
||||
existing.Add(name);
|
||||
}
|
||||
|
||||
|
@ -1,145 +1,143 @@
|
||||
using Connected.Data.Storage;
|
||||
using System.Data;
|
||||
using Connected.Entities.Storage;
|
||||
using Connected.Interop;
|
||||
using System.Data;
|
||||
|
||||
namespace Connected.Data.Schema.Sql;
|
||||
|
||||
internal class SpHelp : SynchronizationQuery<ObjectDescriptor>
|
||||
{
|
||||
private readonly ObjectDescriptor _descriptor;
|
||||
private readonly ObjectDescriptor _descriptor;
|
||||
|
||||
public SpHelp()
|
||||
{
|
||||
_descriptor = new();
|
||||
}
|
||||
public SpHelp()
|
||||
{
|
||||
_descriptor = new();
|
||||
}
|
||||
|
||||
private ObjectDescriptor Result => _descriptor;
|
||||
private ObjectDescriptor Result => _descriptor;
|
||||
|
||||
protected override async Task<ObjectDescriptor> OnExecute()
|
||||
{
|
||||
var operation = new StorageOperation { CommandText = "sp_help", CommandType = CommandType.Text };
|
||||
protected override async Task<ObjectDescriptor> OnExecute()
|
||||
{
|
||||
var operation = new StorageOperation { CommandText = "sp_help", CommandType = CommandType.Text };
|
||||
|
||||
operation.AddParameter(new StorageParameter
|
||||
{
|
||||
Name = "@objname",
|
||||
Type = DbType.String,
|
||||
Value = Escape(Context.Schema.SchemaName(), Context.Schema.Name)
|
||||
}
|
||||
);
|
||||
operation.AddParameter(new StorageParameter
|
||||
{
|
||||
Name = "@objname",
|
||||
Type = DbType.String,
|
||||
Value = Escape(Context.Schema.SchemaName(), Context.Schema.Name)
|
||||
}
|
||||
);
|
||||
|
||||
var rdr = await Context.OpenReader(operation);
|
||||
var rdr = await Context.OpenReader(operation);
|
||||
|
||||
try
|
||||
{
|
||||
ReadMetadata(rdr);
|
||||
ReadColumns(rdr);
|
||||
ReadIdentity(rdr);
|
||||
ReadRowGuid(rdr);
|
||||
ReadFileGroup(rdr);
|
||||
ReadIndexes(rdr);
|
||||
ReadConstraints(rdr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
rdr.Close();
|
||||
}
|
||||
try
|
||||
{
|
||||
ReadMetadata(rdr);
|
||||
ReadColumns(rdr);
|
||||
ReadIdentity(rdr);
|
||||
ReadRowGuid(rdr);
|
||||
ReadFileGroup(rdr);
|
||||
ReadIndexes(rdr);
|
||||
ReadConstraints(rdr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
rdr.Close();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void ReadMetadata(IDataReader rdr)
|
||||
{
|
||||
if (rdr.Read())
|
||||
{
|
||||
Result.MetaData.Name = rdr.GetValue("Name", string.Empty);
|
||||
Result.MetaData.Created = rdr.GetValue("Created_datetime", DateTime.MinValue);
|
||||
Result.MetaData.Owner = rdr.GetValue("Owner", string.Empty);
|
||||
Result.MetaData.Type = rdr.GetValue("Type", string.Empty);
|
||||
}
|
||||
}
|
||||
private void ReadMetadata(IDataReader rdr)
|
||||
{
|
||||
if (rdr.Read())
|
||||
{
|
||||
Result.MetaData.Name = rdr.GetValue("Name", string.Empty);
|
||||
Result.MetaData.Owner = rdr.GetValue("Owner", string.Empty);
|
||||
Result.MetaData.Type = rdr.GetValue("Object_type", string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadColumns(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadColumns(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Columns.Add(new ObjectColumn
|
||||
{
|
||||
Collation = rdr.GetValue("Collation", string.Empty),
|
||||
Computed = !string.Equals(rdr.GetValue("Computed", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
|
||||
FixedLenInSource = rdr.GetValue("FixedLenNullInSource", string.Empty),
|
||||
Length = rdr.GetValue("Length", 0),
|
||||
Name = rdr.GetValue("Column_name", string.Empty),
|
||||
Nullable = !string.Equals(rdr.GetValue("Nullable", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
|
||||
Precision = TypeConversion.Convert<int>(rdr.GetValue("Prec", string.Empty).Trim()),
|
||||
Scale = TypeConversion.Convert<int>(rdr.GetValue("Scale", string.Empty).Trim()),
|
||||
TrimTrailingBlanks = rdr.GetValue("TrimTrailingBlanks", string.Empty),
|
||||
Type = rdr.GetValue("Type", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Columns.Add(new ObjectColumn
|
||||
{
|
||||
Collation = rdr.GetValue("Collation", string.Empty),
|
||||
Computed = !string.Equals(rdr.GetValue("Computed", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
|
||||
FixedLenInSource = rdr.GetValue("FixedLenNullInSource", string.Empty),
|
||||
Length = rdr.GetValue("Length", 0),
|
||||
Name = rdr.GetValue("Column_name", string.Empty),
|
||||
Nullable = !string.Equals(rdr.GetValue("Nullable", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
|
||||
Precision = TypeConversion.Convert<int>(rdr.GetValue("Prec", string.Empty).Trim()),
|
||||
Scale = TypeConversion.Convert<int>(rdr.GetValue("Scale", string.Empty).Trim()),
|
||||
TrimTrailingBlanks = rdr.GetValue("TrimTrailingBlanks", string.Empty),
|
||||
Type = rdr.GetValue("Type", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadIdentity(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadIdentity(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
if (rdr.Read())
|
||||
{
|
||||
Result.Identity.Identity = rdr.GetValue("Identity", string.Empty);
|
||||
Result.Identity.Increment = rdr.GetValue("Increment", 0);
|
||||
Result.Identity.NotForReplication = rdr.GetValue("Not For Replication", 0) != 0;
|
||||
}
|
||||
}
|
||||
if (rdr.Read())
|
||||
{
|
||||
Result.Identity.Identity = rdr.GetValue("Identity", string.Empty);
|
||||
Result.Identity.Increment = rdr.GetValue("Increment", 0);
|
||||
Result.Identity.NotForReplication = rdr.GetValue("Not For Replication", 0) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadRowGuid(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadRowGuid(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
if (rdr.Read())
|
||||
Result.RowGuid.RowGuidCol = rdr.GetValue("RowGuidCol", string.Empty);
|
||||
}
|
||||
if (rdr.Read())
|
||||
Result.RowGuid.RowGuidCol = rdr.GetValue("RowGuidCol", string.Empty);
|
||||
}
|
||||
|
||||
private void ReadFileGroup(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadFileGroup(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
if (rdr.Read())
|
||||
Result.FileGroup.FileGroup = rdr.GetValue("Data_located_on_filegroup", string.Empty);
|
||||
}
|
||||
if (rdr.Read())
|
||||
Result.FileGroup.FileGroup = rdr.GetValue("Data_located_on_filegroup", string.Empty);
|
||||
}
|
||||
|
||||
private void ReadIndexes(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadIndexes(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Indexes.Add(new ObjectIndex
|
||||
{
|
||||
Description = rdr.GetValue("index_description", string.Empty),
|
||||
Keys = rdr.GetValue("index_keys", string.Empty),
|
||||
Name = rdr.GetValue("index_name", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Indexes.Add(new ObjectIndex
|
||||
{
|
||||
Description = rdr.GetValue("index_description", string.Empty),
|
||||
Keys = rdr.GetValue("index_keys", string.Empty),
|
||||
Name = rdr.GetValue("index_name", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConstraints(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
private void ReadConstraints(IDataReader rdr)
|
||||
{
|
||||
rdr.NextResult();
|
||||
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Constraints.Add(new ObjectConstraint
|
||||
{
|
||||
DeleteAction = rdr.GetValue("delete_action", string.Empty),
|
||||
Keys = rdr.GetValue("constraint_keys", string.Empty),
|
||||
Name = rdr.GetValue("constraint_name", string.Empty),
|
||||
StatusEnabled = rdr.GetValue("status_enabled", string.Empty),
|
||||
StatusForReplication = rdr.GetValue("status_for_replication", string.Empty),
|
||||
Type = rdr.GetValue("constraint_type", string.Empty),
|
||||
UpdateAction = rdr.GetValue("update_action", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
while (rdr.Read())
|
||||
{
|
||||
Result.Constraints.Add(new ObjectConstraint
|
||||
{
|
||||
DeleteAction = rdr.GetValue("delete_action", string.Empty),
|
||||
Keys = rdr.GetValue("constraint_keys", string.Empty),
|
||||
Name = rdr.GetValue("constraint_name", string.Empty),
|
||||
StatusEnabled = rdr.GetValue("status_enabled", string.Empty),
|
||||
StatusForReplication = rdr.GetValue("status_for_replication", string.Empty),
|
||||
Type = rdr.GetValue("constraint_type", string.Empty),
|
||||
UpdateAction = rdr.GetValue("update_action", string.Empty)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
using Connected.Data.Schema;
|
||||
using System.Collections.Immutable;
|
||||
using Connected.Data.Schema;
|
||||
using Connected.Data.Sharding;
|
||||
using Connected.Entities.Storage;
|
||||
using Connected.Middleware;
|
||||
using Connected.ServiceModel;
|
||||
using Connected.ServiceModel.Transactions;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Connected.Data.Storage;
|
||||
|
||||
@ -26,7 +26,7 @@ internal sealed class ConnectionProvider : IConnectionProvider, IAsyncDisposable
|
||||
public IMiddlewareService Middleware { get; }
|
||||
private ITransactionContext TransactionService { get; }
|
||||
private List<IStorageConnection> Connections => _connections;
|
||||
public StorageConnectionMode Mode { get; set; } = StorageConnectionMode.Isolated;
|
||||
public StorageConnectionMode Mode { get; set; } = StorageConnectionMode.Shared;
|
||||
public async Task<ImmutableList<IStorageConnection>> Open<TEntity>(StorageContextArgs args)
|
||||
{
|
||||
/*
|
||||
|
@ -1,216 +1,229 @@
|
||||
using Connected.Entities;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Connected.Entities;
|
||||
using Connected.Entities.Annotations;
|
||||
using Connected.Entities.Storage;
|
||||
using Connected.Interop;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Connected.Data.Update;
|
||||
|
||||
internal abstract class CommandBuilder
|
||||
{
|
||||
private readonly List<IStorageParameter> _parameters;
|
||||
private readonly List<PropertyInfo> _whereProperties;
|
||||
private List<PropertyInfo> _properties;
|
||||
private readonly List<IStorageParameter> _parameters;
|
||||
private readonly List<PropertyInfo> _whereProperties;
|
||||
private List<PropertyInfo> _properties;
|
||||
|
||||
protected CommandBuilder()
|
||||
{
|
||||
_parameters = new List<IStorageParameter>();
|
||||
_whereProperties = new List<PropertyInfo>();
|
||||
protected CommandBuilder()
|
||||
{
|
||||
_parameters = new List<IStorageParameter>();
|
||||
_whereProperties = new List<PropertyInfo>();
|
||||
|
||||
Text = new StringBuilder();
|
||||
}
|
||||
Text = new StringBuilder();
|
||||
}
|
||||
|
||||
public StorageOperation? Build(IEntity entity)
|
||||
{
|
||||
Entity = entity;
|
||||
public StorageOperation? Build(IEntity entity)
|
||||
{
|
||||
Entity = entity;
|
||||
|
||||
if (TryGetExisting(out StorageOperation? existing))
|
||||
{
|
||||
/*
|
||||
if (TryGetExisting(out StorageOperation? existing))
|
||||
{
|
||||
/*
|
||||
* We need to rebuild an instance since StorageOperation
|
||||
* is immutable
|
||||
*/
|
||||
var result = new StorageOperation
|
||||
{
|
||||
CommandText = existing.CommandText,
|
||||
CommandTimeout = existing.CommandTimeout,
|
||||
CommandType = existing.CommandType,
|
||||
Concurrency = existing.Concurrency
|
||||
};
|
||||
var result = new StorageOperation
|
||||
{
|
||||
CommandText = existing.CommandText,
|
||||
CommandTimeout = existing.CommandTimeout,
|
||||
CommandType = existing.CommandType,
|
||||
Concurrency = existing.Concurrency
|
||||
};
|
||||
|
||||
if (result.Parameters is null)
|
||||
return result;
|
||||
if (result.Parameters is null)
|
||||
return result;
|
||||
|
||||
foreach (var parameter in result.Parameters)
|
||||
{
|
||||
if (parameter.Direction == ParameterDirection.Input)
|
||||
{
|
||||
if (ResolveProperty(parameter.Name) is PropertyInfo property)
|
||||
{
|
||||
result.AddParameter(new StorageParameter
|
||||
{
|
||||
Value = GetValue(property),
|
||||
Name = parameter.Name,
|
||||
Type = parameter.Type,
|
||||
Direction = parameter.Direction
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var parameter in result.Parameters)
|
||||
{
|
||||
if (parameter.Direction == ParameterDirection.Input)
|
||||
{
|
||||
if (ResolveProperty(parameter.Name) is PropertyInfo property)
|
||||
{
|
||||
result.AddParameter(new StorageParameter
|
||||
{
|
||||
Value = GetValue(property),
|
||||
Name = parameter.Name,
|
||||
Type = parameter.Type,
|
||||
Direction = parameter.Direction
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Schema = Entity.GetSchemaAttribute();
|
||||
Schema = Entity.GetSchemaAttribute();
|
||||
|
||||
return OnBuild();
|
||||
}
|
||||
return OnBuild();
|
||||
}
|
||||
|
||||
protected List<PropertyInfo> Properties => _properties ??= GetProperties();
|
||||
protected List<PropertyInfo> Properties => _properties ??= GetProperties();
|
||||
|
||||
protected List<PropertyInfo> WhereProperties => _whereProperties;
|
||||
protected List<PropertyInfo> WhereProperties => _whereProperties;
|
||||
|
||||
protected string CommandText => Text.ToString();
|
||||
protected string CommandText => Text.ToString();
|
||||
|
||||
protected IEntity Entity { get; private set; }
|
||||
protected IEntity Entity { get; private set; }
|
||||
|
||||
protected SchemaAttribute Schema { get; private set; }
|
||||
protected SchemaAttribute Schema { get; private set; }
|
||||
|
||||
private StringBuilder Text { get; set; }
|
||||
private StringBuilder Text { get; set; }
|
||||
|
||||
protected abstract StorageOperation OnBuild();
|
||||
protected abstract StorageOperation OnBuild();
|
||||
|
||||
protected abstract bool TryGetExisting(out StorageOperation? result);
|
||||
protected abstract bool TryGetExisting(out StorageOperation? result);
|
||||
|
||||
protected List<IStorageParameter> Parameters => _parameters;
|
||||
protected List<IStorageParameter> Parameters => _parameters;
|
||||
|
||||
protected void Write(string text)
|
||||
{
|
||||
Text.Append(text);
|
||||
}
|
||||
protected void Write(string text)
|
||||
{
|
||||
Text.Append(text);
|
||||
}
|
||||
|
||||
protected void Write(char text)
|
||||
{
|
||||
Text.Append(text);
|
||||
}
|
||||
protected void Write(char text)
|
||||
{
|
||||
Text.Append(text);
|
||||
}
|
||||
|
||||
protected void WriteLine(string text)
|
||||
{
|
||||
Text.AppendLine(text);
|
||||
}
|
||||
protected void WriteLine(string text)
|
||||
{
|
||||
Text.AppendLine(text);
|
||||
}
|
||||
|
||||
protected void Trim()
|
||||
{
|
||||
for (var i = Text.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!Text[i].Equals(',') && !Text[i].Equals('\n') && !Text[i].Equals('\r') && !Text[i].Equals(' '))
|
||||
break;
|
||||
protected void Trim()
|
||||
{
|
||||
for (var i = Text.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (!Text[i].Equals(',') && !Text[i].Equals('\n') && !Text[i].Equals('\r') && !Text[i].Equals(' '))
|
||||
break;
|
||||
|
||||
if (i < Text.Length)
|
||||
Text.Length = i;
|
||||
}
|
||||
}
|
||||
if (i < Text.Length)
|
||||
Text.Length = i;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual List<PropertyInfo> GetProperties()
|
||||
{
|
||||
return Interop.Properties.GetImplementedProperties(Entity);
|
||||
}
|
||||
protected virtual List<PropertyInfo> GetProperties()
|
||||
{
|
||||
var props = Interop.Properties.GetImplementedProperties(Entity);
|
||||
var result = new List<PropertyInfo>();
|
||||
|
||||
protected static bool IsVersion(PropertyInfo property)
|
||||
{
|
||||
return property.GetCustomAttribute<ETagAttribute>() is not null;
|
||||
}
|
||||
foreach (var property in props)
|
||||
{
|
||||
var persistence = property.FindAttribute<PersistenceAttribute>();
|
||||
|
||||
protected static string ColumnName(PropertyInfo property)
|
||||
{
|
||||
var dataMember = property.FindAttribute<MemberAttribute>();
|
||||
if (persistence is not null && persistence.Persistence.HasFlag(ColumnPersistence.InMemory))
|
||||
continue;
|
||||
|
||||
return dataMember is null || string.IsNullOrEmpty(dataMember.Member) ? property.Name.ToCamelCase() : dataMember.Member;
|
||||
}
|
||||
result.Add(property);
|
||||
}
|
||||
|
||||
protected static DbType ResolveDbType(PropertyInfo property)
|
||||
{
|
||||
if (IsVersion(property))
|
||||
return DbType.Binary;
|
||||
return result;
|
||||
}
|
||||
|
||||
return property.PropertyType.ToDbType();
|
||||
}
|
||||
protected object? GetValue(PropertyInfo property)
|
||||
{
|
||||
if (IsNull(property))
|
||||
return "NULL";
|
||||
protected static bool IsVersion(PropertyInfo property)
|
||||
{
|
||||
return property.GetCustomAttribute<ETagAttribute>() is not null;
|
||||
}
|
||||
|
||||
if (IsVersion(property))
|
||||
return (byte[])EntityVersion.Parse(property.GetValue(Entity));
|
||||
protected static string ColumnName(PropertyInfo property)
|
||||
{
|
||||
var dataMember = property.FindAttribute<MemberAttribute>();
|
||||
|
||||
return GetValue(property.GetValue(Entity), property.PropertyType.ToDbType());
|
||||
}
|
||||
return dataMember is null || string.IsNullOrEmpty(dataMember.Member) ? property.Name.ToCamelCase() : dataMember.Member;
|
||||
}
|
||||
|
||||
private static object? GetValue(object value, DbType dbType)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DbType.Binary:
|
||||
if (value is byte[] bytes)
|
||||
return Convert.ToBase64String(bytes);
|
||||
else
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(value.ToString()));
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
protected static DbType ResolveDbType(PropertyInfo property)
|
||||
{
|
||||
if (IsVersion(property))
|
||||
return DbType.Binary;
|
||||
|
||||
private bool IsNull(PropertyInfo property)
|
||||
{
|
||||
var result = property.GetValue(Entity);
|
||||
return property.PropertyType.ToDbType();
|
||||
}
|
||||
protected object? GetValue(PropertyInfo property)
|
||||
{
|
||||
if (IsNull(property))
|
||||
return "NULL";
|
||||
|
||||
if (result is null)
|
||||
return true;
|
||||
if (IsVersion(property))
|
||||
return (byte[])EntityVersion.Parse(property.GetValue(Entity));
|
||||
|
||||
if (property.GetCustomAttribute<NullableAttribute>() is null)
|
||||
return false;
|
||||
return GetValue(property.GetValue(Entity), property.PropertyType.ToDbType());
|
||||
}
|
||||
|
||||
var def = Types.GetDefault(property.PropertyType);
|
||||
private static object? GetValue(object value, DbType dbType)
|
||||
{
|
||||
switch (dbType)
|
||||
{
|
||||
case DbType.Binary:
|
||||
if (value is byte[] bytes)
|
||||
return Convert.ToBase64String(bytes);
|
||||
else
|
||||
return Convert.ToBase64String(Encoding.UTF8.GetBytes(value.ToString()));
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return TypeComparer.Compare(result, def);
|
||||
}
|
||||
private bool IsNull(PropertyInfo property)
|
||||
{
|
||||
var result = property.GetValue(Entity);
|
||||
|
||||
protected StorageParameter CreateParameter(PropertyInfo property)
|
||||
{
|
||||
return CreateParameter(property, ParameterDirection.Input);
|
||||
}
|
||||
if (result is null)
|
||||
return true;
|
||||
|
||||
protected StorageParameter CreateParameter(PropertyInfo property, ParameterDirection direction)
|
||||
{
|
||||
var columnName = ColumnName(property);
|
||||
var parameterName = $"@{columnName}";
|
||||
if (property.GetCustomAttribute<NullableAttribute>() is null)
|
||||
return false;
|
||||
|
||||
var parameter = new StorageParameter
|
||||
{
|
||||
Direction = direction,
|
||||
Name = parameterName,
|
||||
Type = ResolveDbType(property),
|
||||
Value = GetValue(property)
|
||||
};
|
||||
var def = Types.GetDefault(property.PropertyType);
|
||||
|
||||
Parameters.Add(parameter);
|
||||
return TypeComparer.Compare(result, def);
|
||||
}
|
||||
|
||||
return parameter;
|
||||
}
|
||||
protected StorageParameter CreateParameter(PropertyInfo property)
|
||||
{
|
||||
return CreateParameter(property, ParameterDirection.Input);
|
||||
}
|
||||
|
||||
private PropertyInfo ResolveProperty(string parameterName)
|
||||
{
|
||||
var propertyName = parameterName[1..];
|
||||
var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
|
||||
protected StorageParameter CreateParameter(PropertyInfo property, ParameterDirection direction)
|
||||
{
|
||||
var columnName = ColumnName(property);
|
||||
var parameterName = $"@{columnName}";
|
||||
|
||||
if (Entity.GetType().GetProperty(propertyName.ToPascalCase(), flags) is PropertyInfo property)
|
||||
return property;
|
||||
var parameter = new StorageParameter
|
||||
{
|
||||
Direction = direction,
|
||||
Name = parameterName,
|
||||
Type = ResolveDbType(property),
|
||||
Value = GetValue(property)
|
||||
};
|
||||
|
||||
if (Entity.GetType().GetProperty(propertyName, flags) is PropertyInfo raw)
|
||||
return raw;
|
||||
Parameters.Add(parameter);
|
||||
|
||||
return null;
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
private PropertyInfo ResolveProperty(string parameterName)
|
||||
{
|
||||
var propertyName = parameterName[1..];
|
||||
var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic;
|
||||
|
||||
if (Entity.GetType().GetProperty(propertyName.ToPascalCase(), flags) is PropertyInfo property)
|
||||
return property;
|
||||
|
||||
if (Entity.GetType().GetProperty(propertyName, flags) is PropertyInfo raw)
|
||||
return raw;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,24 +1,24 @@
|
||||
using Connected.Expressions.Visitors;
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions;
|
||||
using Connected.Expressions.Visitors;
|
||||
|
||||
namespace Connected.Expressions.Translation.Rewriters;
|
||||
|
||||
public class WhereClauseRewriter : DatabaseVisitor
|
||||
{
|
||||
private WhereClauseRewriter(ExpressionCompilationContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
protected WhereClauseRewriter(ExpressionCompilationContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
|
||||
public ExpressionCompilationContext Context { get; }
|
||||
public ExpressionCompilationContext Context { get; }
|
||||
|
||||
public static Expression Rewrite(ExpressionCompilationContext context, Expression expression)
|
||||
{
|
||||
return new WhereClauseRewriter(context).Visit(expression);
|
||||
}
|
||||
public static Expression Rewrite(ExpressionCompilationContext context, Expression expression)
|
||||
{
|
||||
return new WhereClauseRewriter(context).Visit(expression);
|
||||
}
|
||||
|
||||
protected override Expression VisitWhere(Expression whereExpression)
|
||||
{
|
||||
return ParameterRewriter.Rewrite(Context, whereExpression);
|
||||
}
|
||||
protected override Expression VisitWhere(Expression whereExpression)
|
||||
{
|
||||
return ParameterRewriter.Rewrite(Context, whereExpression);
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ internal static class EntitySynchronizer
|
||||
else
|
||||
{
|
||||
/*
|
||||
* entitySynchronization = token1, token2,...
|
||||
* entitySynchronization = token1; token2,...
|
||||
*/
|
||||
var tokens = value.Split(',');
|
||||
/*
|
||||
@ -66,13 +66,20 @@ internal static class EntitySynchronizer
|
||||
|
||||
await Synchronize(schemaService, Assembly.Load(AssemblyName.GetAssemblyName(subTokens[1])), logger);
|
||||
}
|
||||
else if (string.Equals(subTokens[1], "type", StringComparison.OrdinalIgnoreCase))
|
||||
else if (string.Equals(subTokens[0], "type", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
logger.LogTrace("Loading type '{type}'", subTokens[1]);
|
||||
var typeTokens = subTokens[1].Split("/");
|
||||
|
||||
if (Type.GetType(subTokens[1]) is not Type type)
|
||||
if (typeTokens.Length != 2)
|
||||
throw new ArgumentException("Invalid entitySyncronization token '{token}'. Expected type:[assembly]/[type].", subTokens[1]);
|
||||
|
||||
var qualifier = $"{typeTokens[1]}, {typeTokens[0]}";
|
||||
|
||||
logger.LogTrace("Loading type '{type}'", qualifier);
|
||||
|
||||
if (Type.GetType(qualifier) is not Type type)
|
||||
{
|
||||
logger.LogWarning("Entity type '{type}' could not be loaded. Synchronization on the specified type could not be performed.", subTokens[1]);
|
||||
logger.LogWarning("Entity type '{type}' could not be loaded. Synchronization on the specified type could not be performed.", qualifier);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -18,5 +18,33 @@
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ImplementsInterface(this Type type, Type interfaceType)
|
||||
{
|
||||
var interfaces = type.GetInterfaces();
|
||||
|
||||
foreach (var i in interfaces)
|
||||
{
|
||||
if (!i.IsGenericType)
|
||||
{
|
||||
if (i == interfaceType)
|
||||
return true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var definition = i.GetGenericTypeDefinition();
|
||||
|
||||
if (definition == interfaceType)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ImplementsInterface<TInterface>(this Type type)
|
||||
{
|
||||
return ImplementsInterface(type, typeof(TInterface));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ namespace Connected.Interop.Merging
|
||||
|
||||
var addMethod = property.PropertyType.GetMethod(nameof(IList.Add), BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
var instance = addMethod is not null ? Activator.CreateInstance(property.PropertyType) : Array.CreateInstance(property.PropertyType, array.Count);
|
||||
var elementType = instance.GetType().GetElementType();
|
||||
var elementType = property.PropertyType.GenericTypeArguments[0];
|
||||
|
||||
for (var i = 0; i < array.Count; i++)
|
||||
{
|
||||
|
@ -1,9 +1,9 @@
|
||||
using Connected.Interop.Merging;
|
||||
using System.Collections;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using Connected.Interop.Merging;
|
||||
|
||||
namespace Connected.Interop;
|
||||
|
||||
@ -41,12 +41,17 @@ public static class Serializer
|
||||
using var ms = new MemoryStream();
|
||||
using var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = true, SkipValidation = false });
|
||||
|
||||
if (value.GetType().IsEnumerable())
|
||||
SerializeArray(writer, null, value);
|
||||
else if (value.GetType().IsTypePrimitive())
|
||||
SerializePrimitive(writer, value);
|
||||
if (value is JsonNode json)
|
||||
json.WriteTo(writer);
|
||||
else
|
||||
SerializeObject(writer, null, value);
|
||||
{
|
||||
if (value.GetType().IsEnumerable())
|
||||
SerializeArray(writer, null, value);
|
||||
else if (value.GetType().IsTypePrimitive())
|
||||
SerializePrimitive(writer, value);
|
||||
else
|
||||
SerializeObject(writer, null, value);
|
||||
}
|
||||
|
||||
await writer.FlushAsync();
|
||||
|
||||
@ -78,18 +83,20 @@ public static class Serializer
|
||||
if (value is null)
|
||||
return;
|
||||
|
||||
var enumerable = property.GetValue(value) as IEnumerable;
|
||||
|
||||
if (enumerable is null)
|
||||
return;
|
||||
|
||||
if (property is not null)
|
||||
writer.WriteStartArray(property.Name.ToCamelCase());
|
||||
else
|
||||
writer.WriteStartArray();
|
||||
|
||||
if (value is IEnumerable enumerable)
|
||||
{
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
var enumerator = enumerable.GetEnumerator();
|
||||
|
||||
while (enumerator.MoveNext())
|
||||
SerializeObject(writer, null, enumerator.Current);
|
||||
}
|
||||
while (enumerator.MoveNext())
|
||||
SerializeObject(writer, null, enumerator.Current);
|
||||
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
@ -100,10 +107,12 @@ public static class Serializer
|
||||
SerializeArray(writer, property, value);
|
||||
else if (!property.PropertyType.IsTypePrimitive())
|
||||
SerializeObject(writer, property, value);
|
||||
else
|
||||
{
|
||||
writer.WritePropertyName(property.Name.ToCamelCase());
|
||||
|
||||
writer.WritePropertyName(property.Name.ToCamelCase());
|
||||
|
||||
SerializePrimitive(writer, property.GetValue(value));
|
||||
SerializePrimitive(writer, property.GetValue(value));
|
||||
}
|
||||
}
|
||||
|
||||
private static void SerializePrimitive(Utf8JsonWriter writer, object? value)
|
||||
|
@ -96,8 +96,10 @@ namespace Connected.Interop
|
||||
return DbType.Byte;
|
||||
else if (underlyingType == typeof(bool))
|
||||
return DbType.Boolean;
|
||||
else if (underlyingType == typeof(DateTime) || underlyingType == typeof(DateTimeOffset))
|
||||
else if (underlyingType == typeof(DateTime))
|
||||
return DbType.DateTime2;
|
||||
else if (underlyingType == typeof(DateTimeOffset))
|
||||
return DbType.DateTimeOffset;
|
||||
else if (underlyingType == typeof(decimal))
|
||||
return DbType.Decimal;
|
||||
else if (underlyingType == typeof(double))
|
||||
|
@ -68,7 +68,11 @@ public static class HttpExtensions
|
||||
}
|
||||
public static async Task<TResult?> Post<TResult>(this IHttpService factory, string? requestUri, object? content, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return await HandleResponse<TResult>(await factory.CreateClient().SendAsync(await CreatePostMessage(requestUri, content), cancellationToken));
|
||||
var client = factory.CreateClient();
|
||||
var message = await CreatePostMessage(requestUri, content);
|
||||
var response = await client.SendAsync(message, cancellationToken);
|
||||
|
||||
return await HandleResponse<TResult>(response);
|
||||
}
|
||||
private static HttpRequestMessage CreateGetMessage(string? requestUri)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user