github.com/friesencr/pop/v6@v6.1.6/pop_test.go (about) 1 package pop 2 3 import ( 4 stdlog "log" 5 "os" 6 "testing" 7 "time" 8 9 "github.com/friesencr/pop/v6/logging" 10 "github.com/gobuffalo/nulls" 11 "github.com/gobuffalo/validate/v3" 12 "github.com/gobuffalo/validate/v3/validators" 13 "github.com/gofrs/uuid/v5" 14 "github.com/stretchr/testify/suite" 15 ) 16 17 var PDB *Connection 18 19 type PostgreSQLSuite struct { 20 suite.Suite 21 } 22 23 type MySQLSuite struct { 24 suite.Suite 25 } 26 27 type SQLiteSuite struct { 28 suite.Suite 29 } 30 31 type CockroachSuite struct { 32 suite.Suite 33 } 34 35 func TestSpecificSuites(t *testing.T) { 36 switch os.Getenv("SODA_DIALECT") { 37 case "postgres": 38 suite.Run(t, &PostgreSQLSuite{}) 39 case "mysql", "mysql_travis": 40 suite.Run(t, &MySQLSuite{}) 41 case "sqlite": 42 suite.Run(t, &SQLiteSuite{}) 43 case "cockroach": 44 suite.Run(t, &CockroachSuite{}) 45 } 46 } 47 48 func init() { 49 Debug = false 50 AddLookupPaths("./") 51 52 dialect := os.Getenv("SODA_DIALECT") 53 54 if dialect == "" { 55 log(logging.Info, "Skipping integration tests because SODA_DIALECT is blank or unset") 56 return 57 } 58 59 if err := LoadConfigFile(); err != nil { 60 stdlog.Panic(err) 61 } 62 63 var err error 64 log(logging.Info, "Run test with dialect %v", dialect) 65 PDB, err = Connect(dialect) 66 if err != nil { 67 stdlog.Panic(err) 68 } 69 } 70 71 func transaction(fn func(tx *Connection)) { 72 err := PDB.Rollback(func(tx *Connection) { 73 fn(tx) 74 }) 75 if err != nil { 76 stdlog.Fatal(err) 77 } 78 } 79 80 func ts(s string) string { 81 return PDB.Dialect.TranslateSQL(s) 82 } 83 84 type Client struct { 85 ClientID string `db:"id"` 86 } 87 88 func (c Client) TableName() string { 89 return "clients" 90 } 91 92 type User struct { 93 ID int `db:"id"` 94 UserName string `db:"user_name"` 95 Email string `db:"email"` 96 Name nulls.String `db:"name"` 97 Alive nulls.Bool `db:"alive"` 98 CreatedAt time.Time `db:"created_at"` 99 UpdatedAt time.Time `db:"updated_at"` 100 BirthDate nulls.Time `db:"birth_date"` 101 Bio nulls.String `db:"bio"` 102 Price nulls.Float64 `db:"price"` 103 FullName nulls.String `db:"full_name" select:"name as full_name"` 104 Books Books `has_many:"books" order_by:"title asc"` 105 FavoriteSong Song `has_one:"song" fk_id:"u_id"` 106 Houses Addresses `many_to_many:"users_addresses"` 107 } 108 109 type UserPointerAssocs struct { 110 ID int `db:"id"` 111 UserName string `db:"user_name"` 112 Email string `db:"email"` 113 Name nulls.String `db:"name"` 114 Alive nulls.Bool `db:"alive"` 115 CreatedAt time.Time `db:"created_at"` 116 UpdatedAt time.Time `db:"updated_at"` 117 BirthDate nulls.Time `db:"birth_date"` 118 Bio nulls.String `db:"bio"` 119 Price nulls.Float64 `db:"price"` 120 FullName nulls.String `db:"full_name" select:"name as full_name"` 121 Books Books `has_many:"books" order_by:"title asc" fk_id:"user_id"` 122 FavoriteSong *Song `has_one:"song" fk_id:"u_id"` 123 Houses Addresses `many_to_many:"users_addresses"` 124 } 125 126 func (UserPointerAssocs) TableName() string { 127 return "users" 128 } 129 130 // Validate gets run every time you call a "Validate*" (ValidateAndSave, ValidateAndCreate, ValidateAndUpdate) method. 131 // This method is not required and may be deleted. 132 func (u *User) Validate(tx *Connection) (*validate.Errors, error) { 133 return validate.Validate( 134 &validators.StringIsPresent{Field: u.Name.String, Name: "Name"}, 135 ), nil 136 } 137 138 type Users []User 139 140 type UserAttribute struct { 141 ID int `db:"id"` 142 UserName string `db:"user_name"` 143 NickName string `db:"nick_name"` 144 145 User User `json:"user" belongs_to:"user" fk_id:"UserName" primary_id:"UserName"` 146 } 147 148 type Book struct { 149 ID int `db:"id"` 150 Title string `db:"title"` 151 Isbn string `db:"isbn"` 152 UserID nulls.Int `db:"user_id"` 153 User User `belongs_to:"user"` 154 Description string `db:"description"` 155 Writers Writers `has_many:"writers"` 156 TaxiID nulls.Int `db:"taxi_id"` 157 Taxi Taxi `belongs_to:"taxi"` 158 CreatedAt time.Time `db:"created_at"` 159 UpdatedAt time.Time `db:"updated_at"` 160 } 161 162 type Taxi struct { 163 ID int `db:"id"` 164 Model string `db:"model"` 165 UserID nulls.Int `db:"user_id"` 166 AddressID nulls.Int `db:"address_id"` 167 Driver *User `belongs_to:"user" fk_id:"user_id"` 168 Address Address `belongs_to:"address"` 169 ToAddressID *int `db:"to_address_id"` 170 ToAddress *Address `belongs_to:"address"` 171 CreatedAt time.Time `db:"created_at"` 172 UpdatedAt time.Time `db:"updated_at"` 173 } 174 175 type Taxis []Taxi 176 177 // Validate gets run every time you call a "Validate*" (ValidateAndSave, ValidateAndCreate, ValidateAndUpdate) method. 178 // This method is not required and may be deleted. 179 func (b *Book) Validate(tx *Connection) (*validate.Errors, error) { 180 // Execute another query to test if Validate causes eager creation to fail 181 if err := tx.All(&Taxis{}); err != nil { 182 return nil, err 183 } 184 return validate.Validate( 185 &validators.StringIsPresent{Field: b.Description, Name: "Description"}, 186 ), nil 187 } 188 189 type Books []Book 190 191 type Writer struct { 192 ID int `db:"id"` 193 Name string `db:"name"` 194 Addresses Addresses `has_many:"addresses"` 195 Friends []Friend `has_many:"friends"` 196 BookID int `db:"book_id"` 197 Book Book `belongs_to:"book"` 198 CreatedAt time.Time `db:"created_at"` 199 UpdatedAt time.Time `db:"updated_at"` 200 } 201 202 type Writers []Writer 203 204 type Address struct { 205 ID int `db:"id"` 206 Street string `db:"street"` 207 WriterID int `db:"writer_id"` 208 HouseNumber int `db:"house_number"` 209 CreatedAt time.Time `db:"created_at"` 210 UpdatedAt time.Time `db:"updated_at"` 211 TaxisToHere Taxis `has_many:"taxis" fk_id:"to_address_id" order_by:"created_at asc"` 212 } 213 214 type Addresses []Address 215 216 type UsersAddress struct { 217 ID int `db:"id"` 218 UserID int `db:"user_id"` 219 AddressID int `db:"address_id"` 220 CreatedAt time.Time `db:"created_at"` 221 UpdatedAt time.Time `db:"updated_at"` 222 } 223 224 type UsersAddressQuery struct { 225 ID int `db:"id"` 226 UserID int `db:"user_id"` 227 AddressID int `db:"address_id"` 228 CreatedAt time.Time `db:"created_at"` 229 UpdatedAt time.Time `db:"updated_at"` 230 231 UserName *string `db:"name" json:"user_name"` 232 UserEmail *string `db:"email" json:"user_email"` 233 } 234 235 func (UsersAddressQuery) TableName() string { 236 return "users_addresses" 237 } 238 239 type Friend struct { 240 ID int `db:"id"` 241 FirstName string `db:"first_name"` 242 WriterID int `db:"writer_id"` 243 LastName string `db:"last_name"` 244 CreatedAt time.Time `db:"created_at"` 245 UpdatedAt time.Time `db:"updated_at"` 246 } 247 248 func (Friend) TableName() string { 249 return "good_friends" 250 } 251 252 type Family struct { 253 ID int `db:"id"` 254 FirstName string `db:"first_name"` 255 LastName string `db:"last_name"` 256 CreatedAt time.Time `db:"created_at"` 257 UpdatedAt time.Time `db:"updated_at"` 258 } 259 260 func (Family) TableName() string { 261 // schema.table_name 262 return "family.members" 263 } 264 265 type Enemy struct { 266 A string 267 } 268 269 type Song struct { 270 ID uuid.UUID `db:"id"` 271 Title string `db:"title"` 272 UserID int `db:"u_id"` 273 CreatedAt time.Time `json:"created_at" db:"created_at"` 274 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 275 ComposedByID int `json:"composed_by_id" db:"composed_by_id"` 276 ComposedBy Composer `belongs_to:"composer"` 277 } 278 279 type Composer struct { 280 ID int `db:"id"` 281 Name string `db:"name"` 282 CreatedAt time.Time `db:"created_at"` 283 UpdatedAt time.Time `db:"updated_at"` 284 } 285 286 type Course struct { 287 ID uuid.UUID `json:"id" db:"id"` 288 CreatedAt time.Time `json:"created_at" db:"created_at"` 289 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 290 } 291 292 type CourseCode struct { 293 ID uuid.UUID `json:"id" db:"id"` 294 CreatedAt time.Time `json:"created_at" db:"created_at"` 295 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 296 CourseID uuid.UUID `json:"course_id" db:"course_id"` 297 Course Course `json:"-" belongs_to:"course"` 298 // Course Course `belongs_to:"course"` 299 } 300 301 type NetClient struct { 302 ID uuid.UUID `json:"id" db:"id"` 303 Hops []Hop `json:"hop_id" has_many:"hops"` 304 } 305 306 type Hop struct { 307 ID uuid.UUID `json:"id" db:"id"` 308 NetClient *NetClient `json:"net_client" belongs_to:"net_client" fk_id:"NetClientID"` 309 NetClientID uuid.UUID `json:"net_client_id" db:"net_client_id"` 310 Server *Server `json:"course" belongs_to:"server" fk_id:"ServerID" oder_by:"id asc"` 311 ServerID uuid.NullUUID `json:"server_id" db:"server_id"` 312 } 313 314 type Server struct { 315 ID uuid.UUID `json:"id" db:"id"` 316 } 317 318 type ValidatableCar struct { 319 ID int64 `db:"id"` 320 Name string `db:"name"` 321 CreatedAt time.Time `json:"created_at" db:"created_at"` 322 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 323 } 324 325 var validationLogs []string 326 327 func (v *ValidatableCar) Validate(tx *Connection) (*validate.Errors, error) { 328 validationLogs = append(validationLogs, "Validate") 329 verrs := validate.Validate(&validators.StringIsPresent{Field: v.Name, Name: "Name"}) 330 return verrs, nil 331 } 332 333 func (v *ValidatableCar) ValidateSave(tx *Connection) (*validate.Errors, error) { 334 validationLogs = append(validationLogs, "ValidateSave") 335 return nil, nil 336 } 337 338 func (v *ValidatableCar) ValidateUpdate(tx *Connection) (*validate.Errors, error) { 339 validationLogs = append(validationLogs, "ValidateUpdate") 340 return nil, nil 341 } 342 343 func (v *ValidatableCar) ValidateCreate(tx *Connection) (*validate.Errors, error) { 344 validationLogs = append(validationLogs, "ValidateCreate") 345 return nil, nil 346 } 347 348 type NotValidatableCar struct { 349 ID int `db:"id"` 350 Name string `db:"name"` 351 CreatedAt time.Time `json:"created_at" db:"created_at"` 352 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 353 } 354 355 type CallbacksUser struct { 356 ID int `db:"id"` 357 BeforeS string `db:"before_s"` 358 BeforeC string `db:"before_c"` 359 BeforeU string `db:"before_u"` 360 BeforeD string `db:"before_d"` 361 BeforeV string `db:"before_v"` 362 AfterS string `db:"after_s"` 363 AfterC string `db:"after_c"` 364 AfterU string `db:"after_u"` 365 AfterD string `db:"after_d"` 366 AfterF string `db:"after_f"` 367 AfterEF string `db:"after_ef"` 368 CreatedAt time.Time `json:"created_at" db:"created_at"` 369 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 370 } 371 372 type CallbacksUsers []CallbacksUser 373 374 func (u *CallbacksUser) BeforeSave(tx *Connection) error { 375 u.BeforeS = "BeforeSave" 376 return nil 377 } 378 379 func (u *CallbacksUser) BeforeUpdate(tx *Connection) error { 380 u.BeforeU = "BeforeUpdate" 381 return nil 382 } 383 384 func (u *CallbacksUser) BeforeCreate(tx *Connection) error { 385 u.BeforeC = "BeforeCreate" 386 return nil 387 } 388 389 func (u *CallbacksUser) BeforeDestroy(tx *Connection) error { 390 u.BeforeD = "BeforeDestroy" 391 return nil 392 } 393 394 func (u *CallbacksUser) BeforeValidate(tx *Connection) error { 395 u.BeforeV = "BeforeValidate" 396 return nil 397 } 398 399 func (u *CallbacksUser) AfterSave(tx *Connection) error { 400 u.AfterS = "AfterSave" 401 return nil 402 } 403 404 func (u *CallbacksUser) AfterUpdate(tx *Connection) error { 405 u.AfterU = "AfterUpdate" 406 return nil 407 } 408 409 func (u *CallbacksUser) AfterCreate(tx *Connection) error { 410 u.AfterC = "AfterCreate" 411 return nil 412 } 413 414 func (u *CallbacksUser) AfterDestroy(tx *Connection) error { 415 u.AfterD = "AfterDestroy" 416 return nil 417 } 418 419 func (u *CallbacksUser) AfterFind(tx *Connection) error { 420 u.AfterF = "AfterFind" 421 return nil 422 } 423 424 func (u *CallbacksUser) AfterEagerFind(tx *Connection) error { 425 u.AfterEF = "AfterEagerFind" 426 return nil 427 } 428 429 type Label struct { 430 ID string `db:"id"` 431 } 432 433 type SingleID struct { 434 ID int `db:"id"` 435 } 436 437 type Body struct { 438 ID int `json:"id" db:"id"` 439 Head *Head `json:"head" has_one:"head"` 440 } 441 442 type Head struct { 443 ID int `json:"id,omitempty" db:"id"` 444 BodyID int `json:"-" db:"body_id"` 445 Body *Body `json:"body,omitempty" belongs_to:"body"` 446 } 447 448 type HeadPtr struct { 449 ID int `json:"id,omitempty" db:"id"` 450 BodyID *int `json:"-" db:"body_id"` 451 Body *Body `json:"body,omitempty" belongs_to:"body"` 452 } 453 454 type Student struct { 455 ID uuid.UUID `json:"id" db:"id"` 456 CreatedAt time.Time `json:"created_at" db:"created_at"` 457 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 458 } 459 460 // https://github.com/gobuffalo/pop/issues/302 461 type Parent struct { 462 ID uuid.UUID `json:"id" db:"id"` 463 CreatedAt time.Time `json:"created_at" db:"created_at"` 464 UpdatedAt time.Time `json:"updated_at" db:"updated_at"` 465 Students []*Student `many_to_many:"parents_students"` 466 } 467 468 type CrookedColour struct { 469 ID int `db:"pk"` 470 Name string `db:"name"` 471 CreatedAt time.Time `db:"created_at"` 472 UpdatedAt time.Time `db:"updated_at"` 473 } 474 475 type CrookedSong struct { 476 ID string `db:"name"` 477 CreatedAt time.Time `db:"created_at"` 478 UpdatedAt time.Time `db:"updated_at"` 479 } 480 481 type NonStandardID struct { 482 ID int `db:"pk"` 483 OutfacingID string `db:"id"` 484 } 485 486 type InnerStruct struct { 487 ID int `db:"id"` 488 CreatedAt time.Time `db:"created_at"` 489 UpdatedAt time.Time `db:"updated_at"` 490 } 491 492 type EmbeddingStruct struct { 493 InnerStruct 494 AdditionalField string `db:"additional_field"` 495 }