As we can't delete questions, I'll leave my solution (as it might help others in future).
Okay, turns out I implemented this in a way that worked in all my test-cases, but that broke under certain conditions (remember to test thoroughly, kids!)
So - forgetting the fact that I omitted any ::select calls in the above code, rendering $selectColumns useless - I now see that I was abusing the Model::query mechanism (which is technically Eloquent, rather than query builder), thereby in-turn abusing Eloquent models (such that they ended up with unrelated attributes set).
Given this, I've now re-worked it all to use the Eloquent querier, specifying relation conditions using ::whereHas, so it now looks like this:-
$modelName = Article::class;
$filters = ["authors.name" => "John"];
$sorts = ["articles.title" => "ASC"];
// start the query
$query = $this->sourceClass::query();
// apply the filters
foreach ($filters as $filter) {
if(/* filter column belongs to the focal model */) {
// this is the base model
$query->where($filter["column"]->name, stripslashes($filter["comparator"]), $filter["value"]);
} else {
// this is a related model
$relation = /* the 1- end of a 1-N relation (i.e. related via *_id) */
? Str::singular(Str::snake($modelName))
: Str::plural(Str::snake($modelName));
$query->whereHas($relation, function($query) use($filter) {
$query->where($filter[0], $filter[1]);
});
}
}
// apply the sorts
foreach ($sorts as $sort) {
$query->orderBy($sort[0], $sort[1]);
}
// get the data (this also works with ::paginate)
$this->data = $query->get();
It's now working correctly, plus this ensures that loading of relations is done the correct, Eloquent way!
Since this was my eventual solution, I've posted it here as an answer (as it was my answer to this problem). However, it does not answer the question above (namely: Is there any way in which I can force it to return table.column-notation column-names?). I'm going to hold off marking this as the "best" answer, since an answer to that question would still be useful (and - in my opinion - best). I suspect it will be "no", though.
To sum up: Im dum :S