1+ // Copyright 2025 Google LLC
2+ //
3+ // Licensed under the Apache License, Version 2.0 (the "License");
4+ // you may not use this file except in compliance with the License.
5+ // You may obtain a copy of the License at
6+ //
7+ // https://www.apache.org/licenses/LICENSE-2.0
8+ //
9+ // Unless required by applicable law or agreed to in writing, software
10+ // distributed under the License is distributed on an "AS IS" BASIS,
11+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+ // See the License for the specific language governing permissions and
13+ // limitations under the License.
14+
15+ using System . Data ;
16+ using System . Data . Common ;
17+ using System . Text . RegularExpressions ;
18+ using NUnit . Framework . Internal ;
19+ using TypeCode = Google . Cloud . Spanner . V1 . TypeCode ;
20+
21+ namespace Google . Cloud . Spanner . DataProvider . Tests ;
22+
23+ public class SchemaTests : AbstractMockServerTests
24+ {
25+ [ Test ]
26+ public async Task MetaDataCollections ( )
27+ {
28+ await using var conn = await OpenConnectionAsync ( ) ;
29+
30+ var metaDataCollections = await conn . GetSchemaAsync ( DbMetaDataCollectionNames . MetaDataCollections ) ;
31+ Assert . That ( metaDataCollections . Rows , Has . Count . GreaterThan ( 0 ) ) ;
32+
33+ foreach ( var row in metaDataCollections . Rows . OfType < DataRow > ( ) )
34+ {
35+ var collectionName = ( string ) row ! [ "CollectionName" ] ;
36+ Assert . That ( await conn . GetSchemaAsync ( collectionName ) , Is . Not . Null , $ "Collection { collectionName } advertise in MetaDataCollections but is null") ;
37+ }
38+ }
39+
40+ [ Test ]
41+ public async Task NoParameter ( )
42+ {
43+ await using var conn = await OpenConnectionAsync ( ) ;
44+
45+ var dataTable1 = conn . GetSchema ( ) ;
46+ var collections1 = dataTable1 . Rows
47+ . Cast < DataRow > ( )
48+ . Select ( r => ( string ) r [ "CollectionName" ] )
49+ . ToList ( ) ;
50+
51+ var dataTable2 = conn . GetSchema ( DbMetaDataCollectionNames . MetaDataCollections ) ;
52+ var collections2 = dataTable2 . Rows
53+ . Cast < DataRow > ( )
54+ . Select ( r => ( string ) r [ "CollectionName" ] )
55+ . ToList ( ) ;
56+
57+ Assert . That ( collections1 , Is . EquivalentTo ( collections2 ) ) ;
58+ }
59+
60+ [ Test ]
61+ public async Task CaseInsensitiveCollectionName ( )
62+ {
63+ await using var conn = await OpenConnectionAsync ( ) ;
64+
65+ var dataTable1 = conn . GetSchema ( DbMetaDataCollectionNames . MetaDataCollections ) ;
66+ var collections1 = dataTable1 . Rows
67+ . Cast < DataRow > ( )
68+ . Select ( r => ( string ) r [ "CollectionName" ] )
69+ . ToList ( ) ;
70+
71+ var dataTable2 = conn . GetSchema ( "METADATACOLLECTIONS" ) ;
72+ var collections2 = dataTable2 . Rows
73+ . Cast < DataRow > ( )
74+ . Select ( r => ( string ) r [ "CollectionName" ] )
75+ . ToList ( ) ;
76+
77+ var dataTable3 = conn . GetSchema ( "metadatacollections" ) ;
78+ var collections3 = dataTable3 . Rows
79+ . Cast < DataRow > ( )
80+ . Select ( r => ( string ) r [ "CollectionName" ] )
81+ . ToList ( ) ;
82+
83+ var dataTable4 = conn . GetSchema ( "MetaDataCollections" ) ;
84+ var collections4 = dataTable4 . Rows
85+ . Cast < DataRow > ( )
86+ . Select ( r => ( string ) r [ "CollectionName" ] )
87+ . ToList ( ) ;
88+
89+ var dataTable5 = conn . GetSchema ( "METADATACOLLECTIONS" , null ! ) ;
90+ var collections5 = dataTable5 . Rows
91+ . Cast < DataRow > ( )
92+ . Select ( r => ( string ) r [ "CollectionName" ] )
93+ . ToList ( ) ;
94+
95+ var dataTable6 = conn . GetSchema ( "metadatacollections" , null ! ) ;
96+ var collections6 = dataTable6 . Rows
97+ . Cast < DataRow > ( )
98+ . Select ( r => ( string ) r [ "CollectionName" ] )
99+ . ToList ( ) ;
100+
101+ var dataTable7 = conn . GetSchema ( "MetaDataCollections" , null ! ) ;
102+ var collections7 = dataTable7 . Rows
103+ . Cast < DataRow > ( )
104+ . Select ( r => ( string ) r [ "CollectionName" ] )
105+ . ToList ( ) ;
106+
107+ Assert . That ( collections1 , Is . EquivalentTo ( collections2 ) ) ;
108+ Assert . That ( collections1 , Is . EquivalentTo ( collections3 ) ) ;
109+ Assert . That ( collections1 , Is . EquivalentTo ( collections4 ) ) ;
110+ Assert . That ( collections1 , Is . EquivalentTo ( collections5 ) ) ;
111+ Assert . That ( collections1 , Is . EquivalentTo ( collections6 ) ) ;
112+ Assert . That ( collections1 , Is . EquivalentTo ( collections7 ) ) ;
113+ }
114+
115+ [ Test ]
116+ public async Task DataSourceInformation ( )
117+ {
118+ await using var conn = await OpenConnectionAsync ( ) ;
119+ var dataTable = conn . GetSchema ( DbMetaDataCollectionNames . MetaDataCollections ) ;
120+ var metadata = dataTable . Rows
121+ . Cast < DataRow > ( )
122+ . Single ( r => r [ "CollectionName" ] . Equals ( "DataSourceInformation" ) ) ;
123+ Assert . That ( metadata [ "NumberOfRestrictions" ] , Is . Zero ) ;
124+ Assert . That ( metadata [ "NumberOfIdentifierParts" ] , Is . Zero ) ;
125+
126+ var dataSourceInfo = conn . GetSchema ( DbMetaDataCollectionNames . DataSourceInformation ) ;
127+ var row = dataSourceInfo . Rows . Cast < DataRow > ( ) . Single ( ) ;
128+
129+ Assert . That ( row [ "DataSourceProductName" ] , Is . EqualTo ( "Spanner" ) ) ;
130+ Assert . That ( row [ "DataSourceProductVersion" ] , Is . EqualTo ( "1.0.0" ) ) ;
131+ Assert . That ( row [ "DataSourceProductVersionNormalized" ] , Is . EqualTo ( "001.000.0000" ) ) ;
132+
133+ Assert . That ( Regex . Match ( "`some_identifier`" , ( string ) row [ "QuotedIdentifierPattern" ] ) . Groups [ 1 ] . Value ,
134+ Is . EqualTo ( "some_identifier" ) ) ;
135+ }
136+
137+ [ Test ]
138+ public async Task DataTypes ( )
139+ {
140+ await using var connection = await OpenConnectionAsync ( ) ;
141+
142+ var dataTable = connection . GetSchema ( DbMetaDataCollectionNames . MetaDataCollections ) ;
143+ var metadata = dataTable . Rows
144+ . Cast < DataRow > ( )
145+ . Single ( r => r [ "CollectionName" ] . Equals ( "DataTypes" ) ) ;
146+ Assert . That ( metadata [ "NumberOfRestrictions" ] , Is . Zero ) ;
147+ Assert . That ( metadata [ "NumberOfIdentifierParts" ] , Is . Zero ) ;
148+
149+ var dataTypes = connection . GetSchema ( DbMetaDataCollectionNames . DataTypes ) ;
150+
151+ var boolRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Bool" ) ) ;
152+ Assert . That ( boolRow [ "DataType" ] , Is . EqualTo ( "System.Boolean" ) ) ;
153+ Assert . That ( boolRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Bool ) ) ;
154+ Assert . That ( boolRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
155+
156+ var bytesRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Bytes" ) ) ;
157+ Assert . That ( bytesRow [ "DataType" ] , Is . EqualTo ( "System.Byte[]" ) ) ;
158+ Assert . That ( bytesRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Bytes ) ) ;
159+ Assert . That ( bytesRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
160+ Assert . That ( bytesRow [ "IsBestMatch" ] , Is . True ) ;
161+
162+ var dateRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Date" ) ) ;
163+ Assert . That ( dateRow [ "DataType" ] , Is . EqualTo ( "System.DateOnly" ) ) ;
164+ Assert . That ( dateRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Date ) ) ;
165+ Assert . That ( dateRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
166+ Assert . That ( dateRow [ "IsBestMatch" ] , Is . True ) ;
167+
168+ var enumRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Enum" ) ) ;
169+ Assert . That ( enumRow [ "DataType" ] , Is . EqualTo ( "System.Int64" ) ) ;
170+ Assert . That ( enumRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Enum ) ) ;
171+ Assert . That ( enumRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
172+ Assert . That ( enumRow [ "IsBestMatch" ] , Is . False ) ;
173+
174+ var float32Row = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Float32" ) ) ;
175+ Assert . That ( float32Row [ "DataType" ] , Is . EqualTo ( "System.Single" ) ) ;
176+ Assert . That ( float32Row [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Float32 ) ) ;
177+ Assert . That ( float32Row [ "IsUnsigned" ] , Is . False ) ;
178+ Assert . That ( float32Row [ "IsBestMatch" ] , Is . True ) ;
179+
180+ var float64Row = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Float64" ) ) ;
181+ Assert . That ( float64Row [ "DataType" ] , Is . EqualTo ( "System.Double" ) ) ;
182+ Assert . That ( float64Row [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Float64 ) ) ;
183+ Assert . That ( float64Row [ "IsUnsigned" ] , Is . False ) ;
184+ Assert . That ( float64Row [ "IsBestMatch" ] , Is . True ) ;
185+
186+ var int64Row = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Int64" ) ) ;
187+ Assert . That ( int64Row [ "DataType" ] , Is . EqualTo ( "System.Int64" ) ) ;
188+ Assert . That ( int64Row [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Int64 ) ) ;
189+ Assert . That ( int64Row [ "IsUnsigned" ] , Is . False ) ;
190+ Assert . That ( int64Row [ "IsBestMatch" ] , Is . True ) ;
191+
192+ var intervalRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Interval" ) ) ;
193+ Assert . That ( intervalRow [ "DataType" ] , Is . EqualTo ( "System.TimeSpan" ) ) ;
194+ Assert . That ( intervalRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Interval ) ) ;
195+ Assert . That ( intervalRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
196+ Assert . That ( intervalRow [ "IsBestMatch" ] , Is . True ) ;
197+
198+ var jsonRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Json" ) ) ;
199+ Assert . That ( jsonRow [ "DataType" ] , Is . EqualTo ( "System.String" ) ) ;
200+ Assert . That ( jsonRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Json ) ) ;
201+ Assert . That ( jsonRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
202+ Assert . That ( jsonRow [ "IsBestMatch" ] , Is . False ) ;
203+
204+ var numericRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Numeric" ) ) ;
205+ Assert . That ( numericRow [ "DataType" ] , Is . EqualTo ( "System.Decimal" ) ) ;
206+ Assert . That ( numericRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Numeric ) ) ;
207+ Assert . That ( numericRow [ "IsUnsigned" ] , Is . False ) ;
208+ Assert . That ( numericRow [ "IsBestMatch" ] , Is . True ) ;
209+
210+ var protoRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Proto" ) ) ;
211+ Assert . That ( protoRow [ "DataType" ] , Is . EqualTo ( "System.Byte[]" ) ) ;
212+ Assert . That ( protoRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Proto ) ) ;
213+ Assert . That ( protoRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
214+ Assert . That ( protoRow [ "IsBestMatch" ] , Is . False ) ;
215+
216+ var stringRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "String" ) ) ;
217+ Assert . That ( stringRow [ "DataType" ] , Is . EqualTo ( "System.String" ) ) ;
218+ Assert . That ( stringRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . String ) ) ;
219+ Assert . That ( stringRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
220+ Assert . That ( stringRow [ "IsBestMatch" ] , Is . True ) ;
221+
222+ var timestampRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Timestamp" ) ) ;
223+ Assert . That ( timestampRow [ "DataType" ] , Is . EqualTo ( "System.DateTime" ) ) ;
224+ Assert . That ( timestampRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Timestamp ) ) ;
225+ Assert . That ( timestampRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
226+ Assert . That ( timestampRow [ "IsBestMatch" ] , Is . True ) ;
227+
228+ var uuidRow = dataTypes . Rows . Cast < DataRow > ( ) . Single ( r => r [ "TypeName" ] . Equals ( "Uuid" ) ) ;
229+ Assert . That ( uuidRow [ "DataType" ] , Is . EqualTo ( "System.Guid" ) ) ;
230+ Assert . That ( uuidRow [ "ProviderDbType" ] , Is . EqualTo ( ( int ) TypeCode . Uuid ) ) ;
231+ Assert . That ( uuidRow [ "IsUnsigned" ] , Is . EqualTo ( DBNull . Value ) ) ;
232+ Assert . That ( uuidRow [ "IsBestMatch" ] , Is . True ) ;
233+ }
234+
235+ [ Test ]
236+ public async Task Restrictions ( )
237+ {
238+ await using var conn = await OpenConnectionAsync ( ) ;
239+ var restrictions = conn . GetSchema ( DbMetaDataCollectionNames . Restrictions ) ;
240+ Assert . That ( restrictions . Rows , Has . Count . GreaterThan ( 0 ) ) ;
241+ }
242+
243+ [ Test ]
244+ public async Task ReservedWords ( )
245+ {
246+ await using var conn = await OpenConnectionAsync ( ) ;
247+ var reservedWords = conn . GetSchema ( DbMetaDataCollectionNames . ReservedWords ) ;
248+ Assert . That ( reservedWords . Rows , Has . Count . GreaterThan ( 0 ) ) ;
249+ }
250+
251+ }
0 commit comments