Trouble with relationships

I have the following Model

'use strict'

/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')

const TablePrefixer = use('TablePrefixer/Provider');

// https://github.com/ammezie/adonis-graphql-server/blob/master/app/Models/User.js
class EventType extends Model {
  static boot() {
    super.boot()
  }

  static get table() {
    return TablePrefixer.prefixTable('event_type')
  }

  events() {
    return this.hasMany('App/Models/Event', 'id', 'event_type_id')
  }

}

module.exports = EventType

When I try to use the “events” relationship

        const rows = await EventType
          .events()
          .first()

I get an error

TypeError: EventType.events is not a function

I do not know what I am doing wrong.

I have an awful lot of relationships defined, and am using most of them with the .load() function…

TablePrefixer is referenced here

1 Like

Can you show the code of your controller? Where you are trying to get rows.

Because for now it looks like that you are trying to call an instance method events. Of course it will not be available.

For example:

const User = use('App/Models/User')

const user = await User.find(1) // find is a static method returning an instance
const posts = await user.posts().fetch() // posts is an instance method
const posts2 = await User.posts(); // will return error because there is no static method posts in class User
1 Like

Thanks for your reply - it’s got crucial insight that I need

That code is long gone, but the misunderstanding continues

For the sake of clarification, if I swapped the calls would the request then have the contents of the 1st row (undetermined, but valid) and the results of the events() call would have pulled data – or would I have to add a fetch() ?

        const rows = await EventType
          .first()
          .events()

Your reminder of static vs instance methods is greatly appreciated, but my confusion over the deferral of side-effects (in this case, actually reading from the database) lives on

How do you debug this stuff without resorting to just trying it and seeing what comes out the end?

The chaining of the methods is nice, but trying to figure out which ones cause pulls and which one’s do not makes it hard for me to be clear on where the execution pointer is when a given method may be called. When I get tired I just start thrashing about, rearranging the methods to see what works.

I’ve re-read the parts on eager & lazy eager loading so many times, and still don’t really grasp this fully - I am always looking to write code that is more predictable to me. The deferral of side-effects until some [to me] indeterminate point is very difficult. How to add a level of retrieval is unclear to me.

I’m under the gun to deliver an Alpha tomorrow and I’m fairly behind in my plans – I’m having to do all the parts I can and smoke & mirrors the rest for now. Luckily it’s an Alpha.

Do you have any debugging tips you could share? I think I need to be in the weeds to see how the snakes move.

I so appreciate your time and attention and will share concrete code with my next questions.

I’m not sure that I fully understood your question, but writing this

const rows = await EventType
          .first()
          .events()

looks like a really bad practice. The fact that we have chaining doesn’t mean that we should use it everywhere.

Model.first() is a static method. So under the hood is just a knex query like:

return this.db.table(tableName).first()

As a result you get a model instance or null


This code is more readable as for me:

const eventType = await EventType.first(); // .firstOrFail() will be even better
const events = await eventType.events().fetch();

fetch method in the end is needed to actually execute the query. Internally it just calls await this.query (with some additional stuff like converting to instances, calling hooks and etc)