Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/**
Expand Down Expand Up @@ -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;
/**
Expand Down Expand Up @@ -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<unknown, UserFilter, UsersOrderBy>) => ["user", "list", variables] as const;
export type { UserSelect, UserWithRelations, UserFilter, UsersOrderBy, UserCondition } from "../../orm/input-types";
export const usersQueryKey = (variables?: FindManyArgs<unknown, UserFilter, UserCondition, UsersOrderBy>) => ["user", "list", variables] as const;
/**
* Query hook for fetching User list
*
Expand Down
72 changes: 72 additions & 0 deletions graphql/codegen/src/__tests__/codegen/react-query-hooks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<TSelect, TWhere, TCondition = never, TOrderBy = never>.
// 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<unknown, UserFilter, UserCondition, UsersOrderBy>/,
);
});

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<unknown, UserFilter, UsersOrderBy>/,
);
expect(result.content).not.toContain('UserCondition');
});
});

describe('Mutation Hook Generators', () => {
describe('generateCreateMutationHook', () => {
it('generates create mutation hook for simple table', () => {
Expand Down Expand Up @@ -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\[\]/);
});
});
4 changes: 4 additions & 0 deletions graphql/codegen/src/core/codegen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
24 changes: 17 additions & 7 deletions graphql/codegen/src/core/codegen/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
} from './hooks-ast';
import {
getAllRowsQueryName,
getConditionTypeName,
getFilterTypeName,
getListQueryFileName,
getListQueryHookName,
Expand All @@ -75,6 +76,7 @@ export interface QueryGeneratorOptions {
reactQueryEnabled?: boolean;
useCentralizedKeys?: boolean;
hasRelationships?: boolean;
condition?: boolean;
}

export function generateListQueryHook(
Expand All @@ -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`;
Expand Down Expand Up @@ -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,
),
);
Expand All @@ -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',
),
);
Expand All @@ -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,
),
],
Expand Down
6 changes: 6 additions & 0 deletions graphql/codegen/src/core/codegen/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
Loading