diff --git a/controllers/rest/api.go b/controllers/rest/api.go index 5d0e21fd..a3ec4350 100644 --- a/controllers/rest/api.go +++ b/controllers/rest/api.go @@ -16,11 +16,11 @@ import ( "github.com/labstack/echo/v4/middleware" "github.com/getkin/kin-openapi/openapi3" - "github.com/wepala/weos-service/model" - "github.com/wepala/weos-service/projections" - "github.com/labstack/echo/v4" "github.com/labstack/gommon/log" + ds "github.com/ompluscator/dynamic-struct" + "github.com/wepala/weos-service/model" + "github.com/wepala/weos-service/projections" ) //RESTAPI is used to manage the API @@ -35,7 +35,7 @@ type RESTAPI struct { Config *APIConfig e *echo.Echo PathConfigs map[string]*PathConfig - Schemas map[string]interface{} + Schemas map[string]ds.Builder middlewares map[string]Middleware controllers map[string]Controller } @@ -117,7 +117,11 @@ func (p *RESTAPI) GetController(name string) (Controller, error) { } func (p *RESTAPI) GetSchemas() (map[string]interface{}, error) { - return p.projection.Schema, nil + schemes := map[string]interface{}{} + for name, s := range p.Schemas { + schemes[name] = s.Build().New() + } + return schemes, nil } //Initialize and setup configurations for RESTAPI diff --git a/controllers/rest/api_test.go b/controllers/rest/api_test.go index f9e0a8d8..b7e171c5 100644 --- a/controllers/rest/api_test.go +++ b/controllers/rest/api_test.go @@ -227,69 +227,56 @@ func TestRESTAPI_Initialize_UpdateAddedToPut(t *testing.T) { os.Remove("test.db") } -func TestRESTAPI_Initialize_GetEntityBySequenceNuber(t *testing.T) { +func TestRESTAPI_Initialize_UpdateAddedToPatch(t *testing.T) { os.Remove("test.db") - time.Sleep(1 * time.Second) e := echo.New() tapi := api.RESTAPI{} _, err := api.Initialize(e, &tapi, "./fixtures/blog-create-batch.yaml") if err != nil { t.Fatalf("unexpected error '%s'", err) } - mockBlog := &[3]Blog{ - {ID: "1asdas3", Title: "Blog 1", Url: "www.testBlog1.com"}, - {ID: "2gf233", Title: "Blog 2", Url: "www.testBlog2.com"}, - {ID: "3dgff3", Title: "Blog 3", Url: "www.testBlog3.com"}, - } + mockBlog := &Blog{ID: "1246dg", Title: "Test Blog", Url: "www.testBlog.com"} reqBytes, err := json.Marshal(mockBlog) if err != nil { t.Fatalf("error setting up request %s", err) } body := bytes.NewReader(reqBytes) resp := httptest.NewRecorder() - req := httptest.NewRequest(http.MethodPost, "/blogs", body) + req := httptest.NewRequest(http.MethodPatch, "/blogs/"+mockBlog.ID, body) e.ServeHTTP(resp, req) - //confirm that the response is 201 - if resp.Result().StatusCode != http.StatusCreated { - t.Errorf("expected the response code to be %d, got %d", http.StatusCreated, resp.Result().StatusCode) - } - - blogEntity, err := api.GetContentBySequenceNumber(tapi.Application.EventRepository(), "3dgff3", 4) - if err != nil { - t.Fatal(err) - } - - mapEntity, ok := blogEntity.Property.(map[string]interface{}) - - if !ok { - t.Fatal("expected the properties of the blog entity to be mapable") - } - if mapEntity["title"] != "Blog 3" { - t.Errorf("expected the title to be %s got %s", "Blog 3", mapEntity["title"]) - } - - if blogEntity.SequenceNo != int64(1) { - t.Errorf("expected the sequence number to be %d got %d", blogEntity.SequenceNo, 1) + //confirm that the response is 200 + if resp.Result().StatusCode != http.StatusOK { + t.Errorf("expected the response code to be %d, got %d", http.StatusOK, resp.Result().StatusCode) } os.Remove("test.db") } -func TestRESTAPI_Initialize_UpdateAddedToPatch(t *testing.T) { +func TestRESTAPI_Initialize_ViewAddedToGet(t *testing.T) { os.Remove("test.db") e := echo.New() tapi := api.RESTAPI{} - _, err := api.Initialize(e, &tapi, "./fixtures/blog-create-batch.yaml") + _, err := api.Initialize(e, &tapi, "./fixtures/blog.yaml") if err != nil { t.Fatalf("unexpected error '%s'", err) } - mockBlog := &Blog{ID: "1246dg", Title: "Test Blog", Url: "www.testBlog.com"} + + mockID := "1246dg" + mockBlog := &Blog{ID: mockID, Title: "Test Blog", Url: "www.testBlog.com"} reqBytes, err := json.Marshal(mockBlog) if err != nil { t.Fatalf("error setting up request %s", err) } body := bytes.NewReader(reqBytes) resp := httptest.NewRecorder() - req := httptest.NewRequest(http.MethodPatch, "/blogs/"+mockBlog.ID, body) + req := httptest.NewRequest(http.MethodPost, "/blogs", body) + e.ServeHTTP(resp, req) + //confirm that the response is 200 + if resp.Result().StatusCode != http.StatusCreated { + t.Fatalf("expected the response code to be %d, got %d", http.StatusCreated, resp.Result().StatusCode) + } + + resp = httptest.NewRecorder() + req = httptest.NewRequest(http.MethodGet, "/blogs/1", nil) e.ServeHTTP(resp, req) //confirm that the response is 200 if resp.Result().StatusCode != http.StatusOK { @@ -298,21 +285,49 @@ func TestRESTAPI_Initialize_UpdateAddedToPatch(t *testing.T) { os.Remove("test.db") } -func TestRESTAPI_Initialize_ViewAddedToGet(t *testing.T) { +func TestRESTAPI_Initialize_GetEntityBySequenceNuber(t *testing.T) { os.Remove("test.db") + time.Sleep(1 * time.Second) e := echo.New() tapi := api.RESTAPI{} - _, err := api.Initialize(e, &tapi, "./fixtures/blog.yaml") + _, err := api.Initialize(e, &tapi, "./fixtures/blog-create-batch.yaml") if err != nil { t.Fatalf("unexpected error '%s'", err) } - mockID := "1246dg" + mockBlog := &[3]Blog{ + {ID: "1asdas3", Title: "Blog 1", Url: "www.testBlog1.com"}, + {ID: "2gf233", Title: "Blog 2", Url: "www.testBlog2.com"}, + {ID: "3dgff3", Title: "Blog 3", Url: "www.testBlog3.com"}, + } + reqBytes, err := json.Marshal(mockBlog) + if err != nil { + t.Fatalf("error setting up request %s", err) + } + body := bytes.NewReader(reqBytes) resp := httptest.NewRecorder() - req := httptest.NewRequest(http.MethodGet, "/blogs/"+mockID, nil) + req := httptest.NewRequest(http.MethodPost, "/blogs", body) e.ServeHTTP(resp, req) - //confirm that the response is 200 - if resp.Result().StatusCode != http.StatusOK { - t.Errorf("expected the response code to be %d, got %d", http.StatusOK, resp.Result().StatusCode) + //confirm that the response is 201 + if resp.Result().StatusCode != http.StatusCreated { + t.Errorf("expected the response code to be %d, got %d", http.StatusCreated, resp.Result().StatusCode) + } + + blogEntity, err := api.GetContentBySequenceNumber(tapi.Application.EventRepository(), "3dgff3", 4) + if err != nil { + t.Fatal(err) + } + + mapEntity, ok := blogEntity.Property.(map[string]interface{}) + + if !ok { + t.Fatal("expected the properties of the blog entity to be mapable") + } + if mapEntity["title"] != "Blog 3" { + t.Errorf("expected the title to be %s got %s", "Blog 3", mapEntity["title"]) + } + + if blogEntity.SequenceNo != int64(1) { + t.Errorf("expected the sequence number to be %d got %d", blogEntity.SequenceNo, 1) } os.Remove("test.db") } diff --git a/controllers/rest/controller_standard.go b/controllers/rest/controller_standard.go index 30bfa493..de209b0f 100644 --- a/controllers/rest/controller_standard.go +++ b/controllers/rest/controller_standard.go @@ -1,13 +1,18 @@ package rest import ( + "encoding/json" + "errors" + "fmt" "io/ioutil" "net/http" + "strconv" "strings" "github.com/segmentio/ksuid" context2 "github.com/wepala/weos-service/context" "golang.org/x/net/context" + "gorm.io/gorm" "github.com/getkin/kin-openapi/openapi3" "github.com/labstack/echo/v4" @@ -42,7 +47,20 @@ func (c *StandardControllers) Create(app model.Service, spec *openapi3.Swagger, } //reads the request body payload, _ := ioutil.ReadAll(ctxt.Request().Body) - weosID := ksuid.New().String() + + //for inserting weos_id during testing + payMap := map[string]interface{}{} + var weosID string + + json.Unmarshal(payload, &payMap) + if v, ok := payMap["weos_id"]; ok { + if val, ok := v.(string); ok { + weosID = val + } + } + if weosID == "" { + weosID = ksuid.New().String() + } err := app.Dispatcher().Dispatch(newContext, model.Create(newContext, payload, contentType, weosID)) if err != nil { @@ -153,9 +171,121 @@ func (c *StandardControllers) BulkUpdate(app model.Service, spec *openapi3.Swagg } func (c *StandardControllers) View(app model.Service, spec *openapi3.Swagger, path *openapi3.PathItem, operation *openapi3.Operation) echo.HandlerFunc { + var contentType string + var contentTypeSchema *openapi3.SchemaRef + //get the entity information based on the Content Type associated with this operation + for _, requestContent := range operation.Responses.Get(http.StatusOK).Value.Content { + //use the first schema ref to determine the entity type + if requestContent.Schema.Ref != "" { + contentType = strings.Replace(requestContent.Schema.Ref, "#/components/schemas/", "", -1) + //get the schema details from the swagger file + contentTypeSchema = spec.Components.Schemas[contentType] + break + } + } + return func(ctxt echo.Context) error { + cType := &context2.ContentType{} + if contentType != "" && contentTypeSchema.Value != nil { + cType = &context2.ContentType{ + Name: contentType, + Schema: contentTypeSchema.Value, + } + } + + pks, _ := json.Marshal(cType.Schema.Extensions["x-identifier"]) + primaryKeys := []string{} + json.Unmarshal(pks, &primaryKeys) + + if len(primaryKeys) == 0 { + primaryKeys = append(primaryKeys, "id") + } + + newContext := ctxt.Request().Context() + + identifiers := map[string]interface{}{} + + for _, p := range primaryKeys { + identifiers[p] = newContext.Value(p) + } + + sequenceString, _ := newContext.Value("sequence_no").(string) + etag, _ := newContext.Value("If-None-Match").(string) + entityID, _ := newContext.Value("use_entity_id").(string) + + var sequence int + if sequenceString != "" { + sequence, _ = strconv.Atoi(sequenceString) + } + var result map[string]interface{} + var err error + if sequence == 0 && etag == "" && entityID != "true" { + for _, projection := range app.Projections() { + if projection != nil { + result, err = projection.GetByKey(ctxt.Request().Context(), *cType, identifiers) + } + } + } else if etag != "" { + tag, seq := SplitEtag(etag) + seqInt, er := strconv.Atoi(seq) + if er != nil { + return NewControllerError("Invalid sequence number", err, http.StatusBadRequest) + } + r, er := GetContentBySequenceNumber(app.EventRepository(), tag, int64(seqInt)) + err = er + if r.SequenceNo == 0 { + return NewControllerError("No entity found", err, http.StatusNotFound) + } + if err == nil && r.SequenceNo < int64(seqInt) { + return ctxt.JSON(http.StatusNotModified, r.Property) + } + } else { + //get first identifider + id := "" + for _, i := range identifiers { + id = i.(string) + if id != "" { + break + } + } + if sequence != 0 { + r, er := GetContentBySequenceNumber(app.EventRepository(), id, int64(sequence)) + if r != nil && r.ID != "" { + result = r.Property.(map[string]interface{}) + } + err = er + } else { + for _, projection := range app.Projections() { + if projection != nil { + result, err = projection.GetByEntityID(ctxt.Request().Context(), *cType, id) + } + } + } + } + weos_id, ok := result["weos_id"].(string) + if errors.Is(err, gorm.ErrRecordNotFound) || (len(result) == 0) || !ok || weos_id == "" { + return NewControllerError("No entity found", err, http.StatusNotFound) + } else if err != nil { + return NewControllerError(err.Error(), err, http.StatusBadRequest) + } + + sequenceString = fmt.Sprint(result["sequence_no"]) + sequenceNo, _ := strconv.Atoi(sequenceString) + + etag = NewEtag(&model.ContentEntity{ + AggregateRoot: model.AggregateRoot{ + SequenceNo: int64(sequenceNo), + BasicEntity: model.BasicEntity{ID: weos_id}, + }, + }) + + //remove sequence number and weos_id from response + delete(result, "weos_id") + delete(result, "sequence_no") - return ctxt.JSON(http.StatusOK, "View Item") + //set etag + ctxt.Response().Header().Set("Etag", etag) + return ctxt.JSON(http.StatusOK, result) } } diff --git a/controllers/rest/controller_standard_test.go b/controllers/rest/controller_standard_test.go index 72ba503c..99416c47 100644 --- a/controllers/rest/controller_standard_test.go +++ b/controllers/rest/controller_standard_test.go @@ -259,10 +259,22 @@ func TestStandardControllers_CreateBatch(t *testing.T) { }, } + projection := &ProjectionMock{ + GetByKeyFunc: func(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { + return nil, nil + }, + GetByEntityIDFunc: func(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) { + return nil, nil + }, + } + application := &ApplicationMock{ DispatcherFunc: func() model.Dispatcher { return dispatcher }, + ProjectionsFunc: func() []model.Projection { + return []model.Projection{projection} + }, } //initialization will instantiate with application so we need to overwrite with our mock application @@ -416,10 +428,22 @@ func TestStandardControllers_Update(t *testing.T) { }, } + projection := &ProjectionMock{ + GetByKeyFunc: func(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { + return nil, nil + }, + GetByEntityIDFunc: func(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) { + return nil, nil + }, + } + application := &ApplicationMock{ DispatcherFunc: func() model.Dispatcher { return dispatcher }, + ProjectionsFunc: func() []model.Projection { + return []model.Projection{projection} + }, } //initialization will instantiate with application so we need to overwrite with our mock application @@ -481,10 +505,28 @@ func TestStandardControllers_View(t *testing.T) { }, } + projection := &ProjectionMock{ + GetByKeyFunc: func(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { + return map[string]interface{}{ + "id": "1234sd", + "weos_id": "1234sd", + }, nil + }, + GetByEntityIDFunc: func(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) { + return map[string]interface{}{ + "id": "1234sd", + "weos_id": "1234sd", + }, nil + }, + } + application := &ApplicationMock{ DispatcherFunc: func() model.Dispatcher { return dispatcher }, + ProjectionsFunc: func() []model.Projection { + return []model.Projection{projection} + }, } //initialization will instantiate with application so we need to overwrite with our mock application diff --git a/controllers/rest/middleware_initialize.go b/controllers/rest/middleware_initialize.go index d089565f..efde0e6c 100644 --- a/controllers/rest/middleware_initialize.go +++ b/controllers/rest/middleware_initialize.go @@ -14,8 +14,7 @@ import ( ) //CreateSchema creates the table schemas for gorm syntax -func CreateSchema(ctx context.Context, e *echo.Echo, s *openapi3.Swagger) map[string]interface{} { - structs := make(map[string]interface{}) +func CreateSchema(ctx context.Context, e *echo.Echo, s *openapi3.Swagger) map[string]ds.Builder { builders := make(map[string]ds.Builder) relations := make(map[string]map[string]string) keys := make(map[string][]string) @@ -38,18 +37,9 @@ func CreateSchema(ctx context.Context, e *echo.Echo, s *openapi3.Swagger) map[st } } } - f := scheme.GetField("Table") - f.SetTag(`json:"table_alias" gorm:"default:` + name + `"`) - instance := scheme.Build().New() - err := json.Unmarshal([]byte(`{ - "table_alias": "`+name+`" - }`), &instance) - if err != nil { - e.Logger.Errorf("unable to set the table name '%s'", err) - } - structs[name] = instance + builders[name] = scheme } - return structs + return builders } diff --git a/controllers/rest/middleware_initialize_test.go b/controllers/rest/middleware_initialize_test.go index fa79ce22..19ef11e5 100644 --- a/controllers/rest/middleware_initialize_test.go +++ b/controllers/rest/middleware_initialize_test.go @@ -9,7 +9,6 @@ import ( "github.com/getkin/kin-openapi/openapi3" "github.com/labstack/echo/v4" - dynamicstruct "github.com/ompluscator/dynamic-struct" "github.com/wepala/weos-service/controllers/rest" "golang.org/x/net/context" ) @@ -39,14 +38,10 @@ func TestCreateSchema(t *testing.T) { result := rest.CreateSchema(context.Background(), e, swagger) //loop through and confirm each has a table name set - for tableName, table := range result { - reader := dynamicstruct.NewReader(table) - if reader.GetField("Table") == nil { + for _, table := range result { + if table.GetField("Table") == nil { t.Fatalf("expected a table field") } - if reader.GetField("Table").String() != tableName { - t.Errorf("There was an error setting the table name, expected '%s'", tableName) - } } //check for foreign key on Post table to Author @@ -55,12 +50,7 @@ func TestCreateSchema(t *testing.T) { t.Fatalf("expected to find a table Post") } - reader := dynamicstruct.NewReader(postTable) - if !reader.HasField("AuthorId") { - t.Errorf("expected the struct to have field '%s'", "AuthorId") - } - - if !reader.HasField("AuthorEmail") { + if !postTable.HasField("AuthorEmail") { t.Errorf("expected the struct to have field '%s'", "AuthorEmail") } }) diff --git a/controllers/rest/weos_mocks_test.go b/controllers/rest/weos_mocks_test.go index 356c2439..5a47e227 100644 --- a/controllers/rest/weos_mocks_test.go +++ b/controllers/rest/weos_mocks_test.go @@ -10,6 +10,7 @@ import ( "gorm.io/gorm" "net/http" "sync" + weoscontext "github.com/wepala/weos-service/context" ) // Ensure, that EventRepositoryMock does implement weos.EventRepository. @@ -1684,30 +1685,44 @@ func (mock *ApplicationMock) TitleCalls() []struct { return calls } +// Ensure, that ProjectionMock does implement weos.Projection. +// If this is not the case, regenerate this file with moq. var _ weos.Projection = &ProjectionMock{} -// ProjectionMock is a mock implementation of model.Projection. +// ProjectionMock is a mock implementation of weos.Projection. // -// func TestSomethingThatUsesProjection(t *testing.T) { +// func TestSomethingThatUsesProjection(t *testing.T) { // -// // make and configure a mocked model.Projection -// mockedProjection := &ProjectionMock{ -// GetContentEntityFunc: func(ctx context.Context, weosID string) (*model.ContentEntity, error) { -// panic("mock out the GetContentEntity method") -// }, -// GetEventHandlerFunc: func() model.EventHandler { -// panic("mock out the GetEventHandler method") -// }, -// MigrateFunc: func(ctx context.Context) error { -// panic("mock out the Migrate method") -// }, -// } +// // make and configure a mocked weos.Projection +// mockedProjection := &ProjectionMock{ +// GetByEntityIDFunc: func(ctxt context.Context, contentType context.ContentType, id string) (map[string]interface{}, error) { +// panic("mock out the GetByEntityID method") +// }, +// GetByKeyFunc: func(ctxt context.Context, contentType context.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { +// panic("mock out the GetByKey method") +// }, +// GetContentEntityFunc: func(ctx context.Context, weosID string) (*weos.ContentEntity, error) { +// panic("mock out the GetContentEntity method") +// }, +// GetEventHandlerFunc: func() weos.EventHandler { +// panic("mock out the GetEventHandler method") +// }, +// MigrateFunc: func(ctx context.Context) error { +// panic("mock out the Migrate method") +// }, +// } // -// // use mockedProjection in code that requires model.Projection -// // and then make assertions. +// // use mockedProjection in code that requires weos.Projection +// // and then make assertions. // -// } +// } type ProjectionMock struct { + // GetByEntityIDFunc mocks the GetByEntityID method. + GetByEntityIDFunc func(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) + + // GetByKeyFunc mocks the GetByKey method. + GetByKeyFunc func(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) + // GetContentEntityFunc mocks the GetContentEntity method. GetContentEntityFunc func(ctx context.Context, weosID string) (*weos.ContentEntity, error) @@ -1719,6 +1734,24 @@ type ProjectionMock struct { // calls tracks calls to the methods. calls struct { + // GetByEntityID holds details about calls to the GetByEntityID method. + GetByEntityID []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // ContentType is the contentType argument value. + ContentType weoscontext.ContentType + // ID is the id argument value. + ID string + } + // GetByKey holds details about calls to the GetByKey method. + GetByKey []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // ContentType is the contentType argument value. + ContentType weoscontext.ContentType + // Identifiers is the identifiers argument value. + Identifiers map[string]interface{} + } // GetContentEntity holds details about calls to the GetContentEntity method. GetContentEntity []struct { // Ctx is the ctx argument value. @@ -1735,11 +1768,91 @@ type ProjectionMock struct { Ctx context.Context } } + lockGetByEntityID sync.RWMutex + lockGetByKey sync.RWMutex lockGetContentEntity sync.RWMutex lockGetEventHandler sync.RWMutex lockMigrate sync.RWMutex } +// GetByEntityID calls GetByEntityIDFunc. +func (mock *ProjectionMock) GetByEntityID(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) { + if mock.GetByEntityIDFunc == nil { + panic("ProjectionMock.GetByEntityIDFunc: method is nil but Projection.GetByEntityID was just called") + } + callInfo := struct { + Ctxt context.Context + ContentType weoscontext.ContentType + ID string + }{ + Ctxt: ctxt, + ContentType: contentType, + ID: id, + } + mock.lockGetByEntityID.Lock() + mock.calls.GetByEntityID = append(mock.calls.GetByEntityID, callInfo) + mock.lockGetByEntityID.Unlock() + return mock.GetByEntityIDFunc(ctxt, contentType, id) +} + +// GetByEntityIDCalls gets all the calls that were made to GetByEntityID. +// Check the length with: +// len(mockedProjection.GetByEntityIDCalls()) +func (mock *ProjectionMock) GetByEntityIDCalls() []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + ID string +} { + var calls []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + ID string + } + mock.lockGetByEntityID.RLock() + calls = mock.calls.GetByEntityID + mock.lockGetByEntityID.RUnlock() + return calls +} + +// GetByKey calls GetByKeyFunc. +func (mock *ProjectionMock) GetByKey(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { + if mock.GetByKeyFunc == nil { + panic("ProjectionMock.GetByKeyFunc: method is nil but Projection.GetByKey was just called") + } + callInfo := struct { + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} + }{ + Ctxt: ctxt, + ContentType: contentType, + Identifiers: identifiers, + } + mock.lockGetByKey.Lock() + mock.calls.GetByKey = append(mock.calls.GetByKey, callInfo) + mock.lockGetByKey.Unlock() + return mock.GetByKeyFunc(ctxt, contentType, identifiers) +} + +// GetByKeyCalls gets all the calls that were made to GetByKey. +// Check the length with: +// len(mockedProjection.GetByKeyCalls()) +func (mock *ProjectionMock) GetByKeyCalls() []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} +} { + var calls []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} + } + mock.lockGetByKey.RLock() + calls = mock.calls.GetByKey + mock.lockGetByKey.RUnlock() + return calls +} + // GetContentEntity calls GetContentEntityFunc. func (mock *ProjectionMock) GetContentEntity(ctx context.Context, weosID string) (*weos.ContentEntity, error) { if mock.GetContentEntityFunc == nil { @@ -1831,4 +1944,3 @@ func (mock *ProjectionMock) MigrateCalls() []struct { mock.lockMigrate.RUnlock() return calls } - diff --git a/end2end_test.go b/end2end_test.go index 7c564bf1..e0fd0855 100644 --- a/end2end_test.go +++ b/end2end_test.go @@ -13,8 +13,6 @@ import ( "testing" "time" - "github.com/wepala/weos-service/utils" - "github.com/cucumber/godog" "github.com/labstack/echo/v4" ds "github.com/ompluscator/dynamic-struct" @@ -333,6 +331,7 @@ func blogsInTheApi(details *godog.Table) error { if rec.Code != http.StatusCreated { return fmt.Errorf("expected the status to be %d got %d", http.StatusCreated, rec.Code) } + } return nil } @@ -414,7 +413,7 @@ func theIsSubmitted(contentType string) error { if strings.Contains(currScreen, "create") { request = httptest.NewRequest("POST", "/"+strings.ToLower(contentType), body) } else if strings.Contains(currScreen, "update") { - request = httptest.NewRequest("PUT", "/"+strings.ToLower(contentType), body) + request = httptest.NewRequest("PUT", "/"+strings.ToLower(contentType)+"s/"+fmt.Sprint(req["id"]), body) } request = request.WithContext(context.TODO()) header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) @@ -517,7 +516,7 @@ func aEntityConfigurationShouldBeSetup(arg1 string, arg2 *godog.DocString) error func aHeaderWithValue(key, value string) error { header.Add(key, value) - return godog.ErrPending + return nil } func aResponseShouldBeReturned(code int) error { @@ -613,8 +612,8 @@ func theIsUpdated(contentType string, details *godog.Table) error { return nil } -func theEndpointIsHit(endpoint, url string) error { - request := httptest.NewRequest(endpoint, url, nil) +func theEndpointIsHit(method, url string) error { + request := httptest.NewRequest(method, url, nil) request = request.WithContext(context.TODO()) header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) request.Header = header @@ -650,6 +649,12 @@ func aBlogShouldBeReturned(details *godog.Table) error { return nil } +func sojournerIsUpdatingWithId(contentType, id string) error { + requests[strings.ToLower(contentType+"_update")] = map[string]interface{}{"id": id} + currScreen = strings.ToLower(contentType + "_update") + return nil +} + func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Before(reset) //add context steps @@ -681,6 +686,7 @@ func InitializeScenario(ctx *godog.ScenarioContext) { ctx.Step(`^a (\d+) response should be returned$`, aResponseShouldBeReturned) ctx.Step(`^the "([^"]*)" endpoint "([^"]*)" is hit$`, theEndpointIsHit) ctx.Step(`^a blog should be returned$`, aBlogShouldBeReturned) + ctx.Step(`^Sojourner is updating "([^"]*)" with id "([^"]*)"$`, sojournerIsUpdatingWithId) ctx.Step(`^a warning should be output to logs letting the developer know that a parameter for each part of the idenfier must be set$`, aWarningShouldBeOutputToLogsLettingTheDeveloperKnowThatAParameterForEachPartOfTheIdenfierMustBeSet) ctx.Step(`^a "([^"]*)" route should be added to the api$`, aRouteShouldBeAddedToTheApi1) ctx.Step(`^a warning should be output because the endpoint is invalid$`, aWarningShouldBeOutputBecauseTheEndpointIsInvalid) @@ -694,7 +700,7 @@ func TestBDD(t *testing.T) { TestSuiteInitializer: InitializeSuite, Options: &godog.Options{ Format: "pretty", - Tags: "~skipped", + Tags: "WEOS-1135", }, }.Run() if status != 0 { diff --git a/features/view-content.feature b/features/view-content.feature index 4b6101de..8176ee75 100644 --- a/features/view-content.feature +++ b/features/view-content.feature @@ -1,3 +1,4 @@ +@WEOS-1135 Feature: View content Background: @@ -41,6 +42,8 @@ Feature: View content Blog: type: object properties: + id: + type: string title: type: string description: blog title @@ -48,6 +51,8 @@ Feature: View content type: string required: - title + x-identifier: + - id Post: type: object properties: @@ -122,6 +127,14 @@ Feature: View content name: sequence_no schema: type: string + - in: query + name: use_entity_id + schema: + type: boolean + - in: header + name: If-None-Match + schema: + type: string summary: Get Blog by id operationId: Get Blog responses: @@ -179,7 +192,7 @@ Feature: View content The blog should be retrieved using the identifier in the projection. The `ETag` header returned is a combination of the entity id and the sequence no. - When the "GET" endpoint "/blog/1234" is hit + When the "GET" endpoint "/blogs/1234" is hit Then a 200 response should be returned And a blog should be returned | id | title | description | @@ -190,7 +203,7 @@ Feature: View content If the view controller gets a parameter `use_entity_id` set to true then it will use the identifier as the entity id - When the "GET" endpoint "/blog/22xu4iw0bWMwxqbrUvjqEqu5dof?use_entity_id=true" is hit + When the "GET" endpoint "/blogs/22xu4iw0bWMwxqbrUvjqEqu5dof?use_entity_id=true" is hit Then a 200 response should be returned And a blog should be returned | id | title | description | @@ -204,11 +217,11 @@ Feature: View content Given Sojourner is updating "Blog" with id "4567" And "Sojourner" enters "Some New Blog" in the "title" field And the "Blog" is submitted - When the "POST" endpoint "/blog/4567" is hit + When the "GET" endpoint "/blogs/22xu4iw0bWMwxqbrUvjqEqu5dof?sequence_no=1" is hit Then a 200 response should be returned And a blog should be returned - | id | title | description | - | 4567 | Some New Blog | Some Blog 2 | + | id | title | description | + | 4567 | Blog 2 | Some Blog 2 | And the "ETag" header should be "22xu4iw0bWMwxqbrUvjqEqu5dof.2" Scenario: Check if new version of an item is available @@ -216,7 +229,7 @@ Feature: View content Check if version is the latest version https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag Given a header "If-None-Match" with value "22xu1Xa5CS3DK1Om2tB7OBDfWAF.2" - When the "POST" endpoint "/blog/1234" is hit + When the "GET" endpoint "/blogs/1234" is hit Then a 304 response should be returned diff --git a/model/event_repository_mocks_test.go b/model/event_repository_mocks_test.go index 32343cff..ccc3dbf4 100644 --- a/model/event_repository_mocks_test.go +++ b/model/event_repository_mocks_test.go @@ -6,23 +6,24 @@ package model_test import ( "context" "database/sql" - weos "github.com/wepala/weos-service/model" + weoscontext "github.com/wepala/weos-service/context" + "github.com/wepala/weos-service/model" "gorm.io/gorm" "net/http" "sync" ) -// Ensure, that EventRepositoryMock does implement weos.EventRepository. +// Ensure, that EventRepositoryMock does implement model.EventRepository. // If this is not the case, regenerate this file with moq. -var _ weos.EventRepository = &EventRepositoryMock{} +var _ model.EventRepository = &EventRepositoryMock{} -// EventRepositoryMock is a mock implementation of weos.EventRepository. +// EventRepositoryMock is a mock implementation of model.EventRepository. // // func TestSomethingThatUsesEventRepository(t *testing.T) { // -// // make and configure a mocked weos.EventRepository +// // make and configure a mocked model.EventRepository // mockedEventRepository := &EventRepositoryMock{ -// AddSubscriberFunc: func(handler weos.EventHandler) { +// AddSubscriberFunc: func(handler model.EventHandler) { // panic("mock out the AddSubscriber method") // }, // FlushFunc: func() error { @@ -31,36 +32,36 @@ var _ weos.EventRepository = &EventRepositoryMock{} // GetAggregateSequenceNumberFunc: func(ID string) (int64, error) { // panic("mock out the GetAggregateSequenceNumber method") // }, -// GetByAggregateFunc: func(ID string) ([]*weos.Event, error) { +// GetByAggregateFunc: func(ID string) ([]*model.Event, error) { // panic("mock out the GetByAggregate method") // }, -// GetByAggregateAndSequenceRangeFunc: func(ID string, start int64, end int64) ([]*weos.Event, error) { +// GetByAggregateAndSequenceRangeFunc: func(ID string, start int64, end int64) ([]*model.Event, error) { // panic("mock out the GetByAggregateAndSequenceRange method") // }, -// GetByAggregateAndTypeFunc: func(ID string, entityType string) ([]*weos.Event, error) { +// GetByAggregateAndTypeFunc: func(ID string, entityType string) ([]*model.Event, error) { // panic("mock out the GetByAggregateAndType method") // }, -// GetByEntityAndAggregateFunc: func(entityID string, entityType string, rootID string) ([]*weos.Event, error) { +// GetByEntityAndAggregateFunc: func(entityID string, entityType string, rootID string) ([]*model.Event, error) { // panic("mock out the GetByEntityAndAggregate method") // }, -// GetSubscribersFunc: func() ([]weos.EventHandler, error) { +// GetSubscribersFunc: func() ([]model.EventHandler, error) { // panic("mock out the GetSubscribers method") // }, // MigrateFunc: func(ctx context.Context) error { // panic("mock out the Migrate method") // }, -// PersistFunc: func(ctxt context.Context, entity weos.AggregateInterface) error { +// PersistFunc: func(ctxt context.Context, entity model.AggregateInterface) error { // panic("mock out the Persist method") // }, // } // -// // use mockedEventRepository in code that requires weos.EventRepository +// // use mockedEventRepository in code that requires model.EventRepository // // and then make assertions. // // } type EventRepositoryMock struct { // AddSubscriberFunc mocks the AddSubscriber method. - AddSubscriberFunc func(handler weos.EventHandler) + AddSubscriberFunc func(handler model.EventHandler) // FlushFunc mocks the Flush method. FlushFunc func() error @@ -69,32 +70,32 @@ type EventRepositoryMock struct { GetAggregateSequenceNumberFunc func(ID string) (int64, error) // GetByAggregateFunc mocks the GetByAggregate method. - GetByAggregateFunc func(ID string) ([]*weos.Event, error) + GetByAggregateFunc func(ID string) ([]*model.Event, error) // GetByAggregateAndSequenceRangeFunc mocks the GetByAggregateAndSequenceRange method. - GetByAggregateAndSequenceRangeFunc func(ID string, start int64, end int64) ([]*weos.Event, error) + GetByAggregateAndSequenceRangeFunc func(ID string, start int64, end int64) ([]*model.Event, error) // GetByAggregateAndTypeFunc mocks the GetByAggregateAndType method. - GetByAggregateAndTypeFunc func(ID string, entityType string) ([]*weos.Event, error) + GetByAggregateAndTypeFunc func(ID string, entityType string) ([]*model.Event, error) // GetByEntityAndAggregateFunc mocks the GetByEntityAndAggregate method. - GetByEntityAndAggregateFunc func(entityID string, entityType string, rootID string) ([]*weos.Event, error) + GetByEntityAndAggregateFunc func(entityID string, entityType string, rootID string) ([]*model.Event, error) // GetSubscribersFunc mocks the GetSubscribers method. - GetSubscribersFunc func() ([]weos.EventHandler, error) + GetSubscribersFunc func() ([]model.EventHandler, error) // MigrateFunc mocks the Migrate method. MigrateFunc func(ctx context.Context) error // PersistFunc mocks the Persist method. - PersistFunc func(ctxt context.Context, entity weos.AggregateInterface) error + PersistFunc func(ctxt context.Context, entity model.AggregateInterface) error // calls tracks calls to the methods. calls struct { // AddSubscriber holds details about calls to the AddSubscriber method. AddSubscriber []struct { // Handler is the handler argument value. - Handler weos.EventHandler + Handler model.EventHandler } // Flush holds details about calls to the Flush method. Flush []struct { @@ -147,7 +148,7 @@ type EventRepositoryMock struct { // Ctxt is the ctxt argument value. Ctxt context.Context // Entity is the entity argument value. - Entity weos.AggregateInterface + Entity model.AggregateInterface } } lockAddSubscriber sync.RWMutex @@ -163,12 +164,12 @@ type EventRepositoryMock struct { } // AddSubscriber calls AddSubscriberFunc. -func (mock *EventRepositoryMock) AddSubscriber(handler weos.EventHandler) { +func (mock *EventRepositoryMock) AddSubscriber(handler model.EventHandler) { if mock.AddSubscriberFunc == nil { panic("EventRepositoryMock.AddSubscriberFunc: method is nil but EventRepository.AddSubscriber was just called") } callInfo := struct { - Handler weos.EventHandler + Handler model.EventHandler }{ Handler: handler, } @@ -182,10 +183,10 @@ func (mock *EventRepositoryMock) AddSubscriber(handler weos.EventHandler) { // Check the length with: // len(mockedEventRepository.AddSubscriberCalls()) func (mock *EventRepositoryMock) AddSubscriberCalls() []struct { - Handler weos.EventHandler + Handler model.EventHandler } { var calls []struct { - Handler weos.EventHandler + Handler model.EventHandler } mock.lockAddSubscriber.RLock() calls = mock.calls.AddSubscriber @@ -251,7 +252,7 @@ func (mock *EventRepositoryMock) GetAggregateSequenceNumberCalls() []struct { } // GetByAggregate calls GetByAggregateFunc. -func (mock *EventRepositoryMock) GetByAggregate(ID string) ([]*weos.Event, error) { +func (mock *EventRepositoryMock) GetByAggregate(ID string) ([]*model.Event, error) { if mock.GetByAggregateFunc == nil { panic("EventRepositoryMock.GetByAggregateFunc: method is nil but EventRepository.GetByAggregate was just called") } @@ -282,7 +283,7 @@ func (mock *EventRepositoryMock) GetByAggregateCalls() []struct { } // GetByAggregateAndSequenceRange calls GetByAggregateAndSequenceRangeFunc. -func (mock *EventRepositoryMock) GetByAggregateAndSequenceRange(ID string, start int64, end int64) ([]*weos.Event, error) { +func (mock *EventRepositoryMock) GetByAggregateAndSequenceRange(ID string, start int64, end int64) ([]*model.Event, error) { if mock.GetByAggregateAndSequenceRangeFunc == nil { panic("EventRepositoryMock.GetByAggregateAndSequenceRangeFunc: method is nil but EventRepository.GetByAggregateAndSequenceRange was just called") } @@ -321,7 +322,7 @@ func (mock *EventRepositoryMock) GetByAggregateAndSequenceRangeCalls() []struct } // GetByAggregateAndType calls GetByAggregateAndTypeFunc. -func (mock *EventRepositoryMock) GetByAggregateAndType(ID string, entityType string) ([]*weos.Event, error) { +func (mock *EventRepositoryMock) GetByAggregateAndType(ID string, entityType string) ([]*model.Event, error) { if mock.GetByAggregateAndTypeFunc == nil { panic("EventRepositoryMock.GetByAggregateAndTypeFunc: method is nil but EventRepository.GetByAggregateAndType was just called") } @@ -356,7 +357,7 @@ func (mock *EventRepositoryMock) GetByAggregateAndTypeCalls() []struct { } // GetByEntityAndAggregate calls GetByEntityAndAggregateFunc. -func (mock *EventRepositoryMock) GetByEntityAndAggregate(entityID string, entityType string, rootID string) ([]*weos.Event, error) { +func (mock *EventRepositoryMock) GetByEntityAndAggregate(entityID string, entityType string, rootID string) ([]*model.Event, error) { if mock.GetByEntityAndAggregateFunc == nil { panic("EventRepositoryMock.GetByEntityAndAggregateFunc: method is nil but EventRepository.GetByEntityAndAggregate was just called") } @@ -395,7 +396,7 @@ func (mock *EventRepositoryMock) GetByEntityAndAggregateCalls() []struct { } // GetSubscribers calls GetSubscribersFunc. -func (mock *EventRepositoryMock) GetSubscribers() ([]weos.EventHandler, error) { +func (mock *EventRepositoryMock) GetSubscribers() ([]model.EventHandler, error) { if mock.GetSubscribersFunc == nil { panic("EventRepositoryMock.GetSubscribersFunc: method is nil but EventRepository.GetSubscribers was just called") } @@ -452,13 +453,13 @@ func (mock *EventRepositoryMock) MigrateCalls() []struct { } // Persist calls PersistFunc. -func (mock *EventRepositoryMock) Persist(ctxt context.Context, entity weos.AggregateInterface) error { +func (mock *EventRepositoryMock) Persist(ctxt context.Context, entity model.AggregateInterface) error { if mock.PersistFunc == nil { panic("EventRepositoryMock.PersistFunc: method is nil but EventRepository.Persist was just called") } callInfo := struct { Ctxt context.Context - Entity weos.AggregateInterface + Entity model.AggregateInterface }{ Ctxt: ctxt, Entity: entity, @@ -474,11 +475,11 @@ func (mock *EventRepositoryMock) Persist(ctxt context.Context, entity weos.Aggre // len(mockedEventRepository.PersistCalls()) func (mock *EventRepositoryMock) PersistCalls() []struct { Ctxt context.Context - Entity weos.AggregateInterface + Entity model.AggregateInterface } { var calls []struct { Ctxt context.Context - Entity weos.AggregateInterface + Entity model.AggregateInterface } mock.lockPersist.RLock() calls = mock.calls.Persist @@ -486,165 +487,15 @@ func (mock *EventRepositoryMock) PersistCalls() []struct { return calls } -// Ensure, that ProjectionMock does implement weos.Projection. +// Ensure, that LogMock does implement model.Log. // If this is not the case, regenerate this file with moq. -var _ weos.Projection = &ProjectionMock{} +var _ model.Log = &LogMock{} -// ProjectionMock is a mock implementation of model.Projection. -// -// func TestSomethingThatUsesProjection(t *testing.T) { -// -// // make and configure a mocked model.Projection -// mockedProjection := &ProjectionMock{ -// GetContentEntityFunc: func(ctx context.Context, weosID string) (*model.ContentEntity, error) { -// panic("mock out the GetContentEntity method") -// }, -// GetEventHandlerFunc: func() model.EventHandler { -// panic("mock out the GetEventHandler method") -// }, -// MigrateFunc: func(ctx context.Context) error { -// panic("mock out the Migrate method") -// }, -// } -// -// // use mockedProjection in code that requires model.Projection -// // and then make assertions. -// -// } -type ProjectionMock struct { - // GetContentEntityFunc mocks the GetContentEntity method. - GetContentEntityFunc func(ctx context.Context, weosID string) (*weos.ContentEntity, error) - - // GetEventHandlerFunc mocks the GetEventHandler method. - GetEventHandlerFunc func() weos.EventHandler - - // MigrateFunc mocks the Migrate method. - MigrateFunc func(ctx context.Context) error - - // calls tracks calls to the methods. - calls struct { - // GetContentEntity holds details about calls to the GetContentEntity method. - GetContentEntity []struct { - // Ctx is the ctx argument value. - Ctx context.Context - // WeosID is the weosID argument value. - WeosID string - } - // GetEventHandler holds details about calls to the GetEventHandler method. - GetEventHandler []struct { - } - // Migrate holds details about calls to the Migrate method. - Migrate []struct { - // Ctx is the ctx argument value. - Ctx context.Context - } - } - lockGetContentEntity sync.RWMutex - lockGetEventHandler sync.RWMutex - lockMigrate sync.RWMutex -} - -// GetContentEntity calls GetContentEntityFunc. -func (mock *ProjectionMock) GetContentEntity(ctx context.Context, weosID string) (*weos.ContentEntity, error) { - if mock.GetContentEntityFunc == nil { - panic("ProjectionMock.GetContentEntityFunc: method is nil but Projection.GetContentEntity was just called") - } - callInfo := struct { - Ctx context.Context - WeosID string - }{ - Ctx: ctx, - WeosID: weosID, - } - mock.lockGetContentEntity.Lock() - mock.calls.GetContentEntity = append(mock.calls.GetContentEntity, callInfo) - mock.lockGetContentEntity.Unlock() - return mock.GetContentEntityFunc(ctx, weosID) -} - -// GetContentEntityCalls gets all the calls that were made to GetContentEntity. -// Check the length with: -// len(mockedProjection.GetContentEntityCalls()) -func (mock *ProjectionMock) GetContentEntityCalls() []struct { - Ctx context.Context - WeosID string -} { - var calls []struct { - Ctx context.Context - WeosID string - } - mock.lockGetContentEntity.RLock() - calls = mock.calls.GetContentEntity - mock.lockGetContentEntity.RUnlock() - return calls -} - -// GetEventHandler calls GetEventHandlerFunc. -func (mock *ProjectionMock) GetEventHandler() weos.EventHandler { - if mock.GetEventHandlerFunc == nil { - panic("ProjectionMock.GetEventHandlerFunc: method is nil but Projection.GetEventHandler was just called") - } - callInfo := struct { - }{} - mock.lockGetEventHandler.Lock() - mock.calls.GetEventHandler = append(mock.calls.GetEventHandler, callInfo) - mock.lockGetEventHandler.Unlock() - return mock.GetEventHandlerFunc() -} - -// GetEventHandlerCalls gets all the calls that were made to GetEventHandler. -// Check the length with: -// len(mockedProjection.GetEventHandlerCalls()) -func (mock *ProjectionMock) GetEventHandlerCalls() []struct { -} { - var calls []struct { - } - mock.lockGetEventHandler.RLock() - calls = mock.calls.GetEventHandler - mock.lockGetEventHandler.RUnlock() - return calls -} - -// Migrate calls MigrateFunc. -func (mock *ProjectionMock) Migrate(ctx context.Context) error { - if mock.MigrateFunc == nil { - panic("ProjectionMock.MigrateFunc: method is nil but Projection.Migrate was just called") - } - callInfo := struct { - Ctx context.Context - }{ - Ctx: ctx, - } - mock.lockMigrate.Lock() - mock.calls.Migrate = append(mock.calls.Migrate, callInfo) - mock.lockMigrate.Unlock() - return mock.MigrateFunc(ctx) -} - -// MigrateCalls gets all the calls that were made to Migrate. -// Check the length with: -// len(mockedProjection.MigrateCalls()) -func (mock *ProjectionMock) MigrateCalls() []struct { - Ctx context.Context -} { - var calls []struct { - Ctx context.Context - } - mock.lockMigrate.RLock() - calls = mock.calls.Migrate - mock.lockMigrate.RUnlock() - return calls -} - -// Ensure, that LogMock does implement weos.Log. -// If this is not the case, regenerate this file with moq. -var _ weos.Log = &LogMock{} - -// LogMock is a mock implementation of weos.Log. +// LogMock is a mock implementation of model.Log. // // func TestSomethingThatUsesLog(t *testing.T) { // -// // make and configure a mocked weos.Log +// // make and configure a mocked model.Log // mockedLog := &LogMock{ // DebugFunc: func(args ...interface{}) { // panic("mock out the Debug method") @@ -684,7 +535,7 @@ var _ weos.Log = &LogMock{} // }, // } // -// // use mockedLog in code that requires weos.Log +// // use mockedLog in code that requires model.Log // // and then make assertions. // // } @@ -1210,176 +1061,280 @@ func (mock *LogMock) PrintfCalls() []struct { return calls } -// Ensure, that DispatcherMock does implement weos.Dispatcher. +// Ensure, that ProjectionMock does implement model.Projection. // If this is not the case, regenerate this file with moq. -var _ weos.Dispatcher = &DispatcherMock{} +var _ model.Projection = &ProjectionMock{} -// DispatcherMock is a mock implementation of weos.Dispatcher. +// ProjectionMock is a mock implementation of model.Projection. // -// func TestSomethingThatUsesDispatcher(t *testing.T) { +// func TestSomethingThatUsesProjection(t *testing.T) { // -// // make and configure a mocked weos.Dispatcher -// mockedDispatcher := &DispatcherMock{ -// AddSubscriberFunc: func(command *weos.Command, handler weos.CommandHandler) map[string][]weos.CommandHandler { -// panic("mock out the AddSubscriber method") +// // make and configure a mocked model.Projection +// mockedProjection := &ProjectionMock{ +// GetByEntityIDFunc: func(ctxt context.Context, contentType context.ContentType, id string) (map[string]interface{}, error) { +// panic("mock out the GetByEntityID method") // }, -// DispatchFunc: func(ctx context.Context, command *weos.Command) error { -// panic("mock out the Dispatch method") +// GetByKeyFunc: func(ctxt context.Context, contentType context.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { +// panic("mock out the GetByKey method") // }, -// GetSubscribersFunc: func() map[string][]weos.CommandHandler { -// panic("mock out the GetSubscribers method") +// GetContentEntityFunc: func(ctx context.Context, weosID string) (*model.ContentEntity, error) { +// panic("mock out the GetContentEntity method") +// }, +// GetEventHandlerFunc: func() model.EventHandler { +// panic("mock out the GetEventHandler method") +// }, +// MigrateFunc: func(ctx context.Context) error { +// panic("mock out the Migrate method") // }, // } // -// // use mockedDispatcher in code that requires weos.Dispatcher +// // use mockedProjection in code that requires model.Projection // // and then make assertions. // // } -type DispatcherMock struct { - // AddSubscriberFunc mocks the AddSubscriber method. - AddSubscriberFunc func(command *weos.Command, handler weos.CommandHandler) map[string][]weos.CommandHandler +type ProjectionMock struct { + // GetByEntityIDFunc mocks the GetByEntityID method. + GetByEntityIDFunc func(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) - // DispatchFunc mocks the Dispatch method. - DispatchFunc func(ctx context.Context, command *weos.Command) error + // GetByKeyFunc mocks the GetByKey method. + GetByKeyFunc func(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) - // GetSubscribersFunc mocks the GetSubscribers method. - GetSubscribersFunc func() map[string][]weos.CommandHandler + // GetContentEntityFunc mocks the GetContentEntity method. + GetContentEntityFunc func(ctx context.Context, weosID string) (*model.ContentEntity, error) + + // GetEventHandlerFunc mocks the GetEventHandler method. + GetEventHandlerFunc func() model.EventHandler + + // MigrateFunc mocks the Migrate method. + MigrateFunc func(ctx context.Context) error // calls tracks calls to the methods. calls struct { - // AddSubscriber holds details about calls to the AddSubscriber method. - AddSubscriber []struct { - // Command is the command argument value. - Command *weos.Command - // Handler is the handler argument value. - Handler weos.CommandHandler + // GetByEntityID holds details about calls to the GetByEntityID method. + GetByEntityID []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // ContentType is the contentType argument value. + ContentType weoscontext.ContentType + // ID is the id argument value. + ID string + } + // GetByKey holds details about calls to the GetByKey method. + GetByKey []struct { + // Ctxt is the ctxt argument value. + Ctxt context.Context + // ContentType is the contentType argument value. + ContentType weoscontext.ContentType + // Identifiers is the identifiers argument value. + Identifiers map[string]interface{} } - // Dispatch holds details about calls to the Dispatch method. - Dispatch []struct { + // GetContentEntity holds details about calls to the GetContentEntity method. + GetContentEntity []struct { // Ctx is the ctx argument value. Ctx context.Context - // Command is the command argument value. - Command *weos.Command + // WeosID is the weosID argument value. + WeosID string } - // GetSubscribers holds details about calls to the GetSubscribers method. - GetSubscribers []struct { + // GetEventHandler holds details about calls to the GetEventHandler method. + GetEventHandler []struct { + } + // Migrate holds details about calls to the Migrate method. + Migrate []struct { + // Ctx is the ctx argument value. + Ctx context.Context } } - lockAddSubscriber sync.RWMutex - lockDispatch sync.RWMutex - lockGetSubscribers sync.RWMutex + lockGetByEntityID sync.RWMutex + lockGetByKey sync.RWMutex + lockGetContentEntity sync.RWMutex + lockGetEventHandler sync.RWMutex + lockMigrate sync.RWMutex } -// AddSubscriber calls AddSubscriberFunc. -func (mock *DispatcherMock) AddSubscriber(command *weos.Command, handler weos.CommandHandler) map[string][]weos.CommandHandler { - if mock.AddSubscriberFunc == nil { - panic("DispatcherMock.AddSubscriberFunc: method is nil but Dispatcher.AddSubscriber was just called") +// GetByEntityID calls GetByEntityIDFunc. +func (mock *ProjectionMock) GetByEntityID(ctxt context.Context, contentType weoscontext.ContentType, id string) (map[string]interface{}, error) { + if mock.GetByEntityIDFunc == nil { + panic("ProjectionMock.GetByEntityIDFunc: method is nil but Projection.GetByEntityID was just called") } callInfo := struct { - Command *weos.Command - Handler weos.CommandHandler + Ctxt context.Context + ContentType weoscontext.ContentType + ID string }{ - Command: command, - Handler: handler, + Ctxt: ctxt, + ContentType: contentType, + ID: id, } - mock.lockAddSubscriber.Lock() - mock.calls.AddSubscriber = append(mock.calls.AddSubscriber, callInfo) - mock.lockAddSubscriber.Unlock() - return mock.AddSubscriberFunc(command, handler) + mock.lockGetByEntityID.Lock() + mock.calls.GetByEntityID = append(mock.calls.GetByEntityID, callInfo) + mock.lockGetByEntityID.Unlock() + return mock.GetByEntityIDFunc(ctxt, contentType, id) } -// AddSubscriberCalls gets all the calls that were made to AddSubscriber. +// GetByEntityIDCalls gets all the calls that were made to GetByEntityID. // Check the length with: -// len(mockedDispatcher.AddSubscriberCalls()) -func (mock *DispatcherMock) AddSubscriberCalls() []struct { - Command *weos.Command - Handler weos.CommandHandler +// len(mockedProjection.GetByEntityIDCalls()) +func (mock *ProjectionMock) GetByEntityIDCalls() []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + ID string } { var calls []struct { - Command *weos.Command - Handler weos.CommandHandler + Ctxt context.Context + ContentType weoscontext.ContentType + ID string } - mock.lockAddSubscriber.RLock() - calls = mock.calls.AddSubscriber - mock.lockAddSubscriber.RUnlock() + mock.lockGetByEntityID.RLock() + calls = mock.calls.GetByEntityID + mock.lockGetByEntityID.RUnlock() return calls } -// Dispatch calls DispatchFunc. -func (mock *DispatcherMock) Dispatch(ctx context.Context, command *weos.Command) error { - if mock.DispatchFunc == nil { - panic("DispatcherMock.DispatchFunc: method is nil but Dispatcher.Dispatch was just called") +// GetByKey calls GetByKeyFunc. +func (mock *ProjectionMock) GetByKey(ctxt context.Context, contentType weoscontext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { + if mock.GetByKeyFunc == nil { + panic("ProjectionMock.GetByKeyFunc: method is nil but Projection.GetByKey was just called") } callInfo := struct { - Ctx context.Context - Command *weos.Command + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} }{ - Ctx: ctx, - Command: command, + Ctxt: ctxt, + ContentType: contentType, + Identifiers: identifiers, } - mock.lockDispatch.Lock() - mock.calls.Dispatch = append(mock.calls.Dispatch, callInfo) - mock.lockDispatch.Unlock() - return mock.DispatchFunc(ctx, command) + mock.lockGetByKey.Lock() + mock.calls.GetByKey = append(mock.calls.GetByKey, callInfo) + mock.lockGetByKey.Unlock() + return mock.GetByKeyFunc(ctxt, contentType, identifiers) } -// DispatchCalls gets all the calls that were made to Dispatch. +// GetByKeyCalls gets all the calls that were made to GetByKey. // Check the length with: -// len(mockedDispatcher.DispatchCalls()) -func (mock *DispatcherMock) DispatchCalls() []struct { - Ctx context.Context - Command *weos.Command +// len(mockedProjection.GetByKeyCalls()) +func (mock *ProjectionMock) GetByKeyCalls() []struct { + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} } { var calls []struct { - Ctx context.Context - Command *weos.Command + Ctxt context.Context + ContentType weoscontext.ContentType + Identifiers map[string]interface{} } - mock.lockDispatch.RLock() - calls = mock.calls.Dispatch - mock.lockDispatch.RUnlock() + mock.lockGetByKey.RLock() + calls = mock.calls.GetByKey + mock.lockGetByKey.RUnlock() return calls } -// GetSubscribers calls GetSubscribersFunc. -func (mock *DispatcherMock) GetSubscribers() map[string][]weos.CommandHandler { - if mock.GetSubscribersFunc == nil { - panic("DispatcherMock.GetSubscribersFunc: method is nil but Dispatcher.GetSubscribers was just called") +// GetContentEntity calls GetContentEntityFunc. +func (mock *ProjectionMock) GetContentEntity(ctx context.Context, weosID string) (*model.ContentEntity, error) { + if mock.GetContentEntityFunc == nil { + panic("ProjectionMock.GetContentEntityFunc: method is nil but Projection.GetContentEntity was just called") + } + callInfo := struct { + Ctx context.Context + WeosID string + }{ + Ctx: ctx, + WeosID: weosID, + } + mock.lockGetContentEntity.Lock() + mock.calls.GetContentEntity = append(mock.calls.GetContentEntity, callInfo) + mock.lockGetContentEntity.Unlock() + return mock.GetContentEntityFunc(ctx, weosID) +} + +// GetContentEntityCalls gets all the calls that were made to GetContentEntity. +// Check the length with: +// len(mockedProjection.GetContentEntityCalls()) +func (mock *ProjectionMock) GetContentEntityCalls() []struct { + Ctx context.Context + WeosID string +} { + var calls []struct { + Ctx context.Context + WeosID string + } + mock.lockGetContentEntity.RLock() + calls = mock.calls.GetContentEntity + mock.lockGetContentEntity.RUnlock() + return calls +} + +// GetEventHandler calls GetEventHandlerFunc. +func (mock *ProjectionMock) GetEventHandler() model.EventHandler { + if mock.GetEventHandlerFunc == nil { + panic("ProjectionMock.GetEventHandlerFunc: method is nil but Projection.GetEventHandler was just called") } callInfo := struct { }{} - mock.lockGetSubscribers.Lock() - mock.calls.GetSubscribers = append(mock.calls.GetSubscribers, callInfo) - mock.lockGetSubscribers.Unlock() - return mock.GetSubscribersFunc() + mock.lockGetEventHandler.Lock() + mock.calls.GetEventHandler = append(mock.calls.GetEventHandler, callInfo) + mock.lockGetEventHandler.Unlock() + return mock.GetEventHandlerFunc() } -// GetSubscribersCalls gets all the calls that were made to GetSubscribers. +// GetEventHandlerCalls gets all the calls that were made to GetEventHandler. // Check the length with: -// len(mockedDispatcher.GetSubscribersCalls()) -func (mock *DispatcherMock) GetSubscribersCalls() []struct { +// len(mockedProjection.GetEventHandlerCalls()) +func (mock *ProjectionMock) GetEventHandlerCalls() []struct { } { var calls []struct { } - mock.lockGetSubscribers.RLock() - calls = mock.calls.GetSubscribers - mock.lockGetSubscribers.RUnlock() + mock.lockGetEventHandler.RLock() + calls = mock.calls.GetEventHandler + mock.lockGetEventHandler.RUnlock() + return calls +} + +// Migrate calls MigrateFunc. +func (mock *ProjectionMock) Migrate(ctx context.Context) error { + if mock.MigrateFunc == nil { + panic("ProjectionMock.MigrateFunc: method is nil but Projection.Migrate was just called") + } + callInfo := struct { + Ctx context.Context + }{ + Ctx: ctx, + } + mock.lockMigrate.Lock() + mock.calls.Migrate = append(mock.calls.Migrate, callInfo) + mock.lockMigrate.Unlock() + return mock.MigrateFunc(ctx) +} + +// MigrateCalls gets all the calls that were made to Migrate. +// Check the length with: +// len(mockedProjection.MigrateCalls()) +func (mock *ProjectionMock) MigrateCalls() []struct { + Ctx context.Context +} { + var calls []struct { + Ctx context.Context + } + mock.lockMigrate.RLock() + calls = mock.calls.Migrate + mock.lockMigrate.RUnlock() return calls } -// Ensure, that ApplicationMock does implement weos.Service. +// Ensure, that ServiceMock does implement model.Service. // If this is not the case, regenerate this file with moq. -var _ weos.Service = &ApplicationMock{} +var _ model.Service = &ServiceMock{} -// ApplicationMock is a mock implementation of weos.Service. +// ServiceMock is a mock implementation of model.Service. // -// func TestSomethingThatUsesApplication(t *testing.T) { +// func TestSomethingThatUsesService(t *testing.T) { // -// // make and configure a mocked weos.Service -// mockedApplication := &ApplicationMock{ -// AddProjectionFunc: func(projection weos.Projection) error { +// // make and configure a mocked model.Service +// mockedService := &ServiceMock{ +// AddProjectionFunc: func(projection model.Projection) error { // panic("mock out the AddProjection method") // }, -// ConfigFunc: func() *weos.ServiceConfig { +// ConfigFunc: func() *model.ServiceConfig { // panic("mock out the Config method") // }, // DBFunc: func() *gorm.DB { @@ -1388,10 +1343,10 @@ var _ weos.Service = &ApplicationMock{} // DBConnectionFunc: func() *sql.DB { // panic("mock out the DBConnection method") // }, -// DispatcherFunc: func() weos.Dispatcher { +// DispatcherFunc: func() model.Dispatcher { // panic("mock out the Dispatcher method") // }, -// EventRepositoryFunc: func() weos.EventRepository { +// EventRepositoryFunc: func() model.EventRepository { // panic("mock out the EventRepository method") // }, // HTTPClientFunc: func() *http.Client { @@ -1400,13 +1355,13 @@ var _ weos.Service = &ApplicationMock{} // IDFunc: func() string { // panic("mock out the ID method") // }, -// LoggerFunc: func() weos.Log { +// LoggerFunc: func() model.Log { // panic("mock out the Logger method") // }, // MigrateFunc: func(ctx context.Context) error { // panic("mock out the Migrate method") // }, -// ProjectionsFunc: func() []weos.Projection { +// ProjectionsFunc: func() []model.Projection { // panic("mock out the Projections method") // }, // TitleFunc: func() string { @@ -1414,16 +1369,16 @@ var _ weos.Service = &ApplicationMock{} // }, // } // -// // use mockedApplication in code that requires weos.Service +// // use mockedService in code that requires model.Service // // and then make assertions. // // } -type ApplicationMock struct { +type ServiceMock struct { // AddProjectionFunc mocks the AddProjection method. - AddProjectionFunc func(projection weos.Projection) error + AddProjectionFunc func(projection model.Projection) error // ConfigFunc mocks the Config method. - ConfigFunc func() *weos.ServiceConfig + ConfigFunc func() *model.ServiceConfig // DBFunc mocks the DB method. DBFunc func() *gorm.DB @@ -1432,10 +1387,10 @@ type ApplicationMock struct { DBConnectionFunc func() *sql.DB // DispatcherFunc mocks the Dispatcher method. - DispatcherFunc func() weos.Dispatcher + DispatcherFunc func() model.Dispatcher // EventRepositoryFunc mocks the EventRepository method. - EventRepositoryFunc func() weos.EventRepository + EventRepositoryFunc func() model.EventRepository // HTTPClientFunc mocks the HTTPClient method. HTTPClientFunc func() *http.Client @@ -1444,13 +1399,13 @@ type ApplicationMock struct { IDFunc func() string // LoggerFunc mocks the Logger method. - LoggerFunc func() weos.Log + LoggerFunc func() model.Log // MigrateFunc mocks the Migrate method. MigrateFunc func(ctx context.Context) error // ProjectionsFunc mocks the Projections method. - ProjectionsFunc func() []weos.Projection + ProjectionsFunc func() []model.Projection // TitleFunc mocks the Title method. TitleFunc func() string @@ -1460,7 +1415,7 @@ type ApplicationMock struct { // AddProjection holds details about calls to the AddProjection method. AddProjection []struct { // Projection is the projection argument value. - Projection weos.Projection + Projection model.Projection } // Config holds details about calls to the Config method. Config []struct { @@ -1513,12 +1468,12 @@ type ApplicationMock struct { } // AddProjection calls AddProjectionFunc. -func (mock *ApplicationMock) AddProjection(projection weos.Projection) error { +func (mock *ServiceMock) AddProjection(projection model.Projection) error { if mock.AddProjectionFunc == nil { - panic("ApplicationMock.AddProjectionFunc: method is nil but Service.AddProjection was just called") + panic("ServiceMock.AddProjectionFunc: method is nil but Service.AddProjection was just called") } callInfo := struct { - Projection weos.Projection + Projection model.Projection }{ Projection: projection, } @@ -1530,12 +1485,12 @@ func (mock *ApplicationMock) AddProjection(projection weos.Projection) error { // AddProjectionCalls gets all the calls that were made to AddProjection. // Check the length with: -// len(mockedApplication.AddProjectionCalls()) -func (mock *ApplicationMock) AddProjectionCalls() []struct { - Projection weos.Projection +// len(mockedService.AddProjectionCalls()) +func (mock *ServiceMock) AddProjectionCalls() []struct { + Projection model.Projection } { var calls []struct { - Projection weos.Projection + Projection model.Projection } mock.lockAddProjection.RLock() calls = mock.calls.AddProjection @@ -1544,9 +1499,9 @@ func (mock *ApplicationMock) AddProjectionCalls() []struct { } // Config calls ConfigFunc. -func (mock *ApplicationMock) Config() *weos.ServiceConfig { +func (mock *ServiceMock) Config() *model.ServiceConfig { if mock.ConfigFunc == nil { - panic("ApplicationMock.ConfigFunc: method is nil but Service.Config was just called") + panic("ServiceMock.ConfigFunc: method is nil but Service.Config was just called") } callInfo := struct { }{} @@ -1558,8 +1513,8 @@ func (mock *ApplicationMock) Config() *weos.ServiceConfig { // ConfigCalls gets all the calls that were made to Config. // Check the length with: -// len(mockedApplication.ConfigCalls()) -func (mock *ApplicationMock) ConfigCalls() []struct { +// len(mockedService.ConfigCalls()) +func (mock *ServiceMock) ConfigCalls() []struct { } { var calls []struct { } @@ -1570,9 +1525,9 @@ func (mock *ApplicationMock) ConfigCalls() []struct { } // DB calls DBFunc. -func (mock *ApplicationMock) DB() *gorm.DB { +func (mock *ServiceMock) DB() *gorm.DB { if mock.DBFunc == nil { - panic("ApplicationMock.DBFunc: method is nil but Service.DB was just called") + panic("ServiceMock.DBFunc: method is nil but Service.DB was just called") } callInfo := struct { }{} @@ -1584,8 +1539,8 @@ func (mock *ApplicationMock) DB() *gorm.DB { // DBCalls gets all the calls that were made to DB. // Check the length with: -// len(mockedApplication.DBCalls()) -func (mock *ApplicationMock) DBCalls() []struct { +// len(mockedService.DBCalls()) +func (mock *ServiceMock) DBCalls() []struct { } { var calls []struct { } @@ -1596,9 +1551,9 @@ func (mock *ApplicationMock) DBCalls() []struct { } // DBConnection calls DBConnectionFunc. -func (mock *ApplicationMock) DBConnection() *sql.DB { +func (mock *ServiceMock) DBConnection() *sql.DB { if mock.DBConnectionFunc == nil { - panic("ApplicationMock.DBConnectionFunc: method is nil but Service.DBConnection was just called") + panic("ServiceMock.DBConnectionFunc: method is nil but Service.DBConnection was just called") } callInfo := struct { }{} @@ -1610,8 +1565,8 @@ func (mock *ApplicationMock) DBConnection() *sql.DB { // DBConnectionCalls gets all the calls that were made to DBConnection. // Check the length with: -// len(mockedApplication.DBConnectionCalls()) -func (mock *ApplicationMock) DBConnectionCalls() []struct { +// len(mockedService.DBConnectionCalls()) +func (mock *ServiceMock) DBConnectionCalls() []struct { } { var calls []struct { } @@ -1622,9 +1577,9 @@ func (mock *ApplicationMock) DBConnectionCalls() []struct { } // Dispatcher calls DispatcherFunc. -func (mock *ApplicationMock) Dispatcher() weos.Dispatcher { +func (mock *ServiceMock) Dispatcher() model.Dispatcher { if mock.DispatcherFunc == nil { - panic("ApplicationMock.DispatcherFunc: method is nil but Service.Dispatcher was just called") + panic("ServiceMock.DispatcherFunc: method is nil but Service.Dispatcher was just called") } callInfo := struct { }{} @@ -1636,8 +1591,8 @@ func (mock *ApplicationMock) Dispatcher() weos.Dispatcher { // DispatcherCalls gets all the calls that were made to Dispatcher. // Check the length with: -// len(mockedApplication.DispatcherCalls()) -func (mock *ApplicationMock) DispatcherCalls() []struct { +// len(mockedService.DispatcherCalls()) +func (mock *ServiceMock) DispatcherCalls() []struct { } { var calls []struct { } @@ -1648,9 +1603,9 @@ func (mock *ApplicationMock) DispatcherCalls() []struct { } // EventRepository calls EventRepositoryFunc. -func (mock *ApplicationMock) EventRepository() weos.EventRepository { +func (mock *ServiceMock) EventRepository() model.EventRepository { if mock.EventRepositoryFunc == nil { - panic("ApplicationMock.EventRepositoryFunc: method is nil but Service.EventRepository was just called") + panic("ServiceMock.EventRepositoryFunc: method is nil but Service.EventRepository was just called") } callInfo := struct { }{} @@ -1662,8 +1617,8 @@ func (mock *ApplicationMock) EventRepository() weos.EventRepository { // EventRepositoryCalls gets all the calls that were made to EventRepository. // Check the length with: -// len(mockedApplication.EventRepositoryCalls()) -func (mock *ApplicationMock) EventRepositoryCalls() []struct { +// len(mockedService.EventRepositoryCalls()) +func (mock *ServiceMock) EventRepositoryCalls() []struct { } { var calls []struct { } @@ -1674,9 +1629,9 @@ func (mock *ApplicationMock) EventRepositoryCalls() []struct { } // HTTPClient calls HTTPClientFunc. -func (mock *ApplicationMock) HTTPClient() *http.Client { +func (mock *ServiceMock) HTTPClient() *http.Client { if mock.HTTPClientFunc == nil { - panic("ApplicationMock.HTTPClientFunc: method is nil but Service.HTTPClient was just called") + panic("ServiceMock.HTTPClientFunc: method is nil but Service.HTTPClient was just called") } callInfo := struct { }{} @@ -1688,8 +1643,8 @@ func (mock *ApplicationMock) HTTPClient() *http.Client { // HTTPClientCalls gets all the calls that were made to HTTPClient. // Check the length with: -// len(mockedApplication.HTTPClientCalls()) -func (mock *ApplicationMock) HTTPClientCalls() []struct { +// len(mockedService.HTTPClientCalls()) +func (mock *ServiceMock) HTTPClientCalls() []struct { } { var calls []struct { } @@ -1700,9 +1655,9 @@ func (mock *ApplicationMock) HTTPClientCalls() []struct { } // ID calls IDFunc. -func (mock *ApplicationMock) ID() string { +func (mock *ServiceMock) ID() string { if mock.IDFunc == nil { - panic("ApplicationMock.IDFunc: method is nil but Service.ID was just called") + panic("ServiceMock.IDFunc: method is nil but Service.ID was just called") } callInfo := struct { }{} @@ -1714,8 +1669,8 @@ func (mock *ApplicationMock) ID() string { // IDCalls gets all the calls that were made to ID. // Check the length with: -// len(mockedApplication.IDCalls()) -func (mock *ApplicationMock) IDCalls() []struct { +// len(mockedService.IDCalls()) +func (mock *ServiceMock) IDCalls() []struct { } { var calls []struct { } @@ -1726,9 +1681,9 @@ func (mock *ApplicationMock) IDCalls() []struct { } // Logger calls LoggerFunc. -func (mock *ApplicationMock) Logger() weos.Log { +func (mock *ServiceMock) Logger() model.Log { if mock.LoggerFunc == nil { - panic("ApplicationMock.LoggerFunc: method is nil but Service.Logger was just called") + panic("ServiceMock.LoggerFunc: method is nil but Service.Logger was just called") } callInfo := struct { }{} @@ -1740,8 +1695,8 @@ func (mock *ApplicationMock) Logger() weos.Log { // LoggerCalls gets all the calls that were made to Logger. // Check the length with: -// len(mockedApplication.LoggerCalls()) -func (mock *ApplicationMock) LoggerCalls() []struct { +// len(mockedService.LoggerCalls()) +func (mock *ServiceMock) LoggerCalls() []struct { } { var calls []struct { } @@ -1752,9 +1707,9 @@ func (mock *ApplicationMock) LoggerCalls() []struct { } // Migrate calls MigrateFunc. -func (mock *ApplicationMock) Migrate(ctx context.Context) error { +func (mock *ServiceMock) Migrate(ctx context.Context) error { if mock.MigrateFunc == nil { - panic("ApplicationMock.MigrateFunc: method is nil but Service.Migrate was just called") + panic("ServiceMock.MigrateFunc: method is nil but Service.Migrate was just called") } callInfo := struct { Ctx context.Context @@ -1769,8 +1724,8 @@ func (mock *ApplicationMock) Migrate(ctx context.Context) error { // MigrateCalls gets all the calls that were made to Migrate. // Check the length with: -// len(mockedApplication.MigrateCalls()) -func (mock *ApplicationMock) MigrateCalls() []struct { +// len(mockedService.MigrateCalls()) +func (mock *ServiceMock) MigrateCalls() []struct { Ctx context.Context } { var calls []struct { @@ -1783,9 +1738,9 @@ func (mock *ApplicationMock) MigrateCalls() []struct { } // Projections calls ProjectionsFunc. -func (mock *ApplicationMock) Projections() []weos.Projection { +func (mock *ServiceMock) Projections() []model.Projection { if mock.ProjectionsFunc == nil { - panic("ApplicationMock.ProjectionsFunc: method is nil but Service.Projections was just called") + panic("ServiceMock.ProjectionsFunc: method is nil but Service.Projections was just called") } callInfo := struct { }{} @@ -1797,8 +1752,8 @@ func (mock *ApplicationMock) Projections() []weos.Projection { // ProjectionsCalls gets all the calls that were made to Projections. // Check the length with: -// len(mockedApplication.ProjectionsCalls()) -func (mock *ApplicationMock) ProjectionsCalls() []struct { +// len(mockedService.ProjectionsCalls()) +func (mock *ServiceMock) ProjectionsCalls() []struct { } { var calls []struct { } @@ -1809,9 +1764,9 @@ func (mock *ApplicationMock) ProjectionsCalls() []struct { } // Title calls TitleFunc. -func (mock *ApplicationMock) Title() string { +func (mock *ServiceMock) Title() string { if mock.TitleFunc == nil { - panic("ApplicationMock.TitleFunc: method is nil but Service.Title was just called") + panic("ServiceMock.TitleFunc: method is nil but Service.Title was just called") } callInfo := struct { }{} @@ -1823,8 +1778,8 @@ func (mock *ApplicationMock) Title() string { // TitleCalls gets all the calls that were made to Title. // Check the length with: -// len(mockedApplication.TitleCalls()) -func (mock *ApplicationMock) TitleCalls() []struct { +// len(mockedService.TitleCalls()) +func (mock *ServiceMock) TitleCalls() []struct { } { var calls []struct { } diff --git a/model/interfaces.go b/model/interfaces.go index 33236364..170fb45b 100644 --- a/model/interfaces.go +++ b/model/interfaces.go @@ -1,7 +1,10 @@ package model //go:generate moq -out temp_mocks_test.go -pkg model_test . Projection -import "golang.org/x/net/context" +import ( + weosContext "github.com/wepala/weos-service/context" + "golang.org/x/net/context" +) type WeOSEntity interface { Entity @@ -64,4 +67,6 @@ type Projection interface { Datastore GetEventHandler() EventHandler GetContentEntity(ctx context.Context, weosID string) (*ContentEntity, error) + GetByKey(ctxt context.Context, contentType weosContext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) + GetByEntityID(ctxt context.Context, contentType weosContext.ContentType, id string) (map[string]interface{}, error) } diff --git a/model/receiver_test.go b/model/receiver_test.go index c04b612b..8b5d8564 100644 --- a/model/receiver_test.go +++ b/model/receiver_test.go @@ -2,11 +2,12 @@ package model_test import ( "encoding/json" + "testing" + "github.com/getkin/kin-openapi/openapi3" weosContext "github.com/wepala/weos-service/context" "github.com/wepala/weos-service/model" "golang.org/x/net/context" - "testing" ) type Blog struct { @@ -57,7 +58,7 @@ func TestCreateContentType(t *testing.T) { AddSubscriberFunc: func(handler model.EventHandler) { }, } - application := &ApplicationMock{ + application := &ServiceMock{ DispatcherFunc: func() model.Dispatcher { return commandDispatcher }, diff --git a/projections/gorm.go b/projections/gorm.go index 95a14261..4481ef0d 100644 --- a/projections/gorm.go +++ b/projections/gorm.go @@ -18,12 +18,13 @@ type GORMProjection struct { db *gorm.DB logger weos.Log migrationFolder string - Schema map[string]interface{} + Schema map[string]ds.Builder } func (p *GORMProjection) GetByKey(ctxt context.Context, contentType weosContext.ContentType, identifiers map[string]interface{}) (map[string]interface{}, error) { - if scheme, ok := p.Schema[strings.Title(contentType.Name)]; ok { + if s, ok := p.Schema[strings.Title(contentType.Name)]; ok { //pulling the primary keys from the schema in order to match with the keys given for searching + scheme := s.Build().New() pks, _ := json.Marshal(contentType.Schema.Extensions["x-identifier"]) primaryKeys := []string{} json.Unmarshal(pks, &primaryKeys) @@ -49,10 +50,7 @@ func (p *GORMProjection) GetByKey(ctxt context.Context, contentType weosContext. } } - var result *gorm.DB - - result = p.db.Table(contentType.Name).Scopes(ContentQuery()).First(scheme, identifiers) - + result := p.db.Table(contentType.Name).Scopes(ContentQuery()).Find(scheme, identifiers) if result.Error != nil { return nil, result.Error } @@ -69,10 +67,9 @@ func (p *GORMProjection) GetByKey(ctxt context.Context, contentType weosContext. } func (p *GORMProjection) GetByEntityID(ctxt context.Context, contentType weosContext.ContentType, id string) (map[string]interface{}, error) { - if scheme, ok := p.Schema[strings.Title(contentType.Name)]; ok { - var result *gorm.DB - - result = p.db.Table(contentType.Name).Scopes(ContentQuery()).Where("weos_id = ?", id).Take(scheme) + if s, ok := p.Schema[strings.Title(contentType.Name)]; ok { + scheme := s.Build().New() + result := p.db.Table(contentType.Name).Scopes(ContentQuery()).Find(scheme, "weos_id = ?", id) if result.Error != nil { return nil, result.Error @@ -104,8 +101,18 @@ func (p *GORMProjection) Migrate(ctx context.Context) error { //we may need to reorder the creation so that tables don't reference things that don't exist as yet. var err error var tables []interface{} - for _, s := range p.Schema { - tables = append(tables, s) + for name, s := range p.Schema { + f := s.GetField("Table") + f.SetTag(`json:"table_alias" gorm:"default:` + name + `"`) + instance := s.Build().New() + err := json.Unmarshal([]byte(`{ + "table_alias": "`+name+`" + }`), &instance) + if err != nil { + p.logger.Errorf("unable to set the table name '%s'", err) + return err + } + tables = append(tables, instance) } err = p.db.Migrator().AutoMigrate(tables...) @@ -117,10 +124,12 @@ func (p *GORMProjection) GetEventHandler() weos.EventHandler { switch event.Type { case "create": contentType := weosContext.GetContentType(ctx) - eventPayload, ok := p.Schema[strings.Title(contentType.Name)] + //using the schema ensures no nested fields are left out in creation + payload, ok := p.Schema[strings.Title(contentType.Name)] if !ok { p.logger.Errorf("found no content type %s", contentType.Name) } else { + eventPayload := payload.Build().New() mapPayload := map[string]interface{}{} err := json.Unmarshal(event.Payload, &mapPayload) if err != nil { @@ -140,20 +149,26 @@ func (p *GORMProjection) GetEventHandler() weos.EventHandler { } case "update": contentType := weosContext.GetContentType(ctx) - eventPayload, ok := p.Schema[strings.Title(contentType.Name)] + payload, ok := p.Schema[strings.Title(contentType.Name)] mapPayload := map[string]interface{}{} if !ok { p.logger.Errorf("found no content type %s", contentType.Name) } else { - err := json.Unmarshal(event.Payload, &eventPayload) + eventPayload := payload.Build().New() + err := json.Unmarshal(event.Payload, &mapPayload) if err != nil { p.logger.Errorf("error unmarshalling event '%s'", err) } - err = json.Unmarshal(event.Payload, &mapPayload) + //set sequence number + mapPayload["sequence_no"] = event.Meta.SequenceNo + + bytes, _ := json.Marshal(mapPayload) + err = json.Unmarshal(bytes, &eventPayload) if err != nil { p.logger.Errorf("error unmarshalling event '%s'", err) } + reader := ds.NewReader(eventPayload) //replace associations @@ -207,7 +222,7 @@ type QueryModifier func() func(db *gorm.DB) *gorm.DB var ContentQuery QueryModifier //NewProjection creates an instance of the projection -func NewProjection(ctx context.Context, application weos.Service, schemas map[string]interface{}) (*GORMProjection, error) { +func NewProjection(ctx context.Context, application weos.Service, schemas map[string]ds.Builder) (*GORMProjection, error) { projection := &GORMProjection{ db: application.DB(),