Rebase with github repository

pull/2/head
Matija Koželj 2 years ago
parent e38eb7aa1c
commit d7b0a471f0

@ -1,5 +1,6 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Data; using System.Data;
using System.Reflection;
using Connected.Data.Schema.Sql; using Connected.Data.Schema.Sql;
using Connected.Entities.Annotations; using Connected.Entities.Annotations;
@ -44,6 +45,7 @@ internal class ExistingColumn : ISchemaColumn, IExistingSchemaColumn
public DateKind DateKind { get; set; } = DateKind.DateTime; public DateKind DateKind { get; set; } = DateKind.DateTime;
public BinaryKind BinaryKind { get; set; } = BinaryKind.VarBinary; public BinaryKind BinaryKind { get; set; } = BinaryKind.VarBinary;
public PropertyInfo Property { get; set; }
public int DatePrecision { get; set; } public int DatePrecision { get; set; }
public ImmutableArray<string> QueryIndexColumns(string column) public ImmutableArray<string> QueryIndexColumns(string column)

@ -1,4 +1,5 @@
using System.Data; using System.Data;
using System.Reflection;
using Connected.Entities.Annotations; using Connected.Entities.Annotations;
namespace Connected.Data.Schema; namespace Connected.Data.Schema;
@ -21,4 +22,6 @@ public interface ISchemaColumn
DateKind DateKind { get; } DateKind DateKind { get; }
BinaryKind BinaryKind { get; } BinaryKind BinaryKind { get; }
int DatePrecision { get; } int DatePrecision { get; }
PropertyInfo Property { get; }
} }

