-
Notifications
You must be signed in to change notification settings - Fork 874
Expand file tree
/
Copy pathPgComposingConverterResolver.cs
More file actions
68 lines (56 loc) · 3.13 KB
/
PgComposingConverterResolver.cs
File metadata and controls
68 lines (56 loc) · 3.13 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
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Npgsql.Internal.Postgres;
namespace Npgsql.Internal;
abstract class PgComposingConverterResolver<T> : PgConverterResolver<T>
{
readonly PgTypeId? _pgTypeId;
public PgResolverTypeInfo EffectiveTypeInfo { get; }
readonly ConcurrentDictionary<PgConverter, PgConverter> _converters = new(ReferenceEqualityComparer.Instance);
protected PgComposingConverterResolver(PgTypeId? pgTypeId, PgResolverTypeInfo effectiveTypeInfo)
{
if (pgTypeId is null && effectiveTypeInfo.PgTypeId is not null)
throw new ArgumentNullException(nameof(pgTypeId), $"Cannot be null if {nameof(effectiveTypeInfo)}.{nameof(PgTypeInfo.PgTypeId)} is not null.");
_pgTypeId = pgTypeId;
EffectiveTypeInfo = effectiveTypeInfo;
}
protected abstract PgTypeId GetEffectivePgTypeId(PgTypeId pgTypeId);
protected abstract PgTypeId GetPgTypeId(PgTypeId effectivePgTypeId);
protected abstract PgConverter<T> CreateConverter(PgConverterResolution effectiveResolution);
protected abstract PgConverterResolution? GetEffectiveResolution(T? value, PgTypeId? expectedEffectivePgTypeId);
public override PgConverterResolution GetDefault(PgTypeId? pgTypeId)
{
PgTypeId? effectivePgTypeId = pgTypeId is not null ? GetEffectiveTypeId(pgTypeId.GetValueOrDefault()) : null;
var effectiveResolution = EffectiveTypeInfo.GetDefaultResolution(effectivePgTypeId);
return new(GetOrAdd(effectiveResolution), pgTypeId ?? _pgTypeId ?? GetPgTypeId(effectiveResolution.PgTypeId));
}
public override PgConverterResolution? Get(T? value, PgTypeId? expectedPgTypeId)
{
PgTypeId? expectedEffectiveId = expectedPgTypeId is not null ? GetEffectiveTypeId(expectedPgTypeId.GetValueOrDefault()) : null;
if (GetEffectiveResolution(value, expectedEffectiveId) is { } resolution)
return new PgConverterResolution(GetOrAdd(resolution), expectedPgTypeId ?? _pgTypeId ?? GetPgTypeId(resolution.PgTypeId));
return null;
}
public override PgConverterResolution Get(Field field)
{
var effectiveResolution = EffectiveTypeInfo.GetResolution(field with { PgTypeId = GetEffectiveTypeId(field.PgTypeId) });
return new PgConverterResolution(GetOrAdd(effectiveResolution), field.PgTypeId);
}
PgTypeId GetEffectiveTypeId(PgTypeId pgTypeId)
{
if (_pgTypeId == pgTypeId)
return EffectiveTypeInfo.PgTypeId.GetValueOrDefault();
// We have an undecided type info which is asked to resolve for a specific type id
// we'll unfortunately have to look up the effective id, this is rare though.
return GetEffectivePgTypeId(pgTypeId);
}
PgConverter<T> GetOrAdd(PgConverterResolution effectiveResolution)
{
(PgComposingConverterResolver<T> Instance, PgConverterResolution EffectiveResolution) state = (this, effectiveResolution);
return (PgConverter<T>)_converters.GetOrAdd(
effectiveResolution.Converter,
static (_, state) => state.Instance.CreateConverter(state.EffectiveResolution),
state);
}
}