()
| 403 | |
| 404 | // errOrgTeamExists distinguishes the (org, team) primary-key conflict from |
| 405 | // the schema-name conflict on the admin create endpoint — the admin surface |
| 406 | // never overwrites an existing row (that's the internal provisioning |
| 407 | // grandfather path), so an existing row is a 409, not an upsert. |
| 408 | var errOrgTeamExists = errors.New("team already exists in this org") |
| 409 | |
| 410 | // orgTeamUpdate carries the admin-editable fields of one org team — every |
| 411 | // column, this is the operator break-glass surface. Pointer fields are |
| 412 | // presence-aware (nil = preserve). The *Set booleans distinguish an explicit |
| 413 | // JSON null (clear to unset/NULL) from an absent key for the nullable columns. |
| 414 | type orgTeamUpdate struct { |
| 415 | // SchemaName: nil = preserve. A non-nil value is the operator override — |
| 416 | // validated by the handler, refused with ErrOrgTeamSchemaConflict when |
| 417 | // another team in the org already uses it. Changing it does NOT move any |
| 418 | // warehouse data; tables under the old schema are not renamed. |
| 419 | SchemaName *string |
| 420 | Enabled *bool |
| 421 | // Backfill: nil = preserve. The column is NOT NULL (migration 000028), so |
| 422 | // there is no clear path — the handler rejects an explicit null. |
| 423 | Backfill *bool |
| 424 | // Legacy explicit table names for grandfathered teams (NULL = derive from |
| 425 | // schema_name). XSet + nil value clears the column back to NULL. |
| 426 | EventsTableNameSet bool |
| 427 | EventsTableName *string |
| 428 | PersonsTableNameSet bool |
| 429 | PersonsTableName *string |
| 430 | SchemaDataImportsNameSet bool |
| 431 | SchemaDataImportsName *string |
| 432 | // EarliestEventDate: PostHog's cached backfill floor (a cache owned by |
| 433 | // PostHog's sensor — see configstore.OrgTeam.EarliestEventDate). Set + nil |
| 434 | // clears the column back to NULL, making the sensor re-resolve it. |
| 435 | EarliestEventDateSet bool |
| 436 | EarliestEventDate *configstore.EventDate |
| 437 | } |
| 438 | |
| 439 | func (s *gormAPIStore) ListAllOrgTeams() ([]configstore.OrgTeam, error) { |
| 440 | var teams []configstore.OrgTeam |
| 441 | if err := s.db().Order("org_id, team_id").Find(&teams).Error; err != nil { |
| 442 | return nil, err |
| 443 | } |
| 444 | return teams, nil |
| 445 | } |
| 446 | |
| 447 | func (s *gormAPIStore) CreateOrgTeam(orgID string, team *configstore.OrgTeam) error { |
| 448 | return s.db().Transaction(func(tx *gorm.DB) error { |
| 449 | var orgCount int64 |
| 450 | if err := tx.Model(&configstore.Org{}).Where("name = ?", orgID).Count(&orgCount).Error; err != nil { |
| 451 | return err |
| 452 | } |
| 453 | if orgCount == 0 { |
| 454 | return gorm.ErrRecordNotFound |
| 455 | } |
| 456 | var dup int64 |
| 457 | if err := tx.Model(&configstore.OrgTeam{}). |
| 458 | Where("org_id = ? AND team_id = ?", orgID, team.TeamID).Count(&dup).Error; err != nil { |
| 459 | return err |
| 460 | } |
no outgoing calls