1 #Region "Microsoft.VisualBasic::633a486a87f1e57733543dbb7304615f, Microsoft.VisualBasic.Core\ComponentModel\DataSource\SchemaMaps\DataSource.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Class Field
35     
36     '         Constructor: (+1 OverloadsSub New
37     
38     '     Class DataFrameColumnAttribute
39     
40     '         Properties: Description, Index, Name
41     
42     '         Constructor: (+4 OverloadsSub New
43     '         Function: __attrs, __attrsAll, __source, GetIndex, GetMapping
44     '                   (+2 Overloads) LoadMapping, SetNameValue, ToString
45     
46     '     Class DataFrameIO
47     
48     
49     
50     
51     ' /********************************************************************************/
52
53 #End Region
54
55 Imports System.Reflection
56 Imports System.Runtime.CompilerServices
57 Imports Microsoft.VisualBasic.ComponentModel.Collection
58 Imports Microsoft.VisualBasic.Language
59 Imports FieldTuple = System.Collections.Generic.KeyValuePair(Of Microsoft.VisualBasic.ComponentModel.DataSourceModel.SchemaMaps.DataFrameColumnAttribute, System.Reflection.PropertyInfo)
60
61 Namespace ComponentModel.DataSourceModel.SchemaMaps
62
63     ''' <summary>
64     ''' <see cref="DataFrameColumnAttribute"/>属性的别称
65     ''' </summary>
66     Public Class Field : Inherits DataFrameColumnAttribute
67
68         ''' <summary>
69         ''' Initializes a new instance by name.
70         ''' </summary>
71         ''' <param name="FieldName">The name.</param>
72         ''' 
73         <MethodImpl(MethodImplOptions.AggressiveInlining)>
74         Public Sub New(FieldName As String)
75             Call MyBase.New(FieldName)
76         End Sub
77     End Class
78
79     ''' <summary>
80     ''' Represents a column of certain data frames. The mapping between to schema is also can be represent by this attribute. 
81     ''' (也可以使用这个对象来完成在两个数据源之间的属性的映射,由于对于一些列名称的属性值缺失的映射而言,
82     ''' 其是使用属性名来作为列映射名称的,故而在修改这些没有预设的列名称的映射属性的属性名的时候,请注意
83     ''' 要小心维护这种映射关系)
84     ''' </summary>
85     <AttributeUsage(AttributeTargets.[Property] Or AttributeTargets.Field,
86                     Inherited:=True,
87                     AllowMultiple:=False)>
88     Public Class DataFrameColumnAttribute : Inherits Attribute
89
90         Protected Shared ReadOnly __emptyIndex As String() = New String(-1) {}
91
92         ''' <summary>
93         ''' Gets the index.
94         ''' </summary>
95         Public ReadOnly Property Index() As Integer
96
97         ''' <summary>
98         ''' Gets the name.
99         ''' </summary>
100         Public ReadOnly Property Name() As String
101
102         Public Property Description As String
103
104         ''' <summary>
105         ''' Initializes a new instance by name.
106         ''' </summary>
107         ''' <param name="FieldName">The name.</param>
108         Public Sub New(FieldName As String)
109             If String.IsNullOrEmpty(FieldName) Then
110                 Throw New ArgumentNullException(NameOf(FieldName))
111             End If
112             Me._Name = FieldName
113             Me._Index = -1
114         End Sub
115
116         ''' <summary>
117         ''' Initializes a new instance by index.
118         ''' </summary>
119         ''' <param name="index">The index.</param>
120         Public Sub New(index As Integer)
121             If index < 0 Then
122                 Throw New ArgumentOutOfRangeException(NameOf(index))
123             End If
124             Me._Name = Nothing
125             Me._Index = index
126         End Sub
127
128         ''' <summary>
129         ''' 会默认使用目标对象的反射的Name属性作为映射的名称
130         ''' </summary>
131         ''' <remarks></remarks>
132         Public Sub New()
133             _Index = -1
134         End Sub
135
136         ''' <summary>
137         ''' 
138         ''' </summary>
139         ''' <param name="Name">列名称,假若本参数为空的话,则使用属性名称</param>
140         ''' <param name="index">从1开始的下标,表示为第几列</param>
141         ''' <remarks></remarks>
142         Sub New(Optional Name As String = ""Optional index As Integer = -1)
143             _Name = Name
144             _Index = index
145         End Sub
146
147         Public Overrides Function ToString() As String
148             Return _Name
149         End Function
150
151         Const NameException As String = "Name must not be null when Index is not defined."
152
153         Public Function SetNameValue(value As StringAs DataFrameColumnAttribute
154             If Me._Index < 0 AndAlso String.IsNullOrEmpty(value) Then
155                 Throw New ArgumentNullException(NameOf(value), NameException)
156             End If
157             Me._Name = value
158             Return Me
159         End Function
160
161         Public Function GetIndex(names As String()) As Integer
162             Return If(Index >= 0, Index, Array.IndexOf(If(names, __emptyIndex), Name))
163         End Function
164
165         ''' <summary>
166         ''' 没有名称属性的映射使用属性名来表述,请注意,字典的Key是属性的名称
167         ''' </summary>
168         ''' <typeparam name="T"></typeparam>
169         ''' <returns></returns>
170         ''' <remarks></remarks>
171         ''' 
172         <MethodImpl(MethodImplOptions.AggressiveInlining)>
173         Public Shared Function LoadMapping(Of T)(
174                       Optional ignores As String() = Nothing,
175                       Optional mapsAll As Boolean = False) _
176                                        As Dictionary(Of BindProperty(Of DataFrameColumnAttribute))
177
178             Return LoadMapping(GetType(T), ignores, mapsAll)
179         End Function
180
181         ''' <summary>
182         ''' Load the mapping property, if the custom attribute <see cref="DataFrameColumnAttribute"></see> 
183         ''' have no name value, then the property name will be used as the mapping name.
184         ''' (这个函数会自动给空名称值进行属性名的赋值操作的)
185         ''' </summary>
186         ''' <param name="typeInfo">The type should be a class type or its properties should have the 
187         ''' mapping option which was created by the custom attribute <see cref="DataFrameColumnAttribute"></see>
188         ''' </param>
189         ''' <param name="ignores">这个是大小写敏感的</param>
190         ''' <returns></returns>
191         ''' <remarks></remarks>
192         Public Shared Function LoadMapping(
193                                typeInfo As Type,
194                       Optional ignores As String() = Nothing,
195                       Optional mapsAll As Boolean = False) _
196                                        As Dictionary(Of BindProperty(Of DataFrameColumnAttribute))
197
198             Dim ignoreList$() = If(ignores Is Nothing, {}, ignores)
199             Dim source As IEnumerable(Of FieldTuple) = __source(typeInfo, ignoreList, mapsAll)
200             Dim LQuery = LinqAPI.Exec(Of BindProperty(Of DataFrameColumnAttribute)) _
201  _
202                 () <= From pInfo As FieldTuple
203                       In source
204                       Let Mapping As DataFrameColumnAttribute = GetMapping(pInfo)
205                       Select New BindProperty(Of DataFrameColumnAttribute)(Mapping, pInfo.Value) ' 补全名称属性
206
207             Dim out As New Dictionary(Of BindProperty(Of DataFrameColumnAttribute))(LQuery)
208             Return out
209         End Function
210
211         ''' <summary>
212         ''' 假若名称是空的,则会在这里自动的使用属性名称进行赋值
213         ''' </summary>
214         ''' <param name="pinfo"></param>
215         ''' <returns></returns>
216         <MethodImpl(MethodImplOptions.AggressiveInlining)>
217         Private Shared Function GetMapping(pinfo As FieldTuple) As DataFrameColumnAttribute
218             If String.IsNullOrEmpty(pinfo.Key.Name) Then
219                 Return pinfo.Key.SetNameValue(pinfo.Value.Name)
220             Else
221                 Return pinfo.Key
222             End If
223         End Function
224
225         ''' <summary>
226         ''' 
227         ''' </summary>
228         ''' <param name="type"></param>
229         ''' <param name="ignores$"></param>
230         ''' <param name="mapsAll">
231         ''' Some property probably didn't have masked by <see cref="DataFrameColumnAttribute"/>, 
232         ''' so if this option is set to TRUE, then means indexing these property that without <see cref="DataFrameColumnAttribute"/> masked as well. 
233         ''' otherwise only indexing the property that have <see cref="DataFrameColumnAttribute"/> masked on it.
234         ''' </param>
235         ''' <returns></returns>
236         Private Shared Iterator Function __source(type As Type, ignores$(), mapsAll As BooleanAs IEnumerable(Of FieldTuple)
237             Dim props As IEnumerable(Of PropertyInfo) =
238  _
239                 From p As PropertyInfo
240                 In type.GetProperties(BindingFlags.Public Or BindingFlags.Instance)
241                 Where Array.IndexOf(ignores, p.Name) = -1
242                 Select p
243
244             If Not mapsAll Then
245                 For Each x In From pInfo As PropertyInfo
246                               In props
247                               Let attrs As Object() = __attrs(pInfo)
248                               Where Not attrs.IsNullOrEmpty
249                               Let attr = DirectCast(attrs.First, DataFrameColumnAttribute)
250                               Select New FieldTuple(attr, pInfo)
251                     Yield x
252                 Next
253             Else
254                 For Each x In From pInfo As PropertyInfo
255                               In props
256                               Let attr = __attrsAll(pInfo)
257                               Select New FieldTuple(attr, pInfo)
258                     Yield x
259                 Next
260             End If
261         End Function
262
263         Private Shared Function __attrsAll(pp As PropertyInfo) As DataFrameColumnAttribute
264             Dim attrs() = __attrs(pp)
265
266             If attrs.IsNullOrEmpty Then
267                 Return New DataFrameColumnAttribute
268             Else
269                 Return attrs(Scan0)
270             End If
271         End Function
272
273         <MethodImpl(MethodImplOptions.AggressiveInlining)>
274         Public Shared Function __attrs(pp As PropertyInfo) As DataFrameColumnAttribute()
275             Return pp _
276                 .GetCustomAttributes(GetType(DataFrameColumnAttribute), True) _
277                 .Select(Function(o) DirectCast(o, DataFrameColumnAttribute)) _
278                 .ToArray
279         End Function
280     End Class
281
282     Public MustInherit Class DataFrameIO(Of TAttributeType As DataFrameColumnAttribute)
283
284         ''' <summary>
285         ''' 
286         ''' </summary>
287         ''' <returns></returns>
288         ''' <remarks></remarks>
289         Protected MustOverride Function InitializeSchema(Of TEntityType As Class)() As TAttributeType()
290     End Class
291 End Namespace