Skip to content

Commit 6f61b49

Browse files
authored
Added non-generic methods to register composites
1 parent 3a826c9 commit 6f61b49

2 files changed

Lines changed: 76 additions & 22 deletions

File tree

src/Npgsql/TypeMapping/INpgsqlTypeMapper.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public interface INpgsqlTypeMapper
5656
/// </remarks>
5757
/// <param name="pgName">
5858
/// A PostgreSQL type name for the corresponding enum type in the database.
59-
/// If null, the name translator given in <paramref name="nameTranslator"/>will be used.
59+
/// If null, the name translator given in <paramref name="nameTranslator"/> will be used.
6060
/// </param>
6161
/// <param name="nameTranslator">
6262
/// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class).
@@ -89,16 +89,16 @@ bool UnmapEnum<TEnum>(
8989
/// Maps a CLR type to a PostgreSQL composite type.
9090
/// </summary>
9191
/// <remarks>
92-
/// CLR fields and properties by string to PostgreSQL enum labels.
92+
/// CLR fields and properties by string to PostgreSQL names.
9393
/// The translation strategy can be controlled by the <paramref name="nameTranslator"/> parameter,
9494
/// which defaults to <see cref="NpgsqlSnakeCaseNameTranslator"/>.
95-
/// You can also use the <see cref="PgNameAttribute"/> on your members to manually specify a PostgreSQL enum label.
96-
/// If there is a discrepancy between the .NET and database labels while a composite is read or written,
95+
/// You can also use the <see cref="PgNameAttribute"/> on your members to manually specify a PostgreSQL name.
96+
/// If there is a discrepancy between the .NET type and database type while a composite is read or written,
9797
/// an exception will be raised.
9898
/// </remarks>
9999
/// <param name="pgName">
100-
/// A PostgreSQL type name for the corresponding enum type in the database.
101-
/// If null, the name translator given in <paramref name="nameTranslator"/>will be used.
100+
/// A PostgreSQL type name for the corresponding composite type in the database.
101+
/// If null, the name translator given in <paramref name="nameTranslator"/> will be used.
102102
/// </param>
103103
/// <param name="nameTranslator">
104104
/// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class).
@@ -111,11 +111,11 @@ INpgsqlTypeMapper MapComposite<T>(
111111
INpgsqlNameTranslator? nameTranslator = null);
112112

113113
/// <summary>
114-
/// Removes an existing enum mapping.
114+
/// Removes an existing composite mapping.
115115
/// </summary>
116116
/// <param name="pgName">
117117
/// A PostgreSQL type name for the corresponding composite type in the database.
118-
/// If null, the name translator given in <paramref name="nameTranslator"/>will be used.
118+
/// If null, the name translator given in <paramref name="nameTranslator"/> will be used.
119119
/// </param>
120120
/// <param name="nameTranslator">
121121
/// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class).
@@ -125,6 +125,48 @@ bool UnmapComposite<T>(
125125
string? pgName = null,
126126
INpgsqlNameTranslator? nameTranslator = null);
127127

128+
/// <summary>
129+
/// Maps a CLR type to a composite type.
130+
/// </summary>
131+
/// <remarks>
132+
/// Maps CLR fields and properties by string to PostgreSQL names.
133+
/// The translation strategy can be controlled by the <paramref name="nameTranslator"/> parameter,
134+
/// which defaults to <see cref="NpgsqlSnakeCaseNameTranslator"/>.
135+
/// If there is a discrepancy between the .NET type and database type while a composite is read or written,
136+
/// an exception will be raised.
137+
/// </remarks>
138+
/// <param name="compType">The .NET type to be mapped.</param>
139+
/// <param name="pgName">
140+
/// A PostgreSQL type name for the corresponding composite type in the database.
141+
/// If null, the name translator given in <paramref name="nameTranslator"/> will be used.
142+
/// </param>
143+
/// <param name="nameTranslator">
144+
/// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class).
145+
/// Defaults to <see cref="NpgsqlSnakeCaseNameTranslator"/>
146+
/// </param>
147+
[NotNull]
148+
INpgsqlTypeMapper MapComposite(
149+
Type compType,
150+
string? pgName = null,
151+
INpgsqlNameTranslator? nameTranslator = null);
152+
153+
/// <summary>
154+
/// Removes an existing composite mapping.
155+
/// </summary>
156+
/// <param name="compType">The .NET type to be unmapped.</param>
157+
/// <param name="pgName">
158+
/// A PostgreSQL type name for the corresponding composite type in the database.
159+
/// If null, the name translator given in <paramref name="nameTranslator"/> will be used.
160+
/// </param>
161+
/// <param name="nameTranslator">
162+
/// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class).
163+
/// Defaults to <see cref="NpgsqlSnakeCaseNameTranslator"/>
164+
/// </param>
165+
bool UnmapComposite(
166+
Type compType,
167+
string? pgName = null,
168+
INpgsqlNameTranslator? nameTranslator = null);
169+
128170
/// <summary>
129171
/// Resets all mapping changes performed on this type mapper and reverts it to its original, starting state.
130172
/// </summary>

src/Npgsql/TypeMapping/TypeMapperBase.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Reflection;
44
using Npgsql.TypeHandlers;
55
using Npgsql.TypeHandlers.CompositeHandlers;
6+
using Npgsql.TypeHandling;
67
using NpgsqlTypes;
78

89
namespace Npgsql.TypeMapping
@@ -50,7 +51,7 @@ public INpgsqlTypeMapper MapEnum<TEnum>(string? pgName = null, INpgsqlNameTransl
5051
if (nameTranslator == null)
5152
nameTranslator = DefaultNameTranslator;
5253
if (pgName == null)
53-
pgName = GetPgName<TEnum>(nameTranslator);
54+
pgName = GetPgName(typeof(TEnum), nameTranslator);
5455

5556
return AddMapping(new NpgsqlTypeMappingBuilder
5657
{
@@ -69,7 +70,7 @@ public bool UnmapEnum<TEnum>(string? pgName = null, INpgsqlNameTranslator? nameT
6970
if (nameTranslator == null)
7071
nameTranslator = DefaultNameTranslator;
7172
if (pgName == null)
72-
pgName = GetPgName<TEnum>(nameTranslator);
73+
pgName = GetPgName(typeof(TEnum), nameTranslator);
7374

7475
return RemoveMapping(pgName);
7576
}
@@ -79,32 +80,43 @@ public bool UnmapEnum<TEnum>(string? pgName = null, INpgsqlNameTranslator? nameT
7980
#region Composite mapping
8081

8182
public INpgsqlTypeMapper MapComposite<T>(string? pgName = null, INpgsqlNameTranslator? nameTranslator = null)
82-
{
83+
=> MapComposite(typeof(T), pgName, nameTranslator);
84+
85+
public bool UnmapComposite<T>(string? pgName = null, INpgsqlNameTranslator? nameTranslator = null)
86+
=> UnmapComposite(typeof(T), pgName, nameTranslator);
87+
88+
public INpgsqlTypeMapper MapComposite(Type compType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) {
8389
if (pgName != null && pgName.Trim() == "")
8490
throw new ArgumentException("pgName can't be empty", nameof(pgName));
8591

8692
if (nameTranslator == null)
8793
nameTranslator = DefaultNameTranslator;
8894
if (pgName == null)
89-
pgName = GetPgName<T>(nameTranslator);
95+
pgName = GetPgName(compType, nameTranslator);
9096

91-
return AddMapping(new NpgsqlTypeMappingBuilder
92-
{
97+
var thfType = typeof(CompositeTypeHandlerFactory<>);
98+
var thf = (NpgsqlTypeHandlerFactory)Activator.CreateInstance(
99+
thfType.MakeGenericType(compType),
100+
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
101+
binder: null,
102+
args: new object[] { nameTranslator },
103+
culture: null)!;
104+
105+
return AddMapping(new NpgsqlTypeMappingBuilder {
93106
PgTypeName = pgName,
94-
ClrTypes = new[] { typeof(T) },
95-
TypeHandlerFactory = new CompositeTypeHandlerFactory<T>(nameTranslator)
107+
ClrTypes = new[] { compType },
108+
TypeHandlerFactory = thf,
96109
}.Build());
97110
}
98111

99-
public bool UnmapComposite<T>(string? pgName = null, INpgsqlNameTranslator? nameTranslator = null)
100-
{
112+
public bool UnmapComposite(Type compType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) {
101113
if (pgName != null && pgName.Trim() == "")
102114
throw new ArgumentException("pgName can't be empty", nameof(pgName));
103115

104116
if (nameTranslator == null)
105117
nameTranslator = DefaultNameTranslator;
106118
if (pgName == null)
107-
pgName = GetPgName<T>(nameTranslator);
119+
pgName = GetPgName(compType, nameTranslator);
108120

109121
return RemoveMapping(pgName);
110122
}
@@ -115,9 +127,9 @@ public bool UnmapComposite<T>(string? pgName = null, INpgsqlNameTranslator? name
115127

116128
// TODO: why does ReSharper think `GetCustomAttribute<T>` is non-nullable?
117129
// ReSharper disable once ConstantConditionalAccessQualifier ConstantNullCoalescingCondition
118-
static string GetPgName<T>(INpgsqlNameTranslator nameTranslator)
119-
=> typeof(T).GetCustomAttribute<PgNameAttribute>()?.PgName
120-
?? nameTranslator.TranslateTypeName(typeof(T).Name);
130+
static string GetPgName(Type compType, INpgsqlNameTranslator nameTranslator)
131+
=> compType.GetCustomAttribute<PgNameAttribute>()?.PgName
132+
?? nameTranslator.TranslateTypeName(compType.Name);
121133

122134
#endregion Misc
123135
}

0 commit comments

Comments
 (0)