szabadpalya/api/test/seed/insert.go

175 lines
4.3 KiB
Go

package main
import (
"context"
"fmt"
"time"
"github.com/szabadpalya/api/internal/store"
"github.com/szabadpalya/api/internal/store/dbgen"
"github.com/szabadpalya/api/test/seeddata"
)
// reset clears the campaign side of the database. Relations cascade, so
// campaigns and owners are enough; users go too because the seed's
// pledges are anonymous and any account left behind would be an orphan.
//
// Four statements rather than a loop over table names: the order matters, and
// a name interpolated into SQL is the one thing the generated layer cannot
// check.
func (s *seeder) reset(ctx context.Context) error {
if err := s.q.SeedReset(ctx); err != nil {
return err
}
if err := s.q.SeedResetCampaigns(ctx); err != nil {
return err
}
if err := s.q.SeedResetOwners(ctx); err != nil {
return err
}
return s.q.SeedResetUsers(ctx)
}
// campaign writes one fixture campaign and returns how many pledges it created
// and what they add up to.
func (s *seeder) campaign(ctx context.Context, c seeddata.Campaign) (int, int, error) {
endsAt, err := s.store.EndOfDay(c.EndsAt)
if err != nil {
return 0, 0, err
}
tx, err := s.pool.Begin(ctx)
if err != nil {
return 0, 0, err
}
defer tx.Rollback(ctx)
q := s.q.WithTx(tx)
ownerID, err := q.SeedOwner(ctx, dbgen.SeedOwnerParams{
ID: store.NewID(),
Slug: c.Owner.Slug,
Name: c.Owner.Name,
Initials: c.Owner.Initials,
Location: c.Owner.Location,
Blurb: c.Owner.Blurb,
AvatarUrl: c.Owner.AvatarURL,
})
if err != nil {
return 0, 0, err
}
campaignID := store.NewID()
if err := q.SeedCampaign(ctx, dbgen.SeedCampaignParams{
ID: campaignID,
Slug: c.Slug,
Title: c.Title,
Category: c.Category,
Summary: c.Summary,
Art: c.Art,
GoalAmount: c.GoalAmount,
EndsAt: endsAt,
Status: c.Status,
OwnerID: ownerID,
}); err != nil {
return 0, 0, err
}
for i, sec := range c.Story {
if err := q.SeedStorySection(ctx, dbgen.SeedStorySectionParams{
ID: store.NewID(),
CampaignID: campaignID,
Heading: sec.Heading,
Body: sec.Body,
Position: i,
}); err != nil {
return 0, 0, err
}
}
// Was the goal reached? That decides whether physical tiers were charged.
raised := 0
for _, t := range c.Tiers {
raised += t.Price * t.Backers
}
goalReached := raised >= c.GoalAmount
pledgeCount := 0
now := time.Now()
for i, t := range c.Tiers {
var delivery *time.Time
if t.EstimatedDelivery != "" {
d, err := s.store.EndOfDay(t.EstimatedDelivery)
if err != nil {
return 0, 0, err
}
delivery = &d
}
tierID := store.NewID()
if err := q.SeedTier(ctx, dbgen.SeedTierParams{
ID: tierID,
CampaignID: campaignID,
Type: t.Type,
Price: t.Price,
ListPrice: t.ListPrice,
Title: t.Title,
Includes: t.Includes,
InventoryLimit: t.InventoryLimit,
EstimatedDelivery: delivery,
Featured: t.Featured,
Position: i,
}); err != nil {
return 0, 0, err
}
// A physical tier on a campaign that missed its goal is still only
// authorized — that is the fulfillment guard, visible in the fixture.
held := t.Type == "PHYSICAL" && !goalReached
status := "CAPTURED"
var capturedAt *time.Time
if held {
status = "AUTHORIZED"
} else {
capturedAt = &now
}
for n := 0; n < t.Backers; n++ {
pledgeCount++
if err := q.SeedPledge(ctx, dbgen.SeedPledgeParams{
ID: store.NewID(),
CampaignID: campaignID,
TierID: tierID,
BackerEmail: fmt.Sprintf("tamogato-%s@example.invalid", store.NewID()),
Amount: t.Price,
Status: status,
CapturedAt: capturedAt,
}); err != nil {
return 0, 0, err
}
}
}
for _, u := range c.Updates {
if err := q.SeedCampaignUpdate(ctx, dbgen.SeedCampaignUpdateParams{
ID: store.NewID(),
CampaignID: campaignID,
Title: u.Title,
Body: u.Body,
}); err != nil {
return 0, 0, err
}
}
for _, m := range c.Comments {
if err := q.SeedComment(ctx, dbgen.SeedCommentParams{
ID: store.NewID(),
CampaignID: campaignID,
AuthorName: m.AuthorName,
Body: m.Body,
}); err != nil {
return 0, 0, err
}
}
return pledgeCount, raised, tx.Commit(ctx)
}