diff --git a/Makefile b/Makefile index 3104045c..d77e1819 100644 --- a/Makefile +++ b/Makefile @@ -82,6 +82,12 @@ gen-grpc: @buf generate proto @go fmt ./auto/rpc/... +.PHONY: gen-sqlc +gen-sqlc: + @find internal/dao/slonik/ce/mysql internal/dao/slonik/ce/postgres internal/dao/slonik/ce/sqlite -name '*.go' -exec rm -f {} + + @go generate internal/dao/slonik/ce/ce.go + @go fmt ./internal/dao/slonik/ce/... + .PHONY: proto-mod proto-mod: @cd proto/ && buf mod update @@ -114,6 +120,7 @@ install-protobuf-plugins: @go install github.com/bufbuild/buf/cmd/protoc-gen-buf-lint@v1.11.0 @go install google.golang.org/protobuf/cmd/protoc-gen-go@latest @go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest + @go install github.com/kyleconroy/sqlc/cmd/sqlc@latest help: @echo "make: make" diff --git a/go.mod b/go.mod index 61fe1d1e..f34147b2 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/golang-jwt/jwt/v4 v4.4.2 github.com/golang-migrate/migrate/v4 v4.15.2 github.com/huaweicloud/huaweicloud-sdk-go-obs v3.21.12+incompatible + github.com/jackc/pgx/v5 v5.2.0 github.com/json-iterator/go v1.1.12 github.com/meilisearch/meilisearch-go v0.21.0 github.com/minio/minio-go/v7 v7.0.45 @@ -108,9 +109,9 @@ require ( github.com/ugorji/go/codec v1.2.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.37.1-0.20220607072126-8a320890c08d // indirect - go.uber.org/atomic v1.9.0 // indirect + go.uber.org/atomic v1.10.0 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect + golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect golang.org/x/image v0.0.0-20220413100746-70e8d0d3baa9 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/net v0.0.0-20221014081412-f15817d10f9b // indirect diff --git a/go.sum b/go.sum index 3a27eb98..a9a9d0aa 100644 --- a/go.sum +++ b/go.sum @@ -888,6 +888,8 @@ github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1r github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y= github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= +github.com/jackc/pgx/v5 v5.2.0 h1:NdPpngX0Y6z6XDFKqmFQaE+bCtkqzvQIOt1wvBlAqs8= +github.com/jackc/pgx/v5 v5.2.0/go.mod h1:Ptn7zmohNsWEsdxRawMzk3gaKma2obW+NWTnKa0S4nk= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -1479,8 +1481,8 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= @@ -1532,8 +1534,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= +golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= diff --git a/internal/dao/slonik/ce/ce.go b/internal/dao/slonik/ce/ce.go new file mode 100644 index 00000000..6e3cb6ca --- /dev/null +++ b/internal/dao/slonik/ce/ce.go @@ -0,0 +1,3 @@ +package ce + +//go:generate sqlc generate -x diff --git a/internal/dao/slonik/ce/mysql/city.sql.go b/internal/dao/slonik/ce/mysql/city.sql.go new file mode 100644 index 00000000..75ea6e41 --- /dev/null +++ b/internal/dao/slonik/ce/mysql/city.sql.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: city.sql + +package dbr + +import ( + "context" +) + +const createCity = `-- name: CreateCity :exec +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +) +` + +type CreateCityParams struct { + Name string + Slug string +} + +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error { + _, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + return err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = ? +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = ? +WHERE slug = ? +` + +type UpdateCityNameParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug) + return err +} diff --git a/internal/dao/slonik/ce/mysql/db.go b/internal/dao/slonik/ce/mysql/db.go new file mode 100644 index 00000000..451eb52b --- /dev/null +++ b/internal/dao/slonik/ce/mysql/db.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/internal/dao/slonik/ce/mysql/models.go b/internal/dao/slonik/ce/mysql/models.go new file mode 100644 index 00000000..d315b7ca --- /dev/null +++ b/internal/dao/slonik/ce/mysql/models.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "database/sql" + "database/sql/driver" + "fmt" + "time" +) + +type VenuesStatus string + +const ( + VenuesStatusOpen VenuesStatus = "open" + VenuesStatusClosed VenuesStatus = "closed" +) + +func (e *VenuesStatus) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = VenuesStatus(s) + case string: + *e = VenuesStatus(s) + default: + return fmt.Errorf("unsupported scan type for VenuesStatus: %T", src) + } + return nil +} + +type NullVenuesStatus struct { + VenuesStatus VenuesStatus + Valid bool // Valid is true if VenuesStatus is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullVenuesStatus) Scan(value interface{}) error { + if value == nil { + ns.VenuesStatus, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.VenuesStatus.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullVenuesStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.VenuesStatus), nil +} + +type City struct { + Slug string + Name string +} + +// Venues are places where muisc happens +type Venue struct { + ID int64 + // Venues can be either open or closed + Status VenuesStatus + Statuses sql.NullString + // This value appears in public URLs + Slug string + Name string + City string + SpotifyPlaylist string + SongkickID sql.NullString + Tags sql.NullString + CreatedAt time.Time +} diff --git a/internal/dao/slonik/ce/mysql/querier.go b/internal/dao/slonik/ce/mysql/querier.go new file mode 100644 index 00000000..163269e6 --- /dev/null +++ b/internal/dao/slonik/ce/mysql/querier.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" + "database/sql" +) + +type Querier interface { + CreateCity(ctx context.Context, arg CreateCityParams) error + CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) + DeleteVenue(ctx context.Context, arg DeleteVenueParams) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/dao/slonik/ce/mysql/query/city.sql b/internal/dao/slonik/ce/mysql/query/city.sql new file mode 100644 index 00000000..c387e9d0 --- /dev/null +++ b/internal/dao/slonik/ce/mysql/query/city.sql @@ -0,0 +1,23 @@ +/* name: ListCities :many */ +SELECT * +FROM city +ORDER BY name; + +/* name: GetCity :one */ +SELECT * +FROM city +WHERE slug = ?; + +/* name: CreateCity :exec */ +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +); + +/* name: UpdateCityName :exec */ +UPDATE city +SET name = ? +WHERE slug = ?; diff --git a/internal/dao/slonik/ce/mysql/query/venue.sql b/internal/dao/slonik/ce/mysql/query/venue.sql new file mode 100644 index 00000000..a1dd7a16 --- /dev/null +++ b/internal/dao/slonik/ce/mysql/query/venue.sql @@ -0,0 +1,48 @@ +/* name: ListVenues :many */ +SELECT * +FROM venue +WHERE city = ? +ORDER BY name; + +/* name: DeleteVenue :exec */ +DELETE FROM venue +WHERE slug = ? AND slug = ?; + +/* name: GetVenue :one */ +SELECT * +FROM venue +WHERE slug = ? AND city = ?; + +/* name: CreateVenue :execresult */ +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + NOW(), + ?, + ?, + ?, + ? +); + +/* name: UpdateVenueName :exec */ +UPDATE venue +SET name = ? +WHERE slug = ?; + +/* name: VenueCountByCity :many */ +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/internal/dao/slonik/ce/mysql/schema/0001_city.sql b/internal/dao/slonik/ce/mysql/schema/0001_city.sql new file mode 100644 index 00000000..6be35d16 --- /dev/null +++ b/internal/dao/slonik/ce/mysql/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug varchar(255) PRIMARY KEY, + name text NOT NULL +) diff --git a/internal/dao/slonik/ce/mysql/schema/0002_venue.sql b/internal/dao/slonik/ce/mysql/schema/0002_venue.sql new file mode 100644 index 00000000..4fc842ce --- /dev/null +++ b/internal/dao/slonik/ce/mysql/schema/0002_venue.sql @@ -0,0 +1,12 @@ +CREATE TABLE venues ( + id SERIAL primary key, + dropped text, + status ENUM('open', 'closed') not null COMMENT 'Venues can be either open or closed', + statuses text, -- status[], + slug text not null COMMENT 'This value appears in public URLs', + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar(255) not null, + songkick_id text, + tags text -- text[] +) COMMENT='Venues are places where muisc happens'; diff --git a/internal/dao/slonik/ce/mysql/schema/0003_add_column.sql b/internal/dao/slonik/ce/mysql/schema/0003_add_column.sql new file mode 100644 index 00000000..9b334bcc --- /dev/null +++ b/internal/dao/slonik/ce/mysql/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW(); +ALTER TABLE venue DROP COLUMN dropped; diff --git a/internal/dao/slonik/ce/mysql/venue.sql.go b/internal/dao/slonik/ce/mysql/venue.sql.go new file mode 100644 index 00000000..1bc2b0cb --- /dev/null +++ b/internal/dao/slonik/ce/mysql/venue.sql.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: venue.sql + +package dbr + +import ( + "context" + "database/sql" +) + +const createVenue = `-- name: CreateVenue :execresult +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + NOW(), + ?, + ?, + ?, + ? +) +` + +type CreateVenueParams struct { + Slug string + Name string + City string + SpotifyPlaylist string + Status VenuesStatus + Statuses sql.NullString + Tags sql.NullString +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) { + return q.exec(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = ? AND slug = ? +` + +type DeleteVenueParams struct { + Slug string + Slug_2 string +} + +func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = ? AND city = ? +` + +type GetVenueParams struct { + Slug string + City string +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = ? +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateVenueName = `-- name: UpdateVenueName :exec +UPDATE venue +SET name = ? +WHERE slug = ? +` + +type UpdateVenueNameParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error { + _, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug) + return err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string + Count int64 +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/dao/slonik/ce/postgres/city.sql.go b/internal/dao/slonik/ce/postgres/city.sql.go new file mode 100644 index 00000000..d16ffab9 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/city.sql.go @@ -0,0 +1,90 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: city.sql + +package dbr + +import ( + "context" +) + +const createCity = `-- name: CreateCity :one +INSERT INTO city ( + name, + slug +) VALUES ( + $1, + $2 +) RETURNING slug, name +` + +type CreateCityParams struct { + Name string + Slug string +} + +// Create a new city. The slug must be unique. +// This is the second line of the comment +// This is the third line +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) (City, error) { + row := q.db.QueryRow(ctx, createCity, arg.Name, arg.Slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = $1 +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.db.QueryRow(ctx, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.db.Query(ctx, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = $2 +WHERE slug = $1 +` + +type UpdateCityNameParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.db.Exec(ctx, updateCityName, arg.Slug, arg.Name) + return err +} diff --git a/internal/dao/slonik/ce/postgres/db.go b/internal/dao/slonik/ce/postgres/db.go new file mode 100644 index 00000000..837fe9df --- /dev/null +++ b/internal/dao/slonik/ce/postgres/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/dao/slonik/ce/postgres/models.go b/internal/dao/slonik/ce/postgres/models.go new file mode 100644 index 00000000..2a099189 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/models.go @@ -0,0 +1,75 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +// Venues can be either open or closed +type Status string + +const ( + StatusOpen Status = "op!en" + StatusClosed Status = "clo@sed" +) + +func (e *Status) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = Status(s) + case string: + *e = Status(s) + default: + return fmt.Errorf("unsupported scan type for Status: %T", src) + } + return nil +} + +type NullStatus struct { + Status Status + Valid bool // Valid is true if Status is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullStatus) Scan(value interface{}) error { + if value == nil { + ns.Status, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.Status.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullStatus) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.Status), nil +} + +type City struct { + Slug string + Name string +} + +// Venues are places where muisc happens +type Venue struct { + ID int32 + Status Status + Statuses pgtype.Array[Status] + // This value appears in public URLs + Slug string + Name string + City string + SpotifyPlaylist string + SongkickID pgtype.Text + Tags pgtype.Array[string] + CreatedAt pgtype.Timestamp +} diff --git a/internal/dao/slonik/ce/postgres/querier.go b/internal/dao/slonik/ce/postgres/querier.go new file mode 100644 index 00000000..5d494697 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/querier.go @@ -0,0 +1,27 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" +) + +type Querier interface { + // Create a new city. The slug must be unique. + // This is the second line of the comment + // This is the third line + CreateCity(ctx context.Context, arg CreateCityParams) (City, error) + CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) + DeleteVenue(ctx context.Context, slug string) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/dao/slonik/ce/postgres/query.sql b/internal/dao/slonik/ce/postgres/query.sql new file mode 100644 index 00000000..33a78434 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/query.sql @@ -0,0 +1,56 @@ +-- name: GetAuthor :one +SELECT * FROM authors +WHERE author_id = $1; + +-- name: DeleteBookExecResult :execresult +DELETE FROM books +WHERE book_id = $1; + +-- name: DeleteBook :batchexec +DELETE FROM books +WHERE book_id = $1; + +-- name: DeleteBookNamedFunc :batchexec +DELETE FROM books +WHERE book_id = sqlc.arg(book_id); + +-- name: DeleteBookNamedSign :batchexec +DELETE FROM books +WHERE book_id = @book_id; + +-- name: BooksByYear :batchmany +SELECT * FROM books +WHERE year = $1; + +-- name: CreateAuthor :one +INSERT INTO authors (name) VALUES ($1) +RETURNING *; + +-- name: CreateBook :batchone +INSERT INTO books ( + author_id, + isbn, + book_type, + title, + year, + available, + tags +) VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 +) +RETURNING *; + +-- name: UpdateBook :batchexec +UPDATE books +SET title = $1, tags = $2 +WHERE book_id = $3; + +-- name: GetBiography :batchone +SELECT biography FROM authors +WHERE author_id = $1; diff --git a/internal/dao/slonik/ce/postgres/query/city.sql b/internal/dao/slonik/ce/postgres/query/city.sql new file mode 100644 index 00000000..f34dc996 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/query/city.sql @@ -0,0 +1,26 @@ +-- name: ListCities :many +SELECT * +FROM city +ORDER BY name; + +-- name: GetCity :one +SELECT * +FROM city +WHERE slug = $1; + +-- name: CreateCity :one +-- Create a new city. The slug must be unique. +-- This is the second line of the comment +-- This is the third line +INSERT INTO city ( + name, + slug +) VALUES ( + $1, + $2 +) RETURNING *; + +-- name: UpdateCityName :exec +UPDATE city +SET name = $2 +WHERE slug = $1; diff --git a/internal/dao/slonik/ce/postgres/query/venue.sql b/internal/dao/slonik/ce/postgres/query/venue.sql new file mode 100644 index 00000000..8c6bd026 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/query/venue.sql @@ -0,0 +1,49 @@ +-- name: ListVenues :many +SELECT * +FROM venue +WHERE city = $1 +ORDER BY name; + +-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = $1 AND slug = $1; + +-- name: GetVenue :one +SELECT * +FROM venue +WHERE slug = $1 AND city = $2; + +-- name: CreateVenue :one +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + $1, + $2, + $3, + NOW(), + $4, + $5, + $6, + $7 +) RETURNING id; + +-- name: UpdateVenueName :one +UPDATE venue +SET name = $2 +WHERE slug = $1 +RETURNING id; + +-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/internal/dao/slonik/ce/postgres/schema.sql b/internal/dao/slonik/ce/postgres/schema.sql new file mode 100644 index 00000000..b79f773f --- /dev/null +++ b/internal/dao/slonik/ce/postgres/schema.sql @@ -0,0 +1,21 @@ +CREATE TABLE authors ( + author_id SERIAL PRIMARY KEY, + name text NOT NULL DEFAULT '', + biography JSONB +); + +CREATE TYPE book_type AS ENUM ( + 'FICTION', + 'NONFICTION' +); + +CREATE TABLE books ( + book_id SERIAL PRIMARY KEY, + author_id integer NOT NULL REFERENCES authors(author_id), + isbn text NOT NULL DEFAULT '' UNIQUE, + book_type book_type NOT NULL DEFAULT 'FICTION', + title text NOT NULL DEFAULT '', + year integer NOT NULL DEFAULT 2000, + available timestamp with time zone NOT NULL DEFAULT 'NOW()', + tags varchar[] NOT NULL DEFAULT '{}' +); diff --git a/internal/dao/slonik/ce/postgres/schema/0001_city.sql b/internal/dao/slonik/ce/postgres/schema/0001_city.sql new file mode 100644 index 00000000..af38f16b --- /dev/null +++ b/internal/dao/slonik/ce/postgres/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug text PRIMARY KEY, + name text NOT NULL +) diff --git a/internal/dao/slonik/ce/postgres/schema/0002_venue.sql b/internal/dao/slonik/ce/postgres/schema/0002_venue.sql new file mode 100644 index 00000000..940de7a5 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/schema/0002_venue.sql @@ -0,0 +1,18 @@ +CREATE TYPE status AS ENUM ('op!en', 'clo@sed'); +COMMENT ON TYPE status IS 'Venues can be either open or closed'; + +CREATE TABLE venues ( + id SERIAL primary key, + dropped text, + status status not null, + statuses status[], + slug text not null, + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar not null, + songkick_id text, + tags text[] +); +COMMENT ON TABLE venues IS 'Venues are places where muisc happens'; +COMMENT ON COLUMN venues.slug IS 'This value appears in public URLs'; + diff --git a/internal/dao/slonik/ce/postgres/schema/0003_add_column.sql b/internal/dao/slonik/ce/postgres/schema/0003_add_column.sql new file mode 100644 index 00000000..9b334bcc --- /dev/null +++ b/internal/dao/slonik/ce/postgres/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at TIMESTAMP NOT NULL DEFAULT NOW(); +ALTER TABLE venue DROP COLUMN dropped; diff --git a/internal/dao/slonik/ce/postgres/venue.sql.go b/internal/dao/slonik/ce/postgres/venue.sql.go new file mode 100644 index 00000000..384701a2 --- /dev/null +++ b/internal/dao/slonik/ce/postgres/venue.sql.go @@ -0,0 +1,189 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: venue.sql + +package dbr + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const createVenue = `-- name: CreateVenue :one +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + $1, + $2, + $3, + NOW(), + $4, + $5, + $6, + $7 +) RETURNING id +` + +type CreateVenueParams struct { + Slug string + Name string + City string + SpotifyPlaylist string + Status Status + Statuses pgtype.Array[Status] + Tags pgtype.Array[string] +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (int32, error) { + row := q.db.QueryRow(ctx, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) + var id int32 + err := row.Scan(&id) + return id, err +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = $1 AND slug = $1 +` + +func (q *Queries) DeleteVenue(ctx context.Context, slug string) error { + _, err := q.db.Exec(ctx, deleteVenue, slug) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = $1 AND city = $2 +` + +type GetVenueParams struct { + Slug string + City string +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.db.QueryRow(ctx, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = $1 +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.db.Query(ctx, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateVenueName = `-- name: UpdateVenueName :one +UPDATE venue +SET name = $2 +WHERE slug = $1 +RETURNING id +` + +type UpdateVenueNameParams struct { + Slug string + Name string +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) (int32, error) { + row := q.db.QueryRow(ctx, updateVenueName, arg.Slug, arg.Name) + var id int32 + err := row.Scan(&id) + return id, err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string + Count int64 +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.db.Query(ctx, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/dao/slonik/ce/sqlc.yaml b/internal/dao/slonik/ce/sqlc.yaml new file mode 100644 index 00000000..dd0d6bfa --- /dev/null +++ b/internal/dao/slonik/ce/sqlc.yaml @@ -0,0 +1,30 @@ +version: '2' +sql: + - schema: postgres/schema + queries: postgres/query + engine: postgresql + gen: + go: + package: dbr + out: postgres + sql_package: 'pgx/v5' + emit_prepared_queries: true + emit_interface: true + - schema: mysql/schema + queries: mysql/query + engine: mysql + gen: + go: + package: dbr + out: mysql + emit_prepared_queries: true + emit_interface: true + - schema: sqlite/schema + queries: sqlite/query + engine: sqlite + gen: + go: + package: dbr + out: sqlite + emit_prepared_queries: true + emit_interface: true diff --git a/internal/dao/slonik/ce/sqlite/city.sql.go b/internal/dao/slonik/ce/sqlite/city.sql.go new file mode 100644 index 00000000..75ea6e41 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/city.sql.go @@ -0,0 +1,88 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: city.sql + +package dbr + +import ( + "context" +) + +const createCity = `-- name: CreateCity :exec +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +) +` + +type CreateCityParams struct { + Name string + Slug string +} + +func (q *Queries) CreateCity(ctx context.Context, arg CreateCityParams) error { + _, err := q.exec(ctx, q.createCityStmt, createCity, arg.Name, arg.Slug) + return err +} + +const getCity = `-- name: GetCity :one +SELECT slug, name +FROM city +WHERE slug = ? +` + +func (q *Queries) GetCity(ctx context.Context, slug string) (City, error) { + row := q.queryRow(ctx, q.getCityStmt, getCity, slug) + var i City + err := row.Scan(&i.Slug, &i.Name) + return i, err +} + +const listCities = `-- name: ListCities :many +SELECT slug, name +FROM city +ORDER BY name +` + +func (q *Queries) ListCities(ctx context.Context) ([]City, error) { + rows, err := q.query(ctx, q.listCitiesStmt, listCities) + if err != nil { + return nil, err + } + defer rows.Close() + var items []City + for rows.Next() { + var i City + if err := rows.Scan(&i.Slug, &i.Name); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateCityName = `-- name: UpdateCityName :exec +UPDATE city +SET name = ? +WHERE slug = ? +` + +type UpdateCityNameParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error { + _, err := q.exec(ctx, q.updateCityNameStmt, updateCityName, arg.Name, arg.Slug) + return err +} diff --git a/internal/dao/slonik/ce/sqlite/db.go b/internal/dao/slonik/ce/sqlite/db.go new file mode 100644 index 00000000..451eb52b --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/db.go @@ -0,0 +1,178 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" + "database/sql" + "fmt" +) + +type DBTX interface { + ExecContext(context.Context, string, ...interface{}) (sql.Result, error) + PrepareContext(context.Context, string) (*sql.Stmt, error) + QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...interface{}) *sql.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +func Prepare(ctx context.Context, db DBTX) (*Queries, error) { + q := Queries{db: db} + var err error + if q.createCityStmt, err = db.PrepareContext(ctx, createCity); err != nil { + return nil, fmt.Errorf("error preparing query CreateCity: %w", err) + } + if q.createVenueStmt, err = db.PrepareContext(ctx, createVenue); err != nil { + return nil, fmt.Errorf("error preparing query CreateVenue: %w", err) + } + if q.deleteVenueStmt, err = db.PrepareContext(ctx, deleteVenue); err != nil { + return nil, fmt.Errorf("error preparing query DeleteVenue: %w", err) + } + if q.getCityStmt, err = db.PrepareContext(ctx, getCity); err != nil { + return nil, fmt.Errorf("error preparing query GetCity: %w", err) + } + if q.getVenueStmt, err = db.PrepareContext(ctx, getVenue); err != nil { + return nil, fmt.Errorf("error preparing query GetVenue: %w", err) + } + if q.listCitiesStmt, err = db.PrepareContext(ctx, listCities); err != nil { + return nil, fmt.Errorf("error preparing query ListCities: %w", err) + } + if q.listVenuesStmt, err = db.PrepareContext(ctx, listVenues); err != nil { + return nil, fmt.Errorf("error preparing query ListVenues: %w", err) + } + if q.updateCityNameStmt, err = db.PrepareContext(ctx, updateCityName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateCityName: %w", err) + } + if q.updateVenueNameStmt, err = db.PrepareContext(ctx, updateVenueName); err != nil { + return nil, fmt.Errorf("error preparing query UpdateVenueName: %w", err) + } + if q.venueCountByCityStmt, err = db.PrepareContext(ctx, venueCountByCity); err != nil { + return nil, fmt.Errorf("error preparing query VenueCountByCity: %w", err) + } + return &q, nil +} + +func (q *Queries) Close() error { + var err error + if q.createCityStmt != nil { + if cerr := q.createCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createCityStmt: %w", cerr) + } + } + if q.createVenueStmt != nil { + if cerr := q.createVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing createVenueStmt: %w", cerr) + } + } + if q.deleteVenueStmt != nil { + if cerr := q.deleteVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing deleteVenueStmt: %w", cerr) + } + } + if q.getCityStmt != nil { + if cerr := q.getCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getCityStmt: %w", cerr) + } + } + if q.getVenueStmt != nil { + if cerr := q.getVenueStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing getVenueStmt: %w", cerr) + } + } + if q.listCitiesStmt != nil { + if cerr := q.listCitiesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listCitiesStmt: %w", cerr) + } + } + if q.listVenuesStmt != nil { + if cerr := q.listVenuesStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing listVenuesStmt: %w", cerr) + } + } + if q.updateCityNameStmt != nil { + if cerr := q.updateCityNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateCityNameStmt: %w", cerr) + } + } + if q.updateVenueNameStmt != nil { + if cerr := q.updateVenueNameStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing updateVenueNameStmt: %w", cerr) + } + } + if q.venueCountByCityStmt != nil { + if cerr := q.venueCountByCityStmt.Close(); cerr != nil { + err = fmt.Errorf("error closing venueCountByCityStmt: %w", cerr) + } + } + return err +} + +func (q *Queries) exec(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (sql.Result, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).ExecContext(ctx, args...) + case stmt != nil: + return stmt.ExecContext(ctx, args...) + default: + return q.db.ExecContext(ctx, query, args...) + } +} + +func (q *Queries) query(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) (*sql.Rows, error) { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryContext(ctx, args...) + case stmt != nil: + return stmt.QueryContext(ctx, args...) + default: + return q.db.QueryContext(ctx, query, args...) + } +} + +func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, args ...interface{}) *sql.Row { + switch { + case stmt != nil && q.tx != nil: + return q.tx.StmtContext(ctx, stmt).QueryRowContext(ctx, args...) + case stmt != nil: + return stmt.QueryRowContext(ctx, args...) + default: + return q.db.QueryRowContext(ctx, query, args...) + } +} + +type Queries struct { + db DBTX + tx *sql.Tx + createCityStmt *sql.Stmt + createVenueStmt *sql.Stmt + deleteVenueStmt *sql.Stmt + getCityStmt *sql.Stmt + getVenueStmt *sql.Stmt + listCitiesStmt *sql.Stmt + listVenuesStmt *sql.Stmt + updateCityNameStmt *sql.Stmt + updateVenueNameStmt *sql.Stmt + venueCountByCityStmt *sql.Stmt +} + +func (q *Queries) WithTx(tx *sql.Tx) *Queries { + return &Queries{ + db: tx, + tx: tx, + createCityStmt: q.createCityStmt, + createVenueStmt: q.createVenueStmt, + deleteVenueStmt: q.deleteVenueStmt, + getCityStmt: q.getCityStmt, + getVenueStmt: q.getVenueStmt, + listCitiesStmt: q.listCitiesStmt, + listVenuesStmt: q.listVenuesStmt, + updateCityNameStmt: q.updateCityNameStmt, + updateVenueNameStmt: q.updateVenueNameStmt, + venueCountByCityStmt: q.venueCountByCityStmt, + } +} diff --git a/internal/dao/slonik/ce/sqlite/models.go b/internal/dao/slonik/ce/sqlite/models.go new file mode 100644 index 00000000..a178d14a --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/models.go @@ -0,0 +1,28 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "database/sql" + "time" +) + +type City struct { + Slug string + Name string +} + +type Venue struct { + ID int64 + Status string + Statuses sql.NullString + Slug string + Name string + City string + SpotifyPlaylist string + SongkickID sql.NullString + Tags sql.NullString + CreatedAt time.Time +} diff --git a/internal/dao/slonik/ce/sqlite/querier.go b/internal/dao/slonik/ce/sqlite/querier.go new file mode 100644 index 00000000..163269e6 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/querier.go @@ -0,0 +1,25 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 + +package dbr + +import ( + "context" + "database/sql" +) + +type Querier interface { + CreateCity(ctx context.Context, arg CreateCityParams) error + CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) + DeleteVenue(ctx context.Context, arg DeleteVenueParams) error + GetCity(ctx context.Context, slug string) (City, error) + GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) + ListCities(ctx context.Context) ([]City, error) + ListVenues(ctx context.Context, city string) ([]Venue, error) + UpdateCityName(ctx context.Context, arg UpdateCityNameParams) error + UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error + VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) +} + +var _ Querier = (*Queries)(nil) diff --git a/internal/dao/slonik/ce/sqlite/query/city.sql b/internal/dao/slonik/ce/sqlite/query/city.sql new file mode 100644 index 00000000..c387e9d0 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/query/city.sql @@ -0,0 +1,23 @@ +/* name: ListCities :many */ +SELECT * +FROM city +ORDER BY name; + +/* name: GetCity :one */ +SELECT * +FROM city +WHERE slug = ?; + +/* name: CreateCity :exec */ +INSERT INTO city ( + name, + slug +) VALUES ( + ?, + ? +); + +/* name: UpdateCityName :exec */ +UPDATE city +SET name = ? +WHERE slug = ?; diff --git a/internal/dao/slonik/ce/sqlite/query/venue.sql b/internal/dao/slonik/ce/sqlite/query/venue.sql new file mode 100644 index 00000000..b4f5fd40 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/query/venue.sql @@ -0,0 +1,48 @@ +/* name: ListVenues :many */ +SELECT * +FROM venue +WHERE city = ? +ORDER BY name; + +/* name: DeleteVenue :exec */ +DELETE FROM venue +WHERE slug = ? AND slug = ?; + +/* name: GetVenue :one */ +SELECT * +FROM venue +WHERE slug = ? AND city = ?; + +/* name: CreateVenue :execresult */ +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +); + +/* name: UpdateVenueName :exec */ +UPDATE venue +SET name = ? +WHERE slug = ?; + +/* name: VenueCountByCity :many */ +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1; diff --git a/internal/dao/slonik/ce/sqlite/schema/0001_city.sql b/internal/dao/slonik/ce/sqlite/schema/0001_city.sql new file mode 100644 index 00000000..6be35d16 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/schema/0001_city.sql @@ -0,0 +1,4 @@ +CREATE TABLE city ( + slug varchar(255) PRIMARY KEY, + name text NOT NULL +) diff --git a/internal/dao/slonik/ce/sqlite/schema/0002_venue.sql b/internal/dao/slonik/ce/sqlite/schema/0002_venue.sql new file mode 100644 index 00000000..e57166e4 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/schema/0002_venue.sql @@ -0,0 +1,13 @@ +CREATE TABLE venues ( + id integer primary key AUTOINCREMENT, + dropped text, + status text not null, + statuses text, -- status[] + slug text not null, + name varchar(255) not null, + city text not null references city(slug), + spotify_playlist varchar(255) not null, + songkick_id text, + tags text, -- tags[] + CHECK (status = 'open' OR status = 'closed') +); diff --git a/internal/dao/slonik/ce/sqlite/schema/0003_add_column.sql b/internal/dao/slonik/ce/sqlite/schema/0003_add_column.sql new file mode 100644 index 00000000..7d7a6443 --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/schema/0003_add_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE venues RENAME TO venue; +ALTER TABLE venue ADD COLUMN created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP; +ALTER TABLE venue DROP COLUMN dropped; diff --git a/internal/dao/slonik/ce/sqlite/venue.sql.go b/internal/dao/slonik/ce/sqlite/venue.sql.go new file mode 100644 index 00000000..273a4caa --- /dev/null +++ b/internal/dao/slonik/ce/sqlite/venue.sql.go @@ -0,0 +1,193 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.16.0 +// source: venue.sql + +package dbr + +import ( + "context" + "database/sql" +) + +const createVenue = `-- name: CreateVenue :execresult +INSERT INTO venue ( + slug, + name, + city, + created_at, + spotify_playlist, + status, + statuses, + tags +) VALUES ( + ?, + ?, + ?, + CURRENT_TIMESTAMP, + ?, + ?, + ?, + ? +) +` + +type CreateVenueParams struct { + Slug string + Name string + City string + SpotifyPlaylist string + Status string + Statuses sql.NullString + Tags sql.NullString +} + +func (q *Queries) CreateVenue(ctx context.Context, arg CreateVenueParams) (sql.Result, error) { + return q.exec(ctx, q.createVenueStmt, createVenue, + arg.Slug, + arg.Name, + arg.City, + arg.SpotifyPlaylist, + arg.Status, + arg.Statuses, + arg.Tags, + ) +} + +const deleteVenue = `-- name: DeleteVenue :exec +DELETE FROM venue +WHERE slug = ? AND slug = ? +` + +type DeleteVenueParams struct { + Slug string + Slug_2 string +} + +func (q *Queries) DeleteVenue(ctx context.Context, arg DeleteVenueParams) error { + _, err := q.exec(ctx, q.deleteVenueStmt, deleteVenue, arg.Slug, arg.Slug_2) + return err +} + +const getVenue = `-- name: GetVenue :one +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE slug = ? AND city = ? +` + +type GetVenueParams struct { + Slug string + City string +} + +func (q *Queries) GetVenue(ctx context.Context, arg GetVenueParams) (Venue, error) { + row := q.queryRow(ctx, q.getVenueStmt, getVenue, arg.Slug, arg.City) + var i Venue + err := row.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ) + return i, err +} + +const listVenues = `-- name: ListVenues :many +SELECT id, status, statuses, slug, name, city, spotify_playlist, songkick_id, tags, created_at +FROM venue +WHERE city = ? +ORDER BY name +` + +func (q *Queries) ListVenues(ctx context.Context, city string) ([]Venue, error) { + rows, err := q.query(ctx, q.listVenuesStmt, listVenues, city) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Venue + for rows.Next() { + var i Venue + if err := rows.Scan( + &i.ID, + &i.Status, + &i.Statuses, + &i.Slug, + &i.Name, + &i.City, + &i.SpotifyPlaylist, + &i.SongkickID, + &i.Tags, + &i.CreatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const updateVenueName = `-- name: UpdateVenueName :exec +UPDATE venue +SET name = ? +WHERE slug = ? +` + +type UpdateVenueNameParams struct { + Name string + Slug string +} + +func (q *Queries) UpdateVenueName(ctx context.Context, arg UpdateVenueNameParams) error { + _, err := q.exec(ctx, q.updateVenueNameStmt, updateVenueName, arg.Name, arg.Slug) + return err +} + +const venueCountByCity = `-- name: VenueCountByCity :many +SELECT + city, + count(*) +FROM venue +GROUP BY 1 +ORDER BY 1 +` + +type VenueCountByCityRow struct { + City string + Count int64 +} + +func (q *Queries) VenueCountByCity(ctx context.Context) ([]VenueCountByCityRow, error) { + rows, err := q.query(ctx, q.venueCountByCityStmt, venueCountByCity) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VenueCountByCityRow + for rows.Next() { + var i VenueCountByCityRow + if err := rows.Scan(&i.City, &i.Count); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +}