Example #1
0
        public BsonMapper(Func <Type, object> customTypeInstantiator = null)
        {
            this.SerializeNullValues   = false;
            this.TrimWhitespace        = true;
            this.EmptyStringToNull     = true;
            this.ResolveFieldName      = (s) => s;
            this.ResolveMember         = (t, mi, mm) => { };
            this.ResolveCollectionName = (t) => Reflection.IsList(t) ? Reflection.GetListItemType(t).Name : t.Name;
            this.IncludeFields         = false;

            _typeInstantiator = customTypeInstantiator ?? Reflection.CreateInstance;

            #region Register CustomTypes

            RegisterType <Uri>(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString));
            RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime());
            RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64));
            RegisterType <Regex>(
                r => r.Options == RegexOptions.None ? new BsonValue(r.ToString()) : new BsonDocument {
                { "p", r.ToString() }, { "o", (int)r.Options }
            },
                value => value.IsString ? new Regex(value) : new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32)
                );


            #endregion Register CustomTypes
        }
Example #2
0
        /// <summary>
        /// Define a subdocument (or a list of) as a reference
        /// </summary>
        public EntityBuilder <T> DbRef <K>(Expression <Func <T, K> > property, string collectionName)
        {
            if (string.IsNullOrEmpty(collectionName))
            {
                throw new ArgumentNullException("collectionName");
            }

            return(this.GetProperty(property, (p) =>
            {
                var typeRef = typeof(K);
                p.IsDbRef = true;

                if (Reflection.IsList(typeRef))
                {
                    var itemType = typeRef.IsArray ? typeRef.GetElementType() : Reflection.UnderlyingTypeOf(typeRef);
                    var mapper = _mapper.GetPropertyMapper(itemType);

                    RegisterDbRefList(p, collectionName, typeRef, itemType, mapper);
                }
                else
                {
                    var mapper = _mapper.GetPropertyMapper(typeRef);

                    RegisterDbRef(p, collectionName, typeRef, mapper);
                }
            }));
        }
Example #3
0
        /// <summary>
        /// Visit :: x => x.Customer.Name.`ToUpper()`
        /// </summary>
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            // get method declaring type - if is from any kind of list, read as Enumerable
            var isList = Reflection.IsList(node.Method.DeclaringType);

            var declaringType = isList ? typeof(Enumerable) : node.Method.DeclaringType;

            // if special method for index access, eval index value (do not use parameters)
            if (this.IsMethodIndexEval(node, out var obj, out var idx))
            {
                this.Visit(obj);

                var index = this.Evaluate(idx, typeof(string), typeof(int));

                if (index is string)
                {
                    _builder.Append(".");
                    _builder.Append($"['{index}']");
                }
                else
                {
                    _builder.Append($"[{index}]");
                }

                return(node);
            }

            // if not found in resolver, try run method
            if (!_resolver.TryGetValue(declaringType, out var type))
            {
                // if method are called by parameter expression and it's not exists, throw error
                var isParam = ParameterExpressionVisitor.Test(node);

                if (isParam)
                {
                    throw new NotSupportedException($"Method {node.Method.Name} not available to convert to BsonExpression ({node.ToString()}).");
                }

                // otherwise, try compile and execute
                var value = this.Evaluate(node);

                base.Visit(Expression.Constant(value));

                return(node);
            }

            // otherwise I have resolver for this method
            var pattern = type.ResolveMethod(node.Method);

            if (pattern == null)
            {
                throw new NotSupportedException($"Method {Reflection.MethodName(node.Method)} in {node.Method.DeclaringType.Name} are not supported when convert to BsonExpression ({node.ToString()}).");
            }

            // run pattern using object as # and args as @n
            this.ResolvePattern(pattern, node.Object, node.Arguments);

            return(node);
        }
Example #4
0
        public BsonMapper(Func <Type, object> customTypeInstantiator = null)
        {
            this.SerializeNullValues   = false;
            this.TrimWhitespace        = true;
            this.EmptyStringToNull     = true;
            this.ResolveFieldName      = (s) => s;
            this.ResolveMember         = (t, mi, mm) => { };
            this.ResolveCollectionName = (t) => Reflection.IsList(t) ? Reflection.GetListItemType(t).Name : t.Name;

#if NET35
            this.IncludeFields = false;
#endif

            _typeInstantiator = customTypeInstantiator ?? Reflection.CreateInstance;

            #region Register CustomTypes

            RegisterType <Uri>(uri => uri.AbsoluteUri, bson => new Uri(bson.AsString));
            RegisterType <DateTimeOffset>(value => new BsonValue(value.UtcDateTime), bson => bson.AsDateTime.ToUniversalTime());
            RegisterType <TimeSpan>(value => new BsonValue(value.Ticks), bson => new TimeSpan(bson.AsInt64));
            RegisterType <Regex>(
                r => r.Options == RegexOptions.None ? new BsonValue(r.ToString()) : new BsonDocument {
                { "p", r.ToString() }, { "o", (int)r.Options }
            },
                value => value.IsString ? new Regex(value) : new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32)
                );


            #endregion Register CustomTypes

            #region Register AutoId

            // register AutoId for ObjectId, Guid and Int32
            RegisterAutoId
            (
                value => value.Equals(ObjectId.Empty),
                (db, col) => ObjectId.NewObjectId()
            );

            RegisterAutoId
            (
                value => value == Guid.Empty,
                (db, col) => Guid.NewGuid()
            );

            RegisterAutoId
            (
                value => value == 0,
                (db, col) =>
            {
                var max = db.Max(col, "_id");
                return(max.IsMaxValue ? 1 : (max + 1));
            }
            );

            #endregion
        }
