Ejemplo n.º 1
0
        public UpsertFunction(IDocumentMapping mapping)
        {
            FunctionName = mapping.UpsertName;
            TableName    = mapping.TableName;

            var idType = mapping.IdMember.GetMemberType();

            PgIdType        = TypeMappings.GetPgType(idType);
            Id_NpgsqlDbType = TypeMappings.ToDbType(idType);

            Arguments.Add(new UpsertArgument
            {
                Arg          = "docId",
                PostgresType = PgIdType,
                Column       = "id",
                Members      = new[] { mapping.IdMember }
            });
            Arguments.Add(new UpsertArgument
            {
                Arg                = "doc",
                PostgresType       = "JSONB",
                DbType             = NpgsqlDbType.Jsonb,
                Column             = "data",
                BulkInsertPattern  = "writer.Write(serializer.ToJson(x), NpgsqlDbType.Jsonb);",
                BatchUpdatePattern = "*"
            });
        }
Ejemplo n.º 2
0
        public DuplicatedField(EnumStorage enumStorage, MemberInfo[] memberPath) : base(memberPath)
        {
            _enumStorage = enumStorage;
            _dbType      = TypeMappings.ToDbType(MemberType);



            ColumnName = MemberName.ToTableAlias();

            if (MemberType.IsEnum)
            {
                typeof(EnumRegistrar <>).CloseAndBuildAs <IEnumRegistrar>(MemberType).Register();



                _parseObject = expression =>
                {
                    var raw = expression.Value();
                    return(Enum.GetName(MemberType, raw));
                };

                _dbType = NpgsqlDbType.Varchar;
                PgType  = "varchar";
            }
        }
Ejemplo n.º 3
0
        public DuplicatedField(EnumStorage enumStorage, MemberInfo[] memberPath) : base(memberPath)
        {
            _enumStorage = enumStorage;
            _dbType      = TypeMappings.ToDbType(MemberType);


            ColumnName = MemberName.ToTableAlias();

            if (MemberType.GetTypeInfo().IsEnum)
            {
                _parseObject = expression =>
                {
                    var raw = expression.Value();
                    return(Enum.GetName(MemberType, raw));
                };

                _dbType = NpgsqlDbType.Varchar;
                PgType  = "varchar";
            }
            else if (MemberType.IsDateTime())
            {
                PgType  = "timestamp with time zone";
                _dbType = NpgsqlDbType.TimestampTZ;
            }
        }
Ejemplo n.º 4
0
        public Resolver(ISerializer serializer, DocumentMapping mapping)
        {
            _serializer = serializer;
            _mapping    = mapping;
            IdType      = TypeMappings.ToDbType(mapping.IdMember.GetMemberType());


            _loaderSql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = :id";
            _deleteSql    = $"delete from {_mapping.Table.QualifiedName} where id = :id";
            _loadArraySql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = ANY(:ids)";


            _identity = LambdaBuilder.Getter <T, object>(mapping.IdMember);

            _sprocWriter = buildSprocWriter(mapping);


            _upsertName = mapping.UpsertFunction;

            if (mapping.DeleteStyle == DeleteStyle.Remove)
            {
                DeleteByIdSql    = $"delete from {_mapping.Table.QualifiedName} where id = ?";
                DeleteByWhereSql = $"delete from {_mapping.Table.QualifiedName} as d where ?";
            }
            else
            {
                DeleteByIdSql    = $"update {_mapping.Table.QualifiedName} set {DocumentMapping.DeletedColumn} = True, {DocumentMapping.DeletedAtColumn} = now() where id = ?";
                DeleteByWhereSql = $"update {_mapping.Table.QualifiedName} as d set {DocumentMapping.DeletedColumn} = True, {DocumentMapping.DeletedAtColumn} = now() where ?";
            }
        }
