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

Generate CRUD by default for SDL and Services to mitigate issues in GraphQL used in cells #4785

Merged
merged 10 commits into from
Mar 18, 2022
22 changes: 17 additions & 5 deletions docs/docs/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,7 @@ https://community.redwoodjs.com/t/prisma-beta-2-and-redwoodjs-limited-generator-
| Arguments & Options | Description |
| -------------------- | ------------------------------------------------------------------------------------ |
| `model` | Model to generate the sdl for |
| `--crud` | Also generate mutations |
| `--crud` | Set to `false`, or use `--no-crud`, if you do not want to generate mutations |
| `--force, -f` | Overwrite existing files |
| `--tests` | Generate service test and scenario [default: true] |
| `--typescript, --ts` | Generate TypeScript files Enabled by default if we detect your project is TypeScript |
Expand Down Expand Up @@ -1075,7 +1075,7 @@ $ /redwood-app/node_modules/.bin/redwood g sdl user
Done in 1.04s.
```

The generated sdl defines a corresponding type, query, and create/update inputs, without defining any mutations. To also get mutations, add the `--crud` option.
The generated sdl defines a corresponding type, query, create/update inputs, and any mutations. To prevent defining mutations, add the `--no-crud` option.

```javascript
// ./api/src/graphql/users.sdl.js
Expand All @@ -1088,7 +1088,7 @@ export const schema = gql`
}

type Query {
users: [User!]!
users: [User!]! @requireAuth
}

input CreateUserInput {
Expand All @@ -1100,10 +1100,16 @@ export const schema = gql`
email: String
name: String
}

type Mutation {
createUser(input: CreateUserInput!): User! @requireAuth
updateUser(id: Int!, input: UpdateUserInput!): User! @requireAuth
deleteUser(id: Int!): User! @requireAuth
}
`
```

The services file fulfills the query. If the `--crud` option is added, this file will be much more complex.
The services file fulfills the query. If the `--no-crud` option is added, this file will be less complex.

```javascript
// ./api/src/services/users/users.js
Expand All @@ -1129,7 +1135,7 @@ export const schema = gql`
}

type Query {
users: [User!]!
users: [User!]! @requireAuth
}

input CreateUserInput {
Expand All @@ -1141,6 +1147,12 @@ export const schema = gql`
email: String
name: String
}

type Mutation {
createUser(input: CreateUserInput!): User! @requireAuth
updateUser(id: Int!, input: UpdateUserInput!): User! @requireAuth
deleteUser(id: Int!): User! @requireAuth
}
`
```

Expand Down
1 change: 0 additions & 1 deletion packages/cli/src/commands/generate/scaffold/scaffold.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ export const files = async ({
...(await sdlFiles({
...getDefaultArgs(sdlBuilder),
name,
crud: true,
typescript,
})),
...(await serviceFiles({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ exports[`in javascript mode creates a multi word sdl file 1`] = `

type Query {
userProfiles: [UserProfile!]! @requireAuth
userProfile(id: Int!): UserProfile @requireAuth
}

input CreateUserProfileInput {
Expand All @@ -600,6 +601,13 @@ exports[`in javascript mode creates a multi word sdl file 1`] = `
username: String
userId: Int
}

type Mutation {
createUserProfile(input: CreateUserProfileInput!): UserProfile! @requireAuth
updateUserProfile(id: Int!, input: UpdateUserProfileInput!): UserProfile!
@requireAuth
deleteUserProfile(id: Int!): UserProfile! @requireAuth
}
\`
"
`;
Expand Down Expand Up @@ -789,6 +797,7 @@ exports[`in typescript mode creates a multi word sdl file 1`] = `

type Query {
userProfiles: [UserProfile!]! @requireAuth
userProfile(id: Int!): UserProfile @requireAuth
}

input CreateUserProfileInput {
Expand All @@ -800,6 +809,13 @@ exports[`in typescript mode creates a multi word sdl file 1`] = `
username: String
userId: Int
}

type Mutation {
createUserProfile(input: CreateUserProfileInput!): UserProfile! @requireAuth
updateUserProfile(id: Int!, input: UpdateUserProfileInput!): UserProfile!
@requireAuth
deleteUserProfile(id: Int!): UserProfile! @requireAuth
}
\`
"
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const itCreatesAService = (baseArgs = {}) => {

const itCreatesASingleWordSDLFile = (baseArgs = {}) => {
test('creates a single word sdl file', async () => {
const files = await sdl.files({ ...baseArgs, name: 'User' })
const files = await sdl.files({ ...baseArgs, name: 'User', crud: false })
const extension = extensionForBaseArgs(baseArgs)

expect(
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/generate/sdl/sdl.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ const sdlFromSchemaModel = async (name, crud) => {
}
}

export const files = async ({ name, crud, tests, typescript }) => {
export const files = async ({ name, crud = true, tests, typescript }) => {
const { query, createInput, updateInput, idType, relations, enums } =
await sdlFromSchemaModel(name, crud)

Expand Down Expand Up @@ -182,7 +182,7 @@ export const files = async ({ name, crud, tests, typescript }) => {
export const defaults = {
...yargsDefaults,
crud: {
default: false,
default: true,
description: 'Also generate mutations',
type: 'boolean',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,31 @@ exports[`in javascript mode creates a single word service file 1`] = `
export const users = () => {
return db.user.findMany()
}

export const user = ({ id }) => {
return db.user.findUnique({
where: { id },
})
}

export const createUser = ({ input }) => {
return db.user.create({
data: input,
})
}

export const updateUser = ({ id, input }) => {
return db.user.update({
data: input,
where: { id },
})
}

export const deleteUser = ({ id }) => {
return db.user.delete({
where: { id },
})
}
"
`;

Expand Down Expand Up @@ -203,7 +228,7 @@ exports[`in javascript mode creates a single word service scenario file 1`] = `
`;

exports[`in javascript mode creates a single word service test file 1`] = `
"import { users } from './users'
"import { users, user, createUser, updateUser, deleteUser } from './users'

// Generated boilerplate tests do not account for all circumstances
// and can fail without adjustments, e.g. Float and DateTime types.
Expand All @@ -217,6 +242,37 @@ describe('users', () => {

expect(result.length).toEqual(Object.keys(scenario.user).length)
})

scenario('returns a single user', async (scenario) => {
const result = await user({ id: scenario.user.one.id })

expect(result).toEqual(scenario.user.one)
})

scenario('creates a user', async () => {
const result = await createUser({
input: { email: 'String1234567' },
})

expect(result.email).toEqual('String1234567')
})

scenario('updates a user', async (scenario) => {
const original = await user({ id: scenario.user.one.id })
const result = await updateUser({
id: original.id,
input: { email: 'String12345672' },
})

expect(result.email).toEqual('String12345672')
})

scenario('deletes a user', async (scenario) => {
const original = await deleteUser({ id: scenario.user.one.id })
const result = await user({ id: original.id })

expect(result).toEqual(null)
})
})
"
`;
Expand Down Expand Up @@ -313,11 +369,46 @@ describe('transactions', () => {
`;

