public static Schema GetSchemaForType(this ISchemaTypeMap typeMap, Type type) { Schema schema; if (!typeMap.TryGetSchemaForType(type, out schema)) { throw new MissingTypeMappingException(schema); } return(schema); }
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); }