Skip to content

Conversation

@Newbie012
Copy link
Collaborator

@Newbie012 Newbie012 commented Oct 30, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved type and nullability inference for scalar subqueries and subselects so results propagate correctly to parent queries.
  • Tests

    • Added tests validating scalar subquery type inference and nullability behavior.
  • Chores

    • Added a patch changeset entry documenting the fix.
  • Breaking Changes

    • Public AST description API now returns a structured object (map + meta) and exposes relation/non-nullability metadata — callers must adapt.

@changeset-bot
Copy link

changeset-bot bot commented Oct 30, 2025

🦋 Changeset detected

Latest commit: f4f50e4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 17 packages
Name Type
@ts-safeql/generate Patch
@ts-safeql/eslint-plugin Patch
@ts-safeql/shared Patch
@ts-safeql/sql-ast Patch
@ts-safeql-demos/basic-flat-config Patch
@ts-safeql-demos/basic-migrations-raw Patch
@ts-safeql-demos/basic-transform-type Patch
@ts-safeql-demos/basic Patch
@ts-safeql-demos/big-project Patch
@ts-safeql-demos/config-file-flat-config Patch
@ts-safeql-demos/from-config-file Patch
@ts-safeql-demos/multi-connections Patch
@ts-safeql-demos/playground Patch
@ts-safeql-demos/postgresjs-custom-types Patch
@ts-safeql-demos/postgresjs-demo Patch
@ts-safeql-demos/vercel-postgres Patch
@ts-safeql/test-utils Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Oct 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
safeql Ignored Ignored Preview Oct 30, 2025 10:48pm

@coderabbitai
Copy link

coderabbitai bot commented Oct 30, 2025

Walkthrough

Restructures AST description to return { map, meta } (including relations and nonNullableColumns), adds recursive subselect description via getDescribedSelectStmt, centralizes SubLink return-type logic in getSubLinkType, and updates generator call sites and tests to the new shape.

Changes

Cohort / File(s) Summary
AST description core
packages/generate/src/ast-describe.ts
getASTDescription now returns { map, meta } with meta.relations and meta.nonNullableColumns; removed relations/nonNullableColumns from ASTDescriptionOptions; added nonNullableColumns and relations to ASTDescriptionContext; added getDescribedSelectStmt; extracted getSubLinkType; use getRelationsWithJoins + flattenRelationsWithJoinsMap; early return returns { map: Map(), meta: { relations: [], nonNullableColumns: new Set() } }.
Generator usage updates
packages/generate/src/generate.ts
Updated callers to consume new { map, meta } shape: access descriptions via astQueryDescription.map.get(position), use astQueryDescription.meta.relations, and astQueryDescription.meta.nonNullableColumns; removed prior local AST-derived relation/non-nullable computations.
Tests
packages/generate/src/generate.test.ts
Removed unknownColumns expectation from an existing test; added two tests asserting scalar subquery type inference (nullable union and non-nullable when WHERE enforces non-null).
Changeset
.changeset/wet-ears-cross.md
Added patch-level changeset noting fix for scalar subquery type inference.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller as getASTDescription (parent)
    participant NodeDesc as getDescribedNode
    participant SelectDesc as getDescribedSelectStmt
    participant SubCaller as getASTDescription (subquery)
    participant SubLink as getSubLinkType

    Caller->>NodeDesc: describe AST node
    NodeDesc->>SelectDesc: if node is SelectStmt -> route to getDescribedSelectStmt
    SelectDesc->>SelectDesc: build sub-ParseResult (types, cols, relations)
    SelectDesc->>SubCaller: call getASTDescription(sub-ParseResult)
    SubCaller-->>SelectDesc: return { map, meta } (columns + meta)
    SelectDesc->>SelectDesc: pick first column -> produce single-column description
    SelectDesc-->>NodeDesc: return described SelectStmt node
    NodeDesc-->>Caller: incorporate described node into parent map

    Note right of SubLink: getSubLinkType centralizes EXISTS/EXPR_SUBLINK decision and return-type handling
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Focus areas:
    • Verify all call-sites updated to the { map, meta } shape (e.g., .map.get(...)).
    • Inspect getDescribedSelectStmt construction of sub-ParseResult and choice to use the first column for scalar subqueries.
    • Validate getSubLinkType covers relevant SubLink variants and nullability.
    • Confirm correct propagation of meta.relations and meta.nonNullableColumns into context.

Possibly related PRs

Poem

