Skip to content

Commit 4ea9e4a

Browse files
committed
First Relation Compile time Error checking.
1 parent 227bc2f commit 4ea9e4a

5 files changed

+90
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
Diagnostics: [
3+
{
4+
Location: /*
5+
6+
public interface IPersonTable : IRelation<Person>
7+
^^^^^^^^^^^^
8+
{
9+
*/
10+
: (11,29)-(11,41),
11+
Message: Cannot use PrimaryKey together with InKeyValue in Id,
12+
Severity: Error,
13+
Descriptor: {
14+
Id: BTDB0002,
15+
Title: Cannot use PrimaryKey together with InKeyValue in Id,
16+
MessageFormat: Cannot use PrimaryKey together with InKeyValue in Id,
17+
Category: BTDB,
18+
DefaultSeverity: Error,
19+
IsEnabledByDefault: true
20+
}
21+
}
22+
]
23+
}

BTDB.SourceGenerator.Test/RelationTests.VerifyRelationWithSecondaryKey#TestNamespace.IPersonTable.g.verified.cs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
// PrimaryIndex: 3 InKeyValue
1515
// Field: LowerCaseName string reference computed
1616
// SecondaryIndex LowerCaseName: 2 IncludePrimaryKeyOrder 1
17+
// Field: Description string reference
18+
// PrimaryIndex: 4 InKeyValue
1719

1820
namespace TestNamespace;
1921
[CompilerGenerated]

BTDB.SourceGenerator.Test/RelationTests.VerifyRelationWithSecondaryKey#TestNamespace.Person.g.verified.cs

+8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ static void GenGetter4(object @this, ref byte value)
2323
{
2424
Unsafe.As<byte, string>(ref value) = Getter4(Unsafe.As<global::TestNamespace.Person>(@this));
2525
}
26+
[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "<Description>k__BackingField")]
27+
extern static ref string Field5(global::TestNamespace.Person @this);
2628
[ModuleInitializer]
2729
internal static unsafe void Register4BTDB()
2830
{
@@ -67,6 +69,12 @@ internal static unsafe void Register4BTDB()
6769
Type = typeof(string),
6870
PropRefGetter = &GenGetter4,
6971
},
72+
new global::BTDB.Serialization.FieldMetadata
73+
{
74+
Name = "Description",
75+
Type = typeof(string),
76+
ByteOffset = global::BTDB.Serialization.RawData.CalcOffset(dummy, ref Field5(dummy)),
77+
},
7078
};
7179
global::BTDB.Serialization.ReflectionMetadata.Register(metadata);
7280
}

BTDB.SourceGenerator.Test/RelationTests.cs

+22
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,33 @@ public class Person
4242
[PrimaryKey(2)] [SecondaryKey("PersonId", Order = 1) public int PersonId { get; set; }
4343
[PrimaryKey(3, true)] public string Name { get; set; } = null!;
4444
[SecondaryKey("LowerCaseName", IncludePrimaryKeyOrder = 1, Order = 2)] public string LowerCaseName => Name.ToLower();
45+
[InKeyValue(4)] public string Description { get; set; } = null!;
4546
}
4647
4748
public interface IPersonTable : IRelation<Person>
4849
{
4950
}
5051
""");
5152
}
53+
54+
[Fact]
55+
public Task VerifyCannotUsePrimaryKeyTogetherWithInKeyValue()
56+
{
57+
// language=cs
58+
return VerifySourceGenerator(@"
59+
using BTDB.ODBLayer;
60+
61+
namespace TestNamespace;
62+
63+
public class Person
64+
{
65+
[PrimaryKey(1)]
66+
[InKeyValue(2)] public int Id { get; set; }
67+
}
68+
69+
public interface IPersonTable : IRelation<Person>
70+
{
71+
}
72+
");
73+
}
5274
}

BTDB.SourceGenerator/Main.cs

+35
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
146146
semanticModel,
147147
[], []);
148148
if (generationInfo is not { GenType: GenerationType.Class }) return null;
149+
var detectedError = DetectErrors(generationInfo.Fields.AsSpan(),
150+
((InterfaceDeclarationSyntax)syntaxContext.Node).Identifier.GetLocation());
151+
if (detectedError != null)
152+
return detectedError;
149153
return new(GenerationType.RelationIface, namespaceName, interfaceName,
150154
symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), persistedName, false,
151155
false, false,
@@ -258,6 +262,22 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
258262
context.RegisterSourceOutput(gen.Collect(), GenerateCode!);
259263
}
260264

265+
GenerationInfo? DetectErrors(ReadOnlySpan<FieldsInfo> fields, Location location)
266+
{
267+
for (var i = 0; i < fields.Length; i++)
268+
{
269+
if (fields[i].Indexes.ToArray().Any(ii => ii.Name == null && ii.IncludePrimaryKeyOrder == 1))
270+
{
271+
return new(GenerationType.Error, null, "BTDB0002",
272+
"Cannot use PrimaryKey together with InKeyValue in " + fields[i].Name, null, false, false, false,
273+
[],
274+
[], [], [], [], [], [], [], location);
275+
}
276+
}
277+
278+
return null;
279+
}
280+
261281
static bool IsICovariantRelation(INamedTypeSymbol typeSymbol)
262282
{
263283
// Check if the type is BTDB.ODBLayer.ICovariantRelation<?>
@@ -511,6 +531,7 @@ static bool IsICovariantRelation(INamedTypeSymbol typeSymbol)
511531
static EquatableArray<IndexInfo> ExtractIndexInfo(ImmutableArray<AttributeData> attributeDatas)
512532
{
513533
var indexInfos = new List<IndexInfo>();
534+
var hasBothPrimaryAndInKeyValue = 0;
514535
foreach (var attributeData in attributeDatas)
515536
{
516537
if (attributeData.AttributeClass?.Name == "PrimaryKeyAttribute")
@@ -519,6 +540,15 @@ static EquatableArray<IndexInfo> ExtractIndexInfo(ImmutableArray<AttributeData>
519540
var inKeyValue = GetBoolArgForAttributeData(attributeData, 1) ?? false;
520541
var primaryKeyAttribute = new IndexInfo(null, order, inKeyValue, 0);
521542
indexInfos.Add(primaryKeyAttribute);
543+
hasBothPrimaryAndInKeyValue |= 1;
544+
}
545+
546+
if (attributeData.AttributeClass?.Name == "InKeyValueAttribute")
547+
{
548+
var order = GetUintArgForAttributeData(attributeData, 0) ?? 0;
549+
var primaryKeyAttribute = new IndexInfo(null, order, true, 0);
550+
indexInfos.Add(primaryKeyAttribute);
551+
hasBothPrimaryAndInKeyValue |= 2;
522552
}
523553

524554
if (attributeData.AttributeClass?.Name == "SecondaryKeyAttribute")
@@ -531,6 +561,11 @@ static EquatableArray<IndexInfo> ExtractIndexInfo(ImmutableArray<AttributeData>
531561
}
532562
}
533563

564+
if (hasBothPrimaryAndInKeyValue == 3)
565+
{
566+
indexInfos.Add(new(null, 0, false, 1));
567+
}
568+
534569
return new(indexInfos.ToArray());
535570
}
536571

0 commit comments

Comments
 (0)