363 lines
8.9 KiB
Go
363 lines
8.9 KiB
Go
package graphql
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.warky.dev/wdevs/relspecgo/pkg/models"
|
|
"git.warky.dev/wdevs/relspecgo/pkg/readers"
|
|
)
|
|
|
|
func TestReader_ReadDatabase_Simple(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "simple.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
if len(db.Schemas) == 0 {
|
|
t.Fatal("Expected at least one schema")
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
if schema.Name != "public" {
|
|
t.Errorf("Expected schema name 'public', got '%s'", schema.Name)
|
|
}
|
|
|
|
if len(schema.Tables) != 1 {
|
|
t.Fatalf("Expected 1 table, got %d", len(schema.Tables))
|
|
}
|
|
|
|
userTable := schema.Tables[0]
|
|
if userTable.Name != "User" {
|
|
t.Errorf("Expected table name 'User', got '%s'", userTable.Name)
|
|
}
|
|
|
|
// Verify columns
|
|
expectedColumns := map[string]struct {
|
|
sqlType string
|
|
notNull bool
|
|
isPK bool
|
|
}{
|
|
"id": {"bigint", true, true},
|
|
"email": {"text", true, false},
|
|
"name": {"text", false, false},
|
|
"age": {"integer", false, false},
|
|
"active": {"boolean", true, false},
|
|
}
|
|
|
|
if len(userTable.Columns) != len(expectedColumns) {
|
|
t.Fatalf("Expected %d columns, got %d", len(expectedColumns), len(userTable.Columns))
|
|
}
|
|
|
|
for colName, expected := range expectedColumns {
|
|
col, exists := userTable.Columns[colName]
|
|
if !exists {
|
|
t.Errorf("Expected column '%s' not found", colName)
|
|
continue
|
|
}
|
|
|
|
if col.Type != expected.sqlType {
|
|
t.Errorf("Column '%s': expected type '%s', got '%s'", colName, expected.sqlType, col.Type)
|
|
}
|
|
|
|
if col.NotNull != expected.notNull {
|
|
t.Errorf("Column '%s': expected NotNull=%v, got %v", colName, expected.notNull, col.NotNull)
|
|
}
|
|
|
|
if col.IsPrimaryKey != expected.isPK {
|
|
t.Errorf("Column '%s': expected IsPrimaryKey=%v, got %v", colName, expected.isPK, col.IsPrimaryKey)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_WithRelations(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "relations.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
|
|
if len(schema.Tables) != 2 {
|
|
t.Fatalf("Expected 2 tables, got %d", len(schema.Tables))
|
|
}
|
|
|
|
// Find Post table (should have FK to User)
|
|
var postTable *models.Table
|
|
for _, table := range schema.Tables {
|
|
if table.Name == "Post" {
|
|
postTable = table
|
|
break
|
|
}
|
|
}
|
|
|
|
if postTable == nil {
|
|
t.Fatal("Post table not found")
|
|
}
|
|
|
|
// Verify authorId FK column was created
|
|
authorIdCol, exists := postTable.Columns["authorId"]
|
|
if !exists {
|
|
t.Fatal("Expected 'authorId' FK column not found in Post table")
|
|
}
|
|
|
|
if authorIdCol.Type != "bigint" {
|
|
t.Errorf("Expected authorId type 'bigint', got '%s'", authorIdCol.Type)
|
|
}
|
|
|
|
if !authorIdCol.NotNull {
|
|
t.Error("Expected authorId to be NOT NULL")
|
|
}
|
|
|
|
// Verify FK constraint
|
|
fkConstraintFound := false
|
|
for _, constraint := range postTable.Constraints {
|
|
if constraint.Type == models.ForeignKeyConstraint {
|
|
if constraint.ReferencedTable == "User" && len(constraint.Columns) > 0 && constraint.Columns[0] == "authorId" {
|
|
fkConstraintFound = true
|
|
if constraint.OnDelete != "CASCADE" {
|
|
t.Errorf("Expected OnDelete CASCADE, got %s", constraint.OnDelete)
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if !fkConstraintFound {
|
|
t.Error("Foreign key constraint from Post to User not found")
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_WithEnums(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "enums.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
|
|
if len(schema.Enums) != 1 {
|
|
t.Fatalf("Expected 1 enum, got %d", len(schema.Enums))
|
|
}
|
|
|
|
roleEnum := schema.Enums[0]
|
|
if roleEnum.Name != "Role" {
|
|
t.Errorf("Expected enum name 'Role', got '%s'", roleEnum.Name)
|
|
}
|
|
|
|
expectedValues := []string{"ADMIN", "USER", "GUEST"}
|
|
if len(roleEnum.Values) != len(expectedValues) {
|
|
t.Fatalf("Expected %d enum values, got %d", len(expectedValues), len(roleEnum.Values))
|
|
}
|
|
|
|
for i, expected := range expectedValues {
|
|
if roleEnum.Values[i] != expected {
|
|
t.Errorf("Expected enum value '%s' at index %d, got '%s'", expected, i, roleEnum.Values[i])
|
|
}
|
|
}
|
|
|
|
// Verify role column in User table
|
|
userTable := schema.Tables[0]
|
|
roleCol, exists := userTable.Columns["role"]
|
|
if !exists {
|
|
t.Fatal("Expected 'role' column not found")
|
|
}
|
|
|
|
if roleCol.Type != "Role" {
|
|
t.Errorf("Expected role type 'Role', got '%s'", roleCol.Type)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_CustomScalars(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "custom_scalars.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
userTable := schema.Tables[0]
|
|
|
|
// Verify custom scalar mappings
|
|
expectedTypes := map[string]string{
|
|
"createdAt": "timestamp",
|
|
"metadata": "jsonb",
|
|
"birthDate": "date",
|
|
}
|
|
|
|
for colName, expectedType := range expectedTypes {
|
|
col, exists := userTable.Columns[colName]
|
|
if !exists {
|
|
t.Errorf("Expected column '%s' not found", colName)
|
|
continue
|
|
}
|
|
|
|
if col.Type != expectedType {
|
|
t.Errorf("Column '%s': expected type '%s', got '%s'", colName, expectedType, col.Type)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_UUIDMetadata(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "simple.graphql"),
|
|
Metadata: map[string]interface{}{
|
|
"idType": "uuid",
|
|
},
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
userTable := schema.Tables[0]
|
|
|
|
idCol, exists := userTable.Columns["id"]
|
|
if !exists {
|
|
t.Fatal("Expected 'id' column not found")
|
|
}
|
|
|
|
if idCol.Type != "uuid" {
|
|
t.Errorf("Expected id type 'uuid' with metadata, got '%s'", idCol.Type)
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadDatabase_Complex(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "complex.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
db, err := reader.ReadDatabase()
|
|
if err != nil {
|
|
t.Fatalf("ReadDatabase() error = %v", err)
|
|
}
|
|
|
|
schema := db.Schemas[0]
|
|
|
|
// Should have 5 tables: User, Profile, Post, Tag, and PostTag (join table)
|
|
expectedTableCount := 5
|
|
if len(schema.Tables) != expectedTableCount {
|
|
t.Fatalf("Expected %d tables, got %d", expectedTableCount, len(schema.Tables))
|
|
}
|
|
|
|
// Verify PostTag join table exists (many-to-many between Post and Tag)
|
|
var joinTable *models.Table
|
|
for _, table := range schema.Tables {
|
|
if table.Name == "PostTag" {
|
|
joinTable = table
|
|
break
|
|
}
|
|
}
|
|
|
|
if joinTable == nil {
|
|
t.Fatal("Expected PostTag join table not found")
|
|
}
|
|
|
|
// Verify join table has both FK columns
|
|
if _, exists := joinTable.Columns["postId"]; !exists {
|
|
t.Error("Expected 'postId' column in PostTag join table")
|
|
}
|
|
|
|
if _, exists := joinTable.Columns["tagId"]; !exists {
|
|
t.Error("Expected 'tagId' column in PostTag join table")
|
|
}
|
|
|
|
// Verify composite primary key
|
|
pkFound := false
|
|
for _, constraint := range joinTable.Constraints {
|
|
if constraint.Type == models.PrimaryKeyConstraint {
|
|
if len(constraint.Columns) == 2 {
|
|
pkFound = true
|
|
}
|
|
break
|
|
}
|
|
}
|
|
|
|
if !pkFound {
|
|
t.Error("Expected composite primary key in PostTag join table")
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadSchema(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "simple.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
schema, err := reader.ReadSchema()
|
|
if err != nil {
|
|
t.Fatalf("ReadSchema() error = %v", err)
|
|
}
|
|
|
|
if schema.Name != "public" {
|
|
t.Errorf("Expected schema name 'public', got '%s'", schema.Name)
|
|
}
|
|
|
|
if len(schema.Tables) != 1 {
|
|
t.Errorf("Expected 1 table, got %d", len(schema.Tables))
|
|
}
|
|
}
|
|
|
|
func TestReader_ReadTable(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: filepath.Join("..", "..", "..", "tests", "assets", "graphql", "simple.graphql"),
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
table, err := reader.ReadTable()
|
|
if err != nil {
|
|
t.Fatalf("ReadTable() error = %v", err)
|
|
}
|
|
|
|
if table.Name != "User" {
|
|
t.Errorf("Expected table name 'User', got '%s'", table.Name)
|
|
}
|
|
}
|
|
|
|
func TestReader_InvalidPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "/nonexistent/path.graphql",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadDatabase()
|
|
if err == nil {
|
|
t.Error("Expected error for invalid path, got nil")
|
|
}
|
|
}
|
|
|
|
func TestReader_EmptyPath(t *testing.T) {
|
|
opts := &readers.ReaderOptions{
|
|
FilePath: "",
|
|
}
|
|
|
|
reader := NewReader(opts)
|
|
_, err := reader.ReadDatabase()
|
|
if err == nil {
|
|
t.Error("Expected error for empty path, got nil")
|
|
}
|
|
}
|