Example #5
0
        /// <summary>
        /// Try find a Type Resolver for declaring type
        /// </summary>
        private bool TryGetResolver(Type declaringType, out ITypeResolver typeResolver)
        {
            // get method declaring type - if is from any kind of list, read as Enumerable
            var isList     = Reflection.IsList(declaringType);
            var isNullable = Reflection.IsNullable(declaringType);

            var type =
                isList ? typeof(Enumerable) :
                isNullable ? typeof(Nullable) :
                declaringType;

            return(_resolver.TryGetValue(type, out typeResolver));
        }
Example #6
0
        /// <summary>
        /// Use this method to override how your class can be, by default, mapped from entity to Bson document.
        /// Returns an EntityMapper from each requested Type
        /// </summary>
        protected virtual EntityMapper BuildEntityMapper(Type type)
        {
            var mapper = new EntityMapper
            {
                Members = new List <MemberMapper>(),
                ForType = type
            };

            var idAttr     = typeof(BsonIdAttribute);
            var ignoreAttr = typeof(BsonIgnoreAttribute);
            var fieldAttr  = typeof(BsonFieldAttribute);
            var indexAttr  = typeof(BsonIndexAttribute);
            var dbrefAttr  = typeof(BsonRefAttribute);

            var members = this.GetTypeMembers(type);
            var id      = this.GetIdMember(members);

            foreach (var memberInfo in members)
            {
                // checks [BsonIgnore]
                if (memberInfo.IsDefined(ignoreAttr, true))
                {
                    continue;
                }

                // checks field name conversion
                var name = this.ResolveFieldName(memberInfo.Name);

                // check if property has [BsonField]
                var field = (BsonFieldAttribute)memberInfo.GetCustomAttributes(fieldAttr, false).FirstOrDefault();

                // check if property has [BsonField] with a custom field name
                if (field != null && field.Name != null)
                {
                    name = field.Name;
                }

                // checks if memberInfo is id field
                if (memberInfo == id)
                {
                    name = "_id";
                }

                // test if field name is OK (avoid to check in all instances) - do not test internal classes, like DbRef
                if (BsonDocument.IsValidFieldName(name) == false)
                {
                    throw LiteException.InvalidFormat(memberInfo.Name);
                }

                // create getter/setter function
                var getter = Reflection.CreateGenericGetter(type, memberInfo);
                var setter = Reflection.CreateGenericSetter(type, memberInfo);

                // check if property has [BsonId] to get with was setted AutoId = true
                var autoId = (BsonIdAttribute)memberInfo.GetCustomAttributes(idAttr, false).FirstOrDefault();

                // get data type
                var dataType = memberInfo is PropertyInfo ?
                               (memberInfo as PropertyInfo).PropertyType :
                               (memberInfo as FieldInfo).FieldType;

                // check if datatype is list/array
                var isList = Reflection.IsList(dataType);

                // create a property mapper
                var member = new MemberMapper
                {
                    AutoId         = autoId == null ? true : autoId.AutoId,
                    FieldName      = name,
                    MemberName     = memberInfo.Name,
                    DataType       = dataType,
                    IsList         = isList,
                    UnderlyingType = isList ? Reflection.GetListItemType(dataType) : dataType,
                    Getter         = getter,
                    Setter         = setter
                };

                // check if property has [BsonRef]
                var dbRef = (BsonRefAttribute)memberInfo.GetCustomAttributes(dbrefAttr, false).FirstOrDefault();

                if (dbRef != null && memberInfo is PropertyInfo)
                {
                    BsonMapper.RegisterDbRef(this, member, dbRef.Collection ?? this.ResolveCollectionName((memberInfo as PropertyInfo).PropertyType));
                }

                // support callback to user modify member mapper
                if (this.ResolveMember != null)
                {
                    this.ResolveMember(type, memberInfo, member);
                }

                // test if has name and there is no duplicate field
                if (member.FieldName != null && mapper.Members.Any(x => x.FieldName == name) == false)
                {
                    mapper.Members.Add(member);
                }
            }

            return(mapper);
        }