package models import ( "testing" "time" ) func TestSQLNameLowercases(t *testing.T) { tests := []struct { name string got string }{ {"database", (&Database{Name: "MyDB"}).SQLName()}, {"domain", (&Domain{Name: "MyDomain"}).SQLName()}, {"schema", (&Schema{Name: "MySchema"}).SQLName()}, {"table", (&Table{Name: "MyTable"}).SQLName()}, {"view", (&View{Name: "MyView"}).SQLName()}, {"sequence", (&Sequence{Name: "MySeq"}).SQLName()}, {"column", (&Column{Name: "MyCol"}).SQLName()}, {"index", (&Index{Name: "MyIdx"}).SQLName()}, {"relationship", (&Relationship{Name: "MyRel"}).SQLName()}, {"constraint", (&Constraint{Name: "MyCon"}).SQLName()}, {"enum", (&Enum{Name: "MyEnum"}).SQLName()}, {"script", (&Script{Name: "MyScript"}).SQLName()}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.got == "" || tt.got != lower(tt.got) { t.Errorf("SQLName not lowercase: %q", tt.got) } }) } if got := (&Table{}).SQLName(); got != "" { t.Errorf("empty name: %q", got) } if got := (&Table{Name: "MyTable"}).SQLName(); got != "mytable" { t.Errorf("got %q", got) } } func lower(s string) string { b := []byte(s) for i, c := range b { if c >= 'A' && c <= 'Z' { b[i] = c + 32 } } return string(b) } func TestUpdateDatePropagates(t *testing.T) { db := InitDatabase("d") schema := InitSchema("s") schema.RefDatabase = db table := InitTable("t", "s") table.RefSchema = schema table.UpdateDate() for name, v := range map[string]string{"table": table.UpdatedAt, "schema": schema.UpdatedAt, "database": db.UpdatedAt} { ts, err := time.Parse(time.RFC3339, v) if err != nil { t.Fatalf("%s UpdatedAt %q: %v", name, v, err) } if time.Since(ts) > time.Minute { t.Errorf("%s UpdatedAt too old: %v", name, ts) } } // Without references only the receiver is updated. lone := InitTable("lone", "s") lone.UpdateDate() if lone.UpdatedAt == "" { t.Error("lone table not updated") } loneSchema := InitSchema("x") loneSchema.UpdateDate() if loneSchema.UpdatedAt == "" { t.Error("lone schema not updated") } } func TestGetPrimaryKey(t *testing.T) { tests := []struct { name string cols []*Column want string }{ {"none", []*Column{{Name: "a"}}, ""}, {"single", []*Column{{Name: "a"}, {Name: "id", IsPrimaryKey: true}}, "id"}, {"composite ordered by sequence", []*Column{ {Name: "a", IsPrimaryKey: true, Sequence: 2}, {Name: "b", IsPrimaryKey: true, Sequence: 1}, }, "b"}, {"composite without sequence falls back to name", []*Column{ {Name: "z", IsPrimaryKey: true}, {Name: "m", IsPrimaryKey: true}, }, "m"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tbl := InitTable("t", "s") for _, c := range tt.cols { tbl.Columns[c.Name] = c } got := tbl.GetPrimaryKey() if tt.want == "" { if got != nil { t.Errorf("expected nil, got %s", got.Name) } return } if got == nil || got.Name != tt.want { t.Errorf("got %v, want %s", got, tt.want) } }) } if InitTable("empty", "s").GetPrimaryKey() != nil { t.Error("empty table must have no PK") } } func TestColumnLess(t *testing.T) { tests := []struct { a, b *Column want bool }{ {&Column{Name: "a", Sequence: 1}, &Column{Name: "b", Sequence: 2}, true}, {&Column{Name: "a", Sequence: 2}, &Column{Name: "b", Sequence: 1}, false}, {&Column{Name: "a"}, &Column{Name: "b"}, true}, {&Column{Name: "b"}, &Column{Name: "a"}, false}, {&Column{Name: "b", Sequence: 1}, &Column{Name: "a"}, false}, // one side unsequenced: by name {&Column{Name: "a", Sequence: 1}, &Column{Name: "b"}, true}, } for i, tt := range tests { if got := columnLess(tt.a, tt.b); got != tt.want { t.Errorf("case %d: got %v, want %v", i, got, tt.want) } } } func TestGetForeignKeys(t *testing.T) { tbl := InitTable("t", "s") add := func(name string, typ ConstraintType, seq uint) { c := InitConstraint(name, typ) c.Sequence = seq tbl.Constraints[name] = c } add("pk", PrimaryKeyConstraint, 0) add("fk_b", ForeignKeyConstraint, 0) add("fk_a", ForeignKeyConstraint, 0) add("uq", UniqueConstraint, 0) got := tbl.GetForeignKeys() if len(got) != 2 || got[0].Name != "fk_a" || got[1].Name != "fk_b" { t.Errorf("by name: %v", got) } tbl.Constraints["fk_a"].Sequence = 5 tbl.Constraints["fk_b"].Sequence = 2 got = tbl.GetForeignKeys() if got[0].Name != "fk_b" || got[1].Name != "fk_a" { t.Errorf("by sequence: %v", got) } if got := InitTable("e", "s").GetForeignKeys(); got == nil || len(got) != 0 { t.Errorf("empty table must give non-nil empty slice, got %v", got) } } func TestInitConstructors(t *testing.T) { db := InitDatabase("db") if db.Name != "db" || db.Schemas == nil || db.Domains == nil || db.Metadata == nil || db.GUID == "" { t.Errorf("InitDatabase: %+v", db) } s := InitSchema("s") if s.Name != "s" || s.Tables == nil || s.Views == nil || s.Sequences == nil || s.Permissions == nil || s.Metadata == nil || s.Scripts == nil || s.GUID == "" { t.Errorf("InitSchema: %+v", s) } tb := InitTable("t", "s") if tb.Name != "t" || tb.Schema != "s" || tb.Columns == nil || tb.Constraints == nil || tb.Indexes == nil || tb.Relationships == nil || tb.Metadata == nil || tb.GUID == "" { t.Errorf("InitTable: %+v", tb) } c := InitColumn("c", "t", "s") if c.Name != "c" || c.Table != "t" || c.Schema != "s" || c.Metadata == nil || c.GUID == "" { t.Errorf("InitColumn: %+v", c) } ix := InitIndex("i", "t", "s") if ix.Name != "i" || ix.Table != "t" || ix.Schema != "s" || ix.Columns == nil || ix.Include == nil || ix.Metadata == nil || ix.GUID == "" { t.Errorf("InitIndex: %+v", ix) } r := InitRelation("r", "s") if r.Name != "r" || r.FromSchema != "s" || r.ToSchema != "s" || r.Properties == nil || r.FromColumns == nil || r.ToColumns == nil || r.GUID == "" { t.Errorf("InitRelation: %+v", r) } rel := InitRelationship("rel", RelationType("one_to_many")) if rel.Name != "rel" || rel.Type != "one_to_many" || rel.Properties == nil || rel.GUID == "" { t.Errorf("InitRelationship: %+v", rel) } con := InitConstraint("k", UniqueConstraint) if con.Name != "k" || con.Type != UniqueConstraint || con.Columns == nil || con.ReferencedColumns == nil || con.GUID == "" { t.Errorf("InitConstraint: %+v", con) } sc := InitScript("sc") if sc.Name != "sc" || sc.RunAfter == nil || sc.Metadata == nil || sc.GUID == "" { t.Errorf("InitScript: %+v", sc) } v := InitView("v", "s") if v.Name != "v" || v.Schema != "s" || v.Columns == nil || v.Metadata == nil || v.GUID == "" { t.Errorf("InitView: %+v", v) } sq := InitSequence("sq", "s") if sq.Name != "sq" || sq.Schema != "s" || sq.IncrementBy != 1 || sq.StartValue != 1 || sq.GUID == "" { t.Errorf("InitSequence: %+v", sq) } d := InitDomain("d") if d.Name != "d" || d.Tables == nil || d.Metadata == nil || d.GUID == "" { t.Errorf("InitDomain: %+v", d) } dt := InitDomainTable("t", "s") if dt.TableName != "t" || dt.SchemaName != "s" || dt.GUID == "" { t.Errorf("InitDomainTable: %+v", dt) } e := InitEnum("e", "s") if e.Name != "e" || e.Schema != "s" || e.Values == nil || e.GUID == "" { t.Errorf("InitEnum: %+v", e) } // GUIDs are unique per call. if InitTable("t", "s").GUID == InitTable("t", "s").GUID { t.Error("GUIDs must be unique") } }