Skip to content

Composite primary keys generating an incorrect schema #267

Open
@ValentinVignal

Description

Describe the bug

I'm using an entity with composite primary keys. Those primary keys are not used in the generated schema for the read-one, update-one, and delete-one queries/mutations.

Have you read the Contributing Guidelines?

Yes.

To Reproduce

Follow the installation for the example: https://tripss.github.io/nestjs-query/docs/introduction/example

Use this entity:

import { ID, ObjectType } from '@nestjs/graphql';
import { FilterableField, IDField } from '@ptc-org/nestjs-query-graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
@ObjectType('TodoItem')
export class TodoItemEntity {
  @IDField(() => ID)
  @PrimaryGeneratedColumn()
  firstId!: string;

  @IDField(() => ID)
  @PrimaryGeneratedColumn()
  secondId!: string;

  @FilterableField()
  @Column()
  title!: string;
}

And this module:

import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { Module } from '@nestjs/common';
import { TodoItemEntity } from './todo-item.entity';

@Module({
  imports: [
    NestjsQueryGraphQLModule.forFeature({
      // import the NestjsQueryTypeOrmModule to register the entity with typeorm
      // and provide a QueryService
      imports: [NestjsQueryTypeOrmModule.forFeature([TodoItemEntity])],
      resolvers: [
        {
          EntityClass: TodoItemEntity,
          DTOClass: TodoItemEntity,
        },
      ],
    }),
  ],
})
export class TodoItemModule {}

Expected behavior

The schema generated is using id: ID! for the read-one, update-one, and delete-one queries/mutations.

Generated schema
type TodoItem {
  firstId: ID!
  secondId: ID!
  title: String!
}

type DeleteManyResponse {
  # The number of records deleted.
  deletedCount: Int!
}

type TodoItemDeleteResponse {
  firstId: ID
  secondId: ID
  title: String
}

type UpdateManyResponse {
  # The number of records updated.
  updatedCount: Int!
}

type TodoItemEdge {
  # The node containing the TodoItem
  node: TodoItem!

  # Cursor for this node.
  cursor: ConnectionCursor!
}

# Cursor for paging through collections
scalar ConnectionCursor

type PageInfo {
  # true if paging forward and there are more records.
  hasNextPage: Boolean

  # true if paging backwards and there are more records.
  hasPreviousPage: Boolean

  # The cursor of the first returned record.
  startCursor: ConnectionCursor

  # The cursor of the last returned record.
  endCursor: ConnectionCursor
}

type TodoItemConnection {
  # Paging information
  pageInfo: PageInfo!

  # Array of edges.
  edges: [TodoItemEdge!]!
}

type Query {
  todoItem(
    # The id of the record to find.
    id: ID!
  ): TodoItem!
  todoItems(
    # Limit or page results.
    paging: CursorPaging! = { first: 10 }

    # Specify to filter the records returned.
    filter: TodoItemFilter! = {}

    # Specify to sort results.
    sorting: [TodoItemSort!]! = []
  ): TodoItemConnection!
}

input CursorPaging {
  # Paginate before opaque cursor
  before: ConnectionCursor

  # Paginate after opaque cursor
  after: ConnectionCursor

  # Paginate first
  first: Int

  # Paginate last
  last: Int
}

input TodoItemFilter {
  and: [TodoItemFilter!]
  or: [TodoItemFilter!]
  firstId: IDFilterComparison
  secondId: IDFilterComparison
  title: StringFieldComparison
}

input IDFilterComparison {
  is: Boolean
  isNot: Boolean
  eq: ID
  neq: ID
  gt: ID
  gte: ID
  lt: ID
  lte: ID
  like: ID
  notLike: ID
  iLike: ID
  notILike: ID
  in: [ID!]
  notIn: [ID!]
}

input StringFieldComparison {
  is: Boolean
  isNot: Boolean
  eq: String
  neq: String
  gt: String
  gte: String
  lt: String
  lte: String
  like: String
  notLike: String
  iLike: String
  notILike: String
  in: [String!]
  notIn: [String!]
}

input TodoItemSort {
  field: TodoItemSortFields!
  direction: SortDirection!
  nulls: SortNulls
}

enum TodoItemSortFields {
  firstId
  secondId
  title
}

# Sort Directions
enum SortDirection {
  ASC
  DESC
}

# Sort Nulls Options
enum SortNulls {
  NULLS_FIRST
  NULLS_LAST
}

type Mutation {
  createOneTodoItem(input: CreateOneTodoItemInput!): TodoItem!
  createManyTodoItems(input: CreateManyTodoItemsInput!): [TodoItem!]!
  updateOneTodoItem(input: UpdateOneTodoItemInput!): TodoItem!
  updateManyTodoItems(input: UpdateManyTodoItemsInput!): UpdateManyResponse!
  deleteOneTodoItem(input: DeleteOneTodoItemInput!): TodoItemDeleteResponse!
  deleteManyTodoItems(input: DeleteManyTodoItemsInput!): DeleteManyResponse!
}

input CreateOneTodoItemInput {
  # The record to create
  todoItem: CreateTodoItem!
}

input CreateTodoItem {
  firstId: ID!
  secondId: ID!
  title: String!
}

input CreateManyTodoItemsInput {
  # Array of records to create
  todoItems: [CreateTodoItem!]!
}

input UpdateOneTodoItemInput {
  # The id of the record to update
  id: ID!

  # The update to apply.
  update: UpdateTodoItem!
}

input UpdateTodoItem {
  firstId: ID
  secondId: ID
  title: String
}

input UpdateManyTodoItemsInput {
  # Filter used to find fields to update
  filter: TodoItemUpdateFilter!

  # The update to apply to all records found using the filter
  update: UpdateTodoItem!
}

input TodoItemUpdateFilter {
  and: [TodoItemUpdateFilter!]
  or: [TodoItemUpdateFilter!]
  firstId: IDFilterComparison
  secondId: IDFilterComparison
  title: StringFieldComparison
}

input DeleteOneTodoItemInput {
  # The id of the record to delete.
  id: ID!
}

input DeleteManyTodoItemsInput {
  # Filter to find records to delete
  filter: TodoItemDeleteFilter!
}

input TodoItemDeleteFilter {
  and: [TodoItemDeleteFilter!]
  or: [TodoItemDeleteFilter!]
  firstId: IDFilterComparison
  secondId: IDFilterComparison
  title: StringFieldComparison
}

I would expect something like:

type Query {
  todoItem(
-    # The id of the record to find.
-    id: ID!
+    firstId: ID!
+    secondId: ID!
  ): TodoItem!
}

input UpdateOneTodoItemInput {
-  # The id of the record to update
-  id: ID!
+  firstId: ID!
+  secondId: ID!

  # The update to apply.
  update: UpdateTodoItem!
}

input DeleteOneTodoItemInput {
-  # The id of the record to delete.
-  id: ID!
+  firstId: ID!
+  secondId: ID!
}

Desktop (please complete the following information):

  • Node Version: v22.2.0
  • @ptc-org/nestjs-query-core: ^6.1.0,
  • @ptc-org/nestjs-query-graphql: ^6.1.0,
  • @ptc-org/nestjs-query-typeorm: ^6.1.0,

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions