Skip to content

Commit

Permalink
feat: metadata management (#89)
Browse files Browse the repository at this point in the history
* feat: metadata update route & object support

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>

* feat: metadata OAS addition

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>

* fix: conflict resolution

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>

Signed-off-by: Lawrence Zawila <113581282+darkmatterpool@users.noreply.github.com>
  • Loading branch information
darkmatterpool authored Jan 26, 2023
1 parent ae1fa5e commit 3a7e608
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 64 deletions.
54 changes: 54 additions & 0 deletions internal/app/api/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package api

import (
"context"
"encoding/json"
"net/http"

"github.com/pkg/errors"

"github.com/google/uuid"

"github.com/gorilla/mux"
)

type updateMetadataRepository interface {
UpdatePaymentMetadata(ctx context.Context, paymentID uuid.UUID, metadata map[string]string) error
}

type updateMetadataRequest map[string]string

func updateMetadataHandler(repo updateMetadataRepository) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
paymentID, err := uuid.Parse(mux.Vars(r)["paymentID"])
if err != nil {
handleErrorBadRequest(w, r, err)

return
}

var metadata updateMetadataRequest

if r.ContentLength == 0 {
handleErrorBadRequest(w, r, errors.New("body is required"))

return
}

err = json.NewDecoder(r.Body).Decode(&metadata)
if err != nil {
handleError(w, r, err)

return
}

err = repo.UpdatePaymentMetadata(r.Context(), paymentID, metadata)
if err != nil {
handleError(w, r, err)

return
}

w.WriteHeader(http.StatusNoContent)
}
}
50 changes: 11 additions & 39 deletions internal/app/api/payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,7 @@ type paymentResponse struct {
CreatedAt time.Time `json:"createdAt"`
Raw interface{} `json:"raw"`
Adjustments []paymentAdjustment `json:"adjustments"`
Metadata []paymentMetadata `json:"metadata"`
}

type paymentMetadata struct {
Key string `json:"key"`
Value string `json:"value"`
Changelog []paymentMetadataChangelog `json:"changelog"`
}

type paymentMetadataChangelog struct {
Timestamp string `json:"timestamp"`
Value string `json:"value"`
Metadata map[string]string `json:"metadata"`
}

type paymentAdjustment struct {
Expand Down Expand Up @@ -139,19 +128,11 @@ func listPaymentsHandler(repo listPaymentsRepository) http.HandlerFunc {
}
}

