Vincit/objection.js

$fetchGraph returning empty array when it should return data

Open

#2,258 opened on Apr 13, 2022

View on GitHub
 (7 comments) (0 reactions) (0 assignees)JavaScript (663 forks)batch import
bughelp wanted

Repository metrics

Stars
 (7,146 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

I tried asking this in Gitter several weeks ago but didn't get very far.

I'm having a strange issue with $fetchGraph() that I'm sure is something I'm doing wrong. Given these (simplified) models:

class User extends Model {
  static get tableName() {
    return 'users';
  }

  static get relationMappings() {
    return {
      hardwareTokenRegistrations: {
        relation: HasManyRelation,
        modelClass: HardwareTokenRegistration,
        join: {
          from: 'users.id',
          to: 'hardware_token_registrations.user_id',
        },
      },
    };
  }
};

class HardwareTokenRegistration extends Model {
  static get tableName() {
    return 'hardware_token_registrations';
  }

  static get relationMappings() {
    return {
      hardwareToken: {
        relation: HasOneRelation,
        modelClass: HardwareToken,
        join: {
          from: 'hardware_token_registrations.hardware_token_id',
          to: 'hardware_tokens.id',
        },
      },
      user: {
        relation: HasOneRelation,
        modelClass: User,
        join: {
          from: 'hardware_token_registrations.user_id',
          to: 'users.id',
        },
      },
    };
  }
};

Schema:

mfa=# \d users
                                       Table "public.users"
   Column   |           Type           | Collation | Nullable |              Default
------------+--------------------------+-----------+----------+-----------------------------------
 id         | integer                  |           | not null | nextval('users_id_seq'::regclass)
 uuid       | character varying(255)   |           | not null |
 username   | character varying(255)   |           | not null |
 created_at | timestamp with time zone |           |          | CURRENT_TIMESTAMP
 updated_at | timestamp with time zone |           |          | CURRENT_TIMESTAMP
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)
    "users_username_index" btree (username)
    "users_username_unique" UNIQUE CONSTRAINT, btree (username)
    "users_uuid_index" btree (uuid)
    "users_uuid_unique" UNIQUE CONSTRAINT, btree (uuid)
Referenced by:
    TABLE "hardware_token_registrations" CONSTRAINT "hardware_token_registrations_user_id_foreign" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
... others removed ...

mfa=# \d hardware_token_registrations;
                                          Table "public.hardware_token_registrations"
      Column       |           Type           | Collation | Nullable |                         Default
-------------------+--------------------------+-----------+----------+----------------------------------------------------------
 id                | integer                  |           | not null | nextval('hardware_token_registrations_id_seq'::regclass)
 user_id           | integer                  |           | not null |
 hardware_token_id | integer                  |           | not null |
 validation_code   | character varying(255)   |           | not null |
 created_at        | timestamp with time zone |           |          | CURRENT_TIMESTAMP
 updated_at        | timestamp with time zone |           |          | CURRENT_TIMESTAMP
Indexes:
    "hardware_token_registrations_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "hardware_token_registrations_hardware_token_id_foreign" FOREIGN KEY (hardware_token_id) REFERENCES hardware_tokens(id)
    "hardware_token_registrations_user_id_foreign" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE

I have an instance of User and want to fetch its HardwareTokenRegistrations:

let user = await User.query().findById(1);
let userWithRegistrations = await user.$fetchGraph('hardwareTokenRegistrations');

/* 
returns:

User {
  id: 1,
  uuid: 'grahamb',
  username: 'grahamb',
  createdAt: 2021-12-16T23:57:14.000Z,
  updatedAt: 2022-03-30T20:56:59.239Z,
  hardwareTokenRegistrations: []
}
*/

Note that the hardwareTokenRegistrations array is empty. In reality, there is one related record.

The query generated by the $fetchGraph query is:

{
  method: 'select',
  options: {},
  timeout: false,
  cancelOnTimeout: false,
  bindings: [ 1 ],
  __knexQueryUid: 'qCYLMv1SfgVFnMl4FCa_p',
  sql: 'select "hardware_token_registrations".* from "hardware_token_registrations" where "hardware_token_registrations"."user_id" in (?)'
}

If I run the same query manually against the database, the records are retrieved:

mfa=# select "hardware_token_registrations".* from "hardware_token_registrations" where "hardware_token_registrations"."user_id" in (1);
-[ RECORD 1 ]-----+-----------------------------
id                | 1
user_id           | 1
hardware_token_id | 4
validation_code   | 851728
created_at        | 2021-12-16 23:57:14+00
updated_at        | 2022-03-14 21:52:58.75705+00

I can't figure out what I'm doing wrong here. Any clues?

Contributor guide