-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTypeModel.cs
More file actions
113 lines (88 loc) · 3.13 KB
/
Copy pathTypeModel.cs
File metadata and controls
113 lines (88 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace DataKit.Modelling.TypeModels
{
public abstract class TypeModel : IDataModel<TypeModel, PropertyField>
{
private readonly Dictionary<string, PropertyField> _fields
= new Dictionary<string, PropertyField>();
public abstract DataType Type { get; }
public IReadOnlyList<PropertyField> Fields { get; }
IReadOnlyList<IModelField> IDataModel.Fields => Fields;
IModelField IDataModel.this[string fieldName] => _fields[fieldName];
public PropertyField this[string fieldName] => _fields[fieldName];
internal TypeModel(IReadOnlyList<PropertyField> fields)
{
Fields = fields;
foreach (var field in fields)
// in lieu of support of multiple fields with the same name we just go
// with the last one in the list which should be the most derived
_fields[field.FieldName] = field;
}
private static readonly CachedCollection<Type, Type, TypeModel> _cachedCollection =
new CachedCollection<Type, Type, TypeModel>(TypeModelFactory.BuildTypeModel);
public static TypeModel GetModelOf(Type type)
{
return _cachedCollection.GetOrCreate(type, type);
}
public static TypeModel<T> GetModelOf<T>()
=> GetModelOf(typeof(T)) as TypeModel<T>;
public bool TryGetField(string fieldName, out PropertyField field)
=> _fields.TryGetValue(fieldName, out field);
public bool TryGetField(string fieldName, out IModelField field)
{
if (_fields.TryGetValue(fieldName, out var outField))
{
field = outField;
return true;
}
field = null;
return false;
}
public IModelNode Accept(IModelVisitor visitor)
{
return visitor.VisitModel(this);
}
}
public class TypeModel<T> : TypeModel
{
public override DataType Type { get; } = DataType.GetTypeOf<T>();
public TypeModel(IReadOnlyList<PropertyField> fields) :
base(fields)
{
}
private PropertyField GetField(IEnumerable<string> path)
{
var fields = Fields;
var result = default(PropertyField);
foreach (var segment in path)
{
if (fields == null)
throw new InvalidOperationException("Missing sub-model in expression path.");
result = fields.FirstOrDefault(q => q.FieldName == segment);
if (result == null)
throw new InvalidOperationException("Missing field in expression path.");
fields = result.FieldModel?.Fields;
}
return result;
}
public FieldGraphPath<PropertyField> GetField<TValue>(Expression<Func<T, TValue>> expression)
{
var node = expression.Body as MemberExpression;
var path = new List<string>();
while (true)
{
if (node == null || !(node.Member is PropertyInfo))
throw new InvalidOperationException("Expression must be comprised of property expressions.");
path.Insert(0, node.Member.Name);
if (node.Expression == null || node.Expression == expression.Parameters[0])
return new FieldGraphPath<PropertyField>(
path.ToArray(), GetField(path));
node = node.Expression as MemberExpression;
}
}
}
}