Skip to content

Commit 9f8f81d

Browse files
committed
Refactor plugin specs/ops to use strongly typed lists
Refactored plugin specifications and operations from JSON strings to strongly typed lists (PluginSpecification, PluginOperation, PluginOperationParameter). Updated EF Core configuration to use value converters and comparers for JSONB storage. Improved type safety and clarity in application logic and API responses. Added new domain classes for specifications and operations. #50
1 parent 3bf9711 commit 9f8f81d

8 files changed

Lines changed: 137 additions & 11 deletions

File tree

src/FlowSynx.PluginRegistry.Application/Features/Plugins/Query/PluginDetails/PluginDetailsHandler.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
using FlowSynx.PluginRegistry.Domain.Plugin;
33
using MediatR;
44
using Microsoft.Extensions.Logging;
5-
using System.Text.Json;
65

76
namespace FlowSynx.PluginRegistry.Application.Features.Plugins.Query.PluginDetails;
87

@@ -54,8 +53,27 @@ public async Task<Result<PluginDetailsResponse>> Handle(PluginDetailsRequest req
5453
.OrderByDescending(x=>x.LastModifiedOn)
5554
.ThenByDescending(x=>x.CreatedOn)
5655
.Select(x=>x.Version),
57-
Specifications = JsonSerializer.Deserialize<object>(plugin.Specifications ?? ""),
58-
Operations = JsonSerializer.Deserialize<object>(plugin.Operations ?? "")
56+
Specifications = plugin.Specifications.Select(x => new PluginDetailsOSpecification
57+
{
58+
Name = x.Name,
59+
Description = x.Description,
60+
Type = x.Type,
61+
DefaultValue = x.DefaultValue,
62+
IsRequired = x.IsRequired
63+
}).ToList(),
64+
Operations = plugin.Operations.Select(x => new PluginDetailsOperation
65+
{
66+
Name = x.Name,
67+
Description = x.Description,
68+
Parameters = x.Parameters.Select(p => new PluginDetailsOperationParameter
69+
{
70+
Name = p.Name,
71+
Description = p.Description,
72+
Type = p.Type,
73+
DefaultValue = p.DefaultValue,
74+
IsRequired = p.IsRequired
75+
}).ToList()
76+
}).ToList()
5977
};
6078

6179
return await Result<PluginDetailsResponse>.SuccessAsync(response);

