distributed 4.4.0

CQRS/ES framework for Rust using Plain Old Rust Structs — append-only events, replay, snapshots, outbox, service bus, and pluggable infrastructure
Documentation
### What's changed in v4.4.0

* feat: allow has_many onto composite-key child models (#210) (by @patrickleet)

  * feat: allow has_many onto composite-key child models

  GraphQL join compilation already uses a single-column FK
  (child.fk = parent.pk). The surface validator still rejected any
  composite-PK model that participated in a relationship, which forced
  apps to stuff child collections into JSON blobs or invent a surrogate
  id.

  Keep rejecting joins that actually need a composite identity
  (belongs_to targeting a composite PK, has_many from a composite parent,
  m2m). A workspace with a single-column PK can now has_many projects
  whose identity is (workspace_id, path).

  * feat: join composite keys through many-to-many tables

  Many-to-many is a join table, not a direct PK equality. Each end's
  full primary key maps to same-named columns on the through table
  (single-column ends still use foreign_key / target_foreign_key).

  Nested queries and relationship filters AND those equalities, so a
  composite project can list labels without inventing a surrogate id.

  * refactor: resolve m2m join keys once in table/

  Pair through columns with each end's PK in table/, not compile/.
  Explicit foreign_key/target_foreign_key lists through columns in PK
  order; otherwise same-named through columns or unique column FKs.
  Compile formats the pair list. Surface through keys are vectors.
  HasMany SQL uses has_many_join_columns instead of .first()/id.

  * feat: join composite keys on direct has_many and belongs_to

  foreign_key lists FK columns in the other end's PK order. Compile ANDs
  those equalities. A partial list is rejected instead of taking .first().

  * fix: keep missing-FK registry error wording

  HasMany still reports "foreign key \`x\` is not a column on target model".

  * test: cover composite filter exclusion and m2m row-policy keys

  Row policies now resolve m2m join keys, including operational targets.
  The has_many filter fixture includes a non-matching workspace.

  * docs: document composite read-model relationship keys

  GraphQL ANDs PK-order foreign_key lists for has_many, belongs_to, and
  many_to_many. ORM includes stay one-level and single-column.


See full diff: [v4.3.0...v4.4.0](https://github.com/hops-ops/distributed/compare/v4.3.0...v4.4.0)