Ejemplo n.º 5
0
        private void generateBasicSetter(GeneratedMethod method)
        {
            method.Frames.Code($@"
parameters[{ParameterIndex}].NpgsqlDbType = {{0}};
parameters[{ParameterIndex}].Value = _query.{Member.Name};
", TypeMappings.ToDbType(Member.GetMemberType()));
        }
Ejemplo n.º 6
0
        private void generateMaskedStringCode(GeneratedMethod method)
        {
            var maskedValue = Mask.ToFormat($"_query.{Member.Name}");

            method.Frames.Code($@"
parameters[{ParameterIndex}].NpgsqlDbType = {{0}};
parameters[{ParameterIndex}].Value = {maskedValue};
", TypeMappings.ToDbType(Member.GetMemberType()));
        }
Ejemplo n.º 7
0
        public StreamTableColumn(string name, Expression <Func <StreamAction, object> > memberExpression) : base(name, "varchar")
        {
            _memberExpression = memberExpression;
            _member           = FindMembers.Determine(memberExpression).Single();
            var memberType = _member.GetMemberType();

            Type         = TypeMappings.GetPgType(memberType, EnumStorage.AsInteger);
            NpgsqlDbType = TypeMappings.ToDbType(memberType);
        }
Ejemplo n.º 8
0
 public virtual UpsertArgument ToArgument()
 {
     return(new UpsertArgument
     {
         Arg = "arg_" + Name,
         Column = Name,
         DbType = TypeMappings.ToDbType(DotNetType),
         PostgresType = Type,
         Members = new MemberInfo[] { Member }
     });
 }
Ejemplo n.º 9
0
        public DuplicatedField(EnumStorage enumStorage, IField innerField,
                               bool useTimestampWithoutTimeZoneForDateTime = true, bool notNull = false)
        {
            InnerField = innerField;
            MemberName = InnerField.Members.Select(x => x.Name).Join("");
            NotNull    = notNull;
            ColumnName = MemberName.ToTableAlias();
            this.useTimestampWithoutTimeZoneForDateTime = useTimestampWithoutTimeZoneForDateTime;

            PgType = TypeMappings.GetPgType(FieldType, enumStorage);

            if (FieldType.IsEnum)
            {
                if (enumStorage == EnumStorage.AsString)
                {
                    DbType = NpgsqlDbType.Varchar;
                    PgType = "varchar";

                    _parseObject = expression =>
                    {
                        var raw = expression.Value();
                        if (raw == null)
                        {
                            return(null);
                        }
                        return(Enum.GetName(FieldType, raw));
                    };
                }
                else
                {
                    DbType = NpgsqlDbType.Integer;
                    PgType = "integer";
                }
            }
            else if (FieldType.IsDateTime())
            {
                PgType = this.useTimestampWithoutTimeZoneForDateTime
                    ? "timestamp without time zone"
                    : "timestamp with time zone";
                DbType = this.useTimestampWithoutTimeZoneForDateTime
                    ? NpgsqlDbType.Timestamp
                    : NpgsqlDbType.TimestampTz;
            }
            else if (FieldType == typeof(DateTimeOffset) || FieldType == typeof(DateTimeOffset?))
            {
                PgType = "timestamp with time zone";
                DbType = NpgsqlDbType.TimestampTz;
            }
            else
            {
                DbType = TypeMappings.ToDbType(FieldType);
            }
        }
Ejemplo n.º 10
0
        public void execute_to_db_custom_mappings_resolve()
        {
            NpgsqlConnection.GlobalTypeMapper.AddMapping(new NpgsqlTypeMappingBuilder
            {
                PgTypeName         = "varchar",
                NpgsqlDbType       = NpgsqlDbType.Varchar,
                ClrTypes           = new[] { typeof(MappedTarget) },
                TypeHandlerFactory = new TextHandlerFactory()
            }.Build());

            TypeMappings.ToDbType(typeof(MappedTarget)).ShouldBe(NpgsqlDbType.Varchar);
            ShouldThrowExtensions.ShouldThrow <Exception>(() => TypeMappings.ToDbType(typeof(UnmappedTarget)));
        }
Ejemplo n.º 11
0
        public GeneratedType Build(GeneratedAssembly assembly)
        {
            var baseType = typeof(DeleteOne <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType);
            var type     = assembly.AddType($"Delete{_mapping.DocumentType.Name.Sanitize()}ById", baseType);

            var sql = $"delete from {_mapping.Table.QualifiedName} as d where id = ?";

            if (_mapping.DeleteStyle == DeleteStyle.SoftDelete)
            {
                sql =
                    $"update {_mapping.Table.QualifiedName} as d set {DocumentMapping.DeletedColumn} = True, {DocumentMapping.DeletedAtColumn} = now() where id = ?";
            }

            if (_mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                sql += $" and d.{TenantIdColumn.Name} = ?";
            }


            var commandText = Setter.Constant("CommandText", Constant.For(sql));

            type.Setters.Add(commandText);

            var configure = type.MethodFor(nameof(IQueryHandler.ConfigureCommand));

            configure.Frames.Call <CommandBuilder>(x => x.AppendWithParameters(null), call =>
            {
                call.Arguments[0] = commandText;
            });

            // Add the Id parameter
            configure.Frames.Code(@"
// Id parameter
{0}[0].NpgsqlDbType = {1};
{0}[0].Value = {2};

", Use.Type <NpgsqlParameter[]>(), TypeMappings.ToDbType(_mapping.IdType), type.AllInjectedFields[0]);

            if (_mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                configure.Frames.Code($@"
// tenant
{{0}}[1].NpgsqlDbType = {{1}};
{{0}}[1].Value = {{2}}.{nameof(IMartenSession.Tenant)}.{nameof(ITenant.TenantId)};
", Use.Type <NpgsqlParameter[]>(), NpgsqlDbType.Varchar, Use.Type <IMartenSession>());
            }


            return(type);
        }
Ejemplo n.º 12
0
        public DocumentStorage(ISerializer serializer, DocumentMapping mapping)
        {
            _serializer = serializer;
            _mapping    = mapping;
            IdType      = TypeMappings.ToDbType(mapping.IdMember.GetMemberType());


            _loaderSql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = :id";

            _loadArraySql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = ANY(:ids)";

            if (mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                _loaderSql    += $" and {TenantWhereFragment.Filter}";
                _loadArraySql += $" and {TenantWhereFragment.Filter}";
            }


            _identity = LambdaBuilder.Getter <T, object>(mapping.IdMember);

            _sprocWriter = buildSprocWriter(mapping);


            _upsertName = mapping.UpsertFunction;

            if (mapping.DeleteStyle == DeleteStyle.Remove)
            {
                DeleteByIdSql    = $"delete from {_mapping.Table.QualifiedName} as d where id = ?";
                DeleteByWhereSql = $"delete from {_mapping.Table.QualifiedName} as d where ?";
            }
            else
            {
                DeleteByIdSql    = $"update {_mapping.Table.QualifiedName} as d set {DocumentMapping.DeletedColumn} = True, {DocumentMapping.DeletedAtColumn} = now() where id = ?";
                DeleteByWhereSql = $"update {_mapping.Table.QualifiedName} as d set {DocumentMapping.DeletedColumn} = True, {DocumentMapping.DeletedAtColumn} = now() where ?";
            }

            if (mapping.VersionMember is FieldInfo)
            {
                _setVersion = LambdaBuilder.SetField <T, Guid>(mapping.VersionMember.As <FieldInfo>());
            }

            if (mapping.VersionMember is PropertyInfo)
            {
                _setVersion = LambdaBuilder.SetProperty <T, Guid>(mapping.VersionMember.As <PropertyInfo>());
            }
        }
        public static void SetParameterFromMember <T>(this GeneratedMethod method, int index,
                                                      Expression <Func <T, object> > memberExpression)
        {
            var member     = FindMembers.Determine(memberExpression).Single();
            var memberType = member.GetMemberType();
            var pgType     = TypeMappings.ToDbType(memberType);

            if (memberType == typeof(string))
            {
                method.Frames.Code($"parameters[{index}].Value = {{0}}.{member.Name} != null ? (object){{0}}.{member.Name} : {typeof(DBNull).FullNameInCode()}.Value;", Use.Type <T>());
                method.Frames.Code($"parameters[{index}].NpgsqlDbType = {{0}};", pgType);
            }
            else
            {
                method.Frames.Code($"parameters[{index}].Value = {{0}}.{member.Name};", Use.Type <T>());
                method.Frames.Code($"parameters[{index}].NpgsqlDbType = {{0}};", pgType);
            }
        }
Ejemplo n.º 14
0
        public DocumentStorage(StorageStyle storageStyle, DocumentMapping document)
        {
            _mapping = document;

            Fields    = document;
            TableName = document.TableName;

            determineDefaultWhereFragment();

            _idType = TypeMappings.ToDbType(typeof(TId));

            var table = _mapping.Schema.Table;

            _selectFields = table.SelectColumns(storageStyle).Select(x => $"d.{x.Name}").ToArray();
            var fieldSelector = _selectFields.Join(", ");

            _selectClause = $"select {fieldSelector} from {document.TableName.QualifiedName} as d";

            _loaderSql =
                $"select {fieldSelector} from {document.TableName.QualifiedName} as d where id = :id";

            _loadArraySql =
                $"select {fieldSelector} from {document.TableName.QualifiedName} as d where id = ANY(:ids)";

            if (document.TenancyStyle == TenancyStyle.Conjoined)
            {
                _loaderSql    += $" and {CurrentTenantFilter.Filter}";
                _loadArraySql += $" and {CurrentTenantFilter.Filter}";
            }

            UseOptimisticConcurrency = document.UseOptimisticConcurrency;


            _setter = LambdaBuilder.Setter <T, TId>(document.IdMember);

            DeleteFragment = _mapping.DeleteStyle == DeleteStyle.Remove
                ? (IOperationFragment) new HardDelete(this)
                : new SoftDelete(this);

            HardDeleteFragment = new HardDelete(this);

            DuplicatedFields = _mapping.DuplicatedFields;
        }
Ejemplo n.º 15
0
        public DuplicatedField(EnumStorage enumStorage, MemberInfo[] memberPath) : base(enumStorage, memberPath)
        {
            ColumnName = MemberName.ToTableAlias();

            if (MemberType.IsEnum)
            {
                if (enumStorage == EnumStorage.AsString)
                {
                    DbType = NpgsqlDbType.Varchar;
                    PgType = "varchar";

                    _parseObject = expression =>
                    {
                        var raw = expression.Value();
                        return(Enum.GetName(MemberType, raw));
                    };
                }
                else
                {
                    DbType = NpgsqlDbType.Integer;
                    PgType = "integer";
                }
            }
            else if (MemberType.IsDateTime())
            {
                PgType = "timestamp without time zone";
                DbType = NpgsqlDbType.Timestamp;
            }
            else if (MemberType.IsDateTime())
            {
                PgType = "timestamp without time zone";
                DbType = NpgsqlDbType.Timestamp;
            }
            else if (MemberType == typeof(DateTimeOffset) || MemberType == typeof(DateTimeOffset?))
            {
                PgType = "timestamp with time zone";
                DbType = NpgsqlDbType.TimestampTz;
            }
            else
            {
                DbType = TypeMappings.ToDbType(MemberType);
            }
        }
Ejemplo n.º 16
0
        public GeneratedType BuildType(GeneratedAssembly assembly)
        {
            var baseType = typeof(StorageOperation <,>).MakeGenericType(_mapping.DocumentType, _mapping.IdType);
            var type     = assembly.AddType(ClassName, baseType);

            if (_mapping.TenancyStyle == TenancyStyle.Conjoined)
            {
                type.AllInjectedFields.Add(new InjectedField(typeof(ITenant)));
            }

            type.MethodFor("Role").Frames.Return(Constant.ForEnum(_role));
            type.MethodFor("DbType").Frames.Return(Constant.ForEnum(TypeMappings.ToDbType(_mapping.IdType)));
            type.MethodFor("CommandText").Frames.Return(Constant.ForString(CommandText));

            buildConfigureMethod(type);

            buildPostprocessingMethods(type);

            return(type);
        }
Ejemplo n.º 17
0
        public DuplicatedField(StoreOptions storeOptions, MemberInfo[] memberPath, bool useTimestampWithoutTimeZoneForDateTime = true, bool notNull = false)
            : base(storeOptions.DuplicatedFieldEnumStorage, memberPath, notNull)
        {
            ColumnName    = MemberName.ToTableAlias();
            _storeOptions = storeOptions;
            this.useTimestampWithoutTimeZoneForDateTime = useTimestampWithoutTimeZoneForDateTime;

            if (MemberType.IsEnum)
            {
                if (storeOptions.DuplicatedFieldEnumStorage == EnumStorage.AsString)
                {
                    DbType = NpgsqlDbType.Varchar;
                    PgType = "varchar";

                    _parseObject = expression =>
                    {
                        var raw = expression.Value();
                        return(Enum.GetName(MemberType, raw));
                    };
                }
                else
                {
                    DbType = NpgsqlDbType.Integer;
                    PgType = "integer";
                }
            }
            else if (MemberType.IsDateTime())
            {
                PgType = this.useTimestampWithoutTimeZoneForDateTime ? "timestamp without time zone" : "timestamp with time zone";
                DbType = this.useTimestampWithoutTimeZoneForDateTime ? NpgsqlDbType.Timestamp : NpgsqlDbType.TimestampTz;
            }
            else if (MemberType == typeof(DateTimeOffset) || MemberType == typeof(DateTimeOffset?))
            {
                PgType = "timestamp with time zone";
                DbType = NpgsqlDbType.TimestampTz;
            }
            else
            {
                DbType = TypeMappings.ToDbType(MemberType);
            }
        }
Ejemplo n.º 18
0
        public Resolver(ISerializer serializer, DocumentMapping mapping)
        {
            _serializer = serializer;
            _mapping    = mapping;
            IdType      = TypeMappings.ToDbType(mapping.IdMember.GetMemberType());


            _loaderSql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = :id";
            _deleteSql    = $"delete from {_mapping.Table.QualifiedName} where id = :id";
            _loadArraySql =
                $"select {_mapping.SelectFields().Join(", ")} from {_mapping.Table.QualifiedName} as d where id = ANY(:ids)";


            _identity = LambdaBuilder.Getter <T, object>(mapping.IdMember);

            _sprocWriter = buildSprocWriter(mapping);


            _upsertName = mapping.UpsertFunction;
        }
Ejemplo n.º 19
0
        public DocumentStorage(DocumentMapping document)
        {
            _mapping = document;

            _document = document;
            Fields    = document;
            TableName = document.Table;

            _defaultWhere = document.DefaultWhereFragment();

            _idType = TypeMappings.ToDbType(typeof(TId));

            _selectClause = $"select {_document.SelectFields().Select(x => $"d.{x}").Join(", ")} from {document.Table.QualifiedName} as d";

            _loaderSql =
                $"select {document.SelectFields().Join(", ")} from {document.Table.QualifiedName} as d where id = :id";

            _loadArraySql =
                $"select {document.SelectFields().Join(", ")} from {document.Table.QualifiedName} as d where id = ANY(:ids)";

            if (document.TenancyStyle == TenancyStyle.Conjoined)
            {
                _loaderSql    += $" and {TenantWhereFragment.Filter}";
                _loadArraySql += $" and {TenantWhereFragment.Filter}";
            }

            QueryableDocument = document;

            UseOptimisticConcurrency = document.UseOptimisticConcurrency;


            _setter = LambdaBuilder.Setter <T, TId>(document.IdMember);

            DeleteFragment = _mapping.DeleteStyle == DeleteStyle.Remove
                ? (IOperationFragment) new HardDelete(this)
                : new SoftDelete(this);
        }
Ejemplo n.º 20
0
        public static void GenerateDocumentStorage(IDocumentMapping mapping, SourceWriter writer)
        {
            var upsertFunction = mapping.ToUpsertFunction();

            var id_NpgsqlDbType = TypeMappings.ToDbType(mapping.IdMember.GetMemberType());

            var typeName = mapping.DocumentType.GetTypeName();

            var storageArguments = mapping.ToArguments().ToArray();
            var ctorArgs         = storageArguments.Select(x => x.ToCtorArgument()).Join(", ");
            var ctorLines        = storageArguments.Select(x => x.ToCtorLine()).Join("\n");
            var fields           = storageArguments.Select(x => x.ToFieldDeclaration()).Join("\n");

            writer.Write(
                $@"
BLOCK:public class {mapping.DocumentType.Name}Storage : IDocumentStorage, IBulkLoader<{typeName}>, IdAssignment<{typeName}>, IResolver<{typeName}>

{fields}

BLOCK:public {mapping.DocumentType.Name}Storage({ctorArgs})
{ctorLines}
END

public Type DocumentType => typeof ({typeName});

BLOCK:public NpgsqlCommand UpsertCommand(object document, string json)
return UpsertCommand(({typeName})document, json);
END

BLOCK:public NpgsqlCommand LoaderCommand(object id)
return new NpgsqlCommand(`select {mapping.SelectFields("d")} from {mapping.TableName} as d where id = :id`).With(`id`, id);
END

BLOCK:public NpgsqlCommand DeleteCommandForId(object id)
return new NpgsqlCommand(`delete from {mapping.TableName} where id = :id`).With(`id`, id);
END

BLOCK:public NpgsqlCommand DeleteCommandForEntity(object entity)
return DeleteCommandForId((({typeName})entity).{mapping.IdMember.Name});
END

BLOCK:public NpgsqlCommand LoadByArrayCommand<T>(T[] ids)
return new NpgsqlCommand(`select {mapping.SelectFields("d")} from {mapping.TableName} as d where id = ANY(:ids)`).With(`ids`, ids);
END

BLOCK:public void Remove(IIdentityMap map, object entity)
var id = Identity(entity);
map.Remove<{typeName}>(id);
END

BLOCK:public void Delete(IIdentityMap map, object id)
map.Remove<{typeName}>(id);
END

BLOCK:public void Store(IIdentityMap map, object id, object entity)
map.Store<{typeName}>(id, ({typeName})entity);
END

BLOCK:public object Assign({typeName} document)
{mapping.IdStrategy.AssignmentBodyCode(mapping.IdMember)}
return document.{mapping.IdMember.Name};
END

BLOCK:public object Retrieve({typeName} document)
return document.{mapping.IdMember.Name};
END

BLOCK:public {typeName} Build(DbDataReader reader, ISerializer serializer)
return serializer.FromJson<{typeName}>(reader.GetString(0));
END

public NpgsqlDbType IdType => NpgsqlDbType.{id_NpgsqlDbType};

BLOCK:public object Identity(object document)
return (({typeName})document).{mapping.IdMember.Name};
END

BLOCK:public {typeName} Resolve(IIdentityMap map, ILoader loader, object id)
return map.Get(id, () => loader.LoadDocument<{typeName}>(id)) as {typeName};
END

BLOCK:public Task<{typeName}> ResolveAsync(IIdentityMap map, ILoader loader, CancellationToken token, object id)
return map.GetAsync(id, (tk => loader.LoadDocumentAsync<{typeName}>(id, tk)), token).ContinueWith(x => x.Result as {typeName}, token);
END

{mapping.ToResolveMethod(typeName)}

{upsertFunction.ToUpdateBatchMethod(typeName)}

{upsertFunction.ToBulkInsertMethod(typeName)}


END

");
        }
Ejemplo n.º 21
0
 public void execute_to_db_type_as_date()
 {
     // I'm overriding the behavior in Npgsql itself here.
     TypeMappings.ToDbType(typeof(DateTime)).ShouldBe(NpgsqlDbType.Date);
 }
Ejemplo n.º 22
0
 public void execute_to_db_type_as_int()
 {
     TypeMappings.ToDbType(typeof(int)).ShouldBe(NpgsqlDbType.Integer);
     TypeMappings.ToDbType(typeof(int?)).ShouldBe(NpgsqlDbType.Integer);
 }
Ejemplo n.º 23
0
 public CommandParameter(ConstantExpression expression)
 {
     Value  = expression.Value;
     DbType = TypeMappings.ToDbType(expression.Type);
 }
Ejemplo n.º 24
0
        public string ToUpdateBatchParam()
        {
            var dbType = TypeMappings.ToDbType(Members.Last().GetMemberType());

            return($".Param(document.{accessorPath()}, NpgsqlDbType.{dbType})");
        }
Ejemplo n.º 25
0
 public CommandParameter(ConstantExpression expression)
 {
     Value  = expression.Value;
     DbType = TypeMappings.ToDbType(expression.Type == typeof(object) ? expression.Value.GetType() : expression.Type);
 }