Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: WEOS-1382 As a developer I should be able to set the type of id that I want auto generated #138

Merged
merged 3 commits into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ components:
type: object
properties:
id:
type: string
format: ksuid
type: integer
format: uint
firstName:
type: string
lastName:
Expand All @@ -59,7 +59,6 @@ components:
- lastName
x-identifier:
- id
- email
Blog:
type: object
properties:
Expand Down
19 changes: 14 additions & 5 deletions controllers/rest/fixtures/blog-x-schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ components:
Category:
type: object
properties:
title:
id:
type: string
format: uuid
description:
type: string
required:
- title
- id
x-identifier:
- title
- id
Author:
type: object
properties:
Expand All @@ -58,7 +59,6 @@ components:
- lastName
x-identifier:
- id
- email
Blog:
type: object
properties:
Expand Down Expand Up @@ -115,6 +115,15 @@ components:
created:
type: string
format: date-time
Archives:
type: object
properties:
id:
type: integer
title:
type: string
x-identifier:
- id
paths:
/health:
summary: Health Check
Expand Down Expand Up @@ -605,4 +614,4 @@ paths:
summary: Delete author
responses:
200:
description: Delete author
description: Delete author
17 changes: 14 additions & 3 deletions controllers/rest/middleware_initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ func newSchema(ref *openapi3.Schema, logger echo.Logger) (ds.Builder, map[string
relations[name] = strings.TrimPrefix(p.Ref, "#/components/schemas/")
} else {
t := p.Value.Type
f := p.Value.Format
if strings.EqualFold(t, "array") {
t2 := p.Value.Items.Value.Type
if t2 != "object" {
Expand All @@ -133,7 +134,12 @@ func newSchema(ref *openapi3.Schema, logger echo.Logger) (ds.Builder, map[string
} else if t2 == "number" {
instance.AddField(name, []float64{}, tagString)
} else if t == "integer" {
instance.AddField(name, []int{}, tagString)
if f == "uint" {
instance.AddField(name, []uint{}, tagString)
} else {
instance.AddField(name, []int{}, tagString)
}

} else if t == "boolean" {
instance.AddField(name, []bool{}, tagString)
}
Expand Down Expand Up @@ -166,8 +172,13 @@ func newSchema(ref *openapi3.Schema, logger echo.Logger) (ds.Builder, map[string
var numbers *float32
defaultValue = numbers
case "integer":
var integers *int
defaultValue = integers
if f == "uint" {
defaultValue = uint(0)
} else {
var integers *int
defaultValue = integers
}

case "boolean":
var boolean *bool
defaultValue = boolean
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ require (
github.com/coreos/go-oidc/v3 v3.1.0
github.com/cucumber/godog v0.12.2
github.com/getkin/kin-openapi v0.15.0
github.com/google/uuid v1.3.0 // indirect
github.com/jinzhu/inflection v1.0.0
github.com/kr/text v0.2.0 // indirect
github.com/labstack/echo/v4 v4.5.0
Expand Down
43 changes: 43 additions & 0 deletions model/content_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"encoding/json"
"fmt"
"github.com/getkin/kin-openapi/openapi3"
"github.com/google/uuid"
ds "github.com/ompluscator/dynamic-struct"
"github.com/segmentio/ksuid"
weosContext "github.com/wepala/weos/context"
utils "github.com/wepala/weos/utils"
"golang.org/x/net/context"
Expand Down Expand Up @@ -749,3 +751,44 @@ func (w *ContentEntity) UnmarshalJSON(data []byte) error {
err = json.Unmarshal(data, &w.Property)
return err
}

//GenerateID adds a generated id to the payload based on the schema
func GenerateID(payload []byte, entityFactory EntityFactory) ([]byte, error) {
schema := entityFactory.Schema()
properties := entityFactory.Schema().ExtensionProps.Extensions["x-identifier"]
entity := map[string]interface{}{}
err := json.Unmarshal(payload, &entity)
if err != nil {
return payload, err
}
if properties != nil {
propArray := []string{}
err = json.Unmarshal(properties.(json.RawMessage), &propArray)
if err != nil {
return payload, fmt.Errorf("unexpected error unmarshalling identifiers: %s", err)
}
if len(propArray) == 1 { // if there is only one x-identifier specified then it should auto generate the identifier
property := propArray[0]
if entity[property] == nil {
if schema.Properties[property].Value.Format != "" { //if the format is specified
if schema.Properties[property].Value.Type == "string" {
switch schema.Properties[property].Value.Format {
case "ksuid":
entity[property] = ksuid.New().String()
case "uuid":
entity[property] = uuid.NewString()
}
}
} else { //if the format is not specified
errr := "unexpected error: fail to generate identifier " + property + " since the format was not specified"
return payload, NewDomainError(errr, entityFactory.Name(), "", nil)
}
}
}
}
payload, err = json.Marshal(entity)
if err != nil {
return payload, err
}
return payload, nil
}
64 changes: 64 additions & 0 deletions model/content_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -848,3 +848,67 @@ func TestContentEntity_EnumerationFloat(t *testing.T) {
}
})
}

func TestContentEntity_AutoGeneratedID(t *testing.T) {
//load open api spec
api, err := rest.New("../controllers/rest/fixtures/blog-x-schema.yaml")
if err != nil {
t.Fatalf("unexpected error setting up api: %s", err)
}
schemas := rest.CreateSchema(context.TODO(), api.EchoInstance(), api.Swagger)
t.Run("Generating id where the is format specified is ksuid", func(t *testing.T) {
contentType1 := "Author"
entityFactory1 := new(model.DefaultEntityFactory).FromSchemaAndBuilder(contentType1, api.Swagger.Components.Schemas[contentType1].Value, schemas[contentType1])
p1 := map[string]interface{}{"firstName": "my oh my", "lastName": "name"}
payload1, err := json.Marshal(p1)
if err != nil {
t.Errorf("unexpected error marshalling entity; %s", err)
}
payload1, err = model.GenerateID(payload1, entityFactory1)
if err != nil {
t.Errorf("unexpected error generating id; %s", err)
}
err = json.Unmarshal(payload1, &p1)
if err != nil {
t.Errorf("unexpected error unmarshalling entity; %s", err)
}
if p1["id"] == nil {
t.Fatalf("expected id for first entity to be generated got nil")
}
})
t.Run("Generating id where the is format specified is uuid", func(t *testing.T) {
contentType2 := "Category"
entityFactory2 := new(model.DefaultEntityFactory).FromSchemaAndBuilder(contentType2, api.Swagger.Components.Schemas[contentType2].Value, schemas[contentType2])
p2 := map[string]interface{}{"description": "my favorite"}
payload2, err := json.Marshal(p2)
if err != nil {
t.Errorf("unexpected error marshalling entity; %s", err)
}
payload2, err = model.GenerateID(payload2, entityFactory2)
if err != nil {
t.Errorf("unexpected error generating id; %s", err)
}
err = json.Unmarshal(payload2, &p2)
if err != nil {
t.Errorf("unexpected error unmarshalling entity; %s", err)
}
if p2["id"] == nil {
t.Fatalf("expected id for second entity to be generated got nil")
}

})
t.Run("Generating id type is string and the format is not specified ", func(t *testing.T) {
contentType3 := "Archives"
entityFactory3 := new(model.DefaultEntityFactory).FromSchemaAndBuilder(contentType3, api.Swagger.Components.Schemas[contentType3].Value, schemas[contentType3])
p3 := map[string]interface{}{"title": "old blogs"}
payload3, err := json.Marshal(p3)
if err != nil {
t.Errorf("unexpected error marshalling entity; %s", err)
}
payload3, err = model.GenerateID(payload3, entityFactory3)
if err == nil {
t.Errorf("expected error generating id but got nil")
}

})
}
14 changes: 13 additions & 1 deletion model/domain_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,19 @@ func (s *DomainService) CreateBatch(ctx context.Context, payload json.RawMessage
entity.ID = ksuid.New().String()
titem.(map[string]interface{})["weos_id"] = entity.ID
}

mItem, err := json.Marshal(titem)
if err != nil {
return nil, err
}
mItem, err = GenerateID(mItem, entityFactory)
if err != nil {
s.logger.Errorf(err.Error())
return nil, err
}
err = json.Unmarshal(mItem, &titem)
if err != nil {
return nil, err
}
event := NewEntityEvent("create", entity, entity.ID, titem)
entity.NewChange(event)
err = entity.ApplyEvents([]*Event{event})
Expand Down
7 changes: 6 additions & 1 deletion model/receiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ func CreateHandler(ctx context.Context, command *Command, eventStore EventReposi
logger.Debug(err)
return err
}

//Generate id for entity
payload, err = GenerateID(payload, entityFactory)
if err != nil {
logger.Debug(err)
return err
}
//use the entity id that was passed with the command
newEntity.ID = command.Metadata.EntityID
//add create event
Expand Down
Loading