using ZB.MOM.WW.ScadaBridge.Commons.Entities.SecuredWrites; namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; /// /// Operational-state data access for the central PendingSecuredWrites table. /// One row per pending two-person secured /// write; rows are inserted at submission and mutated as the request is decided and /// executed. Mirrors the SiteCalls repository shape. /// public interface ISecuredWriteRepository { /// /// Inserts and returns the store-generated /// . /// /// The pending secured write to persist. /// Cancellation token. /// A task that resolves to the generated identity of the inserted row. Task AddAsync(PendingSecuredWrite securedWrite, CancellationToken ct = default); /// /// Returns the row for the given id, or null if none exists. /// /// The identity to look up. /// Cancellation token. /// A task that resolves to the matching , or null if no row exists. Task GetAsync(long id, CancellationToken ct = default); /// /// Persists the current state of (matched by /// ). /// /// The tracked entity whose changes to persist. /// Cancellation token. /// A task that represents the asynchronous operation. Task UpdateAsync(PendingSecuredWrite securedWrite, CancellationToken ct = default); /// /// Returns up to rows (skipping ) /// optionally filtered by and , /// ordered by SubmittedAtUtc DESC, Id DESC. A null filter argument /// matches every row. /// /// Status filter; null matches every status. /// Site id filter; null matches every site. /// Number of rows to skip (offset paging). /// Maximum number of rows to return. /// When non-null, only rows whose SiteId (site /// identifier) is in the set match; null matches every site. Applied IN ADDITION /// to . Used by the ManagementActor to constrain an unfiltered /// list to a site-scoped caller's permitted sites at the query level (arch-review R2 N3), /// so paging and totals stay correct. /// Cancellation token. /// A task that resolves to a page of matching rows, newest submission first. Task> QueryAsync( string? status, string? siteId, int skip, int take, IReadOnlyCollection? permittedSiteIds = null, CancellationToken ct = default); /// /// Atomically flips a row from Pending to Approved, stamping the /// verifier identity, comment, and decision time, but ONLY if the row is still /// Pending. This is the compare-and-swap guard for the two-verifier race: /// two verifiers may approve the same write concurrently, but the /// conditional WHERE Status='Pending' guarantees exactly one wins. The /// loser observes false and must not relay the write. /// /// Identity of the pending secured write. /// The approving verifier's username. /// Optional free-text comment from the verifier. /// UTC instant the approval decision was made. /// Cancellation token. /// /// A task resolving to true if this caller won the approval (exactly one /// row transitioned), or false if the row was no longer Pending /// (already decided by another verifier). /// Task TryMarkApprovedAsync( long id, string verifierUser, string? verifierComment, DateTime decidedAtUtc, CancellationToken ct = default); /// /// Atomically flips a row from Pending to Expired, stamping the /// expiry as the decision time, but ONLY if the row is still Pending. /// This is the multi-node-safe expiry primitive: the conditional /// WHERE Status='Pending' makes the Pending->Expired transition atomic at /// the row level, so two nodes sweeping the same overdue write concurrently /// produce exactly one winner. The expiry is a system decision — no verifier is /// recorded and stays null. /// The loser observes false (the row was already decided or expired). /// /// Identity of the pending secured write. /// UTC instant the write was deemed expired. /// Cancellation token. /// /// A task resolving to true if this caller won the expiry (exactly one /// row transitioned), or false if the row was no longer Pending. /// Task TryMarkExpiredAsync(long id, DateTime expiredAtUtc, CancellationToken ct = default); /// /// Returns the number of rows matching the optional and /// filters. A null filter argument matches every /// row. Mirrors 's filter composition without paging. /// /// Status filter; null matches every status. /// Site id filter; null matches every site. /// When non-null, only rows whose SiteId (site /// identifier) is in the set match; null matches every site. Applied IN ADDITION /// to . Used by the ManagementActor to constrain an unfiltered /// list to a site-scoped caller's permitted sites at the query level (arch-review R2 N3), /// so paging and totals stay correct. /// Cancellation token. /// A task that resolves to the count of matching rows. Task CountAsync( string? status, string? siteId, IReadOnlyCollection? permittedSiteIds = null, CancellationToken ct = default); }