Skip to content

Commit 47c9c25

Browse files
authored
Merge pull request #818 from constructive-io/devin/1773538794-fix-react-codegen-bugs
fix(codegen): include TCondition in React hooks FindManyArgs + add VectorFilter to types.ts
2 parents 7e9b14b + b8acf20 commit 47c9c25

5 files changed

Lines changed: 106 additions & 14 deletions

File tree

graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,9 +1436,9 @@ import { getClient } from "../client";
14361436
import { buildListSelectionArgs } from "../selection";
14371437
import type { ListSelectionConfig } from "../selection";
14381438
import { userKeys } from "../query-keys";
1439-
import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types";
1439+
import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types";
14401440
import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types";
1441-
export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types";
1441+
export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types";
14421442
/** Query key factory - re-exported from query-keys.ts */
14431443
export const usersQueryKey = userKeys.list;
14441444
/**
@@ -1545,9 +1545,9 @@ import { buildListSelectionArgs } from "../selection";
15451545
import type { ListSelectionConfig } from "../selection";
15461546
import { postKeys } from "../query-keys";
15471547
import type { PostScope } from "../query-keys";
1548-
import type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types";
1548+
import type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy, PostCondition } from "../../orm/input-types";
15491549
import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types";
1550-
export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types";
1550+
export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy, PostCondition } from "../../orm/input-types";
15511551
/** Query key factory - re-exported from query-keys.ts */
15521552
export const postsQueryKey = postKeys.list;
15531553
/**
@@ -1669,10 +1669,10 @@ import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/rea
16691669
import { getClient } from "../client";
16701670
import { buildListSelectionArgs } from "../selection";
16711671
import type { ListSelectionConfig } from "../selection";
1672-
import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types";
1672+
import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types";
16731673
import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types";
1674-
export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types";
1675-
export const usersQueryKey = (variables?: FindManyArgs<unknown, UserFilter, UsersOrderBy>) => ["user", "list", variables] as const;
1674+
export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types";
1675+
export const usersQueryKey = (variables?: FindManyArgs<unknown, UserFilter, UserCondition, UsersOrderBy>) => ["user", "list", variables] as const;
16761676
/**
16771677
* Query hook for fetching User list
16781678
*

graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
generateSingleQueryHook,
2929
} from '../../core/codegen/queries';
3030
import { generateSchemaTypesFile } from '../../core/codegen/schema-types-generator';
31+
import { generateTypesFile } from '../../core/codegen/types';
3132
import type {
3233
CleanFieldType,
3334
CleanOperation,
@@ -335,6 +336,53 @@ describe('Query Hook Generators', () => {
335336
});
336337
});
337338

339+
describe('Regression: FindManyArgs TCondition type arg', () => {
340+
// Bug: queries.ts passed 3 type args to FindManyArgs (TSelect, TWhere, TOrderBy),
341+
// but the template defines 4 params: FindManyArgs<TSelect, TWhere, TCondition = never, TOrderBy = never>.
342+
// This caused TOrderBy to land in the TCondition slot, defaulting TOrderBy to `never`
343+
// and breaking all hook orderBy params.
344+
345+
it('includes Condition type in imports and re-exports when condition is enabled', () => {
346+
const result = generateListQueryHook(simpleUserTable, {
347+
reactQueryEnabled: true,
348+
useCentralizedKeys: true,
349+
condition: true,
350+
});
351+
expect(result.content).toContain('UserCondition');
352+
expect(result.content).toMatch(
353+
/import type \{[^}]*UserCondition[^}]*\} from "\.\.\/\.\.\/orm\/input-types"/,
354+
);
355+
expect(result.content).toMatch(
356+
/export type \{[^}]*UserCondition[^}]*\} from "\.\.\/\.\.\/orm\/input-types"/,
357+
);
358+
});
359+
360+
it('includes Condition type in FindManyArgs type arguments', () => {
361+
const result = generateListQueryHook(simpleUserTable, {
362+
reactQueryEnabled: true,
363+
useCentralizedKeys: false,
364+
condition: true,
365+
});
366+
// FindManyArgs should have 4 type args: unknown, UserFilter, UserCondition, UsersOrderBy
367+
expect(result.content).toMatch(
368+
/FindManyArgs<unknown, UserFilter, UserCondition, UsersOrderBy>/,
369+
);
370+
});
371+
372+
it('omits Condition type when condition is disabled', () => {
373+
const result = generateListQueryHook(simpleUserTable, {
374+
reactQueryEnabled: true,
375+
useCentralizedKeys: false,
376+
condition: false,
377+
});
378+
// FindManyArgs should have 3 type args: unknown, UserFilter, UsersOrderBy
379+
expect(result.content).toMatch(
380+
/FindManyArgs<unknown, UserFilter, UsersOrderBy>/,
381+
);
382+
expect(result.content).not.toContain('UserCondition');
383+
});
384+
});
385+
338386
describe('Mutation Hook Generators', () => {
339387
describe('generateCreateMutationHook', () => {
340388
it('generates create mutation hook for simple table', () => {
@@ -644,3 +692,27 @@ describe('Barrel File Generators', () => {
644692
});
645693
});
646694
});
695+
696+
describe('Regression: VectorFilter in types.ts', () => {
697+
// Bug: VectorFilter was generated in ORM input-types-generator.ts but was missing
698+
// from the React types.ts FILTER_CONFIGS. schema-types.ts imports VectorFilter
699+
// from types.ts, so the missing export caused build failures.
700+
701+
it('exports VectorFilter interface from types.ts', () => {
702+
const result = generateTypesFile([simpleUserTable]);
703+
expect(result).toContain('export interface VectorFilter {');
704+
});
705+
706+
it('VectorFilter has equality and distinct operators with number[] type', () => {
707+
const result = generateTypesFile([simpleUserTable]);
708+
expect(result).toContain('export interface VectorFilter {');
709+
// equality operators
710+
expect(result).toMatch(/isNull\?:\s*boolean/);
711+
// VectorFilter uses number[] type
712+
expect(result).toMatch(/equalTo\?:\s*number\[\]/);
713+
expect(result).toMatch(/notEqualTo\?:\s*number\[\]/);
714+
// distinct operators
715+
expect(result).toMatch(/distinctFrom\?:\s*number\[\]/);
716+
expect(result).toMatch(/notDistinctFrom\?:\s*number\[\]/);
717+
});
718+
});

graphql/codegen/src/core/codegen/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,15 @@ export function generate(options: GenerateOptions): GenerateResult {
190190
hasInvalidation = true;
191191
}
192192

193+
// Condition types (PostGraphile simple equality filters)
194+
const conditionEnabled = config.codegen?.condition !== false;
195+
193196
// 4. Generate table-based query hooks (queries/*.ts)
194197
const queryHooks = generateAllQueryHooks(tables, {
195198
reactQueryEnabled,
196199
useCentralizedKeys,
197200
hasRelationships,
201+
condition: conditionEnabled,
198202
});
199203
for (const hook of queryHooks) {
200204
files.push({

graphql/codegen/src/core/codegen/queries.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import {
5252
} from './hooks-ast';
5353
import {
5454
getAllRowsQueryName,
55+
getConditionTypeName,
5556
getFilterTypeName,
5657
getListQueryFileName,
5758
getListQueryHookName,
@@ -75,6 +76,7 @@ export interface QueryGeneratorOptions {
7576
reactQueryEnabled?: boolean;
7677
useCentralizedKeys?: boolean;
7778
hasRelationships?: boolean;
79+
condition?: boolean;
7880
}
7981

8082
export function generateListQueryHook(
@@ -85,12 +87,14 @@ export function generateListQueryHook(
8587
reactQueryEnabled = true,
8688
useCentralizedKeys = true,
8789
hasRelationships = false,
90+
condition: conditionEnabled = true,
8891
} = options;
8992
const { typeName, pluralName, singularName } = getTableNames(table);
9093
const hookName = getListQueryHookName(table);
9194
const queryName = getAllRowsQueryName(table);
9295
const filterTypeName = getFilterTypeName(table);
9396
const orderByTypeName = getOrderByTypeName(table);
97+
const conditionTypeName = conditionEnabled ? getConditionTypeName(table) : undefined;
9498
const keysName = `${lcFirst(typeName)}Keys`;
9599
const scopeTypeName = `${typeName}Scope`;
96100
const selectTypeName = `${typeName}Select`;
@@ -131,10 +135,12 @@ export function generateListQueryHook(
131135
}
132136
}
133137

138+
const inputTypeImports = [selectTypeName, relationTypeName, filterTypeName, orderByTypeName];
139+
if (conditionTypeName) inputTypeImports.push(conditionTypeName);
134140
statements.push(
135141
createImportDeclaration(
136142
'../../orm/input-types',
137-
[selectTypeName, relationTypeName, filterTypeName, orderByTypeName],
143+
inputTypeImports,
138144
true,
139145
),
140146
);
@@ -152,9 +158,11 @@ export function generateListQueryHook(
152158
);
153159

154160
// Re-exports
161+
const reExportTypes = [selectTypeName, relationTypeName, filterTypeName, orderByTypeName];
162+
if (conditionTypeName) reExportTypes.push(conditionTypeName);
155163
statements.push(
156164
createTypeReExport(
157-
[selectTypeName, relationTypeName, filterTypeName, orderByTypeName],
165+
reExportTypes,
158166
'../../orm/input-types',
159167
),
160168
);
@@ -174,15 +182,17 @@ export function generateListQueryHook(
174182
]);
175183
statements.push(keyDecl);
176184
} else {
185+
const findManyKeyTypeArgs: t.TSType[] = [
186+
t.tsUnknownKeyword(),
187+
typeRef(filterTypeName),
188+
...(conditionTypeName ? [typeRef(conditionTypeName)] : []),
189+
typeRef(orderByTypeName),
190+
];
177191
const keyFn = t.arrowFunctionExpression(
178192
[
179193
createFunctionParam(
180194
'variables',
181-
typeRef('FindManyArgs', [
182-
t.tsUnknownKeyword(),
183-
typeRef(filterTypeName),
184-
typeRef(orderByTypeName),
185-
]),
195+
typeRef('FindManyArgs', findManyKeyTypeArgs),
186196
true,
187197
),
188198
],

graphql/codegen/src/core/codegen/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ const FILTER_CONFIGS: Array<{
9393
operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'],
9494
},
9595
{ name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] },
96+
// Vector filter (for pgvector embedding columns)
97+
{
98+
name: 'VectorFilter',
99+
tsType: 'number[]',
100+
operators: ['equality', 'distinct'],
101+
},
96102
// List filters
97103
{
98104
name: 'StringListFilter',

0 commit comments

Comments
 (0)