Composite primary keys generating an incorrect schema #267
Open
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,