diff options
| author | Michael Williamson <mike@zwobble.org> | 2026-10-16 09:11:52 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2026-10-16 09:11:52 +0100 |
| commit | e2f02b6a09548e74304cbc6e32b6ce720d6dba84 (patch) | |
| tree | 8bb388c9fabd028da7d257919f0f081004d6a3c5 /src | |
| parent | b0c668a96bc8da225d7a0c35dfd7ce4178ebb7c4 (diff) | |
Add primary key constraint to SQL AST
Diffstat (limited to 'src')
7 files changed, 225 insertions, 13 deletions
diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java index 20b28c3..b7d0caf 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriter.java @@ -1,10 +1,7 @@ package org.zwobble.hobgoblin.compiler.output.lang.sql; import org.zwobble.hobgoblin.compiler.output.CodeWriter; -import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition; -import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement; -import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier; -import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement; +import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.*; import java.io.IOException; import java.nio.file.Path; @@ -40,6 +37,8 @@ public class SqlWriter { this.writer = writer; } + // == Statements == + void writeStatement(SqlStatement statement) throws IOException { switch (statement) { case SqlCreateTableStatement createTableStatement -> { @@ -64,6 +63,12 @@ public class SqlWriter { } ); + for (var tableConstraint : createTableStatement.tableConstraints()) { + this.writer.write(","); + this.writer.newLine(); + writeTableConstraint(tableConstraint); + } + this.writer.dedent(); this.writer.newLine(); this.writer.write(");"); @@ -75,6 +80,28 @@ public class SqlWriter { this.writeIdentifier(column.typeName()); } + // == Table constraints == + + void writeTableConstraint(SqlTableConstraint tableConstraint) throws IOException { + switch (tableConstraint) { + case SqlPrimaryKeyConstraint primaryKeyConstraint -> { + writePrimaryKeyConstraint(primaryKeyConstraint); + } + } + } + + private void writePrimaryKeyConstraint(SqlPrimaryKeyConstraint primaryKeyConstraint) throws IOException { + this.writer.write("PRIMARY KEY ("); + writeWithSeparator( + primaryKeyConstraint.columns(), + this::writeIdentifier, + () -> this.writer.write(", ") + ); + this.writer.write(")"); + } + + // == Identifiers == + private void writeIdentifier(SqlIdentifier name) throws IOException { // TODO: handle escaping this.writer.write(name.value()); diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatement.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatement.java index a5fec23..85594a2 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatement.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatement.java @@ -7,42 +7,60 @@ package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; public record SqlCreateTableStatement( org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name, - java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition> columns + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition> columns, + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint> tableConstraints ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement { public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder arbitrary() { - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.arbitrary().build(), java.util.List.of()); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.arbitrary().build(), java.util.List.of(), java.util.List.of()); } public record Builder( org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name, - java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition> columns + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition> columns, + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint> tableConstraints ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlStatement.Builder { public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement build() { - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement(name, columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement(name, columns, tableConstraints); } public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier name) { - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); } public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder withName(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.Builder name) { - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name.build(), columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name.build(), columns, tableConstraints); } public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder withColumns(java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition> columns) { - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); } public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition column) { var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition>(this.columns); columns.add(column); - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); } public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition.Builder column) { var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition>(this.columns); columns.add(column.build()); - return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder withTableConstraints(java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint> tableConstraints) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder addTableConstraint(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint tableConstraint) { + var tableConstraints = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint>(this.tableConstraints); + tableConstraints.add(tableConstraint); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder addTableConstraint(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint.Builder tableConstraint) { + var tableConstraints = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint>(this.tableConstraints); + tableConstraints.add(tableConstraint.build()); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder(name, columns, tableConstraints); } // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement.Builder body diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraint.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraint.java new file mode 100644 index 0000000..1876219 --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraint.java @@ -0,0 +1,44 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint imports + +public record SqlPrimaryKeyConstraint( + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier> columns +) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder arbitrary() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder(java.util.List.of()); + } + + public record Builder( + java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier> columns + ) implements org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint.Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint build() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint(columns); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder withColumns(java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier> columns) { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder(columns); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier column) { + var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier>(this.columns); + columns.add(column); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder(columns); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder addColumn(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier.Builder column) { + var columns = new java.util.ArrayList<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier>(this.columns); + columns.add(column.build()); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder(columns); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint body +} diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlTableConstraint.java b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlTableConstraint.java new file mode 100644 index 0000000..e35162f --- /dev/null +++ b/src/main/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlTableConstraint.java @@ -0,0 +1,18 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint imports + +public sealed interface SqlTableConstraint permits org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint { + public interface Builder { + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint build(); + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint.Builder body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint.Builder body + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint body +} diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriterTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriterTests.java index 5edf06c..2d8c7d3 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriterTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/SqlWriterTests.java @@ -5,6 +5,7 @@ import org.zwobble.hobgoblin.compiler.output.CodeWriter; import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlColumnDefinition; import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement; import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier; +import org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint; import java.io.IOException; import java.io.StringWriter; @@ -14,6 +15,8 @@ import static org.zwobble.precisely.AssertThat.assertThat; import static org.zwobble.precisely.Matchers.equalTo; public class SqlWriterTests { + // == Create table statements == + @Test public void createTableStatement() throws IOException { var sql = SqlCreateTableStatement.arbitrary() @@ -38,6 +41,61 @@ public class SqlWriterTests { )); } + @Test + public void createTableStatementWithTableConstraint() throws IOException { + var sql = SqlCreateTableStatement.arbitrary() + .withName(id("authors")) + .addColumn(SqlColumnDefinition.arbitrary() + .withName(id("id")) + .withTypeName(id("INT")) + ) + .addColumn(SqlColumnDefinition.arbitrary() + .withName(id("name")) + .withTypeName(id("TEXT")) + ) + .addTableConstraint(SqlPrimaryKeyConstraint.arbitrary() + .addColumn(id("id")) + ) + .build(); + + var string = write(writer -> writer.writeStatement(sql)); + + assertThat(string, equalTo(""" + CREATE TABLE authors ( + id INT, + name TEXT, + PRIMARY KEY (id) + );""" + )); + } + + // == Table constraints == + + @Test + public void primaryKeyConstraintWithSingleColumn() throws IOException { + var sql = SqlPrimaryKeyConstraint.arbitrary() + .addColumn(id("id")) + .build(); + + var string = write(writer -> writer.writeTableConstraint(sql)); + + assertThat(string, equalTo("PRIMARY KEY (id)")); + } + + @Test + public void primaryKeyConstraintWithMultipleColumns() throws IOException { + var sql = SqlPrimaryKeyConstraint.arbitrary() + .addColumn(id("a")) + .addColumn(id("b")) + .build(); + + var string = write(writer -> writer.writeTableConstraint(sql)); + + assertThat(string, equalTo("PRIMARY KEY (a, b)")); + } + + // == Test utilities == + private String write(SqlWriter.Write write) throws IOException { return write(write, Optional.empty()); } diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatementMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatementMatcher.java index d6c8d57..d5024ef 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatementMatcher.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlCreateTableStatementMatcher.java @@ -42,6 +42,12 @@ public final class SqlCreateTableStatementMatcher implements org.zwobble.precise return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatementMatcher(submatchers); } + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatementMatcher withTableConstraints(org.zwobble.precisely.Matcher<? super java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlTableConstraint>> tableConstraints) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("tableConstraints", org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatement::tableConstraints, (org.zwobble.precisely.Matcher) tableConstraints)); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatementMatcher(submatchers); + } + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatementMatcher body // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlCreateTableStatementMatcher body } diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraintMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraintMatcher.java new file mode 100644 index 0000000..500896b --- /dev/null +++ b/src/test/java/org/zwobble/hobgoblin/compiler/output/lang/sql/ast/SqlPrimaryKeyConstraintMatcher.java @@ -0,0 +1,41 @@ +// Generated by hobgoblin. + +package org.zwobble.hobgoblin.compiler.output.lang.sql.ast; + +// Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher imports +// Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher imports + +public final class SqlPrimaryKeyConstraintMatcher implements org.zwobble.precisely.Matcher<java.lang.Object> { + public static org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher isSqlPrimaryKeyConstraint() { + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher(java.util.List.of()); + } + + private final java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint>> submatchers; + + private SqlPrimaryKeyConstraintMatcher( + java.util.List<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint>> submatchers + ) { + this.submatchers = submatchers; + } + + public org.zwobble.precisely.MatchResult match(java.lang.Object actual) { + return this.toMatcher().match(actual); + } + + public org.zwobble.precisely.TextTree describe() { + return this.toMatcher().describe(); + } + + private org.zwobble.precisely.Matcher<java.lang.Object> toMatcher() { + return org.zwobble.precisely.Matchers.instanceOf(org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint.class, this.submatchers); + } + + public org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher withColumns(org.zwobble.precisely.Matcher<? super java.util.List<org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlIdentifier>> columns) { + var submatchers = new java.util.ArrayList<org.zwobble.precisely.Matcher<? super org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint>>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("columns", org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraint::columns, (org.zwobble.precisely.Matcher) columns)); + return new org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher(submatchers); + } + + // Custom area start: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher body + // Custom area end: org.zwobble.hobgoblin.compiler.output.lang.sql.ast.SqlPrimaryKeyConstraintMatcher body +} |
