Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b292422
Add basic ID classes and parsing
javiers451 Mar 5, 2026
1c16c42
Fix GetHashCode and Equals
javiers451 Mar 6, 2026
ad08be8
Fix end of input parsing
javiers451 Mar 6, 2026
db55ed3
Handle null as input for parsing
javiers451 Mar 6, 2026
c28ded7
Fix StringBuilder buffer
javiers451 Mar 6, 2026
8b64be0
Check null params for store
javiers451 Mar 6, 2026
6d7ede3
Materialize store on enumeration
javiers451 Mar 6, 2026
8cd0a8b
Bring back spec submodule
javiers451 Mar 6, 2026
0b61e8d
Add XML documentation comments
javiers451 Mar 6, 2026
e78d652
Fix mathcing of shorter non-wildcard pattern
javiers451 Mar 6, 2026
df48d16
Move extraction methods to GtsJsonEntity.
javiers451 Mar 9, 2026
efb1184
Fix extract tests
javiers451 Mar 9, 2026
bae43f8
Try original impl for extract method
javiers451 Mar 9, 2026
49cb31a
Initial instance validation
javiers451 Apr 1, 2026
27911e9
Update readme
javiers451 Apr 1, 2026
6e7730c
Add basic relationship resolution
javiers451 Apr 8, 2026
daf4581
Layout resolution and compatibility
javiers451 Apr 10, 2026
29a9093
Bring back compatibility tests
javiers451 Apr 13, 2026
4cddf82
Fix schema ref format validator
javiers451 Apr 13, 2026
396b321
Basic GTS server impl
javiers451 Apr 13, 2026
3dad591
Start implementing compatibility checking
javiers451 Apr 20, 2026
04ce3ea
Implement CLI
javiers451 Apr 21, 2026
4ed98bb
Fix projects references
javiers451 Apr 21, 2026
87addd9
Start version casting work
javiers451 Apr 21, 2026
18dcf0c
Initiate query engine
javiers451 Apr 30, 2026
dd8386c
Implement attribute access
javiers451 Apr 30, 2026
0510f3e
Start schema validation impl
javiers451 May 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule ".gts-spec"]
path = .gts-spec
url = https://github.com/GlobalTypeSystem/gts-spec.git
1 change: 1 addition & 0 deletions .gts-spec
Submodule .gts-spec added at e08828
15 changes: 15 additions & 0 deletions Gts.Application/Gts.Application.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Gts.Application</RootNamespace>
</PropertyGroup>

<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
<ProjectReference Include="..\Gts.Store\Gts.Store.csproj" />
</ItemGroup>

</Project>
82 changes: 82 additions & 0 deletions Gts.Application/GtsEntityOperations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System.Text.Json.Nodes;
using Gts.Extraction;
using Gts.Store;

namespace Gts.Application;

/// <summary>Adds entities to a registry with the same rules as the GTS HTTP API.</summary>
public static class GtsEntityOperations
{
public sealed record AddResult(bool Ok, string Id, string? SchemaId, bool IsSchema, string? Error);

public static async Task<AddResult> TryAddAsync(
GtsRegistry registry,
JsonObject body,
bool validate,
GtsExtractOptions? extractOptions = null,
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
var opt = extractOptions ?? GtsExtractOptions.Default;
var entity = GtsJsonEntity.ExtractEntity(body, opt);
var extract = GtsJsonEntity.ExtractId(body, opt);

if (!entity.IsSchema)
{
if (string.IsNullOrEmpty(entity.SelectedEntityField))
return new AddResult(false, "", null, false, "Instance must have an id field");
}
else
{
if (entity.GtsId is null)
return new AddResult(false, "", null, true, "Unable to detect GTS ID in schema");
}

if (validate && entity.IsSchema)
{
var rawId = body.TryGetPropertyValue("$id", out var idn) ? idn?.GetValue<string>() : null;
if (!string.IsNullOrEmpty(rawId) && rawId.StartsWith("gts.", StringComparison.Ordinal) &&
!rawId.StartsWith("gts://", StringComparison.Ordinal))
return new AddResult(false, "", null, true, "Schema $id must use gts:// URI format, not plain gts. prefix");
}

try
{
GtsSchemaRefFormatValidator.ValidateRefs(body);
}
catch (Exception ex)
{
return new AddResult(false, "", null, entity.IsSchema, ex.Message);
}

if (entity.IsSchema && entity.GtsId is not null)
{
var schemaVr = await registry.ValidateSchemaAsync(entity.GtsId, entity.Content, cancellationToken)
.ConfigureAwait(false);
if (!schemaVr.Ok)
{
var msg = schemaVr.Errors is { Count: > 0 }
? string.Join("; ", schemaVr.Errors)
: (schemaVr.FailureReason ?? "Schema validation failed");
return new AddResult(false, entity.GtsId.Id, entity.SchemaId, true, msg);
}

await registry.SaveAsync(entity).ConfigureAwait(false);

var idOut = entity.GtsId.Id;
return new AddResult(true, idOut, string.IsNullOrEmpty(entity.SchemaId) ? null : entity.SchemaId, true, null);
}

await registry.SaveAsync(entity).ConfigureAwait(false);

if (validate && !entity.IsSchema && entity.GtsId is not null)
{
var vr = await registry.ValidateInstanceAsync(entity.GtsId.Id, cancellationToken).ConfigureAwait(false);
if (!vr.Ok)
return new AddResult(false, entity.GtsId.Id, entity.SchemaId, false, vr.FailureReason ?? "Validation failed");
}

var idOut = entity.GtsId?.Id ?? extract.Id ?? "";
return new AddResult(true, idOut, string.IsNullOrEmpty(entity.SchemaId) ? null : entity.SchemaId, entity.IsSchema, null);
}
}
Loading