objection.js icon indicating copy to clipboard operation
objection.js copied to clipboard

relationMappings() join doesn't handle ref correctly

Open Yimiprod opened this issue 5 years ago • 5 comments

import { Model } from 'objection';

class FirstClass extends Model {
  static tableName = 'first-class';

  id!: number;
  name!: string;
}

class SecondClass extends Model {
  static tableName = 'second-class';

  id!: number;
  name!: string;
  fkFirstId!: number;

  static relationMappings() {
    return {
      first: {
        relation: Model.HasOneRelation,
        modelClass: FirstClass,
        join: {
          from: SecondClass.ref('fkFirstId'),
          to: FirstClass.ref('id'),
        },
      },
    };
  }
}

with this example, querying with .joinRelated() will throw the error

SecondClass.relationMappings.first: join.from must have format TableName.columnName. For example "SomeTable.id" or in case of composite key ["SomeTable.a", "SomeTable.b"].

Yimiprod avatar Oct 01 '20 17:10 Yimiprod

After some trial and error, i think i've been missguided by the typing in https://github.com/Vincit/objection.js/tree/master/doc/api/types#type-relationjoin that said join.from can be a ReferenceBuilder since it's more a result from a it.

Yimiprod avatar Oct 02 '20 13:10 Yimiprod

No I think this should work. I'll see what's going on as soon as I find the time.

koskimas avatar Oct 04 '20 12:10 koskimas

I'm hitting the same problem in Objection v2.2.3.

Switching from the ref approach to camelCased pluralized strings gets past the problem but seems to introduce another problem. Got past that too but the workaround is a bit awkward and was hoping @koskimas might have advice.

I'm using a class and belongsTo relationship basically the same as Yimiprod's:

static relationMappings = () => ({
  otherModel: {
    relation: Model.BelongsToOneRelation,
    modelClass: OtherModel,

    join: {
      from: 'someModels.otherModelId', // a string corresponding with knexSnakeCaseMappers in the knex config, replacing the ref
      to: 'otherModels.id' 
    },
  },
});

With the string refs in place, it gets past that join.from error, generating a query but one that postgres 12.3 complains about, throwing invalid reference to FROM-clause entry for table "other_models", seemingly due to the auto-generated alias in the join: select "some_models".* from "some_models" inner join "other_models" as "other_models"...

I didn't explicitly add the alias "other_models" anywhere--it's some automatic addition. I got past the issue by explicitly setting an alias both in joinRelated options and by chaining in aliasFor:

return SomeModel.query(tx)
  .joinRelated('otherModel', { alias: 'other' })
  .aliasFor(OtherModel, 'other')
  .where(OtherModel.ref('whatever'), whatever)
  .first();

Rather than overriding the alias in every query, is there a way to declare the alias in the class definition? Or a way to disable the auto-alias, or something better? I'd like to reuse filters/modifiers defined in different classes when composing queries but that depends on stable and consistent identifiers and aliases. Haven't seen a way to do that yet. (Am brand new to Objection.)

ferbs avatar Oct 15 '20 01:10 ferbs

There's no automatic aliasing that would change the alias from otherModel to other_models. That simply isn't possible. other_models is either the real table name or the relation name. Also that's a separate issue and probably caused by invalid usage of either knexSnakeCaseMappers or snakeCaseMappers.

koskimas avatar Oct 17 '20 07:10 koskimas

Bumping this with a TS playgorund example:

https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgWQgEwKYBsA0cBK2AhjMBAHbJFhjDkDmAznoViWZdbQ3AL5wAzKBBBwA5BABGAKwwBjUhTEBuALAAoDTACeYDAWKLyjABbAwjOAF5EGuPbgwiTAFwG2RqjTr0APABVnAD4NXg0NOTZGS0D6OAwADxgMcjRLVEwsW3UHOHIiEAwAQjdGGCgfNXUwzXVIomi4AFVGDCh4pJS0lHRsbLsHMvY5OChDDi9uV3d2ClNzSxsEAdz7J2nlnNXtsY8ONwzsADoACQaqcm1WWfIcFe2HaQg6N02H98FhEDcxAFdWqCMI7ANBiO5bD6rGAQH7rIH-NoAfRBYnu7144Mh9hAvSwAGEoow3LE0Q4arleFUauF1A1tOQRgAKACU1iC-QhcDkc3gCPaNiIAHciMB4C02kcAI6-NraFlHATAQEwFlVe7c4zwSRENBw6xwIUi3kAopHAAkuxIGDQAEUZVA5WI4WJmWrOdrdc5GABtAAMAF0jvlCso4AB6MNwXwAWmjcAACsI9LBtOJgxgxHA0BAMJZyBB4IlgGU4BRHLp9GJDlgxEc4AB+es03Iakv0CDoPUC4WiuB800WwzWu2yqOxIKMp1el1VXLtztev2B9OhiNR2NwQXQADWjFCVSAA

In my case, relatedQuery incorrectly maps QueryBuilder to Model. In my personal project, which has a custom query builder, it maps it to any

damusix avatar Mar 04 '22 22:03 damusix