for metadataIDx := range ret[i].Metadata {
data[i].Metadata = append(data[i].Metadata,
paymentMetadata{
Key: ret[i].Metadata[metadataIDx].Key,
Value: ret[i].Metadata[metadataIDx].Value,
})

for changelogIdx := range ret[i].Metadata[metadataIDx].Changelog {
data[i].Metadata[metadataIDx].Changelog = append(data[i].Metadata[metadataIDx].Changelog,
paymentMetadataChangelog{
Timestamp: ret[i].Metadata[metadataIDx].Changelog[changelogIdx].CreatedAt.Format(time.RFC3339),
Value: ret[i].Metadata[metadataIDx].Changelog[changelogIdx].Value,
})
if ret[i].Metadata != nil {
data[i].Metadata = make(map[string]string)

for metadataIDx := range ret[i].Metadata {
data[i].Metadata[ret[i].Metadata[metadataIDx].Key] = ret[i].Metadata[metadataIDx].Value
}
}
}
Expand Down Expand Up @@ -202,7 +183,6 @@ func readPaymentHandler(repo readPaymentRepository) http.HandlerFunc {
CreatedAt: payment.CreatedAt,
Raw: payment.RawData,
Adjustments: make([]paymentAdjustment, len(payment.Adjustments)),
Metadata: make([]paymentMetadata, len(payment.Metadata)),
}

if payment.AccountID != uuid.Nil {
Expand All @@ -219,19 +199,11 @@ func readPaymentHandler(repo readPaymentRepository) http.HandlerFunc {
}
}

for metadataIDx := range payment.Metadata {
data.Metadata = append(data.Metadata,
paymentMetadata{
Key: payment.Metadata[metadataIDx].Key,
Value: payment.Metadata[metadataIDx].Value,
})

for changelogIdx := range payment.Metadata[metadataIDx].Changelog {
data.Metadata[metadataIDx].Changelog = append(data.Metadata[metadataIDx].Changelog,
paymentMetadataChangelog{
Timestamp: payment.Metadata[metadataIDx].Changelog[changelogIdx].CreatedAt.Format(time.RFC3339),
Value: payment.Metadata[metadataIDx].Changelog[changelogIdx].Value,
})
if payment.Metadata != nil {
data.Metadata = make(map[string]string)

for metadataIDx := range payment.Metadata {
data.Metadata[payment.Metadata[metadataIDx].Key] = payment.Metadata[metadataIDx].Value
}
}

Expand Down
1 change: 1 addition & 0 deletions internal/app/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func httpRouter(store *storage.Storage, serviceInfo api.ServiceInfo, connectorHa

authGroup.Path("/payments").Methods(http.MethodGet).Handler(listPaymentsHandler(store))
authGroup.Path("/payments/{paymentID}").Methods(http.MethodGet).Handler(readPaymentHandler(store))
authGroup.Path("/payments/{paymentID}/metadata").Methods(http.MethodPatch).Handler(updateMetadataHandler(store))

authGroup.Path("/accounts").Methods(http.MethodGet).Handler(listAccountsHandler(store))

Expand Down
6 changes: 3 additions & 3 deletions internal/app/models/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ type Metadata struct {
Key string `bun:",pk,nullzero"`
Value string

Changelog []MetadataChangelog `bun:",pk,nullzero"`
Changelog []MetadataChangelog `bun:",nullzero"`
Payment *Payment `bun:"rel:has-one,join:payment_id=id"`
}

type MetadataChangelog struct {
CreatedAt time.Time
Value string
CreatedAt time.Time `json:"createdAt"`
Value string `json:"value"`
}
39 changes: 39 additions & 0 deletions internal/app/storage/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package storage

import (
"context"
"time"

"github.com/formancehq/payments/internal/app/models"
"github.com/google/uuid"
)

func (s *Storage) UpdatePaymentMetadata(ctx context.Context, paymentID uuid.UUID, metadata map[string]string) error {
var metadataToInsert []models.Metadata // nolint:prealloc // it's against a map

for key, value := range metadata {
metadataToInsert = append(metadataToInsert, models.Metadata{
PaymentID: paymentID,
Key: key,
Value: value,
Changelog: []models.MetadataChangelog{
{
CreatedAt: time.Now(),
Value: value,
},
},
})
}

_, err := s.db.NewInsert().
Model(&metadataToInsert).
On("CONFLICT (payment_id, key) DO UPDATE").
Set("value = EXCLUDED.value").
Set("changelog = metadata.changelog || EXCLUDED.changelog").
Exec(ctx)
if err != nil {
return e("failed to update payment metadata", err)
}

return nil
}
2 changes: 1 addition & 1 deletion internal/app/storage/payments.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (s *Storage) UpsertPayments(ctx context.Context, provider models.ConnectorP
Model(&metadata).
On("CONFLICT (payment_id, key) DO UPDATE").
Set("value = EXCLUDED.value").
Set("changelog = changelog || EXCLUDED.changelog").
Set("changelog = metadata.changelog || EXCLUDED.changelog").
Exec(ctx)
if err != nil {
return e("failed to create metadata", err)
Expand Down
41 changes: 20 additions & 21 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ paths:
responses:
'200':
$ref: '#/components/responses/Payment'
/payments/{paymentId}/metadata:
patch:
summary: Update metadata
tags:
- Payments
operationId: updateMetadata
parameters:
- $ref: '#/components/parameters/PaymentId'
requestBody:
$ref: '#/components/requestBodies/UpdateMetadata'
responses:
'204':
$ref: '#/components/responses/NoContent'
/accounts:
get:
summary: List accounts
Expand Down Expand Up @@ -298,6 +311,12 @@ components:
application/json:
schema:
$ref: '#/components/schemas/StripeTransferRequest'
UpdateMetadata:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PaymentMetadata'

# ---------------------- SCHEMAS ----------------------
schemas:
Expand Down Expand Up @@ -644,9 +663,7 @@ components:
items:
$ref: '#/components/schemas/PaymentAdjustment'
metadata:
type: array
items:
$ref: '#/components/schemas/PaymentMetadata'
$ref: '#/components/schemas/PaymentMetadata'
PaymentAdjustment:
type: object
required:
Expand All @@ -672,27 +689,9 @@ components:
type: boolean
PaymentMetadata:
type: object
required:
- key
- value
properties:
key:
type: string
value:
type: string
changelog:
$ref: '#/components/schemas/PaymentMetadataChangelog'
PaymentMetadataChangelog:
type: object
required:
- timestamp
- value
properties:
timestamp:
type: string
format: date-time
value:
type: string
Account:
type: object
required:
Expand Down

0 comments on commit 3a7e608

Please sign in to comment.