Sequelize, NextJS и Typescript: отношения и запросы терпят неудачу

#node.js #typescript #sequelize.js #next.js

Вопрос:

У меня есть этот файл в проекте NextJS:

 // ~/src/models/user/account.ts

import Joi, { ValidationError } from 'joi';
import Sequelize, { Model } from 'sequelize';

// other imports...

import database from '..';

export class UserAccount extends Model {
  public id?: number;
  public name = '';
  public email = '';
  public password = '';
  public dateOfBirth?: Date;
  public documentNumber = '';
  public documentType: DocumentType = 'cpf';
  public emailConfirmationToken = '';
  public emailConfirmedAt?: Date;
  public resetPasswordToken = '';
  public passwordResetAt?: Date;

  public readonly deletedAt?: Date;
  public readonly createdAt?: Date;
  public readonly updatedAt?: Date;

  // some custom methods...
}

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
UserAccount.associate = (models) =>
  UserAccount.hasMany(models.Launching, {
    foreignKey: 'id',
    as: 'launchings',
  });

UserAccount.init(
  {
    name: { type: Sequelize.STRING, allowNull: false },
    email: Sequelize.STRING,
    // other fields...
  },
  {
    sequelize: database,
    tableName: 'user_accounts',
    // other properties like scope...
  },
);

export default UserAccount;

 

Затем Launching модель, которая «ПРИНАДЛЕЖИТ» UserAccount вышеперечисленному:

 // ~/src/models/launching/launching.ts:

import Joi from 'joi';
import Sequelize, { Model } from 'sequelize';

import database from '..';

class Launching extends Model {
  public id?: number;
  public ownerId?: number;
  public name = '';
  public slug = '';
  public duration = 0;
  public startedAt = new Date();

  public readonly deletedAt?: Date;
  public readonly createdAt?: Date;
  public readonly updatedAt?: Date;
}

Launching.init(
  {
    name: Sequelize.STRING,
    slug: { type: Sequelize.STRING, unique: true, allowNull: false },
    duration: Sequelize.INTEGER,
    startedAt: Sequelize.DATE,
  },
  {
    sequelize: database,
  },
);

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
Launching.associate = (models) =>
  Launching.belongsTo(models.UserAccount, {
    foreignKey: 'owner_id',
    as: 'owner',
  });

 

Это инициатор базы данных:

 import Sequelize, { Options } from 'sequelize';

import databaseConfig from '../config/database';
import logger from '../common/logger';

import processModels from './processModels';

function Database() {
  const connection = new Sequelize.Sequelize({
    ...(databaseConfig as Options),
    logging: (sql, timing) =>
      logger.info(
        sql,
        typeof timing === 'number' ? `Elapsed time: ${timing}ms` : '',
      ),
  });

  processModels(connection);
  return connection;
}

const database = Database();

export default database;
 

My problem is that Sequelize can never «see» my associations. I declared the «associate» method and tried to call it via some «magic loop» reading files from the models directory — as some examples do in Javascript on the web (like here)

But the only result I see in the console is:

  original: Error: Field 'owner_id' doesn't have a default value
      at Packet.asError (~/project/node_modules/mysql2/lib/packets/packet.js:712:17)
      at Execute.execute (~/project/node_modules/mysql2/lib/commands/command.js:28:26)
      at Connection.handlePacket (~/project/node_modules/mysql2/lib/connection.js:425:32)
      at PacketParser.onPacket (~/project/node_modules/mysql2/lib/connection.js:75:12)
      at PacketParser.executeStart (~/project/node_modules/mysql2/lib/packet_parser.js:75:16)
      at Socket.<anonymous> (~/project/node_modules/mysql2/lib/connection.js:82:25)
      at Socket.emit (events.js:310:20)
      at addChunk (_stream_readable.js:286:12)
      at readableAddChunk (_stream_readable.js:268:9)
      at Socket.Readable.push (_stream_readable.js:209:10)
      at TCP.onStreamRead (internal/stream_base_commons.js:186:23) {
    code: 'ER_NO_DEFAULT_FOR_FIELD',
    errno: 1364,
    sqlState: 'HY000',
    sqlMessage: "Field 'owner_id' doesn't have a default value",
    sql: 'INSERT INTO `launchings` (`id`,`name`,`slug`,`duration`,`started_at`,`created_at`,`updated_at`) VALUES (DEFAULT,?,?,?,?,?,?);',
    parameters: [
      'My Project',
      'my-project',
      35,
      '2021-07-16 02:10:07',
      '2021-07-16 02:10:07',
      '2021-07-16 02:10:07'
    ]
  },
  sql: 'INSERT INTO `launchings` (`id`,`name`,`slug`,`duration`,`started_at`,`created_at`,`updated_at`) VALUES (DEFAULT,?,?,?,?,?,?);',
  parameters: [
    'My Project',
    'my-project',
    35,
    '2021-07-16 02:10:07',
    '2021-07-16 02:10:07',
    '2021-07-16 02:10:07'
  ]
}

 

So, actually, my problems are:

  1. Is it possible to use TS and NextJS and Sequelize and its model relations methods? Because it looks like the models are never aware of its relationships.
  2. All the «solutions» I found googling were indicating to «use a different file to declare the relationships, where you can import all the Models and only then call the «hasMany», «belongsTo», methods in each one». It also doesn’t look like a good strategy. And wait: what file, exactly? Because an external file would need to be «imported» by some NextJS file, right? Since I’m not in a regular «NodeJs» application, I do not have an «entry point script file». And «_document.tsx» in NextJs doesn’t sound like a good solution here. Right?