fix: transactionID isolation for GraphQL (#4095)
This commit is contained in:
59
test/custom-graphql/config.ts
Normal file
59
test/custom-graphql/config.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { commitTransaction } from '../../packages/payload/src/utilities/commitTransaction'
|
||||
import { initTransaction } from '../../packages/payload/src/utilities/initTransaction'
|
||||
import { killTransaction } from '../../packages/payload/src/utilities/killTransaction'
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults'
|
||||
import { devUser } from '../credentials'
|
||||
|
||||
const resolveTransactionId = async (_obj, _args, context) => {
|
||||
try {
|
||||
const shouldCommit = await initTransaction(context.req)
|
||||
const transactionID = context.req.transactionID
|
||||
if (shouldCommit) {
|
||||
await commitTransaction(context.req)
|
||||
}
|
||||
return transactionID ? String(transactionID) : null
|
||||
} catch (e) {
|
||||
await killTransaction(context.req)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
collections: [],
|
||||
globals: [],
|
||||
graphQL: {
|
||||
queries: (GraphQL) => {
|
||||
return {
|
||||
TransactionID1: {
|
||||
type: GraphQL.GraphQLString,
|
||||
resolve: resolveTransactionId,
|
||||
},
|
||||
TransactionID2: {
|
||||
type: GraphQL.GraphQLString,
|
||||
resolve: resolveTransactionId,
|
||||
},
|
||||
}
|
||||
},
|
||||
mutations: (GraphQL) => {
|
||||
return {
|
||||
MutateTransactionID1: {
|
||||
type: GraphQL.GraphQLString,
|
||||
resolve: resolveTransactionId,
|
||||
},
|
||||
MutateTransactionID2: {
|
||||
type: GraphQL.GraphQLString,
|
||||
resolve: resolveTransactionId,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
await payload.create({
|
||||
collection: 'users',
|
||||
data: {
|
||||
email: devUser.email,
|
||||
password: devUser.password,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
42
test/custom-graphql/int.spec.ts
Normal file
42
test/custom-graphql/int.spec.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { GraphQLClient } from 'graphql-request'
|
||||
|
||||
import { initPayloadTest } from '../helpers/configHelpers'
|
||||
import configPromise from './config'
|
||||
|
||||
let client: GraphQLClient
|
||||
|
||||
describe('Custom GraphQL', () => {
|
||||
beforeAll(async () => {
|
||||
const { serverURL } = await initPayloadTest({ __dirname, init: { local: false } })
|
||||
const config = await configPromise
|
||||
const url = `${serverURL}${config.routes.api}${config.routes.graphQL}`
|
||||
client = new GraphQLClient(url)
|
||||
})
|
||||
|
||||
describe('Isolated Transaction ID', () => {
|
||||
it('should isolate transaction IDs between queries in the same request', async () => {
|
||||
const query = `query {
|
||||
TransactionID1
|
||||
TransactionID2
|
||||
}`
|
||||
const response = await client.request(query)
|
||||
// either no transactions at all or they are different
|
||||
expect(
|
||||
(response.TransactionID2 === null && response.TransactionID1 === null) ||
|
||||
response.TransactionID2 !== response.TransactionID1,
|
||||
).toBe(true)
|
||||
})
|
||||
it('should isolate transaction IDs between mutations in the same request', async () => {
|
||||
const query = `mutation {
|
||||
MutateTransactionID1
|
||||
MutateTransactionID2
|
||||
}`
|
||||
const response = await client.request(query)
|
||||
// either no transactions at all or they are different
|
||||
expect(
|
||||
(response.MutateTransactionID2 === null && response.MutateTransactionID1 === null) ||
|
||||
response.MutateTransactionID2 !== response.MutateTransactionID1,
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
59
test/custom-graphql/payload-types.ts
Normal file
59
test/custom-graphql/payload-types.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* This file was automatically generated by Payload.
|
||||
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
|
||||
* and re-run `payload generate:types` to regenerate this file.
|
||||
*/
|
||||
|
||||
export interface Config {
|
||||
collections: {
|
||||
users: User
|
||||
'payload-preferences': PayloadPreference
|
||||
'payload-migrations': PayloadMigration
|
||||
}
|
||||
globals: {}
|
||||
}
|
||||
export interface User {
|
||||
id: string
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
email: string
|
||||
resetPasswordToken?: string | null
|
||||
resetPasswordExpiration?: string | null
|
||||
salt?: string | null
|
||||
hash?: string | null
|
||||
loginAttempts?: number | null
|
||||
lockUntil?: string | null
|
||||
password: string | null
|
||||
}
|
||||
export interface PayloadPreference {
|
||||
id: string
|
||||
user: {
|
||||
relationTo: 'users'
|
||||
value: string | User
|
||||
}
|
||||
key?: string | null
|
||||
value?:
|
||||
| {
|
||||
[k: string]: unknown
|
||||
}
|
||||
| unknown[]
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
}
|
||||
export interface PayloadMigration {
|
||||
id: string
|
||||
name?: string | null
|
||||
batch?: number | null
|
||||
updatedAt: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
declare module 'payload' {
|
||||
export interface GeneratedTypes extends Config {}
|
||||
}
|
||||
Reference in New Issue
Block a user