@ -1,13 +1,15 @@
using System.Data; using System.Data;
using System.Reflection;
using Connected.Entities.Annotations; using Connected.Entities.Annotations;
namespace Connected.Data.Schema; namespace Connected.Data.Schema;
internal class SchemaColumn : IEquatable<ISchemaColumn>, ISchemaColumn internal class SchemaColumn : IEquatable<ISchemaColumn>, ISchemaColumn
{ {
public SchemaColumn(ISchema schema) public SchemaColumn(ISchema schema, PropertyInfo property)
{ {
Schema = schema; Schema = schema;
Property = property;
} }
private ISchema Schema { get; } private ISchema Schema { get; }
@ -30,6 +32,8 @@ internal class SchemaColumn : IEquatable<ISchemaColumn>, ISchemaColumn
public int Ordinal { get; set; } public int Ordinal { get; set; }
public PropertyInfo Property { get; set; }
public bool Equals(ISchemaColumn? other) public bool Equals(ISchemaColumn? other)
{ {
if (other is null) if (other is null)

@ -60,6 +60,7 @@ internal class SchemaService : ISchemaService
await middleware.Synchronize(entity, schema); await middleware.Synchronize(entity, schema);
synchronized = true; synchronized = true;
break;
} }
/* /*
* We should notify the environment that entity is no synchronized. * We should notify the environment that entity is no synchronized.
@ -80,7 +81,7 @@ internal class SchemaService : ISchemaService
{ {
var persistence = entityType.GetCustomAttribute<PersistenceAttribute>(); 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) private static ISchema CreateSchema(Type type)
@ -104,7 +105,7 @@ internal class SchemaService : ISchemaService
if (property.FindAttribute<PersistenceAttribute>() is PersistenceAttribute pa && pa.IsVirtual) if (property.FindAttribute<PersistenceAttribute>() is PersistenceAttribute pa && pa.IsVirtual)
continue; continue;
var column = new SchemaColumn(result) var column = new SchemaColumn(result, property)
{ {
Name = ResolveColumnName(property), Name = ResolveColumnName(property),
DataType = DataExtensions.ToDbType(property) DataType = DataExtensions.ToDbType(property)

@ -4,8 +4,7 @@ using Connected.Entities.Annotations;
namespace Connected.Data.Schema.Sql; namespace Connected.Data.Schema.Sql;
[Persistence(Persistence = ColumnPersistence.InMemory)] [Persistence(Persistence = ColumnPersistence.InMemory)]
internal sealed class AdHocSchemaEntity : IEntity internal sealed record AdHocSchemaEntity : Entity
{ {
public State State { get; init; }
public bool Result { 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 Connected.Entities.Storage;
using System.Data;
namespace Connected.Data.Schema.Sql; namespace Connected.Data.Schema.Sql;
@ -50,7 +50,7 @@ internal class SchemaExecutionContext
public async Task Execute(string commandText) 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) public async Task<AdHocSchemaEntity?> Select(string commandText)
@ -74,7 +74,7 @@ internal class SchemaExecutionContext
Constraints.Add(type, existing); Constraints.Add(type, existing);
} }
if (ConstraintNameExists(name)) if (!ConstraintNameExists(name))
existing.Add(name); existing.Add(name);
} }

@ -1,145 +1,143 @@
using Connected.Data.Storage; using System.Data;
using Connected.Entities.Storage; using Connected.Entities.Storage;
using Connected.Interop; using Connected.Interop;
using System.Data;
namespace Connected.Data.Schema.Sql; namespace Connected.Data.Schema.Sql;
internal class SpHelp : SynchronizationQuery<ObjectDescriptor> internal class SpHelp : SynchronizationQuery<ObjectDescriptor>
{ {
private readonly ObjectDescriptor _descriptor; private readonly ObjectDescriptor _descriptor;
public SpHelp() public SpHelp()
{ {
_descriptor = new(); _descriptor = new();
} }
private ObjectDescriptor Result => _descriptor; private ObjectDescriptor Result => _descriptor;
protected override async Task<ObjectDescriptor> OnExecute() protected override async Task<ObjectDescriptor> OnExecute()
{ {
var operation = new StorageOperation { CommandText = "sp_help", CommandType = CommandType.Text }; var operation = new StorageOperation { CommandText = "sp_help", CommandType = CommandType.Text };
operation.AddParameter(new StorageParameter operation.AddParameter(new StorageParameter
{ {
Name = "@objname", Name = "@objname",
Type = DbType.String, Type = DbType.String,
Value = Escape(Context.Schema.SchemaName(), Context.Schema.Name) Value = Escape(Context.Schema.SchemaName(), Context.Schema.Name)
} }
); );
var rdr = await Context.OpenReader(operation); var rdr = await Context.OpenReader(operation);
try try
{ {
ReadMetadata(rdr); ReadMetadata(rdr);
ReadColumns(rdr); ReadColumns(rdr);
ReadIdentity(rdr); ReadIdentity(rdr);
ReadRowGuid(rdr); ReadRowGuid(rdr);
ReadFileGroup(rdr); ReadFileGroup(rdr);
ReadIndexes(rdr); ReadIndexes(rdr);
ReadConstraints(rdr); ReadConstraints(rdr);
} }
finally finally
{ {
rdr.Close(); rdr.Close();
} }
return Result; return Result;
} }
private void ReadMetadata(IDataReader rdr) private void ReadMetadata(IDataReader rdr)
{ {
if (rdr.Read()) if (rdr.Read())
{ {
Result.MetaData.Name = rdr.GetValue("Name", string.Empty); 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.Owner = rdr.GetValue("Owner", string.Empty); Result.MetaData.Type = rdr.GetValue("Object_type", string.Empty);
Result.MetaData.Type = rdr.GetValue("Type", string.Empty); }
} }
}
private void ReadColumns(IDataReader rdr)
private void ReadColumns(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
while (rdr.Read())
while (rdr.Read()) {
{ Result.Columns.Add(new ObjectColumn
Result.Columns.Add(new ObjectColumn {
{ Collation = rdr.GetValue("Collation", string.Empty),
Collation = rdr.GetValue("Collation", string.Empty), Computed = !string.Equals(rdr.GetValue("Computed", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
Computed = !string.Equals(rdr.GetValue("Computed", string.Empty), "no", StringComparison.OrdinalIgnoreCase), FixedLenInSource = rdr.GetValue("FixedLenNullInSource", string.Empty),
FixedLenInSource = rdr.GetValue("FixedLenNullInSource", string.Empty), Length = rdr.GetValue("Length", 0),
Length = rdr.GetValue("Length", 0), Name = rdr.GetValue("Column_name", string.Empty),
Name = rdr.GetValue("Column_name", string.Empty), Nullable = !string.Equals(rdr.GetValue("Nullable", string.Empty), "no", StringComparison.OrdinalIgnoreCase),
Nullable = !string.Equals(rdr.GetValue("Nullable", string.Empty), "no", StringComparison.OrdinalIgnoreCase), Precision = TypeConversion.Convert<int>(rdr.GetValue("Prec", string.Empty).Trim()),
Precision = TypeConversion.Convert<int>(rdr.GetValue("Prec", string.Empty).Trim()), Scale = TypeConversion.Convert<int>(rdr.GetValue("Scale", string.Empty).Trim()),
Scale = TypeConversion.Convert<int>(rdr.GetValue("Scale", string.Empty).Trim()), TrimTrailingBlanks = rdr.GetValue("TrimTrailingBlanks", string.Empty),
TrimTrailingBlanks = rdr.GetValue("TrimTrailingBlanks", string.Empty), Type = rdr.GetValue("Type", string.Empty)
Type = rdr.GetValue("Type", string.Empty) });
}); }
} }
}
private void ReadIdentity(IDataReader rdr)
private void ReadIdentity(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
if (rdr.Read())
if (rdr.Read()) {
{ Result.Identity.Identity = rdr.GetValue("Identity", string.Empty);
Result.Identity.Identity = rdr.GetValue("Identity", string.Empty); Result.Identity.Increment = rdr.GetValue("Increment", 0);
Result.Identity.Increment = rdr.GetValue("Increment", 0); Result.Identity.NotForReplication = rdr.GetValue("Not For Replication", 0) != 0;
Result.Identity.NotForReplication = rdr.GetValue("Not For Replication", 0) != 0; }
} }
}
private void ReadRowGuid(IDataReader rdr)
private void ReadRowGuid(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
if (rdr.Read())
if (rdr.Read()) Result.RowGuid.RowGuidCol = rdr.GetValue("RowGuidCol", string.Empty);
Result.RowGuid.RowGuidCol = rdr.GetValue("RowGuidCol", string.Empty); }
}
private void ReadFileGroup(IDataReader rdr)
private void ReadFileGroup(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
if (rdr.Read())
if (rdr.Read()) Result.FileGroup.FileGroup = rdr.GetValue("Data_located_on_filegroup", string.Empty);
Result.FileGroup.FileGroup = rdr.GetValue("Data_located_on_filegroup", string.Empty); }
}
private void ReadIndexes(IDataReader rdr)
private void ReadIndexes(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
while (rdr.Read())
while (rdr.Read()) {
{ Result.Indexes.Add(new ObjectIndex
Result.Indexes.Add(new ObjectIndex {
{ Description = rdr.GetValue("index_description", string.Empty),
Description = rdr.GetValue("index_description", string.Empty), Keys = rdr.GetValue("index_keys", string.Empty),
Keys = rdr.GetValue("index_keys", string.Empty), Name = rdr.GetValue("index_name", string.Empty)
Name = rdr.GetValue("index_name", string.Empty) });
}); }
} }
}
private void ReadConstraints(IDataReader rdr)
private void ReadConstraints(IDataReader rdr) {
{ rdr.NextResult();
rdr.NextResult();
while (rdr.Read())
while (rdr.Read()) {
{ Result.Constraints.Add(new ObjectConstraint
Result.Constraints.Add(new ObjectConstraint {
{ DeleteAction = rdr.GetValue("delete_action", string.Empty),
DeleteAction = rdr.GetValue("delete_action", string.Empty), Keys = rdr.GetValue("constraint_keys", string.Empty),
Keys = rdr.GetValue("constraint_keys", string.Empty), Name = rdr.GetValue("constraint_name", string.Empty),
Name = rdr.GetValue("constraint_name", string.Empty), StatusEnabled = rdr.GetValue("status_enabled", string.Empty),
StatusEnabled = rdr.GetValue("status_enabled", string.Empty), StatusForReplication = rdr.GetValue("status_for_replication", string.Empty),
StatusForReplication = rdr.GetValue("status_for_replication", string.Empty), Type = rdr.GetValue("constraint_type", string.Empty),
Type = rdr.GetValue("constraint_type", string.Empty), UpdateAction = rdr.GetValue("update_action", 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.Data.Sharding;
using Connected.Entities.Storage; using Connected.Entities.Storage;
using Connected.Middleware; using Connected.Middleware;
using Connected.ServiceModel; using Connected.ServiceModel;
using Connected.ServiceModel.Transactions; using Connected.ServiceModel.Transactions;
using System.Collections.Immutable;
namespace Connected.Data.Storage; namespace Connected.Data.Storage;
@ -26,7 +26,7 @@ internal sealed class ConnectionProvider : IConnectionProvider, IAsyncDisposable
public IMiddlewareService Middleware { get; } public IMiddlewareService Middleware { get; }
private ITransactionContext TransactionService { get; } private ITransactionContext TransactionService { get; }
private List<IStorageConnection> Connections => _connections; 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) 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.Annotations;
using Connected.Entities.Storage; using Connected.Entities.Storage;
using Connected.Interop; using Connected.Interop;
using System.Data;
using System.Reflection;
using System.Text;
namespace Connected.Data.Update; namespace Connected.Data.Update;
internal abstract class CommandBuilder internal abstract class CommandBuilder
{ {
private readonly List<IStorageParameter> _parameters; private readonly List<IStorageParameter> _parameters;
private readonly List<PropertyInfo> _whereProperties; private readonly List<PropertyInfo> _whereProperties;
private List<PropertyInfo> _properties; private List<PropertyInfo> _properties;
protected CommandBuilder() protected CommandBuilder()
{ {
_parameters = new List<IStorageParameter>(); _parameters = new List<IStorageParameter>();
_whereProperties = new List<PropertyInfo>(); _whereProperties = new List<PropertyInfo>();
Text = new StringBuilder(); Text = new StringBuilder();
} }
public StorageOperation? Build(IEntity entity) public StorageOperation? Build(IEntity entity)
{ {
Entity = entity; Entity = entity;
if (TryGetExisting(out StorageOperation? existing)) if (TryGetExisting(out StorageOperation? existing))
{ {
/* /*
* We need to rebuild an instance since StorageOperation * We need to rebuild an instance since StorageOperation
* is immutable * is immutable
*/ */
var result = new StorageOperation var result = new StorageOperation
{ {
CommandText = existing.CommandText, CommandText = existing.CommandText,
CommandTimeout = existing.CommandTimeout, CommandTimeout = existing.CommandTimeout,
CommandType = existing.CommandType, CommandType = existing.CommandType,
Concurrency = existing.Concurrency Concurrency = existing.Concurrency
}; };
if (result.Parameters is null) if (result.Parameters is null)
return result; return result;
foreach (var parameter in result.Parameters) foreach (var parameter in result.Parameters)
{ {
if (parameter.Direction == ParameterDirection.Input) if (parameter.Direction == ParameterDirection.Input)
{ {
if (ResolveProperty(parameter.Name) is PropertyInfo property) if (ResolveProperty(parameter.Name) is PropertyInfo property)
{ {
result.AddParameter(new StorageParameter result.AddParameter(new StorageParameter
{ {
Value = GetValue(property), Value = GetValue(property),
Name = parameter.Name, Name = parameter.Name,
Type = parameter.Type, Type = parameter.Type,
Direction = parameter.Direction 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) protected void Write(string text)
{ {
Text.Append(text); Text.Append(text);
} }
protected void Write(char text) protected void Write(char text)
{ {
Text.Append(text); Text.Append(text);
} }
protected void WriteLine(string text) protected void WriteLine(string text)
{ {
Text.AppendLine(text); Text.AppendLine(text);
} }
protected void Trim() protected void Trim()
{ {
for (var i = Text.Length - 1; i >= 0; i--) for (var i = Text.Length - 1; i >= 0; i--)
{ {
if (!Text[i].Equals(',') && !Text[i].Equals('\n') && !Text[i].Equals('\r') && !Text[i].Equals(' ')) if (!Text[i].Equals(',') && !Text[i].Equals('\n') && !Text[i].Equals('\r') && !Text[i].Equals(' '))
break; break;
if (i < Text.Length) if (i < Text.Length)
Text.Length = i; Text.Length = i;
} }
} }
protected virtual List<PropertyInfo> GetProperties() protected virtual List<PropertyInfo> GetProperties()
{ {
return Interop.Properties.GetImplementedProperties(Entity); var props = Interop.Properties.GetImplementedProperties(Entity);
} var result = new List<PropertyInfo>();
protected static bool IsVersion(PropertyInfo property) foreach (var property in props)
{ {
return property.GetCustomAttribute<ETagAttribute>() is not null; var persistence = property.FindAttribute<PersistenceAttribute>();
}
if (persistence is not null && persistence.Persistence.HasFlag(ColumnPersistence.InMemory))
protected static string ColumnName(PropertyInfo property) continue;
{
var dataMember = property.FindAttribute<MemberAttribute>(); result.Add(property);
}
return dataMember is null || string.IsNullOrEmpty(dataMember.Member) ? property.Name.ToCamelCase() : dataMember.Member;
} return result;
}
protected static DbType ResolveDbType(PropertyInfo property)
{ protected static bool IsVersion(PropertyInfo property)
if (IsVersion(property)) {
return DbType.Binary; return property.GetCustomAttribute<ETagAttribute>() is not null;
}
return property.PropertyType.ToDbType();
} protected static string ColumnName(PropertyInfo property)
protected object? GetValue(PropertyInfo property) {
{ var dataMember = property.FindAttribute<MemberAttribute>();
if (IsNull(property))
return "NULL"; return dataMember is null || string.IsNullOrEmpty(dataMember.Member) ? property.Name.ToCamelCase() : dataMember.Member;
}
if (IsVersion(property))
return (byte[])EntityVersion.Parse(property.GetValue(Entity)); protected static DbType ResolveDbType(PropertyInfo property)
{
return GetValue(property.GetValue(Entity), property.PropertyType.ToDbType()); if (IsVersion(property))
} return DbType.Binary;
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;
}
}
private bool IsNull(PropertyInfo property) return property.PropertyType.ToDbType();
{ }
var result = property.GetValue(Entity); protected object? GetValue(PropertyInfo property)
{
if (IsNull(property))
return "NULL";
if (result is null) if (IsVersion(property))
return true; return (byte[])EntityVersion.Parse(property.GetValue(Entity));
if (property.GetCustomAttribute<NullableAttribute>() is null) return GetValue(property.GetValue(Entity), property.PropertyType.ToDbType());
return false; }
var def = Types.GetDefault(property.PropertyType); private static object? GetValue(object value, DbType dbType)
{
return TypeComparer.Compare(result, def); switch (dbType)
} {
case DbType.Binary:
protected StorageParameter CreateParameter(PropertyInfo property) if (value is byte[] bytes)
{ return Convert.ToBase64String(bytes);
return CreateParameter(property, ParameterDirection.Input); else
} return Convert.ToBase64String(Encoding.UTF8.GetBytes(value.ToString()));
default:
protected StorageParameter CreateParameter(PropertyInfo property, ParameterDirection direction) return value;
{ }
var columnName = ColumnName(property); }
var parameterName = $"@{columnName}";
private bool IsNull(PropertyInfo property)
var parameter = new StorageParameter {
{ var result = property.GetValue(Entity);
Direction = direction,
Name = parameterName, if (result is null)
Type = ResolveDbType(property), return true;
Value = GetValue(property)
}; if (property.GetCustomAttribute<NullableAttribute>() is null)
return false;
Parameters.Add(parameter);
var def = Types.GetDefault(property.PropertyType);
return parameter;
} return TypeComparer.Compare(result, def);
}
private PropertyInfo ResolveProperty(string parameterName)
{ protected StorageParameter CreateParameter(PropertyInfo property)
var propertyName = parameterName[1..]; {
var flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; return CreateParameter(property, ParameterDirection.Input);
}
if (Entity.GetType().GetProperty(propertyName.ToPascalCase(), flags) is PropertyInfo property)
return property; protected StorageParameter CreateParameter(PropertyInfo property, ParameterDirection direction)
{
if (Entity.GetType().GetProperty(propertyName, flags) is PropertyInfo raw) var columnName = ColumnName(property);
return raw; var parameterName = $"@{columnName}";
return null; var parameter = new StorageParameter
} {
Direction = direction,
Name = parameterName,
Type = ResolveDbType(property),
Value = GetValue(property)
};
Parameters.Add(parameter);
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; namespace Connected.Expressions.Translation.Rewriters;
public class WhereClauseRewriter : DatabaseVisitor public class WhereClauseRewriter : DatabaseVisitor
{ {
private WhereClauseRewriter(ExpressionCompilationContext context) protected WhereClauseRewriter(ExpressionCompilationContext context)
{ {
Context = context; Context = context;
} }
public ExpressionCompilationContext Context { get; } public ExpressionCompilationContext Context { get; }
public static Expression Rewrite(ExpressionCompilationContext context, Expression expression) public static Expression Rewrite(ExpressionCompilationContext context, Expression expression)
{ {
return new WhereClauseRewriter(context).Visit(expression); return new WhereClauseRewriter(context).Visit(expression);
} }
protected override Expression VisitWhere(Expression whereExpression) protected override Expression VisitWhere(Expression whereExpression)
{ {
return ParameterRewriter.Rewrite(Context, whereExpression); return ParameterRewriter.Rewrite(Context, whereExpression);
} }
} }

@ -46,7 +46,7 @@ internal static class EntitySynchronizer
else else
{ {
/* /*
* entitySynchronization = token1, token2,... * entitySynchronization = token1; token2,...
*/ */
var tokens = value.Split(','); var tokens = value.Split(',');
/* /*
@ -66,13 +66,20 @@ internal static class EntitySynchronizer
await Synchronize(schemaService, Assembly.Load(AssemblyName.GetAssemblyName(subTokens[1])), logger); 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; continue;
} }

@ -18,5 +18,33 @@
return false; 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 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 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++) 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.Reflection;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Nodes; using System.Text.Json.Nodes;
using Connected.Interop.Merging;
namespace Connected.Interop; namespace Connected.Interop;
@ -41,12 +41,17 @@ public static class Serializer
using var ms = new MemoryStream(); using var ms = new MemoryStream();
using var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = true, SkipValidation = false }); using var writer = new Utf8JsonWriter(ms, new JsonWriterOptions { Indented = true, SkipValidation = false });
if (value.GetType().IsEnumerable()) if (value is JsonNode json)
SerializeArray(writer, null, value); json.WriteTo(writer);
else if (value.GetType().IsTypePrimitive())
SerializePrimitive(writer, value);
else 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(); await writer.FlushAsync();
@ -78,18 +83,20 @@ public static class Serializer
if (value is null) if (value is null)
return; return;
var enumerable = property.GetValue(value) as IEnumerable;
if (enumerable is null)
return;
if (property is not null) if (property is not null)
writer.WriteStartArray(property.Name.ToCamelCase()); writer.WriteStartArray(property.Name.ToCamelCase());
else else
writer.WriteStartArray(); writer.WriteStartArray();
if (value is IEnumerable enumerable) var enumerator = enumerable.GetEnumerator();
{
var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext()) while (enumerator.MoveNext())
SerializeObject(writer, null, enumerator.Current); SerializeObject(writer, null, enumerator.Current);
}
writer.WriteEndArray(); writer.WriteEndArray();
} }
@ -100,10 +107,12 @@ public static class Serializer
SerializeArray(writer, property, value); SerializeArray(writer, property, value);
else if (!property.PropertyType.IsTypePrimitive()) else if (!property.PropertyType.IsTypePrimitive())
SerializeObject(writer, property, value); 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) private static void SerializePrimitive(Utf8JsonWriter writer, object? value)

@ -96,8 +96,10 @@ namespace Connected.Interop
return DbType.Byte; return DbType.Byte;
else if (underlyingType == typeof(bool)) else if (underlyingType == typeof(bool))
return DbType.Boolean; return DbType.Boolean;
else if (underlyingType == typeof(DateTime) || underlyingType == typeof(DateTimeOffset)) else if (underlyingType == typeof(DateTime))
return DbType.DateTime2; return DbType.DateTime2;
else if (underlyingType == typeof(DateTimeOffset))
return DbType.DateTimeOffset;
else if (underlyingType == typeof(decimal)) else if (underlyingType == typeof(decimal))
return DbType.Decimal; return DbType.Decimal;
else if (underlyingType == typeof(double)) 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) 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) private static HttpRequestMessage CreateGetMessage(string? requestUri)
{ {

Loading…
Cancel
Save