Ошибка при попытке вставить строку в таблицу из-за внешнего ключа UUID с sequelize.js - PullRequest
1 голос
/ 14 апреля 2019

Я использую sequelize.js с node.js и postgres. Я получил две простые таблицы из примера в виде «POC». Я изменил идентификатор на UUID, и у меня возникла проблема со вставкой во вторую таблицу (с UUID FK).

Я использую почтальон, чтобы проверить это. Я создаю строки задач с UUID без проблем, Затем я пытаюсь создать элемент todo с идентификатором todo в качестве внешнего ключа. и кажется, что он не может распознать этот идентификатор!

Я попробовал ручной скрипт в postgres, и он работал. Я, вероятно, что-то пропустил, но не могу понять, что.

вот ошибка, которую мне возвращают в почтальоне -

{
    "name": "SequelizeDatabaseError",
    "parent": {
        "name": "error",
        "length": 96,
        "severity": "ERROR",
        "code": "22P02",
        "file": "uuid.c",
        "line": "137",
        "routine": "string_to_uuid",
        "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
    },
    "original": {
        "name": "error",
        "length": 96,
        "severity": "ERROR",
        "code": "22P02",
        "file": "uuid.c",
        "line": "137",
        "routine": "string_to_uuid",
        "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
    },
    "sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
}

Вот соответствующие файлы js -

контроллер todoItems.js -

const TodoItem = require('../dal/models').TodoItem;
const uuid = require('uuid/v4');

module.exports = {
  create(req, res) {
    return TodoItem
      .create({
        content: req.body.content,
        todoId: req.params.todoId,
      })
      .then(todoItem => res.status(201).send(todoItem))
      .catch(error => res.status(400).send(error));
  },

  update(req, res) {
    return TodoItem
      .find({
        where: {
          id: req.params.todoItemId,
          todoId: req.params.todoId,
        },
      })
      .then(todoItem => {
        if (!todoItem) {
          return res.status(404).send({
            message: 'TodoItem Not Found',
          });
        }

        return todoItem
          .update({
            content: req.body.content || todoItem.content,
            complete: req.body.complete || todoItem.complete,
          })
          .then(updatedTodoItem => res.status(200).send(updatedTodoItem))
          .catch(error => res.status(400).send(error));
      })
      .catch(error => res.status(400).send(error));
  },

  destroy(req, res) {
    return TodoItem
      .find({
        where: {
          id: req.params.todoItemId,
          todoId: req.params.todoId,
        },
      })
      .then(todoItem => {
        if (!todoItem) {
          return res.status(404).send({
            message: 'TodoItem Not Found',
          });
        }

        return todoItem
          .destroy()
          .then(() => res.status(204).send())
          .catch(error => res.status(400).send(error));
      })
      .catch(error => res.status(400).send(error));
  },
};

todos.js controller-

const Todo = require('../dal/models').Todo;
const TodoItem = require('../dal/models').TodoItem;

module.exports = {
  create(req, res) {
    return Todo
      .create({
        title: req.body.title,
      })
      .then((todo) => res.status(201).send(todo))
      .catch((error) => res.status(400).send(error));
  },

  list(req, res) {
    return Todo
      .findAll({
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
        order: [
          ['createdAt', 'DESC'],
          [{ model: TodoItem, as: 'todoItems' }, 'createdAt', 'ASC'],
        ],
      })
      .then((todos) => res.status(200).send(todos))
      .catch((error) => res.status(400).send(error));
  },

  retrieve(req, res) {
    return Todo
      .findByPk(req.params.todoId, {
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
      })
      .then((todo) => {
        if (!todo) {
          return res.status(404).send({
            message: 'Todo Not Found',
          });
        }
        return res.status(200).send(todo);
      })
      .catch((error) => res.status(400).send(error));
  },

  update(req, res) {
    return Todo
      .findByPk(req.params.todoId, {
        include: [{
          model: TodoItem,
          as: 'todoItems',
        }],
      })
      .then(todo => {
        if (!todo) {
          return res.status(404).send({
            message: 'Todo Not Found',
          });
        }
        return todo
          .update({
            title: req.body.title || todo.title,
          })
          .then(() => res.status(200).send(todo))
          .catch((error) => res.status(400).send(error));
      })
      .catch((error) => res.status(400).send(error));
  },

  destroy(req, res) {
    return Todo
      .findByPk(req.params.todoId)
      .then(todo => {
        if (!todo) {
          return res.status(400).send({
            message: 'Todo Not Found',
          });
        }
        return todo
          .destroy()
          .then(() => res.status(204).send())
          .catch((error) => res.status(400).send(error));
      })
      .catch((error) => res.status(400).send(error));
  },
};

таблица задач создать миграцию -

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.createTable('Todos', {
      id: {
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
      },
      title: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
    }),
  down: (queryInterface /* , Sequelize */) => queryInterface.dropTable('Todos'),
};

таблица todo-item создать миграцию -

module.exports = {
  up: (queryInterface, Sequelize) =>
    queryInterface.createTable('TodoItems', {
      id: {
        allowNull: false,
        primaryKey: true,
        type: Sequelize.UUID,
      },
      content: {
        type: Sequelize.STRING,
        allowNull: false,
      },
      complete: {
        type: Sequelize.BOOLEAN,
        defaultValue: false,
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE,
      },
      todoId: {
        type: Sequelize.UUID,
        onDelete: 'CASCADE',
        references: {
          model: 'Todos',
          key: 'id',
          as: 'todoId',
        },
      },
    }),
  down: (queryInterface /* , Sequelize */) =>
    queryInterface.dropTable('TodoItems'),
};

модель todo -

const uuid = require('uuid/v4');

'use strict';

module.exports = (sequelize, DataTypes) => {
  const Todo = sequelize.define('Todo', {
    title: {
      type: DataTypes.STRING,
      allowNull: false,
    }
  });
  Todo.associate = (models) => {
    Todo.hasMany(models.TodoItem, {
      foreignKey: 'todoId',
      as: 'todoItems',
    });
  };
  Todo.beforeCreate((item, _ ) => {
    return item.id = uuid();
  });
  return Todo;
};

модель todo-item -

const uuid = require('uuid/v4');

'use strict';

module.exports = (sequelize, DataTypes) => {
  const TodoItem = sequelize.define('TodoItem', {
    content: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    complete: {
      type: DataTypes.BOOLEAN,
      defaultValue: false,
    }
  });
  TodoItem.associate = (models) => {
    TodoItem.belongsTo(models.Todo, {
      foreignKey: 'todoId',
      onDelete: 'CASCADE',
    });
  };
  TodoItem.beforeCreate((item, _ ) => {
    return item.id = uuid();
  });
  return TodoItem;
};

1 Ответ

1 голос
/ 14 апреля 2019

Как выглядит код вашего роутера? Вы используете правильный параметр пути для todoId? Если вы используете экспресс, например. это должно выглядеть как app.post("/todos/:todoId/todo_items", todoItemController.create). Обратите внимание на todoId верблюда. Это гарантирует, что req.params.todoId, на который вы ссылаетесь в контроллере todoItems, будет иметь правильное значение.

Кроме того, убедитесь, что у вас есть правильный анализатор тела для правильной обработки req.body.content. В экспрессе это будет сделано через библиотеку body body-parser и app.use(bodyParser.json()). Добавьте точку останова или оператор журнала в коде создания контроллера todoItem и убедитесь, что у вас действительно есть правильные значения параметров.

...