package graphql import ( "strings" "testing" "git.warky.dev/wdevs/relspecgo/pkg/models" "git.warky.dev/wdevs/relspecgo/pkg/writers" ) func TestWriter_WriteTable_Simple(t *testing.T) { table := models.InitTable("User", "public") idCol := models.InitColumn("id", "User", "public") idCol.Type = "bigint" idCol.IsPrimaryKey = true idCol.NotNull = true table.Columns["id"] = idCol nameCol := models.InitColumn("name", "User", "public") nameCol.Type = "text" nameCol.NotNull = true table.Columns["name"] = nameCol emailCol := models.InitColumn("email", "User", "public") emailCol.Type = "text" emailCol.NotNull = false table.Columns["email"] = emailCol opts := &writers.WriterOptions{ OutputPath: "", } writer := NewWriter(opts) schema := models.InitSchema("public") schema.Tables = []*models.Table{table} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} output := writer.databaseToGraphQL(db) // Verify output contains type definition if !strings.Contains(output, "type User {") { t.Error("Expected 'type User {' in output") } // Verify fields if !strings.Contains(output, "id: ID!") { t.Error("Expected 'id: ID!' in output") } if !strings.Contains(output, "name: String!") { t.Error("Expected 'name: String!' in output") } if !strings.Contains(output, "email: String") { t.Error("Expected 'email: String' in output") } // Ensure email is not followed by ! (nullable) if strings.Contains(output, "email: String!") { t.Error("Did not expect 'email: String!' (should be nullable)") } } func TestWriter_WriteDatabase_WithEnum(t *testing.T) { schema := models.InitSchema("public") // Create enum roleEnum := &models.Enum{ Name: "Role", Schema: "public", Values: []string{"ADMIN", "USER", "GUEST"}, } schema.Enums = []*models.Enum{roleEnum} // Create table with enum field table := models.InitTable("User", "public") idCol := models.InitColumn("id", "User", "public") idCol.Type = "bigint" idCol.IsPrimaryKey = true idCol.NotNull = true table.Columns["id"] = idCol roleCol := models.InitColumn("role", "User", "public") roleCol.Type = "Role" roleCol.NotNull = true table.Columns["role"] = roleCol schema.Tables = []*models.Table{table} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{} writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // Verify enum definition if !strings.Contains(output, "enum Role {") { t.Error("Expected 'enum Role {' in output") } if !strings.Contains(output, "ADMIN") { t.Error("Expected 'ADMIN' enum value in output") } // Verify enum usage in type if !strings.Contains(output, "role: Role!") { t.Error("Expected 'role: Role!' in output") } } func TestWriter_WriteDatabase_WithRelations(t *testing.T) { schema := models.InitSchema("public") // Create User table userTable := models.InitTable("User", "public") userIdCol := models.InitColumn("id", "User", "public") userIdCol.Type = "bigint" userIdCol.IsPrimaryKey = true userIdCol.NotNull = true userTable.Columns["id"] = userIdCol userNameCol := models.InitColumn("name", "User", "public") userNameCol.Type = "text" userNameCol.NotNull = true userTable.Columns["name"] = userNameCol // Create Post table with FK to User postTable := models.InitTable("Post", "public") postIdCol := models.InitColumn("id", "Post", "public") postIdCol.Type = "bigint" postIdCol.IsPrimaryKey = true postIdCol.NotNull = true postTable.Columns["id"] = postIdCol titleCol := models.InitColumn("title", "Post", "public") titleCol.Type = "text" titleCol.NotNull = true postTable.Columns["title"] = titleCol authorIdCol := models.InitColumn("authorId", "Post", "public") authorIdCol.Type = "bigint" authorIdCol.NotNull = true postTable.Columns["authorId"] = authorIdCol // Add FK constraint fkConstraint := models.InitConstraint("fk_post_author", models.ForeignKeyConstraint) fkConstraint.Schema = "public" fkConstraint.Table = "Post" fkConstraint.Columns = []string{"authorId"} fkConstraint.ReferencedSchema = "public" fkConstraint.ReferencedTable = "User" fkConstraint.ReferencedColumns = []string{"id"} postTable.Constraints["fk_post_author"] = fkConstraint schema.Tables = []*models.Table{userTable, postTable} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{} writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // Verify Post has author field (forward relationship) if !strings.Contains(output, "author: User!") { t.Error("Expected 'author: User!' in Post type") } // Verify authorId FK column is NOT in the output if strings.Contains(output, "authorId:") { t.Error("Did not expect 'authorId:' field in output (FK columns should be hidden)") } // Verify User has posts field (reverse relationship) if !strings.Contains(output, "posts: [Post!]!") { t.Error("Expected 'posts: [Post!]!' in User type") } } func TestWriter_WriteDatabase_CustomScalars(t *testing.T) { schema := models.InitSchema("public") table := models.InitTable("Event", "public") idCol := models.InitColumn("id", "Event", "public") idCol.Type = "bigint" idCol.IsPrimaryKey = true idCol.NotNull = true table.Columns["id"] = idCol createdAtCol := models.InitColumn("createdAt", "Event", "public") createdAtCol.Type = "timestamp" createdAtCol.NotNull = true table.Columns["createdAt"] = createdAtCol metadataCol := models.InitColumn("metadata", "Event", "public") metadataCol.Type = "jsonb" metadataCol.NotNull = false table.Columns["metadata"] = metadataCol dateCol := models.InitColumn("eventDate", "Event", "public") dateCol.Type = "date" dateCol.NotNull = false table.Columns["eventDate"] = dateCol schema.Tables = []*models.Table{table} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{} writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // Verify scalar declarations if !strings.Contains(output, "scalar DateTime") { t.Error("Expected 'scalar DateTime' declaration") } if !strings.Contains(output, "scalar JSON") { t.Error("Expected 'scalar JSON' declaration") } if !strings.Contains(output, "scalar Date") { t.Error("Expected 'scalar Date' declaration") } // Verify field types if !strings.Contains(output, "createdAt: DateTime!") { t.Error("Expected 'createdAt: DateTime!' in output") } if !strings.Contains(output, "metadata: JSON") { t.Error("Expected 'metadata: JSON' in output") } if !strings.Contains(output, "eventDate: Date") { t.Error("Expected 'eventDate: Date' in output") } } func TestWriter_WriteDatabase_ManyToMany(t *testing.T) { schema := models.InitSchema("public") // Create Post table postTable := models.InitTable("Post", "public") postIdCol := models.InitColumn("id", "Post", "public") postIdCol.Type = "bigint" postIdCol.IsPrimaryKey = true postIdCol.NotNull = true postTable.Columns["id"] = postIdCol titleCol := models.InitColumn("title", "Post", "public") titleCol.Type = "text" titleCol.NotNull = true postTable.Columns["title"] = titleCol // Create Tag table tagTable := models.InitTable("Tag", "public") tagIdCol := models.InitColumn("id", "Tag", "public") tagIdCol.Type = "bigint" tagIdCol.IsPrimaryKey = true tagIdCol.NotNull = true tagTable.Columns["id"] = tagIdCol nameCol := models.InitColumn("name", "Tag", "public") nameCol.Type = "text" nameCol.NotNull = true tagTable.Columns["name"] = nameCol // Create PostTag join table joinTable := models.InitTable("PostTag", "public") postIdJoinCol := models.InitColumn("postId", "PostTag", "public") postIdJoinCol.Type = "bigint" postIdJoinCol.NotNull = true postIdJoinCol.IsPrimaryKey = true joinTable.Columns["postId"] = postIdJoinCol tagIdJoinCol := models.InitColumn("tagId", "PostTag", "public") tagIdJoinCol.Type = "bigint" tagIdJoinCol.NotNull = true tagIdJoinCol.IsPrimaryKey = true joinTable.Columns["tagId"] = tagIdJoinCol // Add composite PK constraint pkConstraint := models.InitConstraint("pk_posttag", models.PrimaryKeyConstraint) pkConstraint.Schema = "public" pkConstraint.Table = "PostTag" pkConstraint.Columns = []string{"postId", "tagId"} joinTable.Constraints["pk_posttag"] = pkConstraint // Add FK to Post fk1 := models.InitConstraint("fk_posttag_post", models.ForeignKeyConstraint) fk1.Schema = "public" fk1.Table = "PostTag" fk1.Columns = []string{"postId"} fk1.ReferencedSchema = "public" fk1.ReferencedTable = "Post" fk1.ReferencedColumns = []string{"id"} joinTable.Constraints["fk_posttag_post"] = fk1 // Add FK to Tag fk2 := models.InitConstraint("fk_posttag_tag", models.ForeignKeyConstraint) fk2.Schema = "public" fk2.Table = "PostTag" fk2.Columns = []string{"tagId"} fk2.ReferencedSchema = "public" fk2.ReferencedTable = "Tag" fk2.ReferencedColumns = []string{"id"} joinTable.Constraints["fk_posttag_tag"] = fk2 schema.Tables = []*models.Table{postTable, tagTable, joinTable} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{} writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // Verify join table is NOT in output if strings.Contains(output, "type PostTag") { t.Error("Did not expect 'type PostTag' (join tables should be hidden)") } // Verify Post has tags field if !strings.Contains(output, "tags: [Tag!]!") { t.Error("Expected 'tags: [Tag!]!' in Post type") } // Verify Tag has posts field if !strings.Contains(output, "posts: [Post!]!") { t.Error("Expected 'posts: [Post!]!' in Tag type") } } func TestWriter_WriteDatabase_UUIDType(t *testing.T) { schema := models.InitSchema("public") table := models.InitTable("User", "public") idCol := models.InitColumn("id", "User", "public") idCol.Type = "uuid" idCol.IsPrimaryKey = true idCol.NotNull = true table.Columns["id"] = idCol schema.Tables = []*models.Table{table} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{} writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // UUID primary keys should still map to ID if !strings.Contains(output, "id: ID!") { t.Error("Expected 'id: ID!' for UUID primary key") } } func TestWriter_Metadata_NoScalarDeclarations(t *testing.T) { schema := models.InitSchema("public") table := models.InitTable("Event", "public") idCol := models.InitColumn("id", "Event", "public") idCol.Type = "bigint" idCol.IsPrimaryKey = true table.Columns["id"] = idCol createdAtCol := models.InitColumn("createdAt", "Event", "public") createdAtCol.Type = "timestamp" createdAtCol.NotNull = true table.Columns["createdAt"] = createdAtCol schema.Tables = []*models.Table{table} db := models.InitDatabase("test") db.Schemas = []*models.Schema{schema} opts := &writers.WriterOptions{ Metadata: map[string]any{ "includeScalarDeclarations": false, }, } writer := NewWriter(opts) output := writer.databaseToGraphQL(db) // Verify no scalar declarations if strings.Contains(output, "scalar DateTime") { t.Error("Did not expect 'scalar DateTime' with includeScalarDeclarations=false") } // But field should still use DateTime if !strings.Contains(output, "createdAt: DateTime!") { t.Error("Expected 'createdAt: DateTime!' in output") } }