@@ -27,7 +27,6 @@ This package is the **canonical source** for PostGraphile query generation logic
2727- ** Query generators** — ` buildSelect ` , ` buildFindOne ` , ` buildCount ` for read operations
2828- ** Mutation generators** — ` buildPostGraphileCreate ` , ` buildPostGraphileUpdate ` , ` buildPostGraphileDelete `
2929- ** Introspection pipeline** — ` inferTablesFromIntrospection ` to convert a GraphQL schema into ` CleanTable ` metadata
30- - ** QueryBuilder** — fluent API for composing nested queries with filters and pagination
3130- ** AST builders** — low-level ` getAll ` , ` getMany ` , ` getOne ` , ` createOne ` , ` patchOne ` , ` deleteOne `
3231- ** Client utilities** — ` TypedDocumentString ` , ` execute ` , ` DataError ` for type-safe execution and error handling
3332- ** Naming helpers** — server-aware inflection functions that respect PostGraphile's schema naming
@@ -168,105 +167,55 @@ mutation deleteUserMutation($input: DeleteUserInput!) {
168167
169168---
170169
171- ## QueryBuilder (Fluent API)
170+ ## Nested Relations
172171
173- For more control over nested queries, filters, and pagination, use the ` QueryBuilder ` class :
172+ Include related tables in your query with automatic Connection wrapping for hasMany relations :
174173
175174``` ts
176- import { QueryBuilder } from ' @constructive-io/graphql-query' ;
175+ import { buildSelect } from ' @constructive-io/graphql-query' ;
177176
178- const builder = new QueryBuilder ({
179- introspection: { ... queries , ... mutations } // provide your GraphQL schema metadata
180- });
177+ const actionTable = tables .find (t => t .name === ' Action' )! ;
181178
182- const result = builder
183- .query (' Action' )
184- .edges (true )
185- .getMany ({
186- select: {
187- id: true ,
188- name: true ,
189- photo: true ,
190- title: true ,
191- actionResults: {
192- select: {
193- id: true ,
194- actionId: true
195- },
196- variables: {
197- first: 10 ,
198- before: null ,
199- filter: {
200- name: {
201- in: [' abc' , ' def' ]
202- },
203- actionId: {
204- equalTo: ' dc310161-7a42-4b93-6a56-9fa48adcad7e'
205- }
206- }
207- }
208- }
209- }
210- })
211- .print ();
179+ const query = buildSelect (actionTable , tables , {
180+ fieldSelection: {
181+ select: [' id' , ' name' , ' photo' , ' title' ],
182+ include: {
183+ actionResults: [' id' , ' actionId' ], // hasMany → wrapped in nodes { ... }
184+ category: true , // belongsTo → direct nesting
185+ },
186+ },
187+ });
212188```
213189
214190** Generated GraphQL:**
215191
216192``` graphql
217- query getActionsQuery (
218- $first : Int
219- $last : Int
220- $after : Cursor
221- $before : Cursor
222- $offset : Int
223- $condition : ActionCondition
224- $filter : ActionFilter
225- $orderBy : [ActionsOrderBy ! ]
226- ) {
227- actions (
228- first : $first
229- last : $last
230- offset : $offset
231- after : $after
232- before : $before
233- condition : $condition
234- filter : $filter
235- orderBy : $orderBy
236- ) {
193+ query actionsQuery {
194+ actions {
237195 totalCount
238- pageInfo {
239- hasNextPage
240- hasPreviousPage
241- endCursor
242- startCursor
243- }
244- edges {
245- cursor
246- node {
196+ nodes {
197+ id
198+ name
199+ photo
200+ title
201+ actionResults (first : 20 ) {
202+ nodes {
203+ id
204+ actionId
205+ }
206+ }
207+ category {
247208 id
248209 name
249- photo
250- title
251- actionResults (
252- first : 10
253- before : null
254- filter : {
255- name : { in : ["abc" , " def" ] }
256- actionId : { equalTo : " dc310161-7a42-4b93-6a56-9fa48adcad7e" }
257- }
258- ) {
259- nodes {
260- id
261- actionId
262- }
263- }
264210 }
265211 }
266212 }
267213}
268214```
269215
216+ > ** hasMany** relations are automatically wrapped in the PostGraphile Connection pattern (` nodes { ... } ` with a default ` first: 20 ` limit).
217+ > ** belongsTo** relations are nested directly.
218+
270219---
271220
272221## FindOne Query
@@ -319,15 +268,26 @@ query getUsersCountQuery(
319268
320269## Field Selection
321270
322- Control which fields and relations are included in the query :
271+ Control which fields and relations are included using presets or custom selection :
323272
324273``` ts
325274import { buildSelect } from ' @constructive-io/graphql-query' ;
326275
327- const query = buildSelect (userTable , tables , {
276+ // Preset: just id + a few display fields
277+ const minimal = buildSelect (userTable , tables , { fieldSelection: ' minimal' });
278+
279+ // Preset: all scalar fields (no relations)
280+ const allFields = buildSelect (userTable , tables , { fieldSelection: ' all' });
281+
282+ // Preset: everything including relations
283+ const full = buildSelect (userTable , tables , { fieldSelection: ' full' });
284+
285+ // Custom: pick specific fields + exclude some + include specific relations
286+ const custom = buildSelect (userTable , tables , {
328287 fieldSelection: {
329- preset: ' all' , // 'all' | 'scalar' | 'custom'
330- includeRelations: true , // include related tables
288+ select: [' id' , ' name' , ' email' ],
289+ exclude: [' internalNotes' ],
290+ include: { posts: [' id' , ' title' ] },
331291 },
332292});
333293```
0 commit comments