text: Title: Optimise generated types
  Body: In order to circumvent mypy not supporting recursive types we duplicate every would-be recursive type. While this works it leads to a massive number of types being generated which slows down mypy considerably.
  
  This appears to be unavoidable but we can improve performance by only generating types that will actually be used (we currently generate every possible relational type) and potentially re-using types.
  
  We should also add a note to the docs somewhere that mypy performance can be improved by decreasing the depth of generated recursive types.