Skip to content

feat(codegen): add pagination, filtering, search, find-first; remove MCP; unify casing#913

Merged
pyramation merged 9 commits intomainfrom
devin/1774572926-cli-list-pagination
Mar 27, 2026
Merged

feat(codegen): add pagination, filtering, search, find-first; remove MCP; unify casing#913
pyramation merged 9 commits intomainfrom
devin/1774572926-cli-list-pagination

Conversation

@pyramation
Copy link
Copy Markdown
Contributor

@pyramation pyramation commented Mar 27, 2026

Summary

Addresses feedback that auto-generated CLI handleList methods ignore command-line arguments and perform un-paginated findMany queries, causing terminal flooding (especially with large embedding columns). Also adds advanced filtering/ordering capabilities, a search subcommand for tables with search-capable fields, cursor-based pagination, and a find-first subcommand for full TS SDK parity. Additionally removes all MCP (Model Context Protocol) functionality from the codegen, as it was only generating static JSON tool definition files that weren't providing value. Finally, unifies casing conventions to use komoji as the single origin of truth for case transformations.

Changes to cli-utils.ts (runtime helpers):

  • Added parseIntFlag(argv, name) — parses a CLI flag as an integer, handling minimist delivering numbers or strings
  • Added parseStringFlag(argv, name) — parses a CLI flag as a string
  • Added parseOrderByFlag(argv) — parses --orderBy as a comma-separated list
  • Added parseSelectFlag(argv, defaultSelect) — parses --fields into a select object or falls back to default
  • Added parseFindManyArgs(argv, defaultSelect, extraWhere?) — one-stop builder for all findMany args (pagination, filtering, ordering, field selection). Accepts optional extraWhere for the search handler to inject search-field clauses
  • Added parseFindFirstArgs(argv, defaultSelect) — like parseFindManyArgs but only includes select, where, and condition (no pagination)
  • These helpers replace ~50 lines of inline type coercion and conditional spreads per handler with a single function call

Changes to table-command-generator.ts:

  • Removed buildParseIntFlag, buildParseStringFlag, and buildOptionalSpread AST helper functions (no longer needed — logic moved to runtime helpers)
  • buildListHandler now emits: const findManyArgs = parseFindManyArgs(argv, defaultSelect); instead of ~130 lines of inline AST
  • buildFindFirstHandler now emits: const findFirstArgs = parseFindFirstArgs(argv, defaultSelect); instead of ~60 lines of inline AST
  • buildSearchHandler now emits: const findManyArgs = parseFindManyArgs(argv, defaultSelect, searchWhere); instead of ~150 lines of inline AST for limit/offset/select/orderBy parsing
  • Generated imports changed from buildSelectFromPaths, coerceAnswers, stripUndefined, unflattenDotNotation to coerceAnswers, parseFindFirstArgs, parseFindManyArgs, stripUndefined
  • --where and --condition use dot-notation flags (e.g. --where.name.equalTo foo) parsed via unflattenDotNotation (called internally by the runtime helpers)
  • --orderBy accepts a comma-separated string (e.g. NAME_ASC,CREATED_AT_DESC)
  • --last, --after, --before flags for cursor-based pagination
  • Subcommand name → handler name conversion uses toPascalCase from inflekt
  • Usage text includes "List Options", "Find-First Options", and conditional "Search Options" sections
  • buildSearchHandler auto-builds a where clause from the query string for all detected search field types (tsvector, BM25, trigram, vector embedding)
  • Net result of runtime helper refactor: +149 / −653 lines

Changes to docs generators:

  • README tables include find-first and search <query> subcommand rows
  • Skill reference docs updated with cursor pagination and find-first examples

MCP removal (10 files, ~2665 lines deleted):

  • Removed getCliMcpTools(), getMultiTargetCliMcpTools() from cli/docs-generator.ts
  • Removed getOrmMcpTools() from orm/docs-generator.ts
  • Removed getHooksMcpTools() from hooks-docs-generator.ts
  • Removed generateCombinedMcpConfig() from target-docs-generator.ts
  • Removed McpTool interface from docs-utils.ts
  • Removed mcp option from DocsConfig interface in types/config.ts
  • Removed all mcp-related imports, allMcpTools accumulation, and if (docsConfig.mcp) blocks from generate.ts
  • Removed MCP re-exports from cli/index.ts barrel
  • Removed 5 MCP test cases and 2 snapshots from cli-generator.test.ts
  • Updated resolveDocsConfig() to no longer handle mcp option

