Resolve C# raw deletes by schema alias

This commit is contained in:
Meta Vens 2026-06-27 22:07:31 +01:00
commit 19e2b68fec
3 changed files with 87 additions and 4 deletions

View file

@ -941,9 +941,9 @@ namespace GameCult.Networking
if (message == null) throw new ArgumentNullException(nameof(message));
var key = new CultRecordKey(message.RecordKey);
var shard = ResolveShardInternal(message.SchemaId, key);
EnsurePrimary(shard, message.SchemaId, key, message.ShardEpoch);
var descriptor = _cache.Registry.GetRequiredBySchemaId(message.SchemaId);
var descriptor = _documents.ResolveDescriptorForSchemaId(message.SchemaId);
var shard = ResolveShardInternal(descriptor, key);
EnsurePrimary(shard, descriptor.SchemaId, key, message.ShardEpoch);
var previous = _cache.Get(key);
if (previous == null)
{

View file

@ -396,7 +396,7 @@ namespace GameCult.Networking
{
try
{
return _documents.GetRequiredBySchemaId(document.SchemaId);
return ResolveDescriptorForSchemaId(document.SchemaId);
}
catch (InvalidOperationException) when (TryResolveDescriptorByPayloadSchema(document.Payload) is { } descriptor)
{
@ -404,6 +404,40 @@ namespace GameCult.Networking
}
}
internal CultDocumentDescriptor ResolveDescriptorForSchemaId(string schemaId)
{
try
{
return _documents.GetRequiredBySchemaId(schemaId);
}
catch (InvalidOperationException) when (TryResolveDescriptorBySchemaAlias(schemaId) is { } descriptor)
{
return descriptor;
}
}
private CultDocumentDescriptor? TryResolveDescriptorBySchemaAlias(string schemaId)
{
if (string.IsNullOrWhiteSpace(schemaId))
return null;
var candidates = ResolvePayloadSchemaCandidates().ToArray();
var descriptor = candidates.FirstOrDefault(candidate =>
string.Equals(candidate.SchemaId, schemaId, StringComparison.Ordinal) ||
string.Equals(candidate.SchemaName, schemaId, StringComparison.Ordinal) ||
string.Equals(candidate.SchemaVersion, schemaId, StringComparison.Ordinal) ||
candidate.ToCatalogEntry().CompatibleSchemaIds.Any(compatible =>
string.Equals(compatible, schemaId, StringComparison.Ordinal)));
if (descriptor != null)
return descriptor;
var schemaName = InferSchemaName(schemaId);
return string.IsNullOrWhiteSpace(schemaName)
? null
: candidates.FirstOrDefault(candidate =>
string.Equals(candidate.SchemaName, schemaName, StringComparison.Ordinal));
}
private CultDocumentDescriptor? TryResolveDescriptorByPayloadSchema(byte[] payload)
{
var schemaVersion = TryReadSchemaVersion(payload);

View file

@ -1951,6 +1951,55 @@ namespace GameCult.Networking.Tests
Assert.That(database.GetMutationLog("wrong-network-notes"), Is.Empty);
}
[Test]
public async Task CultNetDatabase_Applies_Delete_BySchemaAlias()
{
var cache = new CultCache();
var registry = new CultNetDocumentRegistry(cache.Registry)
.Register(CultNetDocumentBinding.ForDocument<NetworkSchemaNote>(cache.Registry));
var database = new CultNetDatabase(cache, new CultNetDatabaseOptions
{
DocumentRegistry = registry,
Shards =
[
new CultNetShardDescriptor(
"wrong-network-notes",
"runtime-b",
epoch: 1,
isPrimary: false,
schemaIds: ["other.note.v1"],
keyPrefix: "network-note:"),
new CultNetShardDescriptor(
"network-notes",
"runtime-a",
epoch: 2,
isPrimary: true,
schemaIds: ["tests.networking_note.v1"],
keyPrefix: "network-note:")
]
});
var key = new CultRecordKey("network-note:alias-delete");
await database.PutAsync(key, new NetworkSchemaNote
{
Schema = "tests.networking_note.v1",
Text = "delete through alias",
Revision = 13
});
await database.ApplyDeleteAsync(new CultNetDocumentDeleteMessage
{
MessageId = "delete-alias",
SchemaId = "tests.networking_note.v1",
RecordKey = key.Value,
ShardId = "network-notes",
ShardEpoch = 2
});
Assert.That(cache.Get<NetworkSchemaNote>(key), Is.Null);
Assert.That(database.GetMutationLog("network-notes").Last().Kind, Is.EqualTo(CultNetDatabaseChangeKind.Removed));
Assert.That(database.GetMutationLog("wrong-network-notes"), Is.Empty);
}
[Test]
public async Task CultNetDatabase_Predicts_ClientOwnedInput_ThroughSchemaAliasScope()
{