diff --git a/docs/docs/cli-commands.md b/docs/docs/cli-commands.md index 623a3f4c6120..ad4b1575baa4 100644 --- a/docs/docs/cli-commands.md +++ b/docs/docs/cli-commands.md @@ -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 | @@ -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 @@ -1088,7 +1088,7 @@ export const schema = gql` } type Query { - users: [User!]! + users: [User!]! @requireAuth } input CreateUserInput { @@ -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 @@ -1129,7 +1135,7 @@ export const schema = gql` } type Query { - users: [User!]! + users: [User!]! @requireAuth } input CreateUserInput { @@ -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 + } ` ``` diff --git a/packages/cli/src/commands/generate/scaffold/scaffold.js b/packages/cli/src/commands/generate/scaffold/scaffold.js index c752445af78e..1c84585375fa 100644 --- a/packages/cli/src/commands/generate/scaffold/scaffold.js +++ b/packages/cli/src/commands/generate/scaffold/scaffold.js @@ -158,7 +158,6 @@ export const files = async ({ ...(await sdlFiles({ ...getDefaultArgs(sdlBuilder), name, - crud: true, typescript, })), ...(await serviceFiles({ diff --git a/packages/cli/src/commands/generate/sdl/__tests__/__snapshots__/sdl.test.js.snap b/packages/cli/src/commands/generate/sdl/__tests__/__snapshots__/sdl.test.js.snap index aa8f12afb1a3..9ebb851276f3 100644 --- a/packages/cli/src/commands/generate/sdl/__tests__/__snapshots__/sdl.test.js.snap +++ b/packages/cli/src/commands/generate/sdl/__tests__/__snapshots__/sdl.test.js.snap @@ -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 { @@ -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 + } \` " `; @@ -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 { @@ -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 + } \` " `; diff --git a/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js b/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js index 6614099bd88a..b4e6c4e06ab7 100644 --- a/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js +++ b/packages/cli/src/commands/generate/sdl/__tests__/sdl.test.js @@ -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( diff --git a/packages/cli/src/commands/generate/sdl/sdl.js b/packages/cli/src/commands/generate/sdl/sdl.js index 75f2e36fabc9..125fff74571b 100644 --- a/packages/cli/src/commands/generate/sdl/sdl.js +++ b/packages/cli/src/commands/generate/sdl/sdl.js @@ -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) @@ -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', }, diff --git a/packages/cli/src/commands/generate/service/__tests__/__snapshots__/service.test.js.snap b/packages/cli/src/commands/generate/service/__tests__/__snapshots__/service.test.js.snap index 0ee84fa2f6b4..f1f2529f88d3 100644 --- a/packages/cli/src/commands/generate/service/__tests__/__snapshots__/service.test.js.snap +++ b/packages/cli/src/commands/generate/service/__tests__/__snapshots__/service.test.js.snap @@ -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 }, + }) +} " `; @@ -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. @@ -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) + }) }) " `; @@ -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 }, + }) +} " `; @@ -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 @@ -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) + }) }) " `; diff --git a/packages/cli/src/commands/generate/service/__tests__/service.test.js b/packages/cli/src/commands/generate/service/__tests__/service.test.js index e3111af8c7c2..59181de1ead9 100644 --- a/packages/cli/src/commands/generate/service/__tests__/service.test.js +++ b/packages/cli/src/commands/generate/service/__tests__/service.test.js @@ -78,6 +78,7 @@ const itCreatesAMultiWordServiceFile = (baseArgs) => { const files = await service.files({ ...baseArgs, name: 'UserProfile', + crud: false, }) const extension = extensionForBaseArgs(baseArgs) @@ -96,6 +97,7 @@ const itCreatesAMultiWordServiceTestFile = (baseArgs) => { const files = await service.files({ ...baseArgs, name: 'UserProfile', + crud: false, }) const extension = extensionForBaseArgs(baseArgs) @@ -185,6 +187,7 @@ const itCreatesASingleWordServiceFileWithAHasManyRelation = (baseArgs) => { ...baseArgs, name: 'User', relations: ['userProfiles'], + crud: false, }) const extension = extensionForBaseArgs(baseArgs) @@ -204,6 +207,7 @@ const itCreatesASingleWordServiceFileWithABelongsToRelation = (baseArgs) => { ...baseArgs, name: 'User', relations: ['identity'], + crud: false, }) const extension = extensionForBaseArgs(baseArgs) @@ -223,6 +227,7 @@ const itCreatesASingleWordServiceFileWithMultipleRelations = (baseArgs) => { ...baseArgs, name: 'User', relations: ['userProfiles', 'identity'], + crud: false, }) const extension = extensionForBaseArgs(baseArgs) diff --git a/packages/cli/src/commands/generate/service/service.js b/packages/cli/src/commands/generate/service/service.js index d4fd458623fc..1ac9e654234d 100644 --- a/packages/cli/src/commands/generate/service/service.js +++ b/packages/cli/src/commands/generate/service/service.js @@ -333,7 +333,7 @@ export const defaults = { type: 'boolean', }, crud: { - default: false, + default: true, description: 'Create CRUD functions', type: 'boolean', },