Skip to content

Commit

Permalink
feat(cli): Support generating sdls for models with only an id and rel…
Browse files Browse the repository at this point in the history
…ation (#11931)
  • Loading branch information
Tobbe authored Jan 25, 2025
1 parent a8d1c62 commit b144c6f
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 9 deletions.
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

0 comments on commit b144c6f

Please sign in to comment.