# Using Preconditions

By default, `Execute` writes events without any preconditions. To add some, implement the `Preconditions` function on the command and return the preconditions to use, which makes the command `Preconditioned`. Create the preconditions with the functions of the client SDK.

If a precondition does not hold, nothing is written, and `Execute` returns an error of the category `ErrConflict` (see [Handling Errors](/docs/architecturekit/handling-errors)).

## Preventing Duplicates

If a command may only write events in case its subject does not yet have any events, use the `NewIsSubjectPristinePrecondition` function:

```go
func (c AcquireBook) Preconditions() []eventsourcingdb.Precondition {
  return []eventsourcingdb.Precondition{
    eventsourcingdb.NewIsSubjectPristinePrecondition(c.Subject()),
  }
}
```

## Requiring an Existing Subject

If a command may only write events in case its subject already has at least one event, use the `NewIsSubjectPopulatedPrecondition` function:

```go
func (c ReturnBook) Preconditions() []eventsourcingdb.Precondition {
  return []eventsourcingdb.Precondition{
    eventsourcingdb.NewIsSubjectPopulatedPrecondition(c.Subject()),
  }
}
```

## Guarding Against Concurrent Changes

If a command may only write events in case its subject has not changed since the caller last read it, use the `NewIsSubjectOnEventIDPrecondition` function. For that, add a field for the ID of the last event the caller has seen:

```go
type BorrowBook struct {
  BookID          string
  ReaderID        string
  BorrowedUntil   string
  ExpectedEventID string
}

func (c BorrowBook) Preconditions() []eventsourcingdb.Precondition {
  return []eventsourcingdb.Precondition{
    eventsourcingdb.NewIsSubjectOnEventIDPrecondition(c.Subject(), c.ExpectedEventID),
  }
}
```

*Note that the caller has to provide the event ID. A view can keep it for that purpose (see [Defining Views](/docs/architecturekit/defining-views)).*

## Enforcing Rules Across Subjects

If a command may only write events depending on an EventQL query, use the `NewIsEventQLQueryTruePrecondition` function. Preconditions can be combined, and all of them must hold. For example, to acquire every ISBN only once, extend the preconditions of `AcquireBook`:

```go
func (c AcquireBook) Preconditions() []eventsourcingdb.Precondition {
  return []eventsourcingdb.Precondition{
    eventsourcingdb.NewIsSubjectPristinePrecondition(c.Subject()),
    eventsourcingdb.NewIsEventQLQueryTruePrecondition(fmt.Sprintf(
      "FROM e IN events WHERE e.type == 'io.eventsourcingdb.library.book-acquired' AND e.data.isbn == '%s' PROJECT INTO COUNT() == 0",
      c.ISBN,
    )),
  }
}
```

*Note that the query must return a single row with a single value, which is interpreted as a boolean.*
