database: Remove superfluous ID columns
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Rob Watson 2022-05-25 06:50:24 +02:00
parent 8f83d36571
commit 3f134bd417
9 changed files with 48 additions and 38 deletions

View File

@ -7,12 +7,9 @@ package store
import (
"database/sql"
"time"
"github.com/google/uuid"
)
type ElonTweet struct {
ID uuid.UUID
TwitterID int64
Text string
PostedAt time.Time
@ -22,8 +19,7 @@ type ElonTweet struct {
}
type User struct {
ID uuid.UUID
TwitterID string
TwitterID int64
Username string
Name string
AccessToken string

View File

@ -17,11 +17,11 @@ INSERT INTO users (twitter_id, username, name, access_token, refresh_token, crea
ON CONFLICT (twitter_id)
DO
UPDATE SET access_token = EXCLUDED.access_token, refresh_token = EXCLUDED.refresh_token, username = EXCLUDED.username, name = EXCLUDED.name, updated_at = EXCLUDED.updated_at
RETURNING id, twitter_id, username, name, access_token, refresh_token, delete_tweets_enabled, delete_tweets_num_per_iteration, created_at, updated_at
RETURNING twitter_id, username, name, access_token, refresh_token, delete_tweets_enabled, delete_tweets_num_per_iteration, created_at, updated_at
`
type CreateUserParams struct {
TwitterID string
TwitterID int64
Username string
Name string
AccessToken string
@ -42,7 +42,6 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
)
var i User
err := row.Scan(
&i.ID,
&i.TwitterID,
&i.Username,
&i.Name,
@ -57,14 +56,13 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
}
const getLastElonTweet = `-- name: GetLastElonTweet :one
SELECT id, twitter_id, text, posted_at, processed_at, created_at, updated_at from elon_tweets ORDER BY twitter_id DESC LIMIT 1
SELECT twitter_id, text, posted_at, processed_at, created_at, updated_at from elon_tweets ORDER BY twitter_id DESC LIMIT 1
`
func (q *Queries) GetLastElonTweet(ctx context.Context) (ElonTweet, error) {
row := q.db.QueryRow(ctx, getLastElonTweet)
var i ElonTweet
err := row.Scan(
&i.ID,
&i.TwitterID,
&i.Text,
&i.PostedAt,
@ -76,14 +74,13 @@ func (q *Queries) GetLastElonTweet(ctx context.Context) (ElonTweet, error) {
}
const getUserByTwitterID = `-- name: GetUserByTwitterID :one
SELECT id, twitter_id, username, name, access_token, refresh_token, delete_tweets_enabled, delete_tweets_num_per_iteration, created_at, updated_at FROM users WHERE twitter_id = $1
SELECT twitter_id, username, name, access_token, refresh_token, delete_tweets_enabled, delete_tweets_num_per_iteration, created_at, updated_at FROM users WHERE twitter_id = $1
`
func (q *Queries) GetUserByTwitterID(ctx context.Context, twitterID string) (User, error) {
func (q *Queries) GetUserByTwitterID(ctx context.Context, twitterID int64) (User, error) {
row := q.db.QueryRow(ctx, getUserByTwitterID, twitterID)
var i User
err := row.Scan(
&i.ID,
&i.TwitterID,
&i.Username,
&i.Name,
@ -101,7 +98,7 @@ const upsertElonTweet = `-- name: UpsertElonTweet :one
INSERT INTO elon_tweets (twitter_id, text, posted_at, processed_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, NOW(), NOW())
ON CONFLICT (twitter_id) DO NOTHING
RETURNING id, twitter_id, text, posted_at, processed_at, created_at, updated_at
RETURNING twitter_id, text, posted_at, processed_at, created_at, updated_at
`
type UpsertElonTweetParams struct {
@ -120,7 +117,6 @@ func (q *Queries) UpsertElonTweet(ctx context.Context, arg UpsertElonTweetParams
)
var i ElonTweet
err := row.Scan(
&i.ID,
&i.TwitterID,
&i.Text,
&i.PostedAt,

5
go.mod
View File

@ -5,6 +5,8 @@ go 1.18
require (
github.com/go-chi/chi v1.5.4
github.com/gorilla/sessions v1.2.1
github.com/jackc/pgconn v1.12.1
github.com/jackc/pgx/v4 v4.16.1
github.com/stretchr/testify v1.7.1
go.uber.org/zap v1.21.0
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
@ -14,16 +16,13 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/protobuf v1.4.2 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.12.1 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
github.com/jackc/pgtype v1.11.0 // indirect
github.com/jackc/pgx/v4 v4.16.1 // indirect
github.com/jackc/puddle v1.2.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.2.0 // indirect

10
go.sum
View File

@ -42,6 +42,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@ -61,6 +62,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@ -108,8 +110,6 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
@ -119,7 +119,6 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@ -136,10 +135,10 @@ github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
@ -182,6 +181,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@ -199,10 +199,10 @@ github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OK
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=

View File

@ -7,6 +7,7 @@ import (
"encoding/gob"
"html/template"
"net/http"
"strconv"
"time"
"git.netflux.io/rob/elon-eats-my-tweets/config"
@ -15,7 +16,6 @@ import (
"git.netflux.io/rob/elon-eats-my-tweets/twitterapi"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/google/uuid"
"github.com/gorilla/sessions"
"go.uber.org/zap"
"golang.org/x/oauth2"
@ -26,12 +26,12 @@ func init() {
}
type CurrentUser struct {
ID uuid.UUID
TwitterID int64
TwitterName, TwitterUsername string
}
func (cu CurrentUser) IsNil() bool {
return cu.ID == uuid.Nil
return cu.TwitterID == 0
}
type contextKey string
@ -194,8 +194,15 @@ func (h *handler) getCallback(w http.ResponseWriter, r *http.Request) {
return
}
twitterUserID, err := strconv.ParseInt(twitterUser.ID, 10, 64)
if err != nil {
h.logger.With("err", err).Error("error parsing Twitter user ID")
http.Error(w, "error validating user", http.StatusInternalServerError)
return
}
user, err := h.store.CreateUser(r.Context(), store.CreateUserParams{
TwitterID: twitterUser.ID,
TwitterID: twitterUserID,
Username: twitterUser.Username,
Name: twitterUser.Name,
AccessToken: token.AccessToken,
@ -212,7 +219,7 @@ func (h *handler) getCallback(w http.ResponseWriter, r *http.Request) {
// finally, save in the session. To avoid hitting the database on most
// requests we'll store the Twitter name and username in the session.
session.Values[sessionKeyCurrentUser] = CurrentUser{
ID: user.ID,
TwitterID: user.TwitterID,
TwitterName: twitterUser.Name,
TwitterUsername: twitterUser.Username,
}

View File

@ -12,7 +12,6 @@ import (
"git.netflux.io/rob/elon-eats-my-tweets/generated/store"
"git.netflux.io/rob/elon-eats-my-tweets/httpserver"
"git.netflux.io/rob/elon-eats-my-tweets/twitterapi"
"github.com/google/uuid"
"github.com/gorilla/sessions"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@ -48,7 +47,7 @@ func TestGetIndex(t *testing.T) {
},
{
name: "logged out",
currentUser: httpserver.CurrentUser{ID: uuid.New(), TwitterName: "foo", TwitterUsername: "Foo Bar"},
currentUser: httpserver.CurrentUser{TwitterID: 1, TwitterName: "foo", TwitterUsername: "Foo Bar"},
wantBody: "Welcome to your dashboard",
},
}
@ -272,7 +271,7 @@ func TestGetCallback(t *testing.T) {
var mockStore mocks.Store
mockStore.On("CreateUser", mock.Anything, mock.MatchedBy(func(params store.CreateUserParams) bool {
return params.TwitterID == "1" && params.Name == "foo" && params.Username == "Foo Bar"
return params.TwitterID == 1 && params.Name == "foo" && params.Username == "Foo Bar"
})).Return(store.User{}, tc.createUserError)
const callbackURL = "https://www.example.com/callback"

View File

@ -15,12 +15,7 @@ func loggerMiddleware(l *zap.Logger, sessionStore sessions.Store) func(next http
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
t1 := time.Now()
cu, ok := getCurrentUser(r, sessionStore)
var userID string
if ok {
userID = cu.ID.String()
}
cu, _ := getCurrentUser(r, sessionStore)
defer func() {
l.Info("HTTP",
zap.String("proto", r.Proto),
@ -31,7 +26,7 @@ func loggerMiddleware(l *zap.Logger, sessionStore sessions.Store) func(next http
zap.Int("size", ww.BytesWritten()),
zap.String("ip", r.RemoteAddr),
zap.String("reqId", middleware.GetReqID(r.Context())),
zap.String("userID", userID),
zap.Int64("userID", cu.TwitterID),
zap.String("username", cu.TwitterUsername))
}()

View File

@ -0,0 +1,8 @@
ALTER TABLE elon_tweets DROP CONSTRAINT elon_tweets_pkey;
ALTER TABLE elon_tweets ADD COLUMN id uuid PRIMARY KEY DEFAULT gen_random_uuid();
CREATE UNIQUE INDEX index_elon_tweets_on_twitter_id ON elon_tweets (twitter_id);
ALTER TABLE users DROP CONSTRAINT users_pkey;
ALTER TABLE users ADD COLUMN id uuid PRIMARY KEY DEFAULT gen_random_uuid();
ALTER TABLE users ALTER COLUMN twitter_id TYPE CHARACTER VARYING(256);
ALTER TABLE users ALTER COLUMN twitter_id SET NOT NULL;
CREATE UNIQUE INDEX index_users_on_twitter_id ON users (twitter_id);

View File

@ -0,0 +1,10 @@
-- requires an empty db
DROP INDEX index_users_on_twitter_id;
ALTER TABLE users ALTER COLUMN twitter_id DROP DEFAULT;
ALTER TABLE users ALTER COLUMN twitter_id TYPE bigint USING (twitter_id::bigint);
ALTER TABLE users DROP COLUMN id;
ALTER TABLE users ADD PRIMARY KEY (twitter_id);
DROP INDEX index_elon_tweets_on_twitter_id;
ALTER TABLE elon_tweets DROP CONSTRAINT elon_tweets_pkey;
ALTER TABLE elon_tweets DROP COLUMN id;
ALTER TABLE elon_tweets ADD PRIMARY KEY (twitter_id);