feat: build entire backend into single executable (including migrations etc)
This commit is contained in:
		
							parent
							
								
									f94bc67f3d
								
							
						
					
					
						commit
						ded9d06e4a
					
				
					 12 changed files with 137 additions and 32 deletions
				
			
		
							
								
								
									
										2
									
								
								Makefile
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
										
									
									
									
								
							|  | @ -8,7 +8,7 @@ seeddb: | |||
| 
 | ||||
| .PHONY: backend | ||||
| backend: | ||||
| 	CGO_ENABLED=0 go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/u1f320/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD`" ./backend | ||||
| 	CGO_ENABLED=0 go build -v -o pronouns -ldflags="-buildid= -X codeberg.org/u1f320/pronouns.cc/backend/server.Revision=`git rev-parse --short HEAD` -X codeberg.org/u1f320/pronouns.cc/backend/server.Tag=`git describe --tags --long`" . | ||||
| 
 | ||||
| .PHONY: generate | ||||
| generate: | ||||
|  |  | |||
|  | @ -63,6 +63,14 @@ PORT=8080 # Port the API will listen on. Default is 8080, this is also default f | |||
| MINIO_ENDPOINT=localhost:9000 # This always needs to be set, it *does not* need to point to a running MinIO server. | ||||
| ``` | ||||
| 
 | ||||
| ## Updating in production | ||||
| 
 | ||||
| 1. Build the backend with `make backend` | ||||
| 2. Build the frontend with `cd frontend && pnpm install && pnpm build` | ||||
| 3. Stop the servers: `systemctl stop pronouns-api pronouns-fe` | ||||
| 4. Run migrations: `./pronouns database migrate` | ||||
| 5. Start the servers: `systemctl start pronouns-api pronouns-fe` | ||||
| 
 | ||||
| ## License | ||||
| 
 | ||||