exports[`in typescript mode creates a single word service file 1`] = `
"import { db } from 'src/lib/db'
"import type { Prisma } from '@prisma/client'

import { db } from 'src/lib/db'

export const users = () => {
return db.user.findMany()
}

export const user = ({ id }: Prisma.UserWhereUniqueInput) => {
return db.user.findUnique({
where: { id },
})
}

interface CreateUserArgs {
input: Prisma.UserCreateInput
}

export const createUser = ({ input }: CreateUserArgs) => {
return db.user.create({
data: input,
})
}

interface UpdateUserArgs extends Prisma.UserWhereUniqueInput {
input: Prisma.UserUpdateInput
}

export const updateUser = ({ id, input }: UpdateUserArgs) => {
return db.user.update({
data: input,
where: { id },
})
}

export const deleteUser = ({ id }: Prisma.UserWhereUniqueInput) => {
return db.user.delete({
where: { id },
})
}
"
`;

Expand Down Expand Up @@ -451,7 +542,7 @@ export type StandardScenario = typeof standard
`;

exports[`in typescript mode creates a single word service test file 1`] = `
"import { users } from './users'
"import { users, user, createUser, updateUser, deleteUser } from './users'
import type { StandardScenario } from './users.scenarios'

// Generated boilerplate tests do not account for all circumstances
Expand All @@ -466,6 +557,37 @@ describe('users', () => {

expect(result.length).toEqual(Object.keys(scenario.user).length)
})

scenario('returns a single user', async (scenario: StandardScenario) => {
const result = await user({ id: scenario.user.one.id })

expect(result).toEqual(scenario.user.one)
})

scenario('creates a user', async () => {
const result = await createUser({
input: { email: 'String1234567' },
})

expect(result.email).toEqual('String1234567')
})

scenario('updates a user', async (scenario: StandardScenario) => {
const original = await user({ id: scenario.user.one.id })
const result = await updateUser({
id: original.id,
input: { email: 'String12345672' },
})

expect(result.email).toEqual('String12345672')
})

scenario('deletes a user', async (scenario: StandardScenario) => {
const original = await deleteUser({ id: scenario.user.one.id })
const result = await user({ id: original.id })

expect(result).toEqual(null)
})
})
"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const itCreatesAMultiWordServiceFile = (baseArgs) => {
const files = await service.files({
...baseArgs,
name: 'UserProfile',
crud: false,
})
const extension = extensionForBaseArgs(baseArgs)

Expand All @@ -96,6 +97,7 @@ const itCreatesAMultiWordServiceTestFile = (baseArgs) => {
const files = await service.files({
...baseArgs,
name: 'UserProfile',
crud: false,
})
const extension = extensionForBaseArgs(baseArgs)

Expand Down Expand Up @@ -185,6 +187,7 @@ const itCreatesASingleWordServiceFileWithAHasManyRelation = (baseArgs) => {
...baseArgs,
name: 'User',
relations: ['userProfiles'],
crud: false,
})
const extension = extensionForBaseArgs(baseArgs)

Expand All @@ -204,6 +207,7 @@ const itCreatesASingleWordServiceFileWithABelongsToRelation = (baseArgs) => {
...baseArgs,
name: 'User',
relations: ['identity'],
crud: false,
})
const extension = extensionForBaseArgs(baseArgs)

Expand All @@ -223,6 +227,7 @@ const itCreatesASingleWordServiceFileWithMultipleRelations = (baseArgs) => {
...baseArgs,
name: 'User',
relations: ['userProfiles', 'identity'],
crud: false,
})
const extension = extensionForBaseArgs(baseArgs)

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/commands/generate/service/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export const defaults = {
type: 'boolean',
},
crud: {
default: false,
default: true,
description: 'Create CRUD functions',
type: 'boolean',
},
Expand Down