src/FlowSynx.PluginRegistry.Application/Features/Plugins/Query/PluginDetails/PluginDetailsResponse.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ public class PluginDetailsResponse
1414
public string? CategoryTitle { get; set; }
1515
public required string MinimumFlowSynxVersion { get; set; }
1616
public string? TargetFlowSynxVersion { get; set; }
17-
public object? Specifications { get; set; }
18-
public object? Operations { get; set; }
17+
public List<PluginDetailsOSpecification> Specifications { get; set; } = new List<PluginDetailsOSpecification>();
18+
public List<PluginDetailsOperation> Operations { get; set; } = new List<PluginDetailsOperation>();
1919
public DateTime LastUpdated { get; set; }
2020
public int TotalDownload { get; set; } = 0;
2121
public bool IsTrusted { get; set; } = false;
@@ -24,4 +24,29 @@ public class PluginDetailsResponse
2424
public IEnumerable<string> Versions { get; set; } = new List<string>();
2525
public IEnumerable<string> Owners { get; set; } = new List<string>();
2626
public string? Checksum { get; set; }
27+
}
28+
29+
public class PluginDetailsOperation
30+
{
31+
public string Name { get; set; } = string.Empty;
32+
public string? Description { get; set; }
33+
public List<PluginDetailsOperationParameter> Parameters { get; set; } = new List<PluginDetailsOperationParameter>();
34+
}
35+
36+
public class PluginDetailsOperationParameter
37+
{
38+
public string Name { get; set; } = string.Empty;
39+
public string? Description { get; set; }
40+
public string? Type { get; set; }
41+
public string? DefaultValue { get; set; }
42+
public bool? IsRequired { get; set; } = false;
43+
}
44+
45+
public class PluginDetailsOSpecification
46+
{
47+
public string Name { get; set; } = string.Empty;
48+
public string? Description { get; set; }
49+
public string? Type { get; set; }
50+
public string? DefaultValue { get; set; }
51+
public bool? IsRequired { get; set; } = false;
2752
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace FlowSynx.PluginRegistry.Domain.Plugin;
2+
3+
public class PluginOperation
4+
{
5+
public string Name { get; set; } = string.Empty;
6+
public string? Description { get; set; }
7+
public List<PluginOperationParameter> Parameters { get; set; } = new List<PluginOperationParameter>();
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FlowSynx.PluginRegistry.Domain.Plugin;
2+
3+
public class PluginOperationParameter
4+
{
5+
public string Name { get; set; } = string.Empty;
6+
public string? Description { get; set; }
7+
public string? Type { get; set; }
8+
public string? DefaultValue { get; set; }
9+
public bool? IsRequired { get; set; } = false;
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace FlowSynx.PluginRegistry.Domain.Plugin;
2+
3+
public class PluginSpecification
4+
{
5+
public string Name { get; set; } = string.Empty;
6+
public string? Description { get; set; }
7+
public string? Type { get; set; }
8+
public string? DefaultValue { get; set; }
9+
public bool? IsRequired { get; set; } = false;
10+
}

src/FlowSynx.PluginRegistry.Domain/Plugin/PluginVersionEntity.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public class PluginVersionEntity : AuditableEntity<Guid>, ISoftDeletable
2020
public required Guid PluginCategoryId { get; set; }
2121
public required string MinimumFlowSynxVersion { get; set; }
2222
public string? TargetFlowSynxVersion { get; set; }
23-
public string? Specifications { get; set; }
24-
public string? Operations { get; set; }
23+
public List<PluginSpecification> Specifications { get; set; } = new List<PluginSpecification>();
24+
public List<PluginOperation> Operations { get; set; } = new List<PluginOperation>();
2525
public bool? IsLatest { get; set; }
2626
public string? MetadataFile { get; set; }
2727
public string? Checksum { get; set; }

src/FlowSynx.PluginRegistry.Infrastructure/Configurations/PluginVersionEntityConfiguration.cs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using Microsoft.EntityFrameworkCore.Metadata.Builders;
1+
using FlowSynx.PluginRegistry.Domain.Plugin;
22
using Microsoft.EntityFrameworkCore;
3-
using FlowSynx.PluginRegistry.Domain.Plugin;
3+
using Microsoft.EntityFrameworkCore.ChangeTracking;
4+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
5+
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
46

57
namespace FlowSynx.PluginRegistry.Infrastructure.Configurations;
68

@@ -58,6 +60,40 @@ public void Configure(EntityTypeBuilder<PluginVersionEntity> builder)
5860
builder.Property(t => t.TargetFlowSynxVersion)
5961
.HasMaxLength(50);
6062

63+
// JSON serialization for plugin specifications
64+
var pluginSpecificationConverter = new ValueConverter<List<PluginSpecification>?, string>(
65+
v => System.Text.Json.JsonSerializer.Serialize(v),
66+
v => System.Text.Json.JsonSerializer.Deserialize<List<PluginSpecification>?>(v)
67+
);
68+
69+
var pluginSpecificationComparer = new ValueComparer<List<PluginSpecification>>(
70+
(c1, c2) => System.Text.Json.JsonSerializer.Serialize(c1) ==
71+
System.Text.Json.JsonSerializer.Serialize(c2),
72+
c => System.Text.Json.JsonSerializer.Serialize(c).GetHashCode(),
73+
c => System.Text.Json.JsonSerializer.Deserialize<List<PluginSpecification>>(System.Text.Json.JsonSerializer.Serialize(c))
74+
);
75+
76+
builder.Property(e => e.Specifications)
77+
.HasColumnType("jsonb")
78+
.HasConversion(pluginSpecificationConverter, pluginSpecificationComparer);
79+
80+
// JSON serialization for plugin operations
81+
var pluginOperationConverter = new ValueConverter<List<PluginOperation>?, string>(
82+
v => System.Text.Json.JsonSerializer.Serialize(v),
83+
v => System.Text.Json.JsonSerializer.Deserialize<List<PluginOperation>?>(v)
84+
);
85+
86+
var pluginOperationComparer = new ValueComparer<List<PluginOperation>>(
87+
(c1, c2) => System.Text.Json.JsonSerializer.Serialize(c1) ==
88+
System.Text.Json.JsonSerializer.Serialize(c2),
89+
c => System.Text.Json.JsonSerializer.Serialize(c).GetHashCode(),
90+
c => System.Text.Json.JsonSerializer.Deserialize<List<PluginOperation>>(System.Text.Json.JsonSerializer.Serialize(c))
91+
);
92+
93+
builder.Property(e => e.Operations)
94+
.HasColumnType("jsonb")
95+
.HasConversion(pluginOperationConverter, pluginOperationComparer);
96+
6197
builder.HasIndex(v => new { v.PluginId, v.Version })
6298
.IsUnique();
6399
}

src/FlowSynx.Pluginregistry/Services/StatsApiService.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,27 @@ private PluginVersionEntity CreatePluginVersionEntity(Guid id, Guid pluginId, Pl
342342
PluginCategoryId = pluginCategoryId,
343343
MinimumFlowSynxVersion = metadata.MinimumFlowSynxVersion,
344344
TargetFlowSynxVersion = metadata.TargetFlowSynxVersion,
345-
Specifications = System.Text.Json.JsonSerializer.Serialize(metadata.Specifications),
346-
Operations = System.Text.Json.JsonSerializer.Serialize(metadata.Operations),
345+
Specifications = metadata.Specifications.Select(x => new PluginSpecification
346+
{
347+
Name = x.Name,
348+
Description = x.Description,
349+
Type = x.Type,
350+
DefaultValue = x.DefaultValue,
351+
IsRequired = x.IsRequired
352+
}).ToList(),
353+
Operations = metadata.Operations.Select(x => new PluginOperation
354+
{
355+
Name = x.Name,
356+
Description = x.Description,
357+
Parameters = x.Parameters.Select(p => new PluginOperationParameter
358+
{
359+
Name = p.Name,
360+
Description = p.Description,
361+
Type = p.Type,
362+
DefaultValue = p.DefaultValue,
363+
IsRequired = p.IsRequired
364+
}).ToList()
365+
}).ToList(),
347366
IsLatest = true,
348367
MetadataFile = destinationMetadataPath,
349368
Checksum = checksum,

0 commit comments

Comments
 (0)