This finds or upserts a model with an auto primary key, and is a bit more flexible than
    find_or_create.

    First it looks for the model matching either comp, or props if comp is None.

    If not found, it will try to upsert the model, doing nothing. If the returned model is new,
    meaning it's primary key is not set, then the upsert was unable to create the model, meaning
    there was a conflict. If there is a conflict, find model is run again, and this time it
    will succeed*. Otherwise, the constructed model is returned.

    *this is not entirely true. It's possible that the upsert returns with None, meaning that a
    record was created between the first find and the upsert, and then deleted between the upsert
    and the second find. This situation is out of the scope of this method. A possible solution
    would be to repeat the find/uspert cycle until a model can be returned, but I'm going to avoid
    that for simplicty for now.

    :param constructor: the model constructor
    :param props: the properties to construct the model with if not found
    :param comp: the properties to search for the model with. If None, props is used
    :param return_status: if True, a 2-tuple of (model, status) is returned, where status is what
                          occurred with the model. Either 'found', 'created' or 'duplicate'.

def find_or_upsert(self, constructor, props, *, comp=None, return_status=False):
    """This finds or upserts a model with an auto primary key, and is a bit more flexible than
    find_or_create.

    First it looks for the model matching either comp, or props if comp is None.

    If not found, it will try to upsert the model, doing nothing. If the returned model is new,
    meaning it's primary key is not set, then the upsert was unable to create the model, meaning
    there was a conflict. If there is a conflict, find model is run again, and this time it
    will succeed*. Otherwise, the constructed model is returned.

    *this is not entirely true. It's possible that the upsert returns with None, meaning that a
    record was created between the first find and the upsert, and then deleted between the upsert
    and the second find. This situation is out of the scope of this method. A possible solution
    would be to repeat the find/uspert cycle until a model can be returned, but I'm going to avoid
    that for simplicty for now.

    :param constructor: the model constructor
    :param props: the properties to construct the model with if not found
    :param comp: the properties to search for the model with. If None, props is used
    :param return_status: if True, a 2-tuple of (model, status) is returned, where status is what
                          occurred with the model. Either 'found', 'created' or 'duplicate'.
    """
    model = self.find_model(constructor, comp or props)
    status = _UPSERT_STATUS_FOUND

    if model is None:
      model = constructor(**props)
      status = _UPSERT_STATUS_CREATED
      self.insert_model(model, upsert=Upsert(Upsert.DO_NOTHING))
      if model.is_new:
        model = self.find_model(constructor, comp or props)
        status = _UPSERT_STATUS_DUPLICATE

    if return_status:
      return (model, status)
    else:
      return model