Casing unification (toConstantCase / toSnakeCase via inflektkomoji):

  • Replaced all toScreamingSnake (inflekt) → toConstantCase across codegen/utils.ts, naming-helpers.ts, and tests
  • Replaced all underscore (inflekt) → toSnakeCase across query-builder.ts, graphql-naming.ts, and export-utils.ts
  • All case transform imports now come from inflekt (which internally delegates to komoji as of inflekt@0.6.0)
  • Bumped inflekt ^0.5.1 → ^0.6.0 in all 5 consuming packages (graphql/codegen, graphql/query, pgpm/export, graphile/graphile-settings, postgres/pg-codegen)
  • Bumped komoji ^0.8.1 → ^0.9.0 in graphql/codegen (still needs toKebabCase directly)
  • Removed direct komoji dependency from pgpm/export, pgpm/core, and graphql/query (no longer imported directly)
  • Companion PR: constructive-io/dev-utils#74 (merged) — makes komoji the single origin of truth for case transforms; inflekt@0.6.0 re-exports toConstantCase and toSnakeCase from it

Snapshot updates: 5 snapshots updated to reflect the new generated code (runtime helpers). All 312 tests pass (down from 317 — 5 MCP tests removed).

Updates since last revision

  • Runtime helper refactor (+149 / −653 lines): Moved all repetitive inline type coercion and conditional spread AST into runtime helpers in cli-utils.ts. The generator now emits parseFindManyArgs(argv, defaultSelect) instead of ~50 lines of inline ternaries and conditional spreads per handler. This eliminates the previous inconsistency where buildSearchHandler used inline AST while buildListHandler and buildFindFirstHandler used the buildParseIntFlag/buildOptionalSpread helpers — all three handlers now use the same unified runtime helpers.
  • Removed 3 AST helper functions: buildParseIntFlag, buildParseStringFlag, buildOptionalSpread are no longer needed.
  • Generated code is now much cleaner: Each handler's try-body went from ~50+ lines of parsing logic to ~3 lines (defaultSelect declaration + helper call).

Review & Testing Checklist for Human

  • Verify parseFindManyArgs where-merge precedence: In cli-utils.ts, the where variable uses parsed.where ?? extraWhere ? { ... } : undefined. Due to JS operator precedence, ?? binds looser than ?:, so if parsed.where is truthy it will be used directly without merging extraWhere. This means search "query" --where.someField.equalTo val would lose the auto-generated search field clauses. Consider whether this needs parentheses: (parsed.where ?? extraWhere) ? { ... } : undefined or a different merge strategy.
  • Verify underscoretoSnakeCase behavioral change: The old underscore split every uppercase letter (APIKeya_p_i_key); toSnakeCase (komoji) groups acronyms (APIKeyapi_key). Check if any table/model/field names with consecutive uppercase letters exist across consumers. modelNameToGetMany() and pgpm/export's graphqlRowToPostgresRow() operate on arbitrary model/column names.
  • Verify DocsConfig breaking change — any downstream code or config files that reference mcp: true will now fail type-checking. Search for mcp in codegen config files across consuming repos.
  • Review buildSearchHandler AST — still has zero snapshot coverage (test fixtures lack search-capable fields). Consider adding a test fixture with tsvector/embedding columns.
  • Test with a real generated CLI — run codegen against a schema, then verify:
    • cli list --limit 5 --fields id,name
    • cli list --limit 10 --after <cursor> (cursor pagination)
    • cli find-first --where.name.equalTo test
    • cli list --where.name.equalTo test --orderBy NAME_ASC
    • cli search "some query" --limit 10 --fields id,searchScore (if search-capable table)
    • cli search "query" --where.extra.equalTo val (verify both where clauses are present)
    • Verify no mcp.json is generated when docs: true is set

Notes

  • The buildSearchHandler code path has zero snapshot coverage because no test fixture tables have search-capable fields. This is the highest-risk area of the PR.
  • The search subcommand is only generated for tables where categorizeSpecialFields() returns groups with category === 'search' or category === 'embedding'.
  • The find-first subcommand is generated for all tables unconditionally.
  • Minor: skill doc example shows --fields id,id — the template uses --fields id,${pk.name} which produces id,id when PK is id. Cosmetic only.
  • Naming conventions: All case transforms now import from inflekt, which delegates to komoji internally. graphql/codegen still imports toKebabCase directly from komoji since inflekt doesn't re-export it.
  • The pnpm-lock.yaml diff is large but is almost entirely formatting changes (single-quoted vs block-style YAML) plus the dependency resolution updates for the version bumps.

Link to Devin session: https://app.devin.ai/sessions/c92c3a11450342f8875625a60fa1be28
Requested by: @pyramation


Open with Devin

…t commands

- Parse --limit, --offset, --fields flags in generated handleList handlers
- Use buildSelectFromPaths utility for custom field projection
- Build findManyArgs with conditional spread for first/offset pagination
- Update MCP tool schemas with limit/offset/fields input properties
- Update skill docs with pagination and field selection examples
- Update usage text to document new list options
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

…and to CLI

- Add --where, --condition, --orderBy JSON passthrough flags to list commands
- Add parseJsonFlag() utility for runtime JSON parsing of CLI flags
- Generate 'search' subcommand for tables with search-capable fields
  (tsvector, BM25, trigram, vector embedding)
