code: func (r *GormSearchRepository) SearchFullText(ctx context.Context, rawSearchString string, start *int, limit *int, spaceID *string) ([]workitem.WorkItem, int, error) {
  	// parse
  	// generateSearchQuery
  	// ....
  	parsedSearchDict, err := parseSearchString(ctx, rawSearchString)
  	if err != nil {
  		return nil, 0, errs.WithStack(err)
  	}
  
  	sqlSearchQueryParameter := generateSQLSearchInfo(parsedSearchDict)
  	var rows []workitem.WorkItemStorage
  	log.Debug(ctx, map[string]interface{}{"search query": sqlSearchQueryParameter}, "searching for work items")
  	rows, count, err := r.search(ctx, sqlSearchQueryParameter, parsedSearchDict.workItemTypes, start, limit, spaceID)
  	if err != nil {
  		return nil, 0, errs.WithStack(err)
  	}
  	result := make([]workitem.WorkItem, len(rows))
  
  	for index, value := range rows {
  		var err error
  		// FIXME: Against best practice http://go-database-sql.org/retrieving.html
  		wiType, err := r.witr.Load(ctx, value.Type)
  		if err != nil {
  			log.Error(ctx, map[string]interface{}{
  				"err": err,
  				"wit": value.Type,
  			}, "failed to load work item type")
  			spew.Dump(value)
  			return nil, 0, errors.NewInternalError(ctx, errs.Wrap(err, "failed to load work item type"))
  		}
  		wiModel, err := workitem.ConvertWorkItemStorageToModel(wiType, &value)
  		if err != nil {
  			return nil, 0, errors.NewConversionError(err.Error())
  		}
  		result[index] = *wiModel
  	}
  
  	return result, count, nil
  }
docs: // SearchFullText Search returns work items for the given query