1
- import { Request , Response } from "express" ;
2
- import { ExecutionResult , graphql , GraphQLSchema } from "graphql" ;
3
- import { Pool , PoolClient } from "pg" ;
1
+ import { makeWithPgClientViaPgClientAlreadyInTransaction } from "@dataplan/pg/adaptors/pg" ;
2
+ import { execute , hookArgs } from "grafast" ;
4
3
import {
5
- createPostGraphileSchema ,
6
- PostGraphileOptions ,
7
- withPostGraphileContext ,
8
- } from "postgraphile" ;
4
+ ExecutionArgs ,
5
+ ExecutionResult ,
6
+ GraphQLSchema ,
7
+ parse ,
8
+ validate ,
9
+ } from "graphql" ;
10
+ import { Pool , PoolClient } from "pg" ;
11
+ import { postgraphile , PostGraphileInstance } from "postgraphile" ;
9
12
10
13
import {
11
14
createSession ,
12
15
createUsers ,
13
16
poolFromUrl ,
14
17
} from "../../__tests__/helpers" ;
15
- import { getPostGraphileOptions } from "../src/graphile.config" ;
18
+ import { getPreset } from "../src/graphile.config" ;
16
19
17
20
export * from "../../__tests__/helpers" ;
18
21
@@ -96,7 +99,7 @@ export function sanitize(json: any): any {
96
99
// Contains the PostGraphile schema and rootPgPool
97
100
interface ICtx {
98
101
rootPgPool : Pool ;
99
- options : PostGraphileOptions < Request , Response > ;
102
+ pgl : PostGraphileInstance ;
100
103
schema : GraphQLSchema ;
101
104
}
102
105
let ctx : ICtx | null = null ;
@@ -106,17 +109,14 @@ export const setup = async () => {
106
109
connectionString : process . env . TEST_DATABASE_URL ,
107
110
} ) ;
108
111
109
- const options = getPostGraphileOptions ( { rootPgPool } ) ;
110
- const schema = await createPostGraphileSchema (
111
- rootPgPool ,
112
- "app_public" ,
113
- options
114
- ) ;
112
+ const preset = getPreset ( { rootPgPool, authPgPool : rootPgPool } ) ;
113
+ const pgl = postgraphile ( preset ) ;
114
+ const schema = await pgl . getSchema ( ) ;
115
115
116
116
// Store the context
117
117
ctx = {
118
118
rootPgPool,
119
- options ,
119
+ pgl ,
120
120
schema,
121
121
} ;
122
122
} ;
@@ -146,9 +146,10 @@ export const runGraphQLQuery = async function runGraphQLQuery(
146
146
) => void | ExecutionResult | Promise < void | ExecutionResult > = ( ) => { } // Place test assertions in this function
147
147
) {
148
148
if ( ! ctx ) throw new Error ( "No ctx!" ) ;
149
- const { schema, rootPgPool, options } = ctx ;
149
+ const { schema, rootPgPool, pgl } = ctx ;
150
+ const resolvedPreset = pgl . getResolvedPreset ( ) ;
150
151
const req = new MockReq ( {
151
- url : options . graphqlRoute || "/graphql" ,
152
+ url : resolvedPreset . grafserv ?. graphqlPath || "/graphql" ,
152
153
method : "POST" ,
153
154
headers : {
154
155
Accept : "application/json" ,
@@ -159,92 +160,91 @@ export const runGraphQLQuery = async function runGraphQLQuery(
159
160
const res : any = { req } ;
160
161
req . res = res ;
161
162
162
- const {
163
- pgSettings : pgSettingsGenerator ,
164
- additionalGraphQLContextFromRequest,
165
- } = options ;
166
- const pgSettings =
167
- ( typeof pgSettingsGenerator === "function"
168
- ? await pgSettingsGenerator ( req )
169
- : pgSettingsGenerator ) || { } ;
163
+ let checkResult : ExecutionResult | void ;
164
+ const document = parse ( query ) ;
165
+ const errors = validate ( schema , document ) ;
166
+ if ( errors . length > 0 ) {
167
+ throw errors [ 0 ] ;
168
+ }
169
+ const args : ExecutionArgs = {
170
+ schema,
171
+ document,
172
+ contextValue : {
173
+ __TESTING : true ,
174
+ } ,
175
+ variableValues : variables ,
176
+ } ;
177
+ await hookArgs (
178
+ args ,
179
+ { node : { req, res } , expressv4 : { req, res } } ,
180
+ resolvedPreset
181
+ ) ;
170
182
171
183
// Because we're connected as the database owner, we should manually switch to
172
184
// the authenticator role
173
- if ( ! pgSettings . role ) {
174
- pgSettings . role = process . env . DATABASE_AUTHENTICATOR ;
185
+ const context = args . contextValue as Grafast . Context ;
186
+ if ( ! context . pgSettings ?. role ) {
187
+ context . pgSettings = context . pgSettings ?? { } ;
188
+ context . pgSettings . role = process . env . DATABASE_AUTHENTICATOR as string ;
175
189
}
176
190
177
- await withPostGraphileContext (
178
- {
179
- ...options ,
180
- pgPool : rootPgPool ,
181
- pgSettings,
182
- pgForceTransaction : true ,
183
- } ,
184
- async ( context ) => {
185
- let checkResult ;
186
- const { pgClient } = context ;
187
- try {
188
- // This runs our GraphQL query, passing the replacement client
189
- const additionalContext = additionalGraphQLContextFromRequest
190
- ? await additionalGraphQLContextFromRequest ( req , res )
191
- : null ;
192
- const result = await graphql (
193
- schema ,
194
- query ,
195
- null ,
196
- {
197
- ...context ,
198
- ...additionalContext ,
199
- __TESTING : true ,
200
- } ,
201
- variables
202
- ) ;
203
- // Expand errors
204
- if ( result . errors ) {
205
- if ( options . handleErrors ) {
206
- result . errors = options . handleErrors ( result . errors ) ;
207
- } else {
208
- // This does a similar transform that PostGraphile does to errors.
209
- // It's not the same. Sorry.
210
- result . errors = result . errors . map ( ( rawErr ) => {
211
- const e = Object . create ( rawErr ) ;
212
- Object . defineProperty ( e , "originalError" , {
213
- value : rawErr . originalError ,
214
- enumerable : false ,
215
- } ) ;
216
-
217
- if ( e . originalError ) {
218
- Object . keys ( e . originalError ) . forEach ( ( k ) => {
219
- try {
220
- e [ k ] = e . originalError [ k ] ;
221
- } catch ( err ) {
222
- // Meh.
223
- }
224
- } ) ;
191
+ const pgClient = await rootPgPool . connect ( ) ;
192
+ try {
193
+ await pgClient . query ( "begin" ) ;
194
+
195
+ // Override withPgClient with a transactional version for the tests
196
+ const withPgClient = makeWithPgClientViaPgClientAlreadyInTransaction (
197
+ pgClient ,
198
+ true
199
+ ) ;
200
+ context . withPgClient = withPgClient ;
201
+
202
+ const result = ( await execute ( args , resolvedPreset ) ) as ExecutionResult ;
203
+ // Expand errors
204
+ if ( result . errors ) {
205
+ if ( resolvedPreset . grafserv ?. maskError ) {
206
+ result . errors = result . errors . map ( resolvedPreset . grafserv . maskError ) ;
207
+ } else {
208
+ // This does a similar transform that PostGraphile does to errors.
209
+ // It's not the same. Sorry.
210
+ result . errors = result . errors . map ( ( rawErr ) => {
211
+ const e = Object . create ( rawErr ) ;
212
+ Object . defineProperty ( e , "originalError" , {
213
+ value : rawErr . originalError ,
214
+ enumerable : false ,
215
+ } ) ;
216
+
217
+ if ( e . originalError ) {
218
+ Object . keys ( e . originalError ) . forEach ( ( k ) => {
219
+ try {
220
+ e [ k ] = e . originalError [ k ] ;
221
+ } catch ( err ) {
222
+ // Meh.
225
223
}
226
- return e ;
227
224
} ) ;
228
225
}
229
- }
230
-
231
- // This is were we call the `checker` so you can do your assertions.
232
- // Also note that we pass the `replacementPgClient` so that you can
233
- // query the data in the database from within the transaction before it
234
- // gets rolled back.
235
- checkResult = await checker ( result , {
236
- pgClient,
226
+ return e ;
237
227
} ) ;
228
+ }
229
+ }
238
230
239
- // You don't have to keep this, I just like knowing when things change!
240
- expect ( sanitize ( result ) ) . toMatchSnapshot ( ) ;
231
+ // This is were we call the `checker` so you can do your assertions.
232
+ // Also note that we pass the `replacementPgClient` so that you can
233
+ // query the data in the database from within the transaction before it
234
+ // gets rolled back.
235
+ checkResult = await checker ( result , {
236
+ pgClient,
237
+ } ) ;
241
238
242
- return checkResult == null ? result : checkResult ;
243
- } finally {
244
- // Rollback the transaction so no changes are written to the DB - this
245
- // makes our tests fairly deterministic.
246
- await pgClient . query ( "rollback" ) ;
247
- }
239
+ // You don't have to keep this, I just like knowing when things change!
240
+ expect ( sanitize ( result ) ) . toMatchSnapshot ( ) ;
241
+
242
+ return checkResult == null ? result : checkResult ;
243
+ } finally {
244
+ try {
245
+ await pgClient . query ( "rollback" ) ;
246
+ } finally {
247
+ pgClient . release ( ) ;
248
248
}
249
- ) ;
249
+ }
250
250
} ;
0 commit comments