From da1a806e144f1b3d5267f109b16a5cc8650e9097 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 13 Oct 2020 13:41:04 -0400 Subject: [PATCH] webhooks/legacy: address Postgres-specific issues --- webhooks/legacy.go | 29 ++++++++++++++++++++--------- webhooks/legacy_test.go | 8 ++++---- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/webhooks/legacy.go b/webhooks/legacy.go index d76cf79287277597a495284e7485201a6bb39d32..7ea3d8dc06e4cff509e4d782f2ffee80690570c0 100644 --- a/webhooks/legacy.go +++ b/webhooks/legacy.go @@ -13,8 +13,8 @@ import ( "time" "git.sr.ht/~sircmpwn/dowork" - sq "github.com/Masterminds/squirrel" "github.com/google/uuid" + sq "github.com/Masterminds/squirrel" "git.sr.ht/~sircmpwn/core-go/crypto" "git.sr.ht/~sircmpwn/core-go/database" @@ -44,7 +44,8 @@ func NewLegacyQueue() *LegacyQueue { // The select builder should not return any columns, i.e. the caller should use // squirrel.Select() with no parameters. The caller should prepare FROM and any // WHERE clauses which are necessary to refine the subscriber list (e.g. by -// affected resource ID). +// affected resource ID). The caller must alias the webhook table to "sub", e.g. +// sq.Select().From("my_webhook_subscription sub"). // // Name shall be the prefix of the webhook tables, e.g. "user" for // "user_webhook_{delivery,subscription}". @@ -80,6 +81,7 @@ func (lq *LegacyQueue) Schedule(q sq.SelectBuilder, } return nil }); err != nil { + log.Println("Failed to enqueue webhooks: %v", err) return err } @@ -106,11 +108,12 @@ func fetchSubscriptions(ctx context.Context, q sq.SelectBuilder, rows *sql.Rows ) if rows, err = q. - Columns("id", "created", "url", "events"). - Where(sq.Like{"events": "%" + event + "%"}). + Columns("sub.id", "sub.created", "sub.url", "sub.events"). + Where(sq.Like{"sub.events": "%" + event + "%"}). + PlaceholderFormat(sq.Dollar). RunWith(tx). QueryContext(ctx); err != nil { - panic(err) + return err } defer rows.Close() @@ -161,15 +164,21 @@ func (lq *LegacyQueue) queueStage2(ctx context.Context, tx *sql.Tx, headers.Write(&sb) var deliveryID int - sq.Insert(name+"_webhook_delivery"). + err := sq. + Insert(name+"_webhook_delivery"). Columns("uuid", "created", "event", "url", "payload", "payload_headers", "response_status", "subscription_id"). - Values(deliveryUUID, "NOW() at time zone 'utc'", event, sub.URL, - string(payload), sb.String(), -2, sub.ID). + Values(deliveryUUID, + sq.Expr("NOW() at time zone 'utc'"), + event, sub.URL, string(payload), sb.String(), -2, sub.ID). Suffix(`RETURNING (id)`). + PlaceholderFormat(sq.Dollar). RunWith(tx). ScanContext(ctx, &deliveryID) + if err != nil { + return nil, err + } return work.NewTask(func(ctx context.Context) error { return deliverPayload(ctx, name, sub.URL, headers, payload, deliveryID) @@ -226,11 +235,13 @@ func deliverPayload(ctx context.Context, name, url string, if err = database.WithTx(ctx, nil, func(tx *sql.Tx) error { var sb strings.Builder resp.Header.Write(&sb) - _, err := sq.Update(name+"_webhook_delivery"). + _, err := sq. + Update(name+"_webhook_delivery"). Set("response", string(body)). Set("response_status", resp.StatusCode). Set("response_headers", sb.String()). Where("id = ?", deliveryID). + PlaceholderFormat(sq.Dollar). RunWith(tx). ExecContext(ctx) return err diff --git a/webhooks/legacy_test.go b/webhooks/legacy_test.go index 9de9ccee08fd20ed85d397125a8f31e235d37c16..6146ba3c1bb1cf75e9b33115cc612ce412ffb196 100644 --- a/webhooks/legacy_test.go +++ b/webhooks/legacy_test.go @@ -63,8 +63,8 @@ func TestDelivery(t *testing.T) { queue := NewLegacyQueue() q := sq. Select(). - From("user_webhook_subscription"). - Where(`user_id = ?`, 42) + From("user_webhook_subscription sub"). + Where(`sub.user_id = ?`, 42) queue.Schedule(q, "user", "profile:update", []byte(`{"hello": "world"}`)) db, mock, err := sqlmock.New() @@ -74,9 +74,9 @@ func TestDelivery(t *testing.T) { // Lookup phase mock.ExpectBegin() - mock.ExpectQuery(`SELECT .* FROM user_webhook_subscription`). + mock.ExpectQuery(`SELECT .* FROM user_webhook_subscription sub`). WillReturnRows(sqlmock.NewRows([]string{ - "id", "created", "url", "events", + "sub.id", "sub.created", "sub.url", "sub.events", }).AddRow(1337, time.Now().UTC(), srv.URL + "/webhook", "profile:update")). WithArgs(42, sqlmock.AnyArg()) // Any => events LIKE %profile:update%