text: Title: Refactor the internal Query Builder to serialise using type information
  Body: ## Problem
  
  <!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
  
  Currently our Client API is tightly coupled to the internal GraphQL API, this is because we just naively send arguments to the query engine with hardly any pre-processing.
  
  While we do transform certain fields, we cannot ***correctly*** transform arguments like `startsWith` -> `startswith` as a model may have a field named `startsWith` which would incorrectly be sent to the query engine as `startswith`.
  
  ## Suggested solution
  
  <!-- A clear and concise description of what you want to happen. -->
  
  The query builder should take an option that represents the expected type of the arguments, this type should then be traversed and the arguments should be transformed / serialised based on the expected type.
  
  We should generate types that look like this:
  
  ```py
  class StringListFilter(TypedDict, total=False):
      has: str
      has_some: Annotated[List[str], TransformKey('hasSome')]
  ```