Repository navigation
JasperFx 2.75.0
Conjoined document tenancy, and tenancy past the event read path (#898, #899)
JasperFx.Events.ComplianceTests covered conjoined events well — twelve facts, enrolled by all three stores — and the document side had no tenancy seam at all. This release closes that, and extends the event suite past reads.
New: DocumentConjoinedTenancyCompliance (10 facts)
Every fact checks both directions and reuses one document id across two tenants. The second is load-bearing: a store keying documents on id alone does not fail loudly, it folds the two writes into one row — so the second silently overwrites the first and both tenants then read the same document. Distinct ids per tenant, which every tenanted fact used before, passes cleanly on exactly that store.
Covers every read shape with no Where (the fisher#51 leak), LoadAsync on all three identity overloads, insert and update of a shared id, all three Delete routes, tenant-scoped optimistic concurrency and numeric revisions, and the AnyTenant / TenantIsOneOf escapes.
Five new facts on ConjoinedEventTenancyCompliance
inline_and_async_snapshots_of_a_shared_stream_id_stay_isolated_per_tenant— no fact anywhere had registered a projection and written one stream id in two tenants, so a store projecting into a single-tenanted snapshot table passed everything. Both lifecycles, since the inline write knows its tenant and the async write must reconstruct it.async_rebuild_across_many_tenants_produces_one_document_per_tenant_stream— 200 tenants share one stream id, making the count an assertion: 200 documents on a correct store, exactly 1 on a broken one.- the archiving pair, Guid and string stream identity, reaching past the flag to the events and to appendability.
with_the_default_tenant_disabled_every_read_route_is_reachable_through_a_tenant_scope— the first assertion anywhere ofComplianceExceptionKind.DefaultTenantUsageDisabled, declared and never used until now.projection_side_effect_messages_carry_the_event_tenant— the sharedRecordingMessageOutboxwas receiving the tenant id and discarding it.
⚠️ Additive contract change — IDocumentSessionFactory
Gains LightweightSession(string tenantId) and QuerySession(string tenantId), with throwing defaults, so nothing breaks on the bump.
A store implementing IDocumentSessionFactory<TOperations, TQuerySession> must write the explicit non-generic forwarders, exactly as it already does for the parameterless pair:
IDocumentSessionOperations IDocumentSessionFactory.LightweightSession(string tenantId)
=> LightweightSession(tenantId);C# interface implementation is not return-type covariant, so a product-typed member satisfies only the generic interface and leaves the contract member on the throwing default — on tenancy that is otherwise perfectly correct. Same near-miss as IDocumentReadOperations.Events. DocumentSessionFactoryDefaultsTests pins the shape.
Also since 2.74.0
- #897 — say plainly which of the two #886 compliance facts discriminates
- #896 — an opt-in build-time assertion that the source generator is attached
- #895 — hand the compiler exactly one copy of the aggregate source generator
- #890 — the source generator leaves a marker in every assembly it processes
- #889 — decide the source-generated
DetermineAction's action per batch, not per event - #888 — tenant-aware
IEventStore.OpenReadOnlyEventStore(tenantId)
Downstream enrollment
JasperFx/marten#5517, JasperFx/polecat#682, JasperFx/fisher#336. The Polecat one is not just enrollment — document tenancy there is taken from the event store's, store-wide, with no per-type opt-in.