Skip to content

Commit 6536219

Browse files
ISBronnyanchitj
andauthored
Methods for working with compatibility (#2097)
* Methods for working with compatibility * Review fix: Remove GetGlobalCompatibilityAsync * Update CHANGELOG and test --------- Co-authored-by: Anchit Jain <[email protected]>
1 parent 5d38703 commit 6536219

File tree

7 files changed

+114
-19
lines changed

7 files changed

+114
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Enhancements
44

55
- Added support for external JSON schemas in `JsonSerializer` and `JsonDeserializer` (#2042).
6+
- Added compatibility methods to CachedSchemaRegistryClient ([ISBronny](https://github.com/ISBronny), #2097).
67

78

89
# 2.2.0

src/Confluent.SchemaRegistry/CachedSchemaRegistryClient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ namespace Confluent.SchemaRegistry
4747
/// - <see cref="CachedSchemaRegistryClient.GetSubjectVersionsAsync(string)" />
4848
/// - <see cref="CachedSchemaRegistryClient.IsCompatibleAsync(string, Schema)" />
4949
/// - <see cref="CachedSchemaRegistryClient.IsCompatibleAsync(string, string)" />
50+
/// - <see cref="CachedSchemaRegistryClient.GetCompatibilityAsync(string)" />
51+
/// - <see cref="CachedSchemaRegistryClient.UpdateCompatibilityAsync(Compatibility, string)" />
5052
/// </summary>
5153
public class CachedSchemaRegistryClient : ISchemaRegistryClient, IDisposable
5254
{
@@ -524,6 +526,16 @@ public string ConstructKeySubjectName(string topic, string recordType = null)
524526
public string ConstructValueSubjectName(string topic, string recordType = null)
525527
=> valueSubjectNameStrategy(new SerializationContext(MessageComponentType.Value, topic), recordType);
526528

529+
/// <inheritdoc />
530+
public async Task<Compatibility> GetCompatibilityAsync(string subject = null)
531+
=> await restService.GetCompatibilityAsync(subject)
532+
.ConfigureAwait(continueOnCapturedContext: false);
533+
534+
/// <inheritdoc />
535+
public async Task<Compatibility> UpdateCompatibilityAsync(Compatibility compatibility, string subject = null)
536+
=> await restService.UpdateCompatibilityAsync(subject, compatibility)
537+
.ConfigureAwait(continueOnCapturedContext: false);
538+
527539

528540
/// <summary>
529541
/// Releases unmanaged resources owned by this CachedSchemaRegistryClient instance.

src/Confluent.SchemaRegistry/ISchemaRegistryClient.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,5 +291,34 @@ public interface ISchemaRegistryClient : IDisposable
291291
/// </returns>
292292
[Obsolete("SubjectNameStrategy should now be specified via serializer configuration. This method will be removed in a future release.")]
293293
string ConstructValueSubjectName(string topic, string recordType = null);
294+
295+
296+
/// <summary>
297+
/// If the subject is specified returns compatibility type for the specified subject.
298+
/// Otherwise returns global compatibility type.
299+
/// </summary>
300+
/// <param name="subject">
301+
/// The subject to get the compatibility for.
302+
/// </param>
303+
/// <returns>
304+
/// Compatibility type.
305+
/// </returns>
306+
Task<Compatibility> GetCompatibilityAsync(string subject = null);
307+
308+
309+
/// <summary>
310+
/// If the subject is specified sets compatibility type for the specified subject.
311+
/// Otherwise sets global compatibility type.
312+
/// </summary>
313+
/// <param name="subject">
314+
/// The subject to set the compatibility for.
315+
/// </param>
316+
/// <param name="compatibility">
317+
/// Compatibility type.
318+
/// </param>
319+
/// <returns>
320+
/// New compatibility type.
321+
/// </returns>
322+
Task<Compatibility> UpdateCompatibilityAsync(Compatibility compatibility, string subject = null);
294323
}
295324
}

src/Confluent.SchemaRegistry/Rest/DataContracts/Compatibility.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,24 @@ public enum Compatibility
5050
/// Full schema compatibility.
5151
/// </summary>
5252
[EnumMember(Value = "FULL")]
53-
Full
53+
Full,
54+
55+
/// <summary>
56+
/// Forward transitive schema compatibility.
57+
/// </summary>
58+
[EnumMember(Value = "FORWARD_TRANSITIVE")]
59+
ForwardTransitive,
60+
61+
/// <summary>
62+
/// Backward transitive schema compatibility.
63+
/// </summary>
64+
[EnumMember(Value = "BACKWARD_TRANSITIVE")]
65+
BackwardTransitive,
66+
67+
/// <summary>
68+
/// Full transitive schema compatibility.
69+
/// </summary>
70+
[EnumMember(Value = "FULL_TRANSITIVE")]
71+
FullTransitive
5472
}
5573
}

src/Confluent.SchemaRegistry/Rest/IRestService.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,13 @@ namespace Confluent.SchemaRegistry
2929
internal interface IRestService : IDisposable
3030
{
3131
Task<Compatibility> GetCompatibilityAsync(string subject);
32-
Task<Compatibility> GetGlobalCompatibilityAsync();
3332
Task<RegisteredSchema> GetLatestSchemaAsync(string subject);
3433
Task<Schema> GetSchemaAsync(int id, string format = null);
3534
Task<RegisteredSchema> GetSchemaAsync(string subject, int version);
3635
Task<List<string>> GetSubjectsAsync();
3736
Task<List<int>> GetSubjectVersionsAsync(string subject);
3837
Task<int> RegisterSchemaAsync(string subject, Schema schema, bool normalize);
39-
Task<Config> SetCompatibilityAsync(string subject, Compatibility compatibility);
40-
Task<Config> SetGlobalCompatibilityAsync(Compatibility compatibility);
38+
Task<Compatibility> UpdateCompatibilityAsync(string subject, Compatibility compatibility);
4139
Task<bool> TestCompatibilityAsync(string subject, int versionId, Schema schema);
4240
Task<bool> TestLatestCompatibilityAsync(string subject, Schema schema);
4341
Task<RegisteredSchema> LookupSchemaAsync(string subject, Schema schema, bool ignoreDeletedSchemas, bool normalize);

src/Confluent.SchemaRegistry/Rest/RestService.cs

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -355,25 +355,21 @@ public async Task<bool> TestLatestCompatibilityAsync(string subject, Schema sche
355355
: (await RequestAsync<CompatibilityCheck>($"compatibility/subjects/{WebUtility.UrlEncode(subject)}/versions/latest", HttpMethod.Post, schema)
356356
.ConfigureAwait(continueOnCapturedContext: false)).IsCompatible;
357357

358-
#endregion Compatibility
358+
#endregion Compatibility
359359

360360
#region Config
361361

362-
public async Task<Compatibility> GetGlobalCompatibilityAsync()
363-
=> (await RequestAsync<Config>("config", HttpMethod.Get)
364-
.ConfigureAwait(continueOnCapturedContext: false)).CompatibilityLevel;
365-
366362
public async Task<Compatibility> GetCompatibilityAsync(string subject)
367-
=> (await RequestAsync<Config>($"config/{WebUtility.UrlEncode(subject)}", HttpMethod.Get)
368-
.ConfigureAwait(continueOnCapturedContext: false)).CompatibilityLevel;
369-
370-
public async Task<Config> SetGlobalCompatibilityAsync(Compatibility compatibility)
371-
=> await RequestAsync<Config>("config", HttpMethod.Put, new Config(compatibility))
372-
.ConfigureAwait(continueOnCapturedContext: false);
373-
374-
public async Task<Config> SetCompatibilityAsync(string subject, Compatibility compatibility)
375-
=> await RequestAsync<Config>($"config/{WebUtility.UrlEncode(subject)}", HttpMethod.Put, new Config(compatibility))
376-
.ConfigureAwait(continueOnCapturedContext: false);
363+
=> (await RequestAsync<Config>(
364+
string.IsNullOrEmpty(subject) ? "config" : $"config/{WebUtility.UrlEncode(subject)}",
365+
HttpMethod.Get)
366+
.ConfigureAwait(continueOnCapturedContext: false)).CompatibilityLevel;
367+
368+
public async Task<Compatibility> UpdateCompatibilityAsync(string subject, Compatibility compatibility)
369+
=> (await RequestAsync<Config>(
370+
string.IsNullOrEmpty(subject) ? "config" : $"config/{WebUtility.UrlEncode(subject)}",
371+
HttpMethod.Put, new Config(compatibility))
372+
.ConfigureAwait(continueOnCapturedContext: false)).CompatibilityLevel;
377373

378374
#endregion Config
379375

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Xunit;
4+
5+
namespace Confluent.SchemaRegistry.IntegrationTests;
6+
7+
public static partial class Tests
8+
{
9+
[Theory, MemberData(nameof(SchemaRegistryParameters))]
10+
public static async Task UpdateCompatibility(Config config)
11+
{
12+
var sr = new CachedSchemaRegistryClient(new SchemaRegistryConfig { Url = config.Server });
13+
14+
// Case 1: Subject is not specified
15+
16+
var globalCompatibility = await sr.UpdateCompatibilityAsync(Compatibility.BackwardTransitive);
17+
Assert.Equal(Compatibility.BackwardTransitive, globalCompatibility);
18+
19+
Assert.Equal(Compatibility.BackwardTransitive, await sr.GetCompatibilityAsync());
20+
21+
// Case 2: Subject is specified
22+
23+
var testSchema =
24+
"{\"type\":\"record\",\"name\":\"User\",\"namespace\":\"Confluent.Kafka.Examples.AvroSpecific" +
25+
"\",\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"favorite_number\",\"type\":[\"i" +
26+
"nt\",\"null\"]},{\"name\":\"favorite_color\",\"type\":[\"string\",\"null\"]}]}";
27+
28+
29+
var topicName = Guid.NewGuid().ToString();
30+
var subject =
31+
SubjectNameStrategy.Topic.ConstructKeySubjectName(topicName, "Confluent.Kafka.Examples.AvroSpecific.User");
32+
33+
await sr.RegisterSchemaAsync(subject, testSchema);
34+
35+
var compatibility = await sr.UpdateCompatibilityAsync(Compatibility.FullTransitive, subject);
36+
Assert.Equal(Compatibility.FullTransitive, compatibility);
37+
38+
Assert.Equal(Compatibility.FullTransitive, await sr.GetCompatibilityAsync(subject));
39+
Assert.Equal(Compatibility.BackwardTransitive, await sr.GetCompatibilityAsync());
40+
}
41+
}

0 commit comments

Comments
 (0)