using System.Collections.Immutable; using System.Text.Json.Serialization; namespace StellaOps.Scheduler.Models; /// /// Job instructing Cartographer to materialize a graph snapshot for an SBOM version. /// public sealed record GraphBuildJob { public GraphBuildJob( string id, string tenantId, string sbomId, string sbomVersionId, string sbomDigest, GraphJobStatus status, GraphBuildJobTrigger trigger, DateTimeOffset createdAt, string? graphSnapshotId = null, int attempts = 0, string? cartographerJobId = null, string? correlationId = null, DateTimeOffset? startedAt = null, DateTimeOffset? completedAt = null, string? error = null, IEnumerable>? metadata = null, string? schemaVersion = null) : this( id, tenantId, sbomId, sbomVersionId, sbomDigest, Validation.TrimToNull(graphSnapshotId), status, trigger, Validation.EnsureNonNegative(attempts, nameof(attempts)), Validation.TrimToNull(cartographerJobId), Validation.TrimToNull(correlationId), Validation.NormalizeTimestamp(createdAt), Validation.NormalizeTimestamp(startedAt), Validation.NormalizeTimestamp(completedAt), Validation.TrimToNull(error), Validation.NormalizeMetadata(metadata), schemaVersion) { } [JsonConstructor] public GraphBuildJob( string id, string tenantId, string sbomId, string sbomVersionId, string sbomDigest, string? graphSnapshotId, GraphJobStatus status, GraphBuildJobTrigger trigger, int attempts, string? cartographerJobId, string? correlationId, DateTimeOffset createdAt, DateTimeOffset? startedAt, DateTimeOffset? completedAt, string? error, ImmutableSortedDictionary metadata, string? schemaVersion = null) { Id = Validation.EnsureId(id, nameof(id)); TenantId = Validation.EnsureTenantId(tenantId, nameof(tenantId)); SbomId = Validation.EnsureId(sbomId, nameof(sbomId)); SbomVersionId = Validation.EnsureId(sbomVersionId, nameof(sbomVersionId)); SbomDigest = Validation.EnsureDigestFormat(sbomDigest, nameof(sbomDigest)); GraphSnapshotId = Validation.TrimToNull(graphSnapshotId); Status = status; Trigger = trigger; Attempts = Validation.EnsureNonNegative(attempts, nameof(attempts)); CartographerJobId = Validation.TrimToNull(cartographerJobId); CorrelationId = Validation.TrimToNull(correlationId); CreatedAt = Validation.NormalizeTimestamp(createdAt); StartedAt = Validation.NormalizeTimestamp(startedAt); CompletedAt = Validation.NormalizeTimestamp(completedAt); Error = Validation.TrimToNull(error); var materializedMetadata = metadata ?? ImmutableSortedDictionary.Empty; Metadata = materializedMetadata.Count > 0 ? materializedMetadata.WithComparers(StringComparer.Ordinal) : ImmutableSortedDictionary.Empty; SchemaVersion = SchedulerSchemaVersions.EnsureGraphBuildJob(schemaVersion); } public string SchemaVersion { get; } public string Id { get; } public string TenantId { get; } public string SbomId { get; } public string SbomVersionId { get; } public string SbomDigest { get; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? GraphSnapshotId { get; init; } public GraphJobStatus Status { get; init; } public GraphBuildJobTrigger Trigger { get; } public int Attempts { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? CartographerJobId { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? CorrelationId { get; init; } public DateTimeOffset CreatedAt { get; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public DateTimeOffset? StartedAt { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public DateTimeOffset? CompletedAt { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? Error { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ImmutableSortedDictionary Metadata { get; } = ImmutableSortedDictionary.Empty; }