🐰 I hopped through ASTs both deep and wide,
I peeked at subselects where quiet types hide.
I fetched the first column, wrapped meta in map,
Sent relations and nulls back on the lap.
Hooray — a rabbit nudged a type to stride. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "fix: scalar subquery in select list should infer correct type" is directly aligned with the primary objective of the changeset. The raw summary confirms this is focused on resolving type inference issues for scalar subqueries in select lists, as evidenced by the new test cases ("scalar subquery in select list should infer correct type" and "scalar subquery with WHERE should infer non-nullable type") and the changeset description stating "resolution of an issue with type inference for scalar subqueries in select lists." The implementation changes in ast-describe.ts add the necessary mechanisms (getDescribedSelectStmt and getSubLinkType) to support this fix. The title is concise, clear, and specific enough for a developer scanning commit history to understand the primary change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-issue-411

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0510ccb and f4f50e4.

📒 Files selected for processing (1)
  • packages/generate/src/generate.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/generate/src/generate.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, 20)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88abda0 and ab267dc.

📒 Files selected for processing (2)
  • packages/generate/src/ast-describe.ts (3 hunks)
  • packages/generate/src/generate.test.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/generate/src/ast-describe.ts (2)
packages/ast-types/src/index.ts (2)
  • SelectStmt (887-908)
  • ParseResult (4-7)
packages/generate/src/utils/get-relations-with-joins.ts (2)
  • flattenRelationsWithJoinsMap (81-93)
  • getRelationsWithJoins (11-27)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
.changeset/wet-ears-cross.md (1)

5-5: Clarify the changeset description to remove redundancy and improve clarity.

The description contains awkward phrasing with "type inference" repeated. Consider a more concise and formal wording.

Apply this diff to improve clarity:

-Fixed an issue with type inference for scalar subquery type inference.
+Fixed type inference for scalar subqueries in select lists.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab267dc and 1cb4591.

📒 Files selected for processing (2)
  • .changeset/wet-ears-cross.md (1 hunks)
  • packages/generate/src/generate.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/generate/src/generate.test.ts
🧰 Additional context used
🪛 LanguageTool
.changeset/wet-ears-cross.md

[style] ~4-~4: Consider using a different verb for a more formal wording.
Context: --- "@ts-safeql/generate": patch --- Fixed an issue with type inference for scalar...

(FIX_RESOLVE)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: check (ubuntu-latest, 20)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/generate/src/ast-describe.ts (1)

1-1: Fix the Prettier formatting issue.

The CI pipeline reports a formatting error. Please run prettier --write packages/generate/src/ast-describe.ts to fix.

🧹 Nitpick comments (1)
packages/generate/src/ast-describe.ts (1)

523-589: LGTM! Subquery type inference properly implemented.

The refactor centralizes SubLink type resolution in getSubLinkType and adds getDescribedSelectStmt to recursively describe scalar subqueries. The synthetic ParseResult with version: 0 is used to bootstrap the recursive description—this should be fine if the version field isn't used for type inference logic.

Optional: Consider minor simplification.

In getSubLinkType (lines 528-535), you could call getDescribedSelectStmt directly instead of wrapping the SelectStmt in a Node and routing through getDescribedNode. However, routing through the dispatcher maintains consistency with the existing pattern, so this is purely a stylistic suggestion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1cb4591 and cb9cdb2.

📒 Files selected for processing (4)
  • .changeset/wet-ears-cross.md (1 hunks)
  • packages/generate/src/ast-describe.ts (7 hunks)
  • packages/generate/src/generate.test.ts (1 hunks)
  • packages/generate/src/generate.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/generate/src/generate.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/generate/src/ast-describe.ts (4)
packages/generate/src/utils/get-relations-with-joins.ts (3)
  • FlattenedRelationWithJoins (74-79)
  • flattenRelationsWithJoinsMap (81-93)
  • getRelationsWithJoins (11-27)
packages/generate/src/utils/get-nonnullable-columns.ts (1)
  • getNonNullableColumns (325-333)
packages/generate/src/ast-get-sources.ts (1)
  • getSources (42-446)
packages/ast-types/src/index.ts (2)
  • SelectStmt (887-908)
  • ParseResult (4-7)
🪛 GitHub Actions: CI
packages/generate/src/ast-describe.ts

[error] 1-1: Prettier formatting check failed for this file. Code style issues found. Run 'prettier --write' to fix.

🔇 Additional comments (8)
.changeset/wet-ears-cross.md (1)

1-5: LGTM!

The changeset entry correctly documents the patch-level fix for scalar subquery type inference.

packages/generate/src/generate.ts (3)

19-19: LGTM!

The simplified import reflects the architectural improvement—relations and non-nullable column derivation now happen inside getASTDescription.


261-284: LGTM!

The code correctly adapts to the new AST description structure:

  • Accesses column descriptions via .map.get(position)
  • Retrieves non-nullable metadata from .meta.nonNullableColumns

287-298: LGTM!

The context now correctly sources relationsWithJoins from the AST description metadata, eliminating redundant computation.

packages/generate/src/ast-describe.ts (4)

13-18: LGTM!

The new imports support centralizing relations and non-nullable column computation within the AST description flow.


51-59: LGTM! Public API restructured to include metadata.

The new return shape { map, meta } is a breaking change but provides a cleaner API by co-locating relations and non-nullable column metadata with the per-column descriptions. The caller in generate.ts has been updated consistently.


72-104: LGTM! Metadata computation properly centralized.

Computing nonNullableColumns and relations directly from the parsed AST ensures that each invocation (including recursive subquery descriptions) derives accurate metadata. This addresses the previous review concern about losing non-nullability information in scalar subqueries.


278-280: LGTM! Enables recursive subquery description.

Routing SelectStmt nodes through getDescribedNode to the new getDescribedSelectStmt handler enables proper type inference for scalar subqueries.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/generate/src/ast-describe.ts (1)

521-549: Consider nullability for scalar subqueries that may return zero rows.

The getSubLinkType helper correctly handles EXISTS_SUBLINK (bool) and EXPR_SUBLINK (extracts subquery type). However, passing nullable: false at line 548 means scalar subqueries preserve the inner column's nullability without accounting for the zero-row case.

In PostgreSQL, scalar subqueries return NULL when they produce zero rows. For example:

  • (SELECT count(1) FROM tbl) → always returns a row (correct as non-null if count is marked non-null)
  • (SELECT col FROM tbl WHERE false) → returns NULL (but current code infers as non-null if col is NOT NULL)

The current approach correctly handles aggregates without GROUP BY (which always return one row) but may under-estimate nullability for other queries. Fixing this fully would require analyzing whether the subquery is guaranteed to return exactly one row, which is complex.

For now, this is an acceptable approximation that handles the most common cases (like count), but consider enhancing nullability analysis for non-aggregate scalar subqueries in the future.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb9cdb2 and 0510ccb.

📒 Files selected for processing (1)
  • packages/generate/src/ast-describe.ts (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/generate/src/ast-describe.ts (4)
packages/generate/src/utils/get-relations-with-joins.ts (3)
  • FlattenedRelationWithJoins (74-79)
  • flattenRelationsWithJoinsMap (81-93)
  • getRelationsWithJoins (11-27)
packages/generate/src/utils/get-nonnullable-columns.ts (1)
  • getNonNullableColumns (325-333)
packages/generate/src/ast-get-sources.ts (1)
  • getSources (42-446)
packages/ast-types/src/index.ts (2)
  • SelectStmt (887-908)
  • ParseResult (4-7)
🔇 Additional comments (6)
packages/generate/src/ast-describe.ts (6)

51-68: LGTM - Structured return enhances API clarity.

The change from returning a plain Map to returning { map, meta } improves the API by making metadata (relations, nonNullableColumns) first-class. The early-return case correctly provides empty defaults for all fields. Based on the AI summary, downstream consumers in generate.ts have been updated accordingly.


70-72: Good approach - precompute metadata once.

Computing nonNullableColumns and relations upfront and reusing them throughout the description process is efficient and ensures consistent metadata across the AST traversal.


93-103: Context properly initialized with metadata.

The computed nonNullableColumns and relations are correctly threaded through the context and passed to getSources, enabling proper nullability and join-type resolution throughout the description process.


199-205: Return statement matches updated API.

The return value correctly provides both the column map and the metadata, consistent with the new function signature.


276-278: Good - route SelectStmt to dedicated handler.

Adding this routing enables proper description of scalar subqueries that appear directly in the select list, addressing the PR's core objective.


555-587: Well-structured recursive subquery description.

The getDescribedSelectStmt function properly handles nested SelectStmt nodes by:

  1. Constructing a synthetic ParseResult wrapper
  2. Recursively invoking getASTDescription, which independently computes nonNullableColumns via getNonNullableColumns(subParsed) (line 70)
  3. Extracting the first column's type for scalar subquery inference

This approach correctly addresses the previous review concern about preserving non-nullability metadata - instead of passing stale metadata, each subquery gets fresh analysis via getNonNullableColumns.

@Newbie012 Newbie012 merged commit 6ec9a46 into main Nov 1, 2025
4 checks passed
@Newbie012 Newbie012 deleted the fix-issue-411 branch November 1, 2025 20:43
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.

2 participants