Glavin001 / graphql-sequelize-crud

Automatically generate queries and mutations from Sequelize models
https://www.npmjs.com/package/graphql-sequelize-crud
MIT License
128 stars 23 forks source link

Error creating entries that belongs to other models. #17

Closed michaeljota closed 7 years ago

michaeljota commented 7 years ago

Hi! I may be doing something wrong, but I can't make this to work.

I setup as the example, and when trying to create a new entry, an error from Postgres it's returned.

database model

export const Person = database.define('person', {
  firstName: {
    type: Sequelize.STRING,
    allowNull: false,
  },
  lastName: {
    type: Sequelize.STRING,
    allowNull: false,
  },
  email: {
    type: Sequelize.STRING,
    allowNull: false,
    validate: {
      isEmail: true,
    },
  },
});

export const Post = database.define('post', {
  title: {
    type: Sequelize.STRING,
    allowNull: false,
  },
  content: {
    type: Sequelize.TEXT,
    allowNull: false,
  },
});

Person.hasMany(Post);
Post.belongsTo(Person);

query


mutation addPost(
  $content: String!,
  $title: String!
) 
{
  createPost(
    input: {
      title: $title,
      content: $content,
      personId: 50
    }
  ) {
    newPost {
      title
      content
      createdAt
    }
  }
}

variables

{
  "title": "hola",
  "content": "VVLV"
}

the error (as-is)

{
  "data": {
    "createPost": null
  },
  "errors": [
    {
      "message": "la sintaxis de entrada no es válida para integer: «�»",
      "locations": [
        {
          "line": 20,
          "column": 3
        }
      ],
      "path": [
        "createPost"
      ]
    }
  ]
}

I'm new to GraphQL, but as I understand this is the way to do it. Sorry if this is not.

Thanks you!

Update: I try with SQLite, just to see if I was missing something, and still throwing errors.

{
  "data": {
    "createPost": null
  },
  "errors": [
    {
      "message": "SQLITE_CONSTRAINT: FOREIGN KEY constraint failed",
      "locations": [
        {
          "line": 31,
          "column": 3
        }
      ],
      "path": [
        "createPost"
      ]
    }
  ]
}

It's clearer what's happening, but still, I don't know why it is happen.

UPDATE 2: Looking in the Sequelize log:

Executing (default): INSERT INTO `posts` (`id`,`title`,`content`,`createdAt`,`updatedAt`,`personId`) VALUES (NULL,'hola','VVLV','2017-01-23 18:41:41.986 +00:00','2017-01-23 18:41:41.986 +00:00','�');

The personId it's transformed in some unreadable code somewhere, both to humans and to the SQL interpreter, so it acts like no personId it's provided.

According to the docs, the ID should not be human readable, but still be settable with both, string and integers values.

When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID.

Glavin001 commented 7 years ago

I see your personId value is 50. This error appears to be a usage error and not a bug.

The IDs used in the generated GraphQL API are type "global ID" such that they are Relay compliant.

You should see the ID as a global ID when you query for an existing record, in your case for Person model.

Let's say your Person model has a persons query to return the existing records:

query Persons {
  persons {
    id
    firstName
    lastName
  }
}

It may respond like the following:

{
  "data": {
    "users": [
      {
        "id": "UGF0aWVudDox",
        "firstName": "Glavin",
        "lastName": "Wiechert"
      }
    ]
  }
}

Note that in my database ID "UGF0aWVudDox" maps to primary key ID with integer value 1 in my database. So in your case, I would expect to see a long string which represents the record with integer ID 50, for example.

You can test querying by ID, although make sure to update (See #29).

query GetPerson {
  personById: person(id: "UGF0aWVudDox") {
    id
    firstName
    lastName
  }

  personByWhere: patient(where: { id: "UGF0aWVudDox" }) {
    id
    firstName
    lastName
  }

  persons(where: { id: "UGF0aWVudDox" }) {
    id
    firstName
    lastName
  }
}

Returns for me:

{
  "data": {
    "personById": {
      "id": "UGF0aWVudDox",
      "firstName": "Glavin",
      "lastName": "Wiechert"
    },
    "personByWhere": {
      "id": "UGF0aWVudDox",
      "firstName": "Glavin",
      "lastName": "Wiechert"
    },
    "persons": [
      {
        "id": "UGF0aWVudDox",
        "firstName": "Glavin",
        "lastName": "Wiechert"
      }
    ]
  }
}

Hope it helps!

Glavin001 commented 7 years ago

See https://github.com/Glavin001/graphql-sequelize-crud/blob/master/test/getSchema.test.ts#L342-L363 for example.

Take special notice of https://github.com/Glavin001/graphql-sequelize-crud/blob/master/test/getSchema.test.ts#L342 and https://github.com/Glavin001/graphql-sequelize-crud/blob/master/test/getSchema.test.ts#L363

The User ID from the first query (mutation, createUser in this case) is used in the arguments for creating the Todo. The ID would look like UGF0aWVudDo1 even though the database stores integer value 1 (in case of auto-incrementing primary key).

userId = result.data.createUser.newUser.id;
createTodoVariables.input.userId = userId;

Let me know if you have any more questions!

michaeljota commented 6 years ago

I'll try that. Thanks you.