- Search auto-builds where clause from query string for all detected fields
- Update MCP tool schemas with new filter/search properties
- Update generated README, skills, and usage text with examples
- Support both single-target and multi-target CLI configurations
@devin-ai-integration devin-ai-integration bot changed the title feat(codegen): add pagination, offset, and field selection to CLI list commands feat(codegen): add pagination, filtering, ordering, and search to CLI commands Mar 27, 2026
…or where/condition

- Replace parseJsonFlag with unflattenDotNotation for --where and --condition
- CLI now uses --where.field.op <value> instead of --where '<json>'
- Remove parseJsonFlag from cli-utils.ts (no longer needed)
- Update all generated docs (MCP tools, skills, usage text) for dot-notation
- Update snapshots
… TS SDK parity

- Add --last, --after, --before cursor pagination flags to list command
- Add find-first subcommand (CLI equivalent of ORM findFirst)
- Add buildParseIntFlag/buildParseStringFlag/buildOptionalSpread helpers to reduce AST duplication
- Add kebabToPascal for hyphenated subcommand handler names
- Update MCP tool schemas with cursor pagination and find-first
- Update skills and README with new flags and examples
- pageInfo/totalCount already included in list output via ConnectionResult
@devin-ai-integration devin-ai-integration bot changed the title feat(codegen): add pagination, filtering, ordering, and search to CLI commands feat(codegen): add pagination, filtering, ordering, search, and find-first to CLI commands Mar 27, 2026
Remove MCP (Model Context Protocol) tool generation, mcp.json file
generation, and related config/types/tests. MCP was generating static
JSON tool definition files that weren't providing value.

Removed:
- getCliMcpTools(), getMultiTargetCliMcpTools() from cli/docs-generator.ts
- getOrmMcpTools() from orm/docs-generator.ts
- getHooksMcpTools() from hooks-docs-generator.ts
- generateCombinedMcpConfig() from target-docs-generator.ts
- McpTool interface from docs-utils.ts
- mcp option from DocsConfig interface and resolveDocsConfig()
- All MCP imports and if(docsConfig.mcp) blocks from generate.ts
- 5 MCP test cases and 2 snapshots from cli-generator.test.ts
- McpTool re-exports from cli/index.ts barrel
@devin-ai-integration devin-ai-integration bot changed the title feat(codegen): add pagination, filtering, ordering, search, and find-first to CLI commands feat(codegen): add pagination, filtering, search, find-first; remove MCP Mar 27, 2026
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 6 additional findings.

Open in Devin Review

…Case

Use the standard toPascalCase from inflekt instead of a hand-rolled
kebabToPascal helper. inflekt already handles kebab-case input correctly
(e.g. 'find-first' → 'FindFirst').
…eamingSnake, toSnakeCase instead of underscore

- Replace all toScreamingSnake imports/usage with toConstantCase from komoji
- Replace all underscore imports/usage with toSnakeCase from komoji
- Add komoji dependency to graphql/query
- Update tests to use toConstantCase
- All 312 codegen tests pass, full monorepo build succeeds
@devin-ai-integration devin-ai-integration bot changed the title feat(codegen): add pagination, filtering, search, find-first; remove MCP feat(codegen): add pagination, filtering, search, find-first; remove MCP; unify casing Mar 27, 2026
…e/toSnakeCase from inflekt

Now that inflekt@0.6.0 re-exports toConstantCase and toSnakeCase from komoji,
switch all imports to come from inflekt (single import source for case transforms).

- Bump inflekt ^0.5.1 → ^0.6.0 in all 5 packages
- Bump komoji ^0.8.1 → ^0.9.0 in graphql/codegen (still needs toKebabCase)
- Remove komoji from pgpm/export, pgpm/core, graphql/query (no longer imported directly)
- Move toConstantCase/toSnakeCase imports from komoji to inflekt
- All 312 codegen tests pass, full monorepo build succeeds
Move repetitive inline type coercion (parseIntFlag, parseStringFlag,
parseOrderByFlag, parseSelectFlag) and findMany/findFirst arg building
into runtime helpers in cli-utils.ts. The generator now emits simple
calls like parseFindManyArgs(argv, defaultSelect) instead of ~50 lines
of inline ternaries and conditional spreads per handler.

- Added parseIntFlag, parseStringFlag, parseOrderByFlag, parseSelectFlag
- Added parseFindManyArgs (with extraWhere for search handler)
- Added parseFindFirstArgs
- Simplified buildListHandler, buildFindFirstHandler, buildSearchHandler
- Removed buildParseIntFlag, buildParseStringFlag, buildOptionalSpread AST helpers
@pyramation pyramation merged commit 0280453 into main Mar 27, 2026
44 checks passed
@pyramation pyramation deleted the devin/1774572926-cli-list-pagination branch March 27, 2026 12:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant