Skip to content

TRQL: always add FINAL keyword#3051

Merged
matt-aitken merged 1 commit intomainfrom
query-clickhouse-final
Feb 13, 2026
Merged

TRQL: always add FINAL keyword#3051
matt-aitken merged 1 commit intomainfrom
query-clickhouse-final

Conversation

@matt-aitken
Copy link
Member

For now we’re going to always add FINAL to TRQL queries for data correctness.

In the future we will implement an automated optimization where we use SELECT argMax(column, _version) and WHERE _is_deleted = 0. But this is a more complex change and needs more investigation of downsides.

For now we’re going to always add FINAL to TRQL queries for data correctness.

In the future we will implement an automated optimization where we use `SELECT argMax(column, _version)` and `WHERE _is_deleted = 0`. But this is a more complex change and needs more investigation of downsides.
@changeset-bot
Copy link

changeset-bot bot commented Feb 13, 2026

⚠️ No Changeset found

Latest commit: e56beb8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 13, 2026

Walkthrough

This change modifies the FINAL keyword emission logic in JOIN handling within the SQL printer. Previously, FINAL was conditionally appended based on a node.table_final flag. The updated logic now appends FINAL only when the table reference is direct—specifically when node.table is a Field with expression_type "field"—and no longer references the node.table_final flag. The rest of the JOIN construction logic remains unchanged.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 2
❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is incomplete, missing multiple required sections from the template (Checklist, Testing, Screenshots) and lacks structured organization. While it provides some rationale for the change, it does not follow the template format. Follow the provided PR template by including the checklist section with completion status, a Testing section describing the testing steps performed, and other required sections to ensure consistency and clarity.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (2 files):

⚔️ apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx (content)
⚔️ internal-packages/tsql/src/query/printer.ts (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'TRQL: always add FINAL keyword' clearly and concisely describes the main change, which aligns with the PR's objective of adding the FINAL keyword to TRQL queries for data correctness.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 query-clickhouse-final
⚔️ Resolve merge conflicts (beta)
  • Auto-commit resolved conflicts to branch query-clickhouse-final
  • Create stacked PR with resolved conflicts
  • Post resolved changes as copyable diffs in a comment

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
internal-packages/tsql/src/query/printer.ts (1)

1562-1570: LGTM — always emitting FINAL for direct table references is correct for ReplacingMergeTree correctness.

The guard (tableExpr as Field).expression_type === "field" correctly avoids adding FINAL to subqueries and function-based table expressions, which is aligned with the grammar's TableExprIdentifierContext.

Follow-up: node.table_final is now dead code—it's parsed and assigned in parser.ts but never used anywhere in the codebase. Consider removing it from the AST definition and parser to clean up unused properties.

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 35e11e0 and e56beb8.

📒 Files selected for processing (1)
  • internal-packages/tsql/src/query/printer.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead

**/*.{ts,tsx}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • internal-packages/tsql/src/query/printer.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • internal-packages/tsql/src/query/printer.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • internal-packages/tsql/src/query/printer.ts
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • internal-packages/tsql/src/query/printer.ts
🧬 Code graph analysis (1)
internal-packages/tsql/src/query/printer.ts (1)
internal-packages/tsql/src/grammar/TSQLParser.ts (3)
  • tableExpr (5764-5901)
  • tableExpr (8963-8965)
  • tableExpr (11130-11132)
⏰ 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). (27)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@matt-aitken matt-aitken marked this pull request as ready for review February 13, 2026 17:30
Copy link

@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 found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines 1559 to 1560
joinStrings.push(`AS ${this.printIdentifier(node.alias)}`);
}

Choose a reason for hiding this comment

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

🚩 Pre-existing double-alias bug for direct table references with explicit aliases

When a direct table reference has an explicit alias (e.g., FROM runs AS r), the code at internal-packages/tsql/src/query/printer.ts:1494-1497 already embeds the alias into the table string: clickhouseName AS r. Then at internal-packages/tsql/src/query/printer.ts:1557-1559, if node.alias is set, it pushes AS r again. This would produce clickhouseName AS r AS r FINAL, which is invalid ClickHouse syntax.

This is pre-existing (not introduced by this PR), and no tests exercise explicit table aliases in FROM clauses. The alias block at line 1557-1559 appears intended for subqueries/placeholders (which don't embed their own alias), but it fires unconditionally for all expression types including direct table references that already include the alias.

With this PR always adding FINAL, the invalid output becomes more likely to surface if table aliases are ever used in TSQL queries.

(Refers to lines 1557-1560)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@matt-aitken matt-aitken merged commit a3d3b17 into main Feb 13, 2026
40 checks passed
@matt-aitken matt-aitken deleted the query-clickhouse-final branch February 13, 2026 17:34
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