Контекст : я тестирую простую модель в базу данных и из нее. Не настоящий тест, это предшественник некоторых интеграционных тестов. Используя Sequelize и findOne .

Проблема . Прямые данные возвращенного экземпляра модели, т.е. email.ulid, email.address, email.isVerified, не определены.

Мой вопрос . Почему они не определены?

Sequelize: 5.15.0
Typescript: 3.5.3
mysql  Ver 15.1 Distrib 10.4.6-MariaDB

Запись в базу данных .

await testingDatabase.sync({
  force: true
}).then(async () => {
  await Email.create({
    ulid: the_ulid.bytes,
    address: "dave@world.com",
    isVerified: false
  })
})

Получить запись обратно.

await Email.findOne({
  where: { 
    address: "dave@world.com"
  }
  , rejectOnEmpty: true //to shut typescript up
}).then( emailData => {
   console.log("Email: ", email)
})

Console.log экземпляра email:

    Email:  Email {                                                                                                                                                      
      dataValues: {                                                                                                                                                      
        ulid: <Buffer 01 6c a3 36 11 9c 1e 9b a6 ce 60 b7 33 3e e7 21>,                                                                                                  
        address: 'dave@world.com',                                                                                                                                    
        isVerified: false,                                                                                                                                               
        deletedAt: null,                                                                                                                                                 
        createdAt: 2019-08-18T05:32:05.000Z,                                                                                                                             
        updatedAt: 2019-08-18T05:32:05.000Z                                                                                                                              
      },                                                                                                                                                                 
      ...,
      isNewRecord: false,
      ulid: undefined,
      address: undefined,
      isVerified: undefined,
      createdAt: undefined,
      updatedAt: undefined,
      deletedAt: undefined
    }

^^^ Как ясно, сразу выше, все прямые атрибуты в экземпляре равны нулю.

Следующее работает , но с побочным эффектом, который isVerified возвращается как 0, а не false, и впоследствии не дает прямого сравнения с исходными данными. Кроме того, я теряю другие функциональные возможности экземпляра модели, которые пригодятся в более сложных моделях:

Email.findOne({
  where: { address: "dave@world.com" }
, raw: true 
, rejectOnEmpty: true
})

Они также работают , но в результате Typescript жалуется на то, что возвращенный объект не имеет свойств, к которым я затем обращаюсь (хотя они существуют и тест работает):

.then( emailData => {
  console.log("All getters: ", emailData.get())
  // AND
  console.log("All getters(plain): ", emailData.get({plain: true}))
  // AND
  console.log("toJSON: ", emailData.toJSON())
})

Этот следующий (предложенный Vivek) работает, если доступны данные, но JSON.parse не может правильно обработать буфер:

const dataOnly = JSON.parse(JSON.stringify(emailData))

Другие жаловались (SE answer), что console.log каким-то образом опечатывает экземпляр, но при любом другом доступе к этим свойствам они все еще не определено.

5
Paul Parker 18 Авг 2019 в 09:05

2 ответа

Лучший ответ

Решение:

Проблема была с плагином Babel.

Настройка моделей Sequelize в соответствии с документацией Sequelize / Typescript определяет свойства класса для каждой модели представляющие модельные поля.

Плагин Babel:

"@babel/proposal-class-properties"

В:

plugins: [
  "@babel/proposal-class-properties"
, ...
]

Преобразует эти свойства класса в вызовы defineProperty() объекта модели Class, вызываемые по очереди помощником _defineProperty():

  _defineProperty(this, "yourFieldName", void 0);

Это инициализирует свойство объекта со значением undefined.

Очевидно, что когда findOne впоследствии попытался обновить модель, он отказался перезаписать эти существующие свойства в модели.

2
Paul Parker 19 Авг 2019 в 04:20

Вот, пожалуйста, вы можете попробовать просто JSON.parse и JSON.stringify;

Email.findOne({
  where: { 
    address: "dave@world.com"
  }
}).then( emailData => {
   const dataOnly = JSON.parse(JSON.stringify(emailData));
   console.log(dataOnly); // <--- YOUR DATA
   console.log(emailData); // <--- YOUR INSTANCE
})

«Typescript жалуется, что у возвращенного объекта нет свойств, к которым я затем обращаюсь»

.then( emailData => {
  console.log("All getters: ", emailData.get())
  // AND
  console.log("All getters(plain): ", emailData.get({plain: true}))
  return emailData.get({plain: true}); // <-- I think you forgot to return this
});

Я думаю, что ошибка в том, что вы не можете вернуть результат обратно. Проверьте приведенный выше код.

0
Vivek Doshi 18 Авг 2019 в 09:58