|     Copyright (C) 2022  Sam <u1f320> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| package main | ||||
| package backend | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
|  | @ -12,14 +12,22 @@ import ( | |||
| 
 | ||||
| 	"github.com/go-chi/render" | ||||
| 	_ "github.com/joho/godotenv/autoload" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| var Command = &cli.Command{ | ||||
| 	Name:   "web", | ||||
| 	Usage:  "Run the API server", | ||||
| 	Action: run, | ||||
| } | ||||
| 
 | ||||
| func run(c *cli.Context) error { | ||||
| 	port := ":" + os.Getenv("PORT") | ||||
| 
 | ||||
| 	s, err := server.New() | ||||
| 	if err != nil { | ||||
| 		log.Fatalf("Error creating server: %v", err) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	// set render.Decode to a custom one that checks content length | ||||
|  | @ -44,10 +52,12 @@ func main() { | |||
| 	case <-ctx.Done(): | ||||
| 		log.Info("Interrupt signal received, shutting down...") | ||||
| 		s.DB.Close() | ||||
| 		return | ||||
| 		return nil | ||||
| 	case err := <-e: | ||||
| 		log.Fatalf("Error running server: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| const MaxContentLength = 2 * 1024 * 1024 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| package main | ||||
| package backend | ||||
| 
 | ||||
| import ( | ||||
| 	"codeberg.org/u1f320/pronouns.cc/backend/routes/auth" | ||||
|  |  | |||
|  | @ -16,7 +16,10 @@ import ( | |||
| ) | ||||
| 
 | ||||
| // Revision is the git commit, filled at build time | ||||
| var Revision = "[unknown]" | ||||
| var ( | ||||
| 	Revision = "[unknown]" | ||||
| 	Tag      = "[unknown]" | ||||
| ) | ||||
| 
 | ||||
| // Repository is the URL of the git repository | ||||
| const Repository = "https://codeberg.org/u1f320/pronouns.cc" | ||||
|  |  | |||
							
								
								
									
										4
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -19,12 +19,14 @@ require ( | |||
| 	github.com/minio/minio-go/v7 v7.0.37 | ||||
| 	github.com/rs/xid v1.4.0 | ||||
| 	github.com/rubenv/sql-migrate v1.1.1 | ||||
| 	github.com/urfave/cli/v2 v2.25.0 | ||||
| 	go.uber.org/zap v1.21.0 | ||||
| 	golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/cespare/xxhash/v2 v2.1.2 // indirect | ||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect | ||||
| 	github.com/dustin/go-humanize v1.0.0 // indirect | ||||
| 	github.com/go-gorp/gorp/v3 v3.0.2 // indirect | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
|  | @ -47,8 +49,10 @@ require ( | |||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||
| 	github.com/pkg/errors v0.9.1 // indirect | ||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||
| 	github.com/sirupsen/logrus v1.9.0 // indirect | ||||
| 	github.com/tilinna/clock v1.0.2 // indirect | ||||
| 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect | ||||
| 	go.uber.org/atomic v1.7.0 // indirect | ||||
| 	go.uber.org/multierr v1.6.0 // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect | ||||
|  |  | |||
							
								
								
									
										10
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -78,6 +78,8 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 | |||
| github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= | ||||
| github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= | ||||
| github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
|  | @ -407,6 +409,8 @@ github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThC | |||
| github.com/rubenv/sql-migrate v1.1.1 h1:haR5Hn8hbW9/SpAICrXoZqXnywS7Q5WijwkQENPeNWY= | ||||
| github.com/rubenv/sql-migrate v1.1.1/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ= | ||||
| github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= | ||||
| github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= | ||||
| github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | ||||
| github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= | ||||
|  | @ -442,6 +446,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ | |||
| github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= | ||||
| github.com/tilinna/clock v1.0.2 h1:6BO2tyAC9JbPExKH/z9zl44FLu1lImh3nDNKA0kgrkI= | ||||
| github.com/tilinna/clock v1.0.2/go.mod h1:ZsP7BcY7sEEz7ktc0IVy8Us6boDrK8VradlKRUGfOao= | ||||
| github.com/urfave/cli/v2 v2.25.0 h1:ykdZKuQey2zq0yin/l7JOm9Mh+pg72ngYMeB0ABn6q8= | ||||
| github.com/urfave/cli/v2 v2.25.0/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= | ||||
| github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= | ||||
| github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= | ||||
| github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
|  | @ -859,8 +867,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |||
| gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | ||||
| gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | ||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||||
| gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||
| gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= | ||||
| gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= | ||||
| gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= | ||||
|  |  | |||
							
								
								
									
										40
									
								
								main.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								main.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"codeberg.org/u1f320/pronouns.cc/backend" | ||||
| 	"codeberg.org/u1f320/pronouns.cc/backend/server" | ||||
| 	"codeberg.org/u1f320/pronouns.cc/scripts/cleandb" | ||||
| 	"codeberg.org/u1f320/pronouns.cc/scripts/migrate" | ||||
| 	"codeberg.org/u1f320/pronouns.cc/scripts/seeddb" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| 
 | ||||
| var app = &cli.App{ | ||||
| 	HelpName: "pronouns.cc", | ||||
| 	Usage:    "Pronoun card website and API", | ||||
| 	Version:  server.Tag, | ||||
| 	Commands: []*cli.Command{ | ||||
| 		backend.Command, | ||||
| 		{ | ||||
| 			Name:    "database", | ||||
| 			Aliases: []string{"db"}, | ||||
| 			Usage:   "Manage the database", | ||||
| 			Subcommands: []*cli.Command{ | ||||
| 				migrate.Command, | ||||
| 				seeddb.Command, | ||||
| 				cleandb.Command, | ||||
| 			}, | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	err := app.Run(os.Args) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,22 +1,28 @@ | |||
| package main | ||||
| package cleandb | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
| 
 | ||||
| 	dbpkg "codeberg.org/u1f320/pronouns.cc/backend/db" | ||||
| 	"github.com/georgysavva/scany/pgxscan" | ||||
| 	"github.com/joho/godotenv" | ||||
| 	"github.com/rs/xid" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| var Command = &cli.Command{ | ||||
| 	Name:   "clean", | ||||
| 	Usage:  "Clean deleted tokens + users daily", | ||||
| 	Action: run, | ||||
| } | ||||
| 
 | ||||
| func run(c *cli.Context) error { | ||||
| 	err := godotenv.Load() | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error loading .env file:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
|  | @ -24,7 +30,7 @@ func main() { | |||
| 	db, err := dbpkg.New() | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error opening database:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 	defer db.Close() | ||||
| 
 | ||||
|  | @ -35,7 +41,7 @@ func main() { | |||
| 	ct, err := db.Exec(ctx, "DELETE FROM tokens WHERE invalidated = true OR expires < $1", time.Now()) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("executing query:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("deleted %v invalidated or expired tokens\n", ct.RowsAffected()) | ||||
|  | @ -48,12 +54,12 @@ func main() { | |||
| 	ORDER BY id`, time.Now().Add(-dbpkg.SelfDeleteAfter), time.Now().Add(-dbpkg.ModDeleteAfter)) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error getting to-be-deleted users:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	if len(users) == 0 { | ||||
| 		fmt.Println("there are no users pending deletion") | ||||
| 		os.Exit(0) | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	for _, u := range users { | ||||
|  | @ -102,8 +108,9 @@ func main() { | |||
| 	ct, err = db.Exec(ctx, "DELETE FROM users WHERE id = ANY($1)", ids) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("error deleting users: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Printf("deleted %v users!\n", ct.RowsAffected()) | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
							
								
								
									
										10
									
								
								scripts/migrate/008_data_exports.sql
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								scripts/migrate/008_data_exports.sql
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | |||
| -- +migrate Up | ||||
| 
 | ||||
| -- 2023-03-15: Add data export | ||||
| 
 | ||||
| create table data_exports ( | ||||
|     id         serial primary key, | ||||
|     user_id    text not null references users (id) on delete cascade, | ||||
|     hash       text not null, | ||||
|     created_at timestamptz not null default now() | ||||
| ); | ||||
|  | @ -1,5 +1,5 @@ | |||
| // migrate runs (forward) migrations | ||||
| package main | ||||
| package migrate | ||||
| 
 | ||||
| import ( | ||||
| 	"database/sql" | ||||
|  | @ -9,6 +9,7 @@ import ( | |||
| 
 | ||||
| 	"github.com/joho/godotenv" | ||||
| 	migrate "github.com/rubenv/sql-migrate" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 
 | ||||
| 	// SQL driver | ||||
| 	_ "github.com/jackc/pgx/v4/stdlib" | ||||
|  | @ -17,7 +18,13 @@ import ( | |||
| //go:embed *.sql | ||||
| var migrations embed.FS | ||||
| 
 | ||||
| func main() { | ||||
| var Command = &cli.Command{ | ||||
| 	Name:   "migrate", | ||||
| 	Usage:  "Migrate the database", | ||||
| 	Action: run, | ||||
| } | ||||
| 
 | ||||
| func run(c *cli.Context) error { | ||||
| 	err := godotenv.Load() | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error loading .env file:", err) | ||||
|  | @ -42,7 +49,7 @@ func main() { | |||
| 
 | ||||
| 	if err := db.Ping(); err != nil { | ||||
| 		fmt.Println("error pinging database:", err) | ||||
| 		return | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	src := &migrate.EmbedFileSystemMigrationSource{ | ||||
|  | @ -54,7 +61,7 @@ func main() { | |||
| 	n, err := migrate.Exec(db, "postgres", src, migrate.Up) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error executing migrations:", err) | ||||
| 		return | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	if n == 0 { | ||||
|  | @ -62,4 +69,5 @@ func main() { | |||
| 	} else { | ||||
| 		fmt.Printf("executed %v migrations!\n", n) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  |  | |||
|  | @ -1,28 +1,34 @@ | |||
| package main | ||||
| package seeddb | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"codeberg.org/u1f320/pronouns.cc/backend/db" | ||||
| 	"github.com/jackc/pgx/v4/pgxpool" | ||||
| 	"github.com/joho/godotenv" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| var Command = &cli.Command{ | ||||
| 	Name:   "seed", | ||||
| 	Usage:  "Seed the database with test data", | ||||
| 	Action: run, | ||||
| } | ||||
| 
 | ||||
| func run(c *cli.Context) error { | ||||
| 	err := godotenv.Load() | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error loading .env file:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	ctx := c.Context | ||||
| 
 | ||||
| 	pool, err := pgxpool.Connect(ctx, os.Getenv("DATABASE_URL")) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error opening database:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 	defer pool.Close() | ||||
| 
 | ||||
|  | @ -33,19 +39,19 @@ func main() { | |||
| 	tx, err := pg.Begin(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error beginning transaction:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	u, err := pg.CreateUser(ctx, tx, "test") | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error creating user:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	_, err = pg.UpdateUser(ctx, tx, u.ID, ptr("testing"), ptr("This is a bio!"), &[]string{"https://pronouns.cc"}, nil) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error setting user info:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = pg.SetUserNamesPronouns(ctx, tx, u.ID, []db.FieldEntry{ | ||||
|  | @ -57,7 +63,7 @@ func main() { | |||
| 	}) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error setting pronouns:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = pg.SetUserFields(ctx, tx, u.ID, []db.Field{ | ||||
|  | @ -114,16 +120,17 @@ func main() { | |||
| 	}) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error setting fields:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	err = tx.Commit(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("error committing transaction:", err) | ||||
| 		os.Exit(1) | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	fmt.Println("Created testing user with ID", u.ID, "and name", u.Username) | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func ptr[T any](v T) *T { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue