-
Notifications
You must be signed in to change notification settings - Fork 513
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix 4580 Add PostgreSql Select Distinct On (#4584)
* Add PostgreSql Distinct On Initial grammar and fixture TODO Validate Distinct On Columns match Order By Columns Integration Test * Add DistinctOnExpressionMixin Initial attempt at annotating errors for DISTINCT ON "DISTINCT ON expression(s) must match the leftmost ORDER BY expression(s)" * Add mixin to handle annotated errors I looked at the CockRoachDB implementation (compatible with Postgres) Essentially, the simplest check is to ensure the ORDER BY columns exist in the DISTINCT ON columns. * Can use none instead of any Remove the negation
- Loading branch information
Showing
4 changed files
with
110 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
...otlin/app/cash/sqldelight/dialects/postgresql/grammar/mixins/DistinctOnExpressionMixin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package app.cash.sqldelight.dialects.postgresql.grammar.mixins | ||
|
||
import app.cash.sqldelight.dialects.postgresql.grammar.psi.PostgreSqlDistinctOnExpr | ||
import com.alecstrong.sql.psi.core.SqlAnnotationHolder | ||
import com.alecstrong.sql.psi.core.psi.QueryElement | ||
import com.alecstrong.sql.psi.core.psi.SqlColumnName | ||
import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl | ||
import com.alecstrong.sql.psi.core.psi.SqlResultColumn | ||
import com.alecstrong.sql.psi.core.psi.SqlSelectStmt | ||
import com.alecstrong.sql.psi.core.psi.impl.SqlCompoundSelectStmtImpl | ||
import com.intellij.lang.ASTNode | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.util.PsiTreeUtil | ||
|
||
internal abstract class DistinctOnExpressionMixin(node: ASTNode) : | ||
SqlCompositeElementImpl(node), PostgreSqlDistinctOnExpr { | ||
|
||
private val distinctOnColumns get() = children.filterIsInstance<SqlResultColumn>() | ||
|
||
override fun queryAvailable(child: PsiElement): Collection<QueryElement.QueryResult> { | ||
return (parent as SqlSelectStmt).queryExposed() | ||
} | ||
|
||
// Some idea of the basic validation finds the ORDER BY columns in the DISTINCT ON | ||
// https://github.com/cockroachdb/cockroach/blob/b994d025c678f495cb8b93044e35a8c59595bd78/pkg/sql/opt/optbuilder/distinct.go#L87 | ||
override fun annotate(annotationHolder: SqlAnnotationHolder) { | ||
super.annotate(annotationHolder) | ||
|
||
val orderByTerms = (parent.parent as SqlCompoundSelectStmtImpl).orderingTermList | ||
|
||
val orderByColumnNames = | ||
orderByTerms.mapNotNull { PsiTreeUtil.findChildOfType(it, SqlColumnName::class.java) } | ||
|
||
val distinctOnColumnNames = | ||
distinctOnColumns.mapNotNull { PsiTreeUtil.findChildOfType(it, SqlColumnName::class.java) } | ||
|
||
orderByColumnNames.zip(distinctOnColumnNames) { orderByCol, _ -> | ||
if (distinctOnColumnNames.none { distinctOnCol -> distinctOnCol.textMatches(orderByCol) }) { | ||
annotationHolder.createErrorAnnotation( | ||
element = orderByCol, | ||
message = "SELECT DISTINCT ON expressions must match initial ORDER BY expressions", | ||
) | ||
} | ||
} | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
dialects/postgresql/src/testFixtures/resources/fixtures_postgresql/select-distinct-on/Test.s
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
CREATE TABLE person ( | ||
id INTEGER PRIMARY KEY, | ||
name TEXT, | ||
created_at TIMESTAMPTZ | ||
); | ||
|
||
SELECT DISTINCT ON (name) * | ||
FROM person; | ||
|
||
SELECT DISTINCT ON (name) * | ||
FROM person | ||
ORDER BY name, created_at DESC; | ||
|
||
SELECT DISTINCT ON (id, name) id, name | ||
FROM person | ||
ORDER BY name DESC; | ||
|
||
SELECT DISTINCT ON (name, id) id, name, created_at | ||
FROM person | ||
ORDER BY id DESC; | ||
|
||
SELECT DISTINCT ON (name, id) id, name | ||
FROM person | ||
ORDER BY id, name ASC; | ||
|
||
SELECT DISTINCT ON (name, id) id, name | ||
FROM person | ||
ORDER BY id, name, created_at ASC; | ||
|
||
-- fail | ||
SELECT DISTINCT ON (name) * | ||
FROM person | ||
ORDER BY created_at DESC; | ||
|
||
-- fail | ||
SELECT DISTINCT ON (name, created_at) id, name, created_at | ||
FROM person | ||
ORDER BY id, name, created_at DESC; | ||
|
||
-- fail | ||
SELECT DISTINCT ON (name, id) id, name, created_at | ||
FROM person | ||
ORDER BY name, created_at, id DESC; |
3 changes: 3 additions & 0 deletions
3
.../postgresql/src/testFixtures/resources/fixtures_postgresql/select-distinct-on/failure.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Test.s line 33:9 - SELECT DISTINCT ON expressions must match initial ORDER BY expressions | ||
Test.s line 38:9 - SELECT DISTINCT ON expressions must match initial ORDER BY expressions | ||
Test.s line 43:15 - SELECT DISTINCT ON expressions must match initial ORDER BY expressions |