Example #1
0
        public static Schema GetSchemaForType(this ISchemaTypeMap typeMap, Type type)
        {
            Schema schema;

            if (!typeMap.TryGetSchemaForType(type, out schema))
            {
                throw new MissingTypeMappingException(schema);
            }
            return(schema);
        }
Example #2
0
        public void ApplyToEditable(IEditable target, object source)
        {
            if (source == null)
            {
                target.Set(null);
                return;
            }

            if (source is ICursor)
            {
                target.Set(source);
                return;
            }

            var obj = target as IEditableObject;

            if (obj != null)
            {
                if (target.Schema.Id == (int)BuiltInSchema.DateTimeOffset && source is DateTimeOffset)
                {
                    var sourceDate = (DateTimeOffset)source;
                    obj.GetField("Time").Set(sourceDate.DateTime);
                    obj.GetField("Offset").Set(sourceDate.Offset);
                }
                else if (target.Schema.Id == (int)BuiltInSchema.Version && source is Version)
                {
                    var sourceVersion = (Version)source;
                    obj.GetField("Major").Set(sourceVersion.Major);
                    obj.GetField("Minor").Set(sourceVersion.Minor);
                    obj.GetField("Build").Set(sourceVersion.Build);
                    obj.GetField("Revision").Set(sourceVersion.Revision);
                }
                else
                {
                    var sourceType = source.GetType();

                    // read properties
                    var properties = sourceType.GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    foreach (var p in properties.Where(x => x.CanRead))
                    {
                        Field f;
                        if (obj.Schema.TryLookup(p.Name, out f))
                        {
                            var field = obj.GetField(f.Index);
                            var value = p.GetGetMethod().Invoke(source, null);

                            try
                            {
                                ApplyToEditable(field, value);
                            }
                            catch (Exception e)
                            {
                                throw new Exception(string.Format("Error setting field '{0}': {1}", p.Name, e.Message), e);
                            }
                        }
                    }

                    // read fields
                    var fields = sourceType.GetTypeInfo().GetFields(BindingFlags.Public | BindingFlags.Instance);
                    foreach (var p in fields)
                    {
                        Field f;
                        if (obj.Schema.TryLookup(p.Name, out f))
                        {
                            var field = obj.GetField(f.Index);
                            var value = p.GetValue(source);

                            try
                            {
                                ApplyToEditable(field, value);
                            }
                            catch (Exception e)
                            {
                                throw new Exception(string.Format("Error setting field '{0}': {1}", p.Name, e.Message), e);
                            }
                        }
                    }

                    if (obj.Schema.Id == (int)BuiltInSchema.Item &&
                        (!sourceType.GetTypeInfo().IsGenericType || sourceType.GetGenericTypeDefinition() != typeof(Item <>)) &&
                        typeof(Item).GetTypeInfo().IsAssignableFrom(sourceType))
                    {
                        var field = obj.GetField(ItemLayout.Data);
                        ApplyToEditable(field, source);
                    }
                }
                return;
            }

            var list = target as IEditableList;

            if (list != null)
            {
                var sourceEnum = source as System.Collections.IEnumerable;
                if (sourceEnum == null)
                {
                    throw new Exception("Provider type for list values does not implement IEnumerable");
                }

                list.Clear();   // ensure the list in non-null

                foreach (var x in sourceEnum)
                {
                    ApplyToEditable(list.Add(), x);
                }

                return;
            }

            var variable = target as IEditableVariable;

            if (variable != null)
            {
                if (source != null)
                {
                    Schema schema;
                    if (schemaTypeMap.TryGetSchemaForType(source.GetType(), out schema))
                    {
                        variable.DataSchema = schema;
                        if (variable.IsNull)
                        {
                            variable.Set(editableFactory.Create(schema));
                        }
                        ApplyToEditable(variable.Get <IEditable>(), source);
                    }
                    else
                    {
                        if (source.GetType() != typeof(Item))
                        {
                            throw new MissingTypeMappingException(source.GetType());
                        }
                        else
                        {
                            variable.Set(null);
                        }
                    }
                }
                else
                {
                    variable.Set(null);
                }

                return;
            }

            if (source is Choice)
            {
                source = ((Choice)source).Value;
            }

            target.Set(source);
        }
        Schema BuildSchemaForClass(Type type, string schemaName, List <Tuple <Type, Schema> > schemaList, bool onlyMissing)
        {
            var excludedProperties = new List <String>();

            if (typeof(Item).IsAssignableFrom(type))
            {
                excludedProperties.AddRange(typeof(Item).GetTypeInfo().GetProperties().Select(x => x.Name));
            }

            var sb = new SchemaBuilder(schemaName, DataType.Class, null);

            foreach (var p in type.GetTypeInfo().GetProperties().Where(x => x.CanRead && x.CanWrite && !excludedProperties.Contains(x.Name)))
            {
                if (p.GetCustomAttribute <NonRecordFieldAttribute>() != null)
                {
                    continue;
                }

                var fieldAttribute = p.GetCustomAttribute <RecordFieldAttribute>();

                string caption     = null;
                string description = null;
                int?   maxLength   = null;
                bool?  nullable    = null;

                if (fieldAttribute != null)
                {
                    caption     = fieldAttribute.Caption;
                    description = fieldAttribute.Description;
                    if (fieldAttribute.MaxLength > 0)
                    {
                        maxLength = fieldAttribute.MaxLength;
                    }
                    nullable = fieldAttribute.Nullable;
                }

                if (nullable == null && (Nullable.GetUnderlyingType(p.PropertyType) != null || typeof(INullable).IsAssignableFrom(p.PropertyType)))
                {
                    nullable = true;
                }

                Schema schema;
                Type   propertyType = Nullable.GetUnderlyingType(p.PropertyType) ?? p.PropertyType;
                if (propertyType == typeof(Choice) || propertyType == typeof(MultiChoice))
                {
                    if (fieldAttribute == null)
                    {
                        throw new Exception(string.Format("CacheFieldAttribute missing for property '{0}' of type {1}.", p.Name, propertyType));
                    }

                    schema = schemaProvider.GetSchemaByName(fieldAttribute.SchemaName);
                    if (p.PropertyType == typeof(Choice) && schema.DataType != DataType.Choice)
                    {
                        throw new Exception(string.Format("Choice field expected but field has data type: '{0}'", schema.DataType));
                    }
                    else if (p.PropertyType == typeof(MultiChoice) && schema.DataType != DataType.MultiChoice)
                    {
                        throw new Exception(string.Format("MultiChoice field expected but field has data type: '{0}'", schema.DataType));
                    }
                    sb.AddField(p.Name, schema, nullable.Value, maxLength, caption, description);
                }
                else if (EditablePrimitive.TryGetPrimitiveSchemaForType(p.PropertyType, out schema))
                {
                    // primitive data type first (covers nullable primitive types)
                    nullable = nullable ?? (p.PropertyType == typeof(string) || p.PropertyType == typeof(byte[]));
                    sb.AddField(p.Name, schema, nullable.Value, maxLength, caption, description);
                }
                else if (typeof(ICursor).IsAssignableFrom(p.PropertyType))
                {
                    // create variable field (if no schema was explicitely specified)
                    if (fieldAttribute != null && fieldAttribute.SchemaName != null)
                    {
                        schema = schemaProvider.GetSchemaByName(fieldAttribute.SchemaName);
                    }
                    else
                    {
                        schema = Schema.BuiltIn[BuiltInSchema.Variable];
                    }

                    sb.AddField(p.Name, schema, nullable ?? true, maxLength, caption, description);
                }
                else if (p.PropertyType == typeof(object))
                {
                    sb.AddField(p.Name, Schema.BuiltIn[BuiltInSchema.Variable], nullable ?? true, maxLength, caption, description);
                }
                else
                {
                    if (propertyType.GetTypeInfo().IsEnum&& fieldAttribute != null)
                    {
                        schema = schemaProvider.GetSchemaByName(fieldAttribute.SchemaName);
                    }
                    else if (!typeMap.TryGetSchemaForType(propertyType, out schema))
                    {
                        var t = schemaList.Find(x => x.Item1 == propertyType);
                        if (t != null)
                        {
                            schema = t.Item2;
                        }
                        else
                        {
                            schema = BuildSchemaRecursively(propertyType, null, schemaList, onlyMissing);
                        }
                    }

                    if (schema == null)
                    {
                        throw new MissingTypeMappingException(string.Format("Unable to generate a schema for property '{0}' (type'{1}') of class '{2}'.", p.Name, p.PropertyType.FullName, type.FullName));
                    }

                    // a schema was registerd for the property type
                    if (!nullable.HasValue)
                    {
                        nullable = !p.PropertyType.GetTypeInfo().IsValueType;
                    }

                    sb.AddField(p.Name, schema, nullable.Value, maxLength, caption, description);
                }
            }

            var result = sb.ToSchema();

            var recordAttribute = type.GetTypeInfo().GetCustomAttribute <RecordAttribute>();

            if (recordAttribute != null)
            {
                result.Id = recordAttribute.SchemaId;
            }

            schemaList.Add(Tuple.Create(type, result));
            return(result);
        }