Skip to content

Commit 7fa00ee

Browse files
[release] [minor]
1. support more data types across all databases 2. refactor column mapping logic to support column length as part of the deciding factor of a csharp data type (applies only to mysql and boolean for now) 3. add DB specific docs on data types and specific query annotations' implementations
1 parent 2a719b0 commit 7fa00ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1354
-667
lines changed

CodeGenerator/Generators/CsprojGen.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace SqlcGenCsharp.Generators;
77

88
internal class CsprojGen(string outputDirectory, string projectName, string namespaceName, Options options)
99
{
10-
private const string DefaultDapperVersion = "2.1.35";
10+
private const string DefaultDapperVersion = "2.1.66";
1111
private const string DefaultNpgsqlVersion = "8.0.6";
1212
private const string DefaultMysqlConnectorVersion = "2.4.0";
1313
private const string DefaultSqliteVersion = "9.0.0";

CodeGenerator/Generators/UtilsGen.cs

+19-2
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,31 @@ public static string TransformQueryForSqliteBatch(string originalSql, int cntRec
7878

7979
var optionalNullToNStringConverter = dbDriver.Options.DriverName is DriverName.MySqlConnector
8080
? $$"""
81-
public class NullToNStringConverter : DefaultTypeConverter
81+
public class NullToStringConverter : DefaultTypeConverter
8282
{
8383
public override {{dbDriver.AddNullableSuffixIfNeeded("string", true)}} ConvertToString(
84-
{{dbDriver.AddNullableSuffixIfNeeded("object", true)}} value, IWriterRow row, MemberMapData memberMapData)
84+
{{dbDriver.AddNullableSuffixIfNeeded("object", false)}} value, IWriterRow row, MemberMapData memberMapData)
8585
{
8686
return value == null ? @"\N" : base.ConvertToString(value, row, memberMapData);
8787
}
8888
}
89+
90+
public class BoolToBitConverter : DefaultTypeConverter
91+
{
92+
public override {{dbDriver.AddNullableSuffixIfNeeded("string", true)}} ConvertToString(
93+
{{dbDriver.AddNullableSuffixIfNeeded("object", false)}} value, IWriterRow row, MemberMapData memberMapData)
94+
{
95+
switch (value)
96+
{
97+
case null:
98+
return @"\N";
99+
case bool b:
100+
return b ? "1" : "0";
101+
default:
102+
return base.ConvertToString(value, row, memberMapData);
103+
}
104+
}
105+
}
89106
"""
90107
: string.Empty;
91108

Drivers/ColumnMapping.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33

44
namespace SqlcGenCsharp.Drivers;
55

6-
public class ColumnMapping(string csharpType, Dictionary<string, string?> dbTypes, Func<int, string> readerFn, Func<int, string>? readerArrayFn = null)
6+
public record DbTypeInfo(int? Length = null, string? NpgsqlTypeOverride = null);
7+
8+
public class ColumnMapping(
9+
string csharpType,
10+
Dictionary<string, DbTypeInfo> dbTypes, Func<int, string> readerFn, Func<int, string>? readerArrayFn = null)
711
{
812
public string CsharpType { get; } = csharpType;
913
public Func<int, string> ReaderFn { get; } = readerFn;
1014
public Func<int, string>? ReaderArrayFn { get; } = readerArrayFn;
11-
public Dictionary<string, string?> DbTypes { get; } = dbTypes;
15+
public Dictionary<string, DbTypeInfo> DbTypes { get; } = dbTypes;
1216
}

Drivers/DbDriver.cs

+14-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public abstract class DbDriver
1717

1818
private HashSet<string> NullableTypesInDotnetCore { get; } = ["string", "object"];
1919

20-
private HashSet<string> NullableTypes { get; } = ["bool", "short", "int", "long", "float", "double", "decimal", "DateTime"];
20+
private HashSet<string> NullableTypes { get; } = ["bool", "byte", "short", "int", "long", "float", "double", "decimal", "DateTime"];
2121

2222
protected abstract List<ColumnMapping> ColumnMappings { get; }
2323

@@ -64,9 +64,8 @@ public string GetCsharpType(Column column)
6464

6565
string GetTypeWithoutNullableSuffix()
6666
{
67-
var columnType = column.Type.Name.ToLower();
6867
foreach (var columnMapping in ColumnMappings
69-
.Where(columnMapping => columnMapping.DbTypes.ContainsKey(columnType)))
68+
.Where(columnMapping => DoesColumnMappingApply(columnMapping, column)))
7069
{
7170
if (column.IsArray || column.IsSqlcSlice) return $"{columnMapping.CsharpType}[]";
7271
return columnMapping.CsharpType;
@@ -75,11 +74,20 @@ string GetTypeWithoutNullableSuffix()
7574
}
7675
}
7776

78-
public string GetColumnReader(Column column, int ordinal)
77+
private static bool DoesColumnMappingApply(ColumnMapping columnMapping, Column column)
7978
{
8079
var columnType = column.Type.Name.ToLower();
80+
if (!columnMapping.DbTypes.TryGetValue(columnType, out var typeInfo))
81+
return false;
82+
if (typeInfo.Length is null)
83+
return true;
84+
return typeInfo.Length.Value == column.Length;
85+
}
86+
87+
public string GetColumnReader(Column column, int ordinal)
88+
{
8189
foreach (var columnMapping in ColumnMappings
82-
.Where(columnMapping => columnMapping.DbTypes.ContainsKey(columnType)))
90+
.Where(columnMapping => DoesColumnMappingApply(columnMapping, column)))
8391
{
8492
if (column.IsArray)
8593
return columnMapping.ReaderArrayFn?.Invoke(ordinal) ?? throw new InvalidOperationException("ReaderArrayFn is null");
@@ -94,7 +102,7 @@ public string GetColumnReader(Column column, int ordinal)
94102
foreach (var columnMapping in ColumnMappings)
95103
{
96104
if (columnMapping.DbTypes.TryGetValue(columnType, out var dbTypeOverride))
97-
return dbTypeOverride;
105+
return dbTypeOverride.NpgsqlTypeOverride;
98106
}
99107
throw new NotSupportedException($"Column {column.Name} has unsupported column type: {column.Type.Name}");
100108
}

Drivers/MySqlConnectorDriver.cs

+64-54
Original file line numberDiff line numberDiff line change
@@ -14,70 +14,73 @@ public partial class MySqlConnectorDriver(Options options, Dictionary<string, Ta
1414
{
1515
protected override List<ColumnMapping> ColumnMappings { get; } =
1616
[
17+
new("bool",
18+
new Dictionary<string, DbTypeInfo>
19+
{
20+
{ "tinyint", new DbTypeInfo(Length: 1) }
21+
}, ordinal => $"reader.GetBoolean({ordinal})"),
22+
new("short",
23+
new Dictionary<string, DbTypeInfo>
24+
{
25+
{ "tinyint", new DbTypeInfo() },
26+
{ "smallint", new DbTypeInfo() },
27+
{ "year", new DbTypeInfo() }
28+
}, ordinal => $"reader.GetInt16({ordinal})"),
1729
new("long",
18-
new Dictionary<string, string?>
30+
new Dictionary<string, DbTypeInfo>
1931
{
20-
{ "bigint", null }
32+
{ "bigint", new DbTypeInfo() }
2133
}, ordinal => $"reader.GetInt64({ordinal})"),
34+
new("byte",
35+
new Dictionary<string, DbTypeInfo>
36+
{
37+
{ "bit", new DbTypeInfo() }
38+
}, ordinal => $"reader.GetFieldValue<byte>({ordinal})"),
2239
new("byte[]",
23-
new Dictionary<string, string?>
40+
new Dictionary<string, DbTypeInfo>
2441
{
25-
{ "binary", null },
26-
{ "blob", null },
27-
{ "longblob", null },
28-
{ "mediumblob", null },
29-
{ "tinyblob", null },
30-
{ "varbinary", null }
42+
{ "binary", new DbTypeInfo() },
43+
{ "blob", new DbTypeInfo() },
44+
{ "longblob", new DbTypeInfo() },
45+
{ "mediumblob", new DbTypeInfo() },
46+
{ "tinyblob", new DbTypeInfo() },
47+
{ "varbinary", new DbTypeInfo() }
3148
}, ordinal => $"reader.GetFieldValue<byte[]>({ordinal})"),
3249
new("string",
33-
new Dictionary<string, string?>
50+
new Dictionary<string, DbTypeInfo>
3451
{
35-
{ "char", null },
36-
{ "decimal", null },
37-
{ "longtext", null },
38-
{ "mediumtext", null },
39-
{ "text", null },
40-
{ "time", null },
41-
{ "tinytext", null },
42-
{ "varchar", null },
43-
{ "var_string", null },
44-
{ "json", null }
52+
{ "char", new DbTypeInfo() },
53+
{ "decimal", new DbTypeInfo() },
54+
{ "longtext", new DbTypeInfo() },
55+
{ "mediumtext", new DbTypeInfo() },
56+
{ "text", new DbTypeInfo() },
57+
{ "time", new DbTypeInfo() },
58+
{ "tinytext", new DbTypeInfo() },
59+
{ "varchar", new DbTypeInfo() },
60+
{ "var_string", new DbTypeInfo() },
61+
{ "json", new DbTypeInfo() }
4562
}, ordinal => $"reader.GetString({ordinal})"),
4663
new("DateTime",
47-
new Dictionary<string, string?>
64+
new Dictionary<string, DbTypeInfo>
4865
{
49-
{ "date", null },
50-
{ "datetime", null },
51-
{ "timestamp", null }
66+
{ "date", new DbTypeInfo() },
67+
{ "datetime", new DbTypeInfo() },
68+
{ "timestamp", new DbTypeInfo() }
5269
}, ordinal => $"reader.GetDateTime({ordinal})"),
53-
new("short",
54-
new Dictionary<string, string?>
55-
{
56-
{ "smallint", null },
57-
{ "year", null }
58-
}, ordinal => $"reader.GetInt16({ordinal})"),
5970
new("int",
60-
new Dictionary<string, string?>
71+
new Dictionary<string, DbTypeInfo>
6172
{
62-
{ "int", null },
63-
{ "mediumint", null },
73+
{ "int", new DbTypeInfo() },
74+
{ "mediumint", new DbTypeInfo() },
6475
}, ordinal => $"reader.GetInt32({ordinal})"),
65-
new("bool",
66-
new Dictionary<string, string?>
67-
{
68-
{ "bit", null },
69-
{ "tinyint", null },
70-
{ "bool", null },
71-
{ "boolean", null }
72-
}, ordinal => $"reader.GetBoolean({ordinal})"),
7376
new("double",
74-
new Dictionary<string, string?>
77+
new Dictionary<string, DbTypeInfo>
7578
{
76-
{ "double", null },
77-
{ "float", null }
79+
{ "double", new DbTypeInfo() },
80+
{ "float", new DbTypeInfo() }
7881
}, ordinal => $"reader.GetDouble({ordinal})"),
7982
new("object",
80-
new Dictionary<string, string?>(), ordinal => $"reader.GetValue({ordinal})")
83+
new Dictionary<string, DbTypeInfo>(), ordinal => $"reader.GetValue({ordinal})")
8184
];
8285

8386
public override UsingDirectiveSyntax[] GetUsingDirectives()
@@ -170,24 +173,31 @@ public string GetCopyFromImpl(Query query, string queryTextConstant)
170173
var csvWriterVar = Variable.CsvWriter.AsVarName();
171174
var loaderVar = Variable.Loader.AsVarName();
172175
var connectionVar = Variable.Connection.AsVarName();
176+
var nullConverterFn = Variable.NullConverterFn.AsVarName();
173177

174178
var loaderColumns = query.Params.Select(p => $"\"{p.Column.Name}\"").JoinByComma();
175179
var (establishConnection, connectionOpen) = EstablishConnection(query);
176180
return $$"""
177181
const string supportedDateTimeFormat = "yyyy-MM-dd H:mm:ss";
178182
var {{Variable.Config.AsVarName()}} = new CsvConfiguration(CultureInfo.CurrentCulture) { Delimiter = "{{csvDelimiter}}" };
183+
var {{nullConverterFn}} = new Utils.NullToStringConverter();
179184
using (var {{Variable.Writer.AsVarName()}} = new StreamWriter("{{tempCsvFilename}}", false, new UTF8Encoding(false)))
180185
using (var {{csvWriterVar}} = new CsvWriter({{Variable.Writer.AsVarName()}}, {{Variable.Config.AsVarName()}}))
181186
{
182-
var options = new TypeConverterOptions { Formats = new[] { supportedDateTimeFormat } };
183-
{{csvWriterVar}}.Context.TypeConverterOptionsCache.AddOptions<DateTime>(options);
184-
{{csvWriterVar}}.Context.TypeConverterOptionsCache.AddOptions<DateTime?>(options);
185-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<bool?>(new Utils.NullToNStringConverter());
186-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<short?>(new Utils.NullToNStringConverter());
187-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<int?>(new Utils.NullToNStringConverter());
188-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<long?>(new Utils.NullToNStringConverter());
189-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<DateTime?>(new Utils.NullToNStringConverter());
190-
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<string>(new Utils.NullToNStringConverter());
187+
var {{Variable.Options}} = new TypeConverterOptions { Formats = new[] { supportedDateTimeFormat } };
188+
{{csvWriterVar}}.Context.TypeConverterOptionsCache.AddOptions<DateTime>({{Variable.Options}});
189+
{{csvWriterVar}}.Context.TypeConverterOptionsCache.AddOptions<DateTime?>({{Variable.Options}});
190+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<bool?>(new Utils.BoolToBitConverter());
191+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<byte?>({{nullConverterFn}});
192+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<short?>({{nullConverterFn}});
193+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<int?>({{nullConverterFn}});
194+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<long?>({{nullConverterFn}});
195+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<float?>({{nullConverterFn}});
196+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<decimal?>({{nullConverterFn}});
197+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<double?>({{nullConverterFn}});
198+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<DateTime?>({{nullConverterFn}});
199+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<{{AddNullableSuffixIfNeeded("string", false)}}>({{nullConverterFn}});
200+
{{csvWriterVar}}.Context.TypeConverterCache.AddConverter<{{AddNullableSuffixIfNeeded("object", false)}}>({{nullConverterFn}});
191201
await {{csvWriterVar}}.WriteRecordsAsync({{Variable.Args.AsVarName()}});
192202
}
193203

0 commit comments

Comments
 (0)