-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathTypeCategory.cs
More file actions
158 lines (139 loc) · 7.44 KB
/
Copy pathTypeCategory.cs
File metadata and controls
158 lines (139 loc) · 7.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using System.Runtime.CompilerServices;
using NpgsqlTypes;
namespace NpgsqlRest;
/// <summary>
/// Flags enum representing PostgreSQL type categories for optimized type dispatch.
/// Used for fast bitwise checks instead of multiple boolean property accesses.
/// </summary>
[Flags]
public enum TypeCategory : ushort
{
None = 0,
/// <summary>Smallint, Integer, Bigint, Numeric, Real, Double, Money</summary>
Numeric = 1 << 0,
/// <summary>Boolean</summary>
Boolean = 1 << 1,
/// <summary>Json, Jsonb</summary>
Json = 1 << 2,
/// <summary>Text, Varchar, Char, Name, Xml, JsonPath</summary>
Text = 1 << 3,
/// <summary>Timestamp, TimestampTz</summary>
DateTime = 1 << 4,
/// <summary>Date</summary>
Date = 1 << 5,
/// <summary>Types requiring JSON string escaping</summary>
NeedsEscape = 1 << 6,
/// <summary>Types requiring ::text cast</summary>
CastToText = 1 << 7,
/// <summary>Bytea</summary>
Binary = 1 << 8,
/// <summary>Time, TimeTz</summary>
Time = 1 << 9,
}
/// <summary>
/// Pre-computed lookup table for NpgsqlDbType to TypeCategory mapping.
/// Enables O(1) type category lookup instead of multiple switch expressions.
/// </summary>
public static class TypeCategoryLookup
{
private static readonly TypeCategory[] _lookup;
static TypeCategoryLookup()
{
// NpgsqlDbType values range from 0 to approximately 70+
// Use 128 as safe upper bound
_lookup = new TypeCategory[128];
// Numeric types
_lookup[(int)NpgsqlDbType.Smallint] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Integer] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Bigint] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Numeric] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Real] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Double] = TypeCategory.Numeric;
_lookup[(int)NpgsqlDbType.Money] = TypeCategory.Numeric;
// Boolean
_lookup[(int)NpgsqlDbType.Boolean] = TypeCategory.Boolean;
// JSON types
_lookup[(int)NpgsqlDbType.Json] = TypeCategory.Json | TypeCategory.Text;
_lookup[(int)NpgsqlDbType.Jsonb] = TypeCategory.Json | TypeCategory.Text;
// Text types (also set NeedsEscape for those requiring JSON escaping)
_lookup[(int)NpgsqlDbType.Text] = TypeCategory.Text | TypeCategory.NeedsEscape;
_lookup[(int)NpgsqlDbType.Varchar] = TypeCategory.Text | TypeCategory.NeedsEscape;
_lookup[(int)NpgsqlDbType.Char] = TypeCategory.Text | TypeCategory.NeedsEscape;
_lookup[(int)NpgsqlDbType.Name] = TypeCategory.Text | TypeCategory.NeedsEscape;
_lookup[(int)NpgsqlDbType.Xml] = TypeCategory.Text | TypeCategory.NeedsEscape;
_lookup[(int)NpgsqlDbType.JsonPath] = TypeCategory.Text | TypeCategory.NeedsEscape;
// DateTime types
_lookup[(int)NpgsqlDbType.Timestamp] = TypeCategory.DateTime;
_lookup[(int)NpgsqlDbType.TimestampTz] = TypeCategory.DateTime;
// Date
_lookup[(int)NpgsqlDbType.Date] = TypeCategory.Date;
// Time types
_lookup[(int)NpgsqlDbType.Time] = TypeCategory.Time;
_lookup[(int)NpgsqlDbType.TimeTz] = TypeCategory.Time;
// Binary
_lookup[(int)NpgsqlDbType.Bytea] = TypeCategory.Binary | TypeCategory.NeedsEscape | TypeCategory.CastToText;
// Types that need escape (non-text types that still need JSON escaping)
_lookup[(int)NpgsqlDbType.TsQuery] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.TsVector] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Citext] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.LQuery] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.LTree] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.LTxtQuery] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Hstore] = TypeCategory.NeedsEscape | TypeCategory.CastToText;
// Types that need cast to text (but don't necessarily need escape)
_lookup[(int)NpgsqlDbType.Interval] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Bit] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Varbit] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Inet] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.MacAddr] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Cidr] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.MacAddr8] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Box] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Circle] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Line] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.LSeg] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Path] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Point] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Polygon] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Oid] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Xid] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Xid8] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Cid] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Regtype] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Regconfig] = TypeCategory.CastToText;
// Note: Range and Multirange types (IntegerRange, BigIntRange, etc.) are composed values
// (e.g., Range | Integer = 0x40000000 | 9) and cannot be stored in a simple lookup.
// They are handled separately - the GetCategory method returns CastToText for them
// via the IsRangeOrMultirange check.
_lookup[(int)NpgsqlDbType.Int2Vector] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Oidvector] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.PgLsn] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Tid] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Geometry] = TypeCategory.CastToText;
_lookup[(int)NpgsqlDbType.Geography] = TypeCategory.CastToText;
// UUID and Refcursor don't have specific categories - they're handled as-is
_lookup[(int)NpgsqlDbType.Uuid] = TypeCategory.None;
_lookup[(int)NpgsqlDbType.Refcursor] = TypeCategory.Text;
}
// NpgsqlDbType flags for Range and Multirange
private const int RangeFlag = 0x40000000; // NpgsqlDbType.Range
private const int MultirangeFlag = 0x20000000; // NpgsqlDbType.Multirange
/// <summary>
/// Gets the type category for the specified NpgsqlDbType.
/// Array, Range, and Multirange modifiers are automatically stripped before lookup.
/// Range and Multirange types are automatically classified as CastToText.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TypeCategory GetCategory(NpgsqlDbType dbType)
{
int rawValue = (int)dbType;
// Check for Range or Multirange types - these always need CastToText
if ((rawValue & (RangeFlag | MultirangeFlag)) != 0)
{
return TypeCategory.CastToText;
}
// Strip Array flag and look up in table
int index = rawValue & ~(int)NpgsqlDbType.Array;
return (uint)index < (uint)_lookup.Length ? _lookup[index] : TypeCategory.None;
}
}