Follow-up from #273 (closed). The document storage runtime is now fully on the shared closed-shape runtime, and event append + stream-version ride IEventStoreSqlDialect / the shared EventStorage<TId> base. The remaining hand-written, EventGraph-driven event operations are the last bespoke SQL in Polecat.
Why this is a separate issue
The shared Weasel.Storage.Events.EventStorage<TId> base exposes seams only for the append/stream lifecycle:
AppendEvent · QuickAppendEventWithVersion · QuickAppendEvents · InsertStream · UpdateStreamVersion · AssertStreamVersion
There is no seam for archive / tombstone / progression. Marten keeps analogous operations store-local too, so converging these is blocked on adding the seams to Weasel.Storage.Events first (cross-repo Weasel work), then Polecat implementing the SQL Server dialect of them.
Polecat operations still bespoke (all in src/Polecat/Internal/Operations/)
| Operation |
SQL |
Target tables |
ArchiveStreamOperation |
UPDATE … SET is_archived = 1 |
pc_streams + pc_events |
UnArchiveStreamOperation |
UPDATE … SET is_archived = 0 |
pc_streams + pc_events |
TombstoneStreamOperation |
DELETE FROM … |
pc_events + pc_streams |
ProgressMergeOperation |
MERGE (Floor == 0) |
pc_event_progression |
ProgressUpdateOperation |
UPDATE (Floor > 0) |
pc_event_progression |
AssertDcbConsistencyOperation |
SELECT CASE WHEN EXISTS … over pc_event_tag_* |
DCB tag tables |
Proposed seam shape (to design upstream in Weasel first)
Extend the shared event storage contract — either new abstract methods on EventStorage<TId> or a companion interface — with dialect-provided operation factories:
IStorageOperation ArchiveStream(StreamAction / id, string tenantId, bool archived) — covers archive + un-archive (one flag).
IStorageOperation TombstoneStream(StreamAction / id, string tenantId) — hard delete of a stream's events + row.
- Progression:
IStorageOperation UpdateProgress(string projectionName, long ceiling, ...) with a merge-or-update variant (or let the dialect choose based on floor). This is the async-daemon high-water / projection-progress write; today PolecatProjectionBatch picks ProgressMerge vs ProgressUpdate.
AssertDcbConsistencyOperation is the most Polecat-specific (DCB tag-table EXISTS check) and may stay store-local even after the others converge — worth evaluating separately.
Suggested sequencing
- [Weasel] Design + add the archive/tombstone/progression seams to
Weasel.Storage.Events (mirroring how IEventStoreSqlDialect / EventStorage<TId> already factor append). Release.
- [Polecat] Implement the SQL Server dialect of the new seams (
SYSDATETIMEOFFSET(), pc_* tables, tenancy #234), retire the bespoke operation classes, keep the existing event-store test suite as the safety net.
Non-goals
- Not converging
DocumentMapping (config the descriptor is built from), the LINQ query-builder, the session/unit-of-work pipeline, or infra SQL (master-table tenancy, flat-table projections) — all intentionally store-local, matching Marten.
Low urgency: the current bespoke operations are correct and fully tested; this is about single-sourcing the last of the event-write SQL once the shared seams exist.
Follow-up from #273 (closed). The document storage runtime is now fully on the shared closed-shape runtime, and event append + stream-version ride
IEventStoreSqlDialect/ the sharedEventStorage<TId>base. The remaining hand-written,EventGraph-driven event operations are the last bespoke SQL in Polecat.Why this is a separate issue
The shared
Weasel.Storage.Events.EventStorage<TId>base exposes seams only for the append/stream lifecycle:There is no seam for archive / tombstone / progression. Marten keeps analogous operations store-local too, so converging these is blocked on adding the seams to
Weasel.Storage.Eventsfirst (cross-repo Weasel work), then Polecat implementing the SQL Server dialect of them.Polecat operations still bespoke (all in
src/Polecat/Internal/Operations/)ArchiveStreamOperationUPDATE … SET is_archived = 1pc_streams+pc_eventsUnArchiveStreamOperationUPDATE … SET is_archived = 0pc_streams+pc_eventsTombstoneStreamOperationDELETE FROM …pc_events+pc_streamsProgressMergeOperationMERGE(Floor == 0)pc_event_progressionProgressUpdateOperationUPDATE(Floor > 0)pc_event_progressionAssertDcbConsistencyOperationSELECT CASE WHEN EXISTS …overpc_event_tag_*Proposed seam shape (to design upstream in Weasel first)
Extend the shared event storage contract — either new abstract methods on
EventStorage<TId>or a companion interface — with dialect-provided operation factories:IStorageOperation ArchiveStream(StreamAction / id, string tenantId, bool archived)— covers archive + un-archive (one flag).IStorageOperation TombstoneStream(StreamAction / id, string tenantId)— hard delete of a stream's events + row.IStorageOperation UpdateProgress(string projectionName, long ceiling, ...)with a merge-or-update variant (or let the dialect choose based on floor). This is the async-daemon high-water / projection-progress write; todayPolecatProjectionBatchpicksProgressMergevsProgressUpdate.AssertDcbConsistencyOperationis the most Polecat-specific (DCB tag-tableEXISTScheck) and may stay store-local even after the others converge — worth evaluating separately.Suggested sequencing
Weasel.Storage.Events(mirroring howIEventStoreSqlDialect/EventStorage<TId>already factor append). Release.SYSDATETIMEOFFSET(),pc_*tables, tenancy#234), retire the bespoke operation classes, keep the existing event-store test suite as the safety net.Non-goals
DocumentMapping(config the descriptor is built from), the LINQ query-builder, the session/unit-of-work pipeline, or infra SQL (master-table tenancy, flat-table projections) — all intentionally store-local, matching Marten.Low urgency: the current bespoke operations are correct and fully tested; this is about single-sourcing the last of the event-write SQL once the shared seams exist.