Skip to content

Commit

Permalink
feat: implement get and delete (#1077)
Browse files Browse the repository at this point in the history
* refactor: unify error handling for entitlements

* feat: implement get and delete

* chore: add new errorencoder

* fix: expose new handlers

---------

Signed-off-by: Alex Goth <[email protected]>
  • Loading branch information
GAlexIHU authored Jun 27, 2024
1 parent edc19b8 commit 3cab451
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 22 deletions.
23 changes: 17 additions & 6 deletions internal/entitlement/connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,21 @@ const (
)

type ListEntitlementsParams struct {
Namespace string
Limit int
Offset int
OrderBy ListEntitlementsOrderBy
Namespace string
Limit int
Offset int
OrderBy ListEntitlementsOrderBy
IncludeDeleted bool
}

type Connector interface {
// Entitlement Management
CreateEntitlement(ctx context.Context, input CreateEntitlementInputs) (*Entitlement, error)
GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey models.SubjectKey) ([]Entitlement, error)
GetEntitlement(ctx context.Context, namespace string, id string) (*Entitlement, error)
DeleteEntitlement(ctx context.Context, namespace string, id string) error

GetEntitlementValue(ctx context.Context, namespace string, subjectKey string, id string, at time.Time) (EntitlementValue, error)

GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey models.SubjectKey) ([]Entitlement, error)
ListEntitlements(ctx context.Context, params ListEntitlementsParams) ([]Entitlement, error)
}

Expand Down Expand Up @@ -122,6 +125,14 @@ func (c *entitlementConnector) CreateEntitlement(ctx context.Context, input Crea
return ent, nil
}

func (c *entitlementConnector) GetEntitlement(ctx context.Context, namespace string, id string) (*Entitlement, error) {
return c.entitlementRepo.GetEntitlement(ctx, models.NamespacedID{Namespace: namespace, ID: id})
}

func (c *entitlementConnector) DeleteEntitlement(ctx context.Context, namespace string, id string) error {
return c.entitlementRepo.DeleteEntitlement(ctx, models.NamespacedID{Namespace: namespace, ID: id})
}

func (c *entitlementConnector) GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey models.SubjectKey) ([]Entitlement, error) {
return c.entitlementRepo.GetEntitlementsOfSubject(ctx, namespace, subjectKey)
}
Expand Down
78 changes: 78 additions & 0 deletions internal/entitlement/httpdriver/entitlement.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import (

type EntitlementHandler interface {
CreateEntitlement() CreateEntitlementHandler
GetEntitlement() GetEntitlementHandler
DeleteEntitlement() DeleteEntitlementHandler
GetEntitlementValue() GetEntitlementValueHandler
GetEntitlementsOfSubjectHandler() GetEntitlementsOfSubjectHandler
ListEntitlements() ListEntitlementsHandler
Expand Down Expand Up @@ -313,6 +315,82 @@ func (h *entitlementHandler) ListEntitlements() ListEntitlementsHandler {
)
}

type GetEntitlementHandlerRequest struct {
EntitlementId string
Namespace string
}
type GetEntitlementHandlerResponse = *api.Entitlement
type GetEntitlementHandlerParams struct {
EntitlementId string
}
type GetEntitlementHandler httptransport.HandlerWithArgs[GetEntitlementHandlerRequest, GetEntitlementHandlerResponse, GetEntitlementHandlerParams]

func (h *entitlementHandler) GetEntitlement() GetEntitlementHandler {
return httptransport.NewHandlerWithArgs(
func(ctx context.Context, r *http.Request, params GetEntitlementHandlerParams) (GetEntitlementHandlerRequest, error) {
ns, err := h.resolveNamespace(ctx)
if err != nil {
return GetEntitlementHandlerRequest{}, err
}

return GetEntitlementHandlerRequest{
EntitlementId: params.EntitlementId,
Namespace: ns,
}, nil
},
func(ctx context.Context, request GetEntitlementHandlerRequest) (GetEntitlementHandlerResponse, error) {
entitlement, err := h.connector.GetEntitlement(ctx, request.Namespace, request.EntitlementId)
if err != nil {
return nil, err
}

return Parser.ToAPIGeneric(entitlement)
},
commonhttp.JSONResponseEncoder[GetEntitlementHandlerResponse],
httptransport.AppendOptions(
h.options,
httptransport.WithOperationName("getEntitlement"),
httptransport.WithErrorEncoder(getErrorEncoder()),
)...,
)
}

type DeleteEntitlementHandlerRequest struct {
EntitlementId string
Namespace string
}
type DeleteEntitlementHandlerResponse = interface{}
type DeleteEntitlementHandlerParams struct {
EntitlementId string
}
type DeleteEntitlementHandler httptransport.HandlerWithArgs[DeleteEntitlementHandlerRequest, DeleteEntitlementHandlerResponse, DeleteEntitlementHandlerParams]

func (h *entitlementHandler) DeleteEntitlement() DeleteEntitlementHandler {
return httptransport.NewHandlerWithArgs(
func(ctx context.Context, r *http.Request, params DeleteEntitlementHandlerParams) (DeleteEntitlementHandlerRequest, error) {
ns, err := h.resolveNamespace(ctx)
if err != nil {
return DeleteEntitlementHandlerRequest{}, err
}

return DeleteEntitlementHandlerRequest{
EntitlementId: params.EntitlementId,
Namespace: ns,
}, nil
},
func(ctx context.Context, request DeleteEntitlementHandlerRequest) (DeleteEntitlementHandlerResponse, error) {
err := h.connector.DeleteEntitlement(ctx, request.Namespace, request.EntitlementId)
return nil, err
},
commonhttp.EmptyResponseEncoder[DeleteEntitlementHandlerResponse](http.StatusNoContent),
httptransport.AppendOptions(
h.options,
httptransport.WithOperationName("deleteEntitlement"),
httptransport.WithErrorEncoder(getErrorEncoder()),
)...,
)
}

func (h *entitlementHandler) resolveNamespace(ctx context.Context) (string, error) {
ns, ok := h.namespaceDecoder.GetNamespace(ctx)
if !ok {
Expand Down
15 changes: 15 additions & 0 deletions internal/entitlement/postgresadapter/entitlement.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (a *entitlementDBAdapter) GetEntitlement(ctx context.Context, entitlementID
Where(
db_entitlement.ID(entitlementID.ID),
db_entitlement.Namespace(entitlementID.Namespace),
db_entitlement.Or(db_entitlement.DeletedAtGT(time.Now()), db_entitlement.DeletedAtIsNil()),
).
First(ctx)

Expand All @@ -48,6 +49,7 @@ func (a *entitlementDBAdapter) GetEntitlement(ctx context.Context, entitlementID
func (a *entitlementDBAdapter) GetEntitlementOfSubject(ctx context.Context, namespace string, subjectKey string, id string) (*entitlement.Entitlement, error) {
res, err := withLatestUsageReset(a.db.Entitlement.Query()).
Where(
db_entitlement.Or(db_entitlement.DeletedAtGT(time.Now()), db_entitlement.DeletedAtIsNil()),
db_entitlement.SubjectKey(string(subjectKey)),
db_entitlement.Namespace(namespace),
db_entitlement.ID(id),
Expand Down Expand Up @@ -109,9 +111,18 @@ func (a *entitlementDBAdapter) CreateEntitlement(ctx context.Context, entitlemen
return mapEntitlementEntity(res), nil
}

func (a *entitlementDBAdapter) DeleteEntitlement(ctx context.Context, entitlementID models.NamespacedID) error {
_, err := a.db.Entitlement.Update().
Where(db_entitlement.ID(entitlementID.ID), db_entitlement.Namespace(entitlementID.Namespace)).
SetDeletedAt(time.Now()).
Save(ctx)
return err
}

func (a *entitlementDBAdapter) GetEntitlementsOfSubject(ctx context.Context, namespace string, subjectKey models.SubjectKey) ([]entitlement.Entitlement, error) {
res, err := withLatestUsageReset(a.db.Entitlement.Query()).
Where(
db_entitlement.Or(db_entitlement.DeletedAtGT(time.Now()), db_entitlement.DeletedAtIsNil()),
db_entitlement.SubjectKey(string(subjectKey)),
db_entitlement.Namespace(namespace),
).
Expand All @@ -134,6 +145,10 @@ func (a *entitlementDBAdapter) ListEntitlements(ctx context.Context, params enti
query := withLatestUsageReset(a.db.Entitlement.Query().
Where(db_entitlement.Namespace(params.Namespace)))

if !params.IncludeDeleted {
query = query.Where(db_entitlement.Or(db_entitlement.DeletedAtGT(time.Now()), db_entitlement.DeletedAtIsNil()))
}

if params.Limit > 0 {
query = query.Limit(params.Limit)
}
Expand Down
1 change: 1 addition & 0 deletions internal/entitlement/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type EntitlementRepo interface {
CreateEntitlement(ctx context.Context, entitlement CreateEntitlementRepoInputs) (*Entitlement, error)
GetEntitlement(ctx context.Context, entitlementID models.NamespacedID) (*Entitlement, error)
GetEntitlementOfSubject(ctx context.Context, namespace string, subjectKey string, id string) (*Entitlement, error)
DeleteEntitlement(ctx context.Context, entitlementID models.NamespacedID) error

ListEntitlements(ctx context.Context, params ListEntitlementsParams) ([]Entitlement, error)

Expand Down
24 changes: 24 additions & 0 deletions internal/server/router/entitlement.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,27 @@ func (a *Router) ListEntitlements(w http.ResponseWriter, r *http.Request, params
}
a.entitlementHandler.ListEntitlements().With(params).ServeHTTP(w, r)
}

// Delete entitlement
// (DELETE /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId})
func (a *Router) DeleteEntitlement(w http.ResponseWriter, r *http.Request, subjectIdOrKey api.SubjectIdOrKey, entitlementId api.EntitlementId) {
if !a.config.EntitlementsEnabled {
unimplemented.DeleteEntitlement(w, r, subjectIdOrKey, entitlementId)
return
}
a.entitlementHandler.DeleteEntitlement().With(httpdriver.DeleteEntitlementHandlerParams{
EntitlementId: entitlementId,
}).ServeHTTP(w, r)
}

// Get entitlement
// (GET /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId})
func (a *Router) GetEntitlement(w http.ResponseWriter, r *http.Request, subjectIdOrKey api.SubjectIdOrKey, entitlementId api.EntitlementId) {
if !a.config.EntitlementsEnabled {
unimplemented.GetEntitlement(w, r, subjectIdOrKey, entitlementId)
return
}
a.entitlementHandler.GetEntitlement().With(httpdriver.GetEntitlementHandlerParams{
EntitlementId: entitlementId,
}).ServeHTTP(w, r)
}
16 changes: 0 additions & 16 deletions internal/server/router/noop.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,7 @@ package router
// We explicitly define no-op implementations for future APIs instead of just using the codegen version.

import (
"fmt"
"net/http"

"github.com/openmeterio/openmeter/api"
"github.com/openmeterio/openmeter/pkg/framework/commonhttp"
)

var unimplemented api.ServerInterface = api.Unimplemented{}

// Delete entitlement
// (DELETE /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId})
func (a *Router) DeleteEntitlement(w http.ResponseWriter, r *http.Request, subjectIdOrKey api.SubjectIdOrKey, entitlementId api.EntitlementId) {
commonhttp.NewHTTPError(http.StatusNotImplemented, fmt.Errorf("not implemented")).EncodeError(r.Context(), w)
}

// Get entitlement
// (GET /api/v1/subjects/{subjectIdOrKey}/entitlements/{entitlementId})
func (a *Router) GetEntitlement(w http.ResponseWriter, r *http.Request, subjectIdOrKey api.SubjectIdOrKey, entitlementId api.EntitlementId) {
commonhttp.NewHTTPError(http.StatusNotImplemented, fmt.Errorf("not implemented")).EncodeError(r.Context(), w)
}
2 changes: 2 additions & 0 deletions openmeter/entitlement/httpdriver/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type GetEntitlementsOfSubjectHandler = httpdriver.GetEntitlementsOfSubjectHandle
type ListEntitlementGrantsHandler = httpdriver.ListEntitlementGrantsHandler
type ResetEntitlementUsageHandler = httpdriver.ResetEntitlementUsageHandler
type ListEntitlementsHandler = httpdriver.ListEntitlementsHandler
type GetEntitlementHandler = httpdriver.GetEntitlementHandler
type DeleteEntitlementHandler = httpdriver.DeleteEntitlementHandler

func NewEntitlementHandler(
connector entitlement.EntitlementConnector,
Expand Down
3 changes: 3 additions & 0 deletions openmeter/entitlement/httpdriver/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type GetEntitlementsOfSubjectHandlerRequest = httpdriver.GetEntitlementsOfSubjec
type ListEntitlementGrantHandlerRequest = httpdriver.ListEntitlementGrantHandlerRequest
type ResetEntitlementUsageHandlerRequest = httpdriver.ResetEntitlementUsageHandlerRequest
type ListEntitlementsHandlerRequest = httpdriver.ListEntitlementsHandlerRequest
type GetEntitlementHandlerRequest = httpdriver.GetEntitlementHandlerRequest

// responses
type CreateEntitlementHandlerResponse = httpdriver.CreateEntitlementHandlerResponse
Expand All @@ -21,6 +22,7 @@ type GetEntitlementsOfSubjectHandlerResponse = httpdriver.GetEntitlementsOfSubje
type ListEntitlementGrantHandlerResponse = httpdriver.ListEntitlementGrantHandlerResponse
type ResetEntitlementUsageHandlerResponse = httpdriver.ResetEntitlementUsageHandlerResponse
type ListEntitlementsHandlerResponse = httpdriver.ListEntitlementsHandlerResponse
type GetEntitlementHandlerResponse = httpdriver.GetEntitlementHandlerResponse

// params
type CreateEntitlementHandlerParams = httpdriver.CreateEntitlementHandlerParams
Expand All @@ -31,3 +33,4 @@ type GetEntitlementsOfSubjectHandlerParams = httpdriver.GetEntitlementsOfSubject
type ListEntitlementGrantsHandlerParams = httpdriver.ListEntitlementGrantsHandlerParams
type ResetEntitlementUsageHandlerParams = httpdriver.ResetEntitlementUsageHandlerParams
type ListEntitlementsHandlerParams = httpdriver.ListEntitlementsHandlerParams
type GetEntitlementHandlerParams = httpdriver.GetEntitlementHandlerParams

0 comments on commit 3cab451

Please sign in to comment.