@@ -129,28 +129,39 @@ public TypeInfoMappingCollection(IEnumerable<TypeInfoMapping> items)
129129 var typeMatch = type is not null && looseTypeMatch ;
130130 var dataTypeMatch = dataTypeName is not null && mapping . DataTypeNameEquals ( dataTypeName . Value . Value ) ;
131131
132- switch ( mapping . MatchRequirement )
132+ var matchRequirement = mapping . MatchRequirement ;
133+ if ( dataTypeMatch && typeMatch
134+ || matchRequirement is not MatchRequirement . All && dataTypeMatch && looseTypeMatch
135+ || matchRequirement is MatchRequirement . Single && dataTypeName is null && typeMatch )
133136 {
134- case var _ when dataTypeMatch && typeMatch :
135- case not MatchRequirement . All when dataTypeMatch && looseTypeMatch :
136- case MatchRequirement . Single when dataTypeName is null && looseTypeMatch :
137- var resolvedMapping = mapping with
138- {
139- Type = type ?? mapping . Type ,
140- // Make sure plugins (which match on unqualified names) and resolvers get the fully qualified name to canonicalize.
141- DataTypeName = dataTypeName is not null ? dataTypeName . GetValueOrDefault ( ) . Value : mapping . DataTypeName
142- } ;
143- return resolvedMapping . Factory ( options , resolvedMapping , dataTypeName is not null ) ;
144- // DataTypeName is explicitly requiring dataTypeName so it won't be used for a fallback, Single would have matched above already.
145- case MatchRequirement . All when fallback is null && dataTypeName is null && typeMatch :
146- fallback = mapping . TypeMatchPredicate is not null ? mapping with { Type = type ! } : mapping ;
147- break ;
148- default :
149- continue ;
137+ var resolvedDataTypeName = ResolveFullyQualifiedDataTypeName ( dataTypeName , mapping . DataTypeName , options ) ;
138+ return mapping . Factory ( options , mapping with { Type = type ?? mapping . Type , DataTypeName = resolvedDataTypeName } , dataTypeName is not null ) ;
150139 }
140+
141+ // DataTypeName is explicitly requiring dataTypeName so it won't be used for a fallback, Single would have matched above already.
142+ if ( matchRequirement is MatchRequirement . All && fallback is null && dataTypeName is null && typeMatch )
143+ fallback = mapping ;
144+ }
145+
146+ if ( fallback is { } fbMapping )
147+ {
148+ var resolvedDataTypeName = ResolveFullyQualifiedDataTypeName ( dataTypeName , fbMapping . DataTypeName , options ) ;
149+ return fbMapping . Factory ( options , fbMapping with { Type = type ! , DataTypeName = resolvedDataTypeName } , dataTypeName is not null ) ;
151150 }
152151
153- return fallback ? . Factory ( options , fallback . Value , dataTypeName is not null ) ;
152+ return null ;
153+
154+ static string ResolveFullyQualifiedDataTypeName ( DataTypeName ? dataTypeName , string mappingDataTypeName , PgSerializerOptions options )
155+ {
156+ // Make sure plugins (which match on unqualified names) and converter resolvers get the fully qualified name to canonicalize.
157+ if ( dataTypeName is not null )
158+ return dataTypeName . GetValueOrDefault ( ) . Value ;
159+
160+ if ( TypeInfoMappingHelpers . TryResolveFullyQualifiedName ( options , mappingDataTypeName , out var fqDataTypeName ) )
161+ return fqDataTypeName . Value ;
162+
163+ throw new NotSupportedException ( $ "Cannot resolve '{ mappingDataTypeName } ' to a fully qualified datatype name. The datatype was not found in the current database info.") ;
164+ }
154165 }
155166
156167 bool TryGetMapping ( Type type , string dataTypeName , out TypeInfoMapping value )
@@ -177,13 +188,17 @@ TypeInfoMapping GetMapping(Type type, string dataTypeName)
177188 static TypeInfoFactory CreateComposedFactory ( Type mappingType , TypeInfoMapping innerMapping , Func < TypeInfoMapping , PgTypeInfo , PgConverter > mapper , bool copyPreferredFormat = false , bool supportsWriting = true )
178189 => ( options , mapping , dataTypeNameMatch ) =>
179190 {
180- var innerInfo = innerMapping . Factory ( options , innerMapping , dataTypeNameMatch ) ;
191+ var resolvedInnerMapping = innerMapping ;
192+ if ( ! DataTypeName . IsFullyQualified ( innerMapping . DataTypeName . AsSpan ( ) ) )
193+ resolvedInnerMapping = innerMapping with { DataTypeName = new DataTypeName ( mapping . DataTypeName ) . Schema + "." + innerMapping . DataTypeName } ;
194+
195+ var innerInfo = innerMapping . Factory ( options , resolvedInnerMapping , dataTypeNameMatch ) ;
181196 var converter = mapper ( mapping , innerInfo ) ;
182197 var preferredFormat = copyPreferredFormat ? innerInfo . PreferredFormat : null ;
183198 var writingSupported = supportsWriting && innerInfo . SupportsWriting ;
184199 var unboxedType = ComputeUnboxedType ( defaultType : mappingType , converter . TypeToConvert , mapping . Type ) ;
185200
186- return new PgTypeInfo ( options , converter , TypeInfoMappingHelpers . ResolveFullyQualifiedName ( options , mapping . DataTypeName ) , unboxedType )
201+ return new PgTypeInfo ( options , converter , options . GetCanonicalTypeId ( new DataTypeName ( mapping . DataTypeName ) ) , unboxedType )
187202 {
188203 PreferredFormat = preferredFormat ,
189204 SupportsWriting = writingSupported
@@ -194,15 +209,19 @@ static TypeInfoFactory CreateComposedFactory(Type mappingType, TypeInfoMapping i
194209 static TypeInfoFactory CreateComposedFactory ( Type mappingType , TypeInfoMapping innerMapping , Func < TypeInfoMapping , PgResolverTypeInfo , PgConverterResolver > mapper , bool copyPreferredFormat = false , bool supportsWriting = true )
195210 => ( options , mapping , dataTypeNameMatch ) =>
196211 {
197- var innerInfo = ( PgResolverTypeInfo ) innerMapping . Factory ( options , innerMapping , dataTypeNameMatch ) ;
212+ var resolvedInnerMapping = innerMapping ;
213+ if ( ! DataTypeName . IsFullyQualified ( innerMapping . DataTypeName . AsSpan ( ) ) )
214+ resolvedInnerMapping = innerMapping with { DataTypeName = new DataTypeName ( mapping . DataTypeName ) . Schema + "." + innerMapping . DataTypeName } ;
215+
216+ var innerInfo = ( PgResolverTypeInfo ) innerMapping . Factory ( options , resolvedInnerMapping , dataTypeNameMatch ) ;
198217 var resolver = mapper ( mapping , innerInfo ) ;
199218 var preferredFormat = copyPreferredFormat ? innerInfo . PreferredFormat : null ;
200219 var writingSupported = supportsWriting && innerInfo . SupportsWriting ;
201220 var unboxedType = ComputeUnboxedType ( defaultType : mappingType , resolver . TypeToConvert , mapping . Type ) ;
202221 // We include the data type name if the inner info did so as well.
203222 // This way we can rely on its logic around resolvedDataTypeName, including when it ignores that flag.
204223 PgTypeId ? pgTypeId = innerInfo . PgTypeId is not null
205- ? TypeInfoMappingHelpers . ResolveFullyQualifiedName ( options , mapping . DataTypeName )
224+ ? options . GetCanonicalTypeId ( new DataTypeName ( mapping . DataTypeName ) )
206225 : null ;
207226 return new PgResolverTypeInfo ( options , resolver , pgTypeId , unboxedType )
208227 {
@@ -689,30 +708,38 @@ static void ThrowBoxingNotSupported(bool resolver)
689708
690709public static class TypeInfoMappingHelpers
691710{
692- internal static PgTypeId ResolveFullyQualifiedName ( PgSerializerOptions options , string dataTypeName )
693- => ! DataTypeName . IsFullyQualified ( dataTypeName . AsSpan ( ) )
694- ? options . ToCanonicalTypeId ( options . DatabaseInfo . GetPostgresType ( dataTypeName ) )
695- : new ( new DataTypeName ( dataTypeName ) ) ;
711+ internal static bool TryResolveFullyQualifiedName ( PgSerializerOptions options , string dataTypeName , out DataTypeName fqDataTypeName )
712+ {
713+ if ( DataTypeName . IsFullyQualified ( dataTypeName . AsSpan ( ) ) )
714+ {
715+ fqDataTypeName = new DataTypeName ( dataTypeName ) ;
716+ return true ;
717+ }
718+
719+ if ( options . DatabaseInfo . TryGetPostgresTypeByName ( dataTypeName , out var pgType ) )
720+ {
721+ fqDataTypeName = pgType . DataTypeName ;
722+ return true ;
723+ }
724+
725+ fqDataTypeName = default ;
726+ return false ;
727+ }
696728
697729 internal static PostgresType GetPgType ( this TypeInfoMapping mapping , PgSerializerOptions options )
698- => ! DataTypeName . IsFullyQualified ( mapping . DataTypeName . AsSpan ( ) )
699- ? options . DatabaseInfo . GetPostgresType ( mapping . DataTypeName )
700- : options . DatabaseInfo . GetPostgresType ( new DataTypeName ( mapping . DataTypeName ) ) ;
730+ => options . DatabaseInfo . GetPostgresType ( new DataTypeName ( mapping . DataTypeName ) ) ;
701731
702732 public static PgTypeInfo CreateInfo ( this TypeInfoMapping mapping , PgSerializerOptions options , PgConverter converter , DataFormat ? preferredFormat = null , bool supportsWriting = true )
703- => new ( options , converter , ResolveFullyQualifiedName ( options , mapping . DataTypeName ) )
733+ => new ( options , converter , new DataTypeName ( mapping . DataTypeName ) )
704734 {
705735 PreferredFormat = preferredFormat ,
706736 SupportsWriting = supportsWriting
707737 } ;
708738
709739 public static PgResolverTypeInfo CreateInfo ( this TypeInfoMapping mapping , PgSerializerOptions options , PgConverterResolver resolver , bool includeDataTypeName = true , DataFormat ? preferredFormat = null , bool supportsWriting = true )
710- {
711- PgTypeId ? pgTypeId = includeDataTypeName ? ResolveFullyQualifiedName ( options , mapping . DataTypeName ) : null ;
712- return new ( options , resolver , pgTypeId )
740+ => new ( options , resolver , includeDataTypeName ? new DataTypeName ( mapping . DataTypeName ) : null )
713741 {
714742 PreferredFormat = preferredFormat ,
715743 SupportsWriting = supportsWriting
716744 } ;
717- }
718745}
0 commit comments