Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): Support generating sdls for models with only an id and relation #11931

Merged
merged 2 commits into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changesets/11931.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
- feat(cli): Support generating sdls for models with only an id and relation (#11931) by @Tobbe

It's now possible to generate SDL files for models that look like this

```prisma
// This would be seeded with available car brands
model CarBrand {
brand String @id
cars Car[]
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -1572,6 +1572,66 @@ exports[`with graphql documentations > in typescript mode > creates a single wor
"
`;

exports[`without graphql documentations > in javascript mode > create an sdl file for model with only id and relation 1`] = `
"export const schema = gql\`
type Car {
id: Int!
brand: String!
carBrand: CarBrand!
}

type Query {
cars: [Car!]! @requireAuth
car(id: Int!): Car @requireAuth
}

input CreateCarInput {
brand: String!
}

input UpdateCarInput {
brand: String
}

type Mutation {
createCar(input: CreateCarInput!): Car! @requireAuth
updateCar(id: Int!, input: UpdateCarInput!): Car! @requireAuth
deleteCar(id: Int!): Car! @requireAuth
}
\`
"
`;

exports[`without graphql documentations > in javascript mode > create an sdl file for model with only id and relation 2`] = `
"export const schema = gql\`
type CarBrand {
brand: String!
cars: [Car]!
}

type Query {
carBrands: [CarBrand!]! @requireAuth
carBrand(brand: String!): CarBrand @requireAuth
}

input CreateCarBrandInput {
brand: String!
}

input UpdateCarBrandInput {
brand: String!
}

type Mutation {
createCarBrand(input: CreateCarBrandInput!): CarBrand! @requireAuth
updateCarBrand(brand: String!, input: UpdateCarBrandInput!): CarBrand!
@requireAuth
deleteCarBrand(brand: String!): CarBrand! @requireAuth
}
\`
"
`;

exports[`without graphql documentations > in javascript mode > creates a multi word sdl file 1`] = `
"export const schema = gql\`
type UserProfile {
Expand Down Expand Up @@ -1809,6 +1869,66 @@ exports[`without graphql documentations > in javascript mode > creates a single
"
`;

exports[`without graphql documentations > in typescript mode > create an sdl file for model with only id and relation 1`] = `
"export const schema = gql\`
type Car {
id: Int!
brand: String!
carBrand: CarBrand!
}

type Query {
cars: [Car!]! @requireAuth
car(id: Int!): Car @requireAuth
}

input CreateCarInput {
brand: String!
}

input UpdateCarInput {
brand: String
}

type Mutation {
createCar(input: CreateCarInput!): Car! @requireAuth
updateCar(id: Int!, input: UpdateCarInput!): Car! @requireAuth
deleteCar(id: Int!): Car! @requireAuth
}
\`
"
`;

exports[`without graphql documentations > in typescript mode > create an sdl file for model with only id and relation 2`] = `
"export const schema = gql\`
type CarBrand {
brand: String!
cars: [Car]!
}

type Query {
carBrands: [CarBrand!]! @requireAuth
carBrand(brand: String!): CarBrand @requireAuth
}

input CreateCarBrandInput {
brand: String!
}

input UpdateCarBrandInput {
brand: String!
}

type Mutation {
createCarBrand(input: CreateCarBrandInput!): CarBrand! @requireAuth
updateCarBrand(brand: String!, input: UpdateCarBrandInput!): CarBrand!
@requireAuth
deleteCarBrand(brand: String!): CarBrand! @requireAuth
}
\`
"
`;

exports[`without graphql documentations > in typescript mode > creates a multi word sdl file 1`] = `
"export const schema = gql\`
type UserProfile {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@ enum Color {
}

model CustomData {
id Int @id @default(autoincrement())
data String
id Int @id @default(autoincrement())
data String
}

// This would be seeded with available car brands
model CarBrand {
brand String @id
cars Car[]
}

model Car {
id Int @id @default(autoincrement())
brand String
carBrand CarBrand @relation(fields: [brand], references: [brand])
}
33 changes: 33 additions & 0 deletions packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,37 @@ const itCreatesAnSDLFileWithByteDefinitions = (baseArgs = {}) => {
})
}

const itCreatesAnSslFileForModelWithOnlyIdAndRelation = (baseArgs = {}) => {
test('create an sdl file for model with only id and relation', async () => {
const files = {
...(await sdl.files({
...baseArgs,
name: 'Car',
crud: true,
})),
...(await sdl.files({
...baseArgs,
name: 'CarBrand',
crud: true,
})),
}
const extension = extensionForBaseArgs(baseArgs)

expect(
files[
path.normalize(`/path/to/project/api/src/graphql/cars.sdl.${extension}`)
],
).toMatchSnapshot()
expect(
files[
path.normalize(
`/path/to/project/api/src/graphql/carBrands.sdl.${extension}`,
)
],
).toMatchSnapshot()
})
}

describe('without graphql documentations', () => {
describe('in javascript mode', () => {
const baseArgs = { ...getDefaultArgs(sdl.defaults), tests: true }
Expand All @@ -249,6 +280,7 @@ describe('without graphql documentations', () => {
itCreatesAnSDLFileWithEnumDefinitions(baseArgs)
itCreatesAnSDLFileWithJsonDefinitions(baseArgs)
itCreatesAnSDLFileWithByteDefinitions(baseArgs)
itCreatesAnSslFileForModelWithOnlyIdAndRelation(baseArgs)
})

describe('in typescript mode', () => {
Expand All @@ -267,6 +299,7 @@ describe('without graphql documentations', () => {
itCreatesAnSDLFileWithEnumDefinitions(baseArgs)
itCreatesAnSDLFileWithJsonDefinitions(baseArgs)
itCreatesAnSDLFileWithByteDefinitions(baseArgs)
itCreatesAnSslFileForModelWithOnlyIdAndRelation(baseArgs)
})
})

Expand Down
17 changes: 10 additions & 7 deletions packages/cli/src/commands/generate/sdl/sdl.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,13 @@ const modelFieldToSDL = ({
Bytes: 'Byte',
}

const fieldContent = `${field.name}: ${field.isList ? '[' : ''}${
prismaTypeToGraphqlType[field.type] || field.type
}${field.isList ? ']' : ''}${
(field.isRequired && required) | field.isList ? '!' : ''
}`
const gqlType = prismaTypeToGraphqlType[field.type] || field.type
const type = field.isList ? `[${gqlType}]` : gqlType
// lists and id fields are always required (lists can be empty, that's fine)
const isRequired =
(field.isRequired && required) || field.isList || field.isId
const fieldContent = `${field.name}: ${type}${isRequired ? '!' : ''}`

if (docs) {
return addFieldGraphQLComment(field, fieldContent)
} else {
Expand All @@ -98,7 +100,8 @@ const inputSDL = (model, required, types = {}, docs = false) => {
.filter((field) => {
const idField = model.fields.find((field) => field.isId)

if (idField) {
// Only ignore the id field if it has a default value
if (idField && idField.default) {
ignoredFields.push(idField.name)
}

Expand Down Expand Up @@ -162,7 +165,7 @@ const idName = (model, crud) => {
const sdlFromSchemaModel = async (name, crud, docs = false) => {
const model = await getSchema(name)

// get models for user-defined types referenced
// get models for referenced user-defined types
const types = (
await Promise.all(
model.fields
Expand Down
Loading