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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
namespace CrupestApi.Commons.Crud;
public static class ColumnMetadataKeys
{
public const string ColumnName = nameof(ColumnAttribute.ColumnName);
public const string NotNull = nameof(ColumnAttribute.NotNull);
public const string IsPrimaryKey = nameof(ColumnAttribute.IsPrimaryKey);
public const string IsAutoIncrement = nameof(ColumnAttribute.IsAutoIncrement);
public const string Index = nameof(ColumnAttribute.Index);
/// <summary>
/// This will add hooks for string type column to coerce null to ""(empty string) when get or set. No effect on non-string type.
/// </summary>
public const string DefaultEmptyForString = nameof(ColumnAttribute.DefaultEmptyForString);
/// <summary>
/// This indicates that you take care of generate this column value when create entity. User calling the api can not specify the value.
/// </summary>
public const string ClientGenerate = nameof(ColumnAttribute.DefaultEmptyForString);
}
public interface IColumnMetadata
{
bool TryGetValue(string key, out object? value);
object? GetValueOrDefault(string key)
{
if (TryGetValue(key, out var value))
{
return value;
}
else
{
return null;
}
}
T? GetValueOrDefault<T>(string key)
{
return (T?)GetValueOrDefault(key);
}
object? this[string key]
{
get
{
if (TryGetValue(key, out var value))
{
return value;
}
else
{
throw new KeyNotFoundException("Key not found.");
}
}
}
}
public enum ColumnIndexType
{
None,
Unique,
NonUnique
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ColumnAttribute : Attribute, IColumnMetadata
{
// if null, use the property name.
public string? ColumnName { get; init; }
// default false.
public bool NotNull { get; init; }
// default false
public bool IsPrimaryKey { get; init; }
// default false
public bool IsAutoIncrement { get; init; }
// default None
public ColumnIndexType Index { get; init; } = ColumnIndexType.None;
/// <see cref="ColumnMetadataKeys.DefaultEmptyForString"/>
public bool DefaultEmptyForString { get; init; }
/// <see cref="ColumnMetadataKeys.ClientGenerate"/>
public bool ClientGenerate { get; init; }
public bool TryGetValue(string key, out object? value)
{
var property = GetType().GetProperty(key);
if (property is null)
{
value = null;
return false;
}
value = property.GetValue(this);
return true;
}
}
public class AggregateColumnMetadata : IColumnMetadata
{
private IDictionary<string, object?> _own = new Dictionary<string, object?>();
private IList<IColumnMetadata> _children = new List<IColumnMetadata>();
public void Add(string key, object? value)
{
_own[key] = value;
}
public void Remove(string key)
{
_own.Remove(key);
}
public void Add(IColumnMetadata child)
{
_children.Add(child);
}
public void Remove(IColumnMetadata child)
{
_children.Remove(child);
}
public bool TryGetValue(string key, out object? value)
{
if (_own.ContainsKey(key))
{
value = _own[key];
return true;
}
bool found = false;
value = null;
foreach (var child in _children)
{
if (child.TryGetValue(key, out var tempValue))
{
value = tempValue;
found = true;
}
}
return found;
}
}
|