From 3afb8859dabdaaa81a6bbbe530d75a4186cc039c Mon Sep 17 00:00:00 2001 From: Michael Williamson Date: Tue, 13 Oct 2026 19:43:04 +0100 Subject: Specify primary key for tables --- examples/18-database/src/data.hob | 11 ++++++----- hobgoblin/src/ast/untyped.hob | 1 + .../ast/untyped/UntypedTableDefinitionNode.java | 20 +++++++++++++------- .../zwobble/hobgoblin/compiler/parser/Parser.java | 5 +++++ .../untyped/UntypedTableDefinitionNodeMatcher.java | 6 ++++++ .../parser/ParserDatabaseSchemaDefinitionTests.java | 2 ++ .../compiler/parser/ParserTableDefinitionTests.java | 2 ++ 7 files changed, 35 insertions(+), 12 deletions(-) diff --git a/examples/18-database/src/data.hob b/examples/18-database/src/data.hob index cad23dd..a168821 100644 --- a/examples/18-database/src/data.hob +++ b/examples/18-database/src/data.hob @@ -1,11 +1,12 @@ -struct StructWithInt32 { - field a: Int32; - field b: Int32; +struct Author { + field id: Int32; + field name: String; } databaseSchema Data { - table structs { - row StructWithInt32; + table authors { + row Author; + primaryKey id; } // // query fetchAllStructs() { diff --git a/hobgoblin/src/ast/untyped.hob b/hobgoblin/src/ast/untyped.hob index d01e331..c72590a 100644 --- a/hobgoblin/src/ast/untyped.hob +++ b/hobgoblin/src/ast/untyped.hob @@ -93,6 +93,7 @@ sum UntypedDatabaseSchemaStatementNode { struct UntypedTableDefinitionNode { field name: String; field rowType: UntypedTypeLevelExpressionNode; + field primaryKey: String; field docComment: DocComment; field source: Source; } diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java index faaef14..ebff463 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNode.java @@ -8,41 +8,47 @@ package org.zwobble.hobgoblin.compiler.ast.untyped; public record UntypedTableDefinitionNode( String name, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode rowType, + String primaryKey, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaStatementNode { public static org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder arbitrary() { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder("", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelReferenceNode.arbitrary().build(), "", org.zwobble.hobgoblin.compiler.ast.HobgoblinNativeAst.arbitraryDocComment(), org.zwobble.hobgoblin.compiler.sources.HobgoblinNativeSources.arbitrarySource()); } public record Builder( String name, org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode rowType, + String primaryKey, org.zwobble.hobgoblin.compiler.ast.DocComment docComment, org.zwobble.hobgoblin.compiler.sources.Source source ) implements org.zwobble.hobgoblin.compiler.ast.untyped.UntypedDatabaseSchemaStatementNode.Builder { public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode build() { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode(name, rowType, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode(name, rowType, primaryKey, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withName(String name) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withRowType(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode rowType) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withRowType(org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTypeLevelExpressionNode.Builder rowType) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType.build(), docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType.build(), primaryKey, docComment, source); + } + + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withPrimaryKey(String primaryKey) { + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withDocComment(org.zwobble.hobgoblin.compiler.ast.DocComment docComment) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder withSource(org.zwobble.hobgoblin.compiler.sources.Source source) { - return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, docComment, source); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder(name, rowType, primaryKey, docComment, source); } // Custom area start: org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode.Builder body diff --git a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java index 23ba43b..3563d0a 100644 --- a/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java +++ b/src/main/java/org/zwobble/hobgoblin/compiler/parser/Parser.java @@ -370,6 +370,10 @@ public class Parser { var rowType = parseTypeLevelExpression(tokens); tokens.skip(TokenType.SYMBOL_SEMICOLON); + tokens.skip(TokenType.IDENTIFIER, "primaryKey"); + var primaryKey = parseIdentifier(tokens); + tokens.skip(TokenType.SYMBOL_SEMICOLON); + tokens.skip(TokenType.SYMBOL_BRACE_CLOSE); var end = tokens.endPosition(); @@ -378,6 +382,7 @@ public class Parser { return new UntypedTableDefinitionNode( name, rowType, + primaryKey, docComment, source ); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNodeMatcher.java b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNodeMatcher.java index 8e4226c..6f8bdfc 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNodeMatcher.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/ast/untyped/UntypedTableDefinitionNodeMatcher.java @@ -42,6 +42,12 @@ public final class UntypedTableDefinitionNodeMatcher implements org.zwobble.prec return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNodeMatcher(submatchers); } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNodeMatcher withPrimaryKey(org.zwobble.precisely.Matcher primaryKey) { + var submatchers = new java.util.ArrayList>(this.submatchers); + submatchers.add(org.zwobble.precisely.Matchers.has("primaryKey", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode::primaryKey, (org.zwobble.precisely.Matcher) primaryKey)); + return new org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNodeMatcher(submatchers); + } + public org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNodeMatcher withDocComment(org.zwobble.precisely.Matcher docComment) { var submatchers = new java.util.ArrayList>(this.submatchers); submatchers.add(org.zwobble.precisely.Matchers.has("docComment", org.zwobble.hobgoblin.compiler.ast.untyped.UntypedTableDefinitionNode::docComment, (org.zwobble.precisely.Matcher) docComment)); diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java index 5c41fa1..4a74324 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserDatabaseSchemaDefinitionTests.java @@ -33,10 +33,12 @@ public class ParserDatabaseSchemaDefinitionTests { databaseSchema BlogApp { table posts { row Post; + primaryKey id; } table author { row Author; + primaryKey id; } }"""; diff --git a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserTableDefinitionTests.java b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserTableDefinitionTests.java index 889b30c..3c3b259 100644 --- a/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserTableDefinitionTests.java +++ b/src/test/java/org/zwobble/hobgoblin/compiler/parser/ParserTableDefinitionTests.java @@ -14,6 +14,7 @@ public class ParserTableDefinitionTests { var source = """ table posts { row Post; + primaryKey id; }"""; var node = parseString( @@ -24,6 +25,7 @@ public class ParserTableDefinitionTests { assertThat(node, isUntypedTableDefinitionNode() .withName(equalTo("posts")) .withRowType(isUntypedTypeLevelReferenceNode().withName(equalTo("Post"))) + .withPrimaryKey(equalTo("id")) ); } } -- cgit v1.2.3