diff --git a/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap index 89631177b..1ed497d76 100644 --- a/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap +++ b/graphql/codegen/src/__tests__/codegen/__snapshots__/react-query-hooks.test.ts.snap @@ -1436,9 +1436,9 @@ import { getClient } from "../client"; import { buildListSelectionArgs } from "../selection"; import type { ListSelectionConfig } from "../selection"; import { userKeys } from "../query-keys"; -import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types"; import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types"; -export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const usersQueryKey = userKeys.list; /** @@ -1545,9 +1545,9 @@ import { buildListSelectionArgs } from "../selection"; import type { ListSelectionConfig } from "../selection"; import { postKeys } from "../query-keys"; import type { PostScope } from "../query-keys"; -import type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types"; +import type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy, PostCondition } from "../../orm/input-types"; import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types"; -export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy } from "../../orm/input-types"; +export type { PostSelect, PostWithRelations, PostFilter, PostsOrderBy, PostCondition } from "../../orm/input-types"; /** Query key factory - re-exported from query-keys.ts */ export const postsQueryKey = postKeys.list; /** @@ -1669,10 +1669,10 @@ import type { UseQueryOptions, UseQueryResult, QueryClient } from "@tanstack/rea import { getClient } from "../client"; import { buildListSelectionArgs } from "../selection"; import type { ListSelectionConfig } from "../selection"; -import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; +import type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types"; import type { FindManyArgs, InferSelectResult, ConnectionResult, HookStrictSelect } from "../../orm/select-types"; -export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy } from "../../orm/input-types"; -export const usersQueryKey = (variables?: FindManyArgs) => ["user", "list", variables] as const; +export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types"; +export const usersQueryKey = (variables?: FindManyArgs) => ["user", "list", variables] as const; /** * Query hook for fetching User list * diff --git a/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts b/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts index c5e0f5b99..54b279494 100644 --- a/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts +++ b/graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts @@ -28,6 +28,7 @@ import { generateSingleQueryHook, } from '../../core/codegen/queries'; import { generateSchemaTypesFile } from '../../core/codegen/schema-types-generator'; +import { generateTypesFile } from '../../core/codegen/types'; import type { CleanFieldType, CleanOperation, @@ -335,6 +336,53 @@ describe('Query Hook Generators', () => { }); }); +describe('Regression: FindManyArgs TCondition type arg', () => { + // Bug: queries.ts passed 3 type args to FindManyArgs (TSelect, TWhere, TOrderBy), + // but the template defines 4 params: FindManyArgs. + // This caused TOrderBy to land in the TCondition slot, defaulting TOrderBy to `never` + // and breaking all hook orderBy params. + + it('includes Condition type in imports and re-exports when condition is enabled', () => { + const result = generateListQueryHook(simpleUserTable, { + reactQueryEnabled: true, + useCentralizedKeys: true, + condition: true, + }); + expect(result.content).toContain('UserCondition'); + expect(result.content).toMatch( + /import type \{[^}]*UserCondition[^}]*\} from "\.\.\/\.\.\/orm\/input-types"/, + ); + expect(result.content).toMatch( + /export type \{[^}]*UserCondition[^}]*\} from "\.\.\/\.\.\/orm\/input-types"/, + ); + }); + + it('includes Condition type in FindManyArgs type arguments', () => { + const result = generateListQueryHook(simpleUserTable, { + reactQueryEnabled: true, + useCentralizedKeys: false, + condition: true, + }); + // FindManyArgs should have 4 type args: unknown, UserFilter, UserCondition, UsersOrderBy + expect(result.content).toMatch( + /FindManyArgs/, + ); + }); + + it('omits Condition type when condition is disabled', () => { + const result = generateListQueryHook(simpleUserTable, { + reactQueryEnabled: true, + useCentralizedKeys: false, + condition: false, + }); + // FindManyArgs should have 3 type args: unknown, UserFilter, UsersOrderBy + expect(result.content).toMatch( + /FindManyArgs/, + ); + expect(result.content).not.toContain('UserCondition'); + }); +}); + describe('Mutation Hook Generators', () => { describe('generateCreateMutationHook', () => { it('generates create mutation hook for simple table', () => { @@ -644,3 +692,27 @@ describe('Barrel File Generators', () => { }); }); }); + +describe('Regression: VectorFilter in types.ts', () => { + // Bug: VectorFilter was generated in ORM input-types-generator.ts but was missing + // from the React types.ts FILTER_CONFIGS. schema-types.ts imports VectorFilter + // from types.ts, so the missing export caused build failures. + + it('exports VectorFilter interface from types.ts', () => { + const result = generateTypesFile([simpleUserTable]); + expect(result).toContain('export interface VectorFilter {'); + }); + + it('VectorFilter has equality and distinct operators with number[] type', () => { + const result = generateTypesFile([simpleUserTable]); + expect(result).toContain('export interface VectorFilter {'); + // equality operators + expect(result).toMatch(/isNull\?:\s*boolean/); + // VectorFilter uses number[] type + expect(result).toMatch(/equalTo\?:\s*number\[\]/); + expect(result).toMatch(/notEqualTo\?:\s*number\[\]/); + // distinct operators + expect(result).toMatch(/distinctFrom\?:\s*number\[\]/); + expect(result).toMatch(/notDistinctFrom\?:\s*number\[\]/); + }); +}); diff --git a/graphql/codegen/src/core/codegen/index.ts b/graphql/codegen/src/core/codegen/index.ts index bf641c3e7..a314e3768 100644 --- a/graphql/codegen/src/core/codegen/index.ts +++ b/graphql/codegen/src/core/codegen/index.ts @@ -190,11 +190,15 @@ export function generate(options: GenerateOptions): GenerateResult { hasInvalidation = true; } + // Condition types (PostGraphile simple equality filters) + const conditionEnabled = config.codegen?.condition !== false; + // 4. Generate table-based query hooks (queries/*.ts) const queryHooks = generateAllQueryHooks(tables, { reactQueryEnabled, useCentralizedKeys, hasRelationships, + condition: conditionEnabled, }); for (const hook of queryHooks) { files.push({ diff --git a/graphql/codegen/src/core/codegen/queries.ts b/graphql/codegen/src/core/codegen/queries.ts index c1ebd28bc..5d28d5caa 100644 --- a/graphql/codegen/src/core/codegen/queries.ts +++ b/graphql/codegen/src/core/codegen/queries.ts @@ -52,6 +52,7 @@ import { } from './hooks-ast'; import { getAllRowsQueryName, + getConditionTypeName, getFilterTypeName, getListQueryFileName, getListQueryHookName, @@ -75,6 +76,7 @@ export interface QueryGeneratorOptions { reactQueryEnabled?: boolean; useCentralizedKeys?: boolean; hasRelationships?: boolean; + condition?: boolean; } export function generateListQueryHook( @@ -85,12 +87,14 @@ export function generateListQueryHook( reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, + condition: conditionEnabled = true, } = options; const { typeName, pluralName, singularName } = getTableNames(table); const hookName = getListQueryHookName(table); const queryName = getAllRowsQueryName(table); const filterTypeName = getFilterTypeName(table); const orderByTypeName = getOrderByTypeName(table); + const conditionTypeName = conditionEnabled ? getConditionTypeName(table) : undefined; const keysName = `${lcFirst(typeName)}Keys`; const scopeTypeName = `${typeName}Scope`; const selectTypeName = `${typeName}Select`; @@ -131,10 +135,12 @@ export function generateListQueryHook( } } + const inputTypeImports = [selectTypeName, relationTypeName, filterTypeName, orderByTypeName]; + if (conditionTypeName) inputTypeImports.push(conditionTypeName); statements.push( createImportDeclaration( '../../orm/input-types', - [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], + inputTypeImports, true, ), ); @@ -152,9 +158,11 @@ export function generateListQueryHook( ); // Re-exports + const reExportTypes = [selectTypeName, relationTypeName, filterTypeName, orderByTypeName]; + if (conditionTypeName) reExportTypes.push(conditionTypeName); statements.push( createTypeReExport( - [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], + reExportTypes, '../../orm/input-types', ), ); @@ -174,15 +182,17 @@ export function generateListQueryHook( ]); statements.push(keyDecl); } else { + const findManyKeyTypeArgs: t.TSType[] = [ + t.tsUnknownKeyword(), + typeRef(filterTypeName), + ...(conditionTypeName ? [typeRef(conditionTypeName)] : []), + typeRef(orderByTypeName), + ]; const keyFn = t.arrowFunctionExpression( [ createFunctionParam( 'variables', - typeRef('FindManyArgs', [ - t.tsUnknownKeyword(), - typeRef(filterTypeName), - typeRef(orderByTypeName), - ]), + typeRef('FindManyArgs', findManyKeyTypeArgs), true, ), ], diff --git a/graphql/codegen/src/core/codegen/types.ts b/graphql/codegen/src/core/codegen/types.ts index f9dfcc498..1d8837e79 100644 --- a/graphql/codegen/src/core/codegen/types.ts +++ b/graphql/codegen/src/core/codegen/types.ts @@ -93,6 +93,12 @@ const FILTER_CONFIGS: Array<{ operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'], }, { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] }, + // Vector filter (for pgvector embedding columns) + { + name: 'VectorFilter', + tsType: 'number[]', + operators: ['equality', 'distinct'], + }, // List filters { name: 'StringListFilter',