From 585728b94ea1037ddb3c009a0ff18ff62a1c3db3 Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Mon, 2 Nov 2026 18:37:17 +0000 Subject: Add test around generating SQL SELECT --- .../output/generators/sql/SqlGenerator.java | 20 +++++-- .../output/generators/sql/SqlGeneratorTests.java | 69 ++++++++++++++++++++++ 2 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 src/test/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGeneratorTests.java (limited to 'src') diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java index 624b3fe..456ffd8 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGenerator.java @@ -1,5 +1,6 @@ package org.zwobble.hobgoblin.compiler.output.generators.sql; +import org.zwobble.hobgoblin.compiler.ast.typed.Relation; import org.zwobble.hobgoblin.compiler.ast.typed.RelationTable; import org.zwobble.hobgoblin.compiler.ast.typed.TypedQueryDefinitionNode; import org.zwobble.hobgoblin.compiler.ast.typed.TypedTableDefinitionNode; @@ -56,7 +57,11 @@ public class SqlGenerator { TypedQueryDefinitionNode queryDefinition, TypesInfo typesInfo ) { - switch (queryDefinition.relation()) { + return generateRelation(queryDefinition.relation(), typesInfo); + } + + SqlSelectStatement generateRelation(Relation relation, TypesInfo typesInfo) { + switch (relation) { case RelationTable relationTable -> { var table = relationTable.table(); var schemaInfo = typesInfo.databaseSchemaInfo(table.databaseSchema()); @@ -73,14 +78,17 @@ public class SqlGenerator { }) .toList(); + // Order by the primary key to ensure stable ordering. + var orderBy = List.of( + new SqlOrderingTerm(new SqlRef( + generateColumnName(tableInfo.primaryKey().name()) + )) + ); + return new SqlSelectStatement( columns, generateTableName(table.name()), - List.of( - new SqlOrderingTerm(new SqlRef( - generateColumnName(tableInfo.primaryKey().name()) - )) - ) + orderBy ); } } diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGeneratorTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGeneratorTests.java new file mode 100644 index 0000000..0438baf --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/generators/sql/SqlGeneratorTests.java @@ -0,0 +1,69 @@ +package org.zwobble.hobgoblin.compiler.output.generators.sql; + +import org.junit.jupiter.api.Test; +import org.zwobble.hobgoblin.compiler.ast.typed.RelationTable; +import org.zwobble.hobgoblin.compiler.builtins.NativeTypes; +import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier; +import org.zwobble.hobgoblin.compiler.sources.NullSource; +import org.zwobble.hobgoblin.compiler.typechecker.TypesInfoInMemory; +import org.zwobble.hobgoblin.compiler.types.*; +import org.zwobble.hobgoblin.compiler.util.SequencedMaps; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlOrderingTermMatcher.isSqlOrderingTerm; +import static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlRefMatcher.isSqlRef; +import static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlResultColumnMatcher.isSqlResultColumn; +import static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlSelectStatementMatcher.isSqlSelectStatement; +import static org.zwobble.precisely.AssertThat.assertThat; +import static org.zwobble.precisely.Matchers.equalTo; +import static org.zwobble.precisely.Matchers.isSequence; + +public class SqlGeneratorTests { + @Test + public void relationTableIsTranslatedToSelectFromTable() { + var namespaceName = NamespaceName.of("App"); + var databaseSchema = new DatabaseSchema(namespaceName, "blog"); + var table = new Table(databaseSchema, "authors"); + var authorType = new SimpleStructType(namespaceName, "Author"); + var authorIdField = new Field("id", NativeTypes.INT_32, NullSource.INSTANCE); + var authorNameField = new Field("name", NativeTypes.STRING, NullSource.INSTANCE); + + var typesInfo = TypesInfoInMemory.empty(); + var databaseSchemaInfo = new DatabaseSchemaInfo(SequencedMaps.ofEntries( + Map.entry("authors", new TableInfo(table, authorType, authorIdField)) + )); + typesInfo.defineDatabaseSchema(databaseSchema, databaseSchemaInfo); + typesInfo.defineStructType(authorType, Optional.of(List.of(authorIdField, authorNameField))); + + var sqlGenerator = new SqlGenerator(); + + var relation = RelationTable.arbitrary() + .withTable(table) + .build(); + + var statement = sqlGenerator.generateRelation(relation, typesInfo); + + assertThat(statement, isSqlSelectStatement() + .withColumns(isSequence( + isSqlResultColumn() + .withExpression(isSqlRef().withName(equalTo(id("id")))) + .withAlias(equalTo(id("id"))), + isSqlResultColumn() + .withExpression(isSqlRef().withName(equalTo(id("name")))) + .withAlias(equalTo(id("name"))) + )) + .withFrom(equalTo(id("authors"))) + .withOrderBy(isSequence( + isSqlOrderingTerm() + .withExpression(isSqlRef().withName(equalTo(id("id")))) + )) + ); + } + + private SqlIdentifier id(String value) { + return new SqlIdentifier(value); + } +} -- cgit v1.2.3