Docs / ArchitectureKit 2.0 / Guides / Writing to Several Subjects

Writing to Several Subjects

A command acts on a single subject, since it is a decision on the state of that subject. Some events are no such decision, for example a summary derived from many subjects, which has to be written together with a note on each of them, either all or none, such as an InventoryTaken event that counts the books, with a BookCounted event for each of them.

To write events to several subjects at once, call the Write function with a context, the store, the events together with their subjects, and the preconditions:

written, err := architecturekit.Write(context.TODO(), store, []architecturekit.EventOn{
  {Subject: "/inventories/2026", Event: InventoryTaken{BookCount: 2}},
  {Subject: "/books/42", Event: BookCounted{Inventory: "2026"}},
  {Subject: "/books/23", Event: BookCounted{Inventory: "2026"}},
}, architecturekit.OnPristineSubject("/inventories/2026"))
if errors.Is(err, architecturekit.ErrConflict) {
  // Somebody else has taken the inventory already.
}

Write writes the events with the source of the store, and returns them as the database recorded them. If a precondition does not hold, nothing is written, and the error belongs to the category ErrConflict. If the data of one of the events can not be encoded as JSON, nothing is written either, and the error belongs to the category ErrPermanent. So does an event without a subject, or one that is nil, a nil pointer included. Other failures belong to the same categories as for Execute, or leave the outcome of the write unknown, as with Execute (see Handling Errors).

Like a command, a write declares at least one precondition, such as OnPristineSubject or one made with Require, or Unconditionally to write without any. OnStateRead has nothing to guard, since Write reads no state, so Write refuses it with an error of the category ErrPermanent, without writing anything. It refuses no preconditions at all, a precondition that is nil, as with Require(nil), Unconditionally combined with others, and a zero Precondition the same way, as Execute does (see Using Preconditions). An event ID of OnEventID that is not a revision makes Write fail with an error that wraps ErrNotARevision, as with Execute, without writing anything either (see Checking the Revision of the Caller).

Note that Write never decides again, since there is nothing to decide. If nothing is to be written, call it with no events, which writes nothing. It still needs preconditions, though, as any other write, and fails with an error of the category ErrPermanent without them, so declare them, for example with Unconditionally().

Note that Write knows no state, so unlike Execute, it does not refuse an event that a state has no rule for. Every state that reads one of the subjects needs a rule for the events written to it, since reading the subject fails otherwise.