Skip to content

Commit

Permalink
Merge pull request #54 from wepala/WEOS-1267
Browse files Browse the repository at this point in the history
feature: WEOS-1133 Create a list method on projection and helper function
  • Loading branch information
RandyDeo authored Jan 24, 2022
2 parents dd4f194 + beb89c7 commit c819896
Show file tree
Hide file tree
Showing 2 changed files with 237 additions and 0 deletions.
51 changes: 51 additions & 0 deletions projections/gorm.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,57 @@ func (p *GORMProjection) GetContentEntity(ctx context.Context, weosID string) (*
return newEntity, nil
}

//GetContentEntities returns a list of content entities as well as the total found
func (p *GORMProjection) GetContentEntities(ctx context.Context, page int, limit int, query string, sortOptions map[string]string, filterOptions map[string]interface{}) ([]map[string]interface{}, int64, error) {
var count int64
var result *gorm.DB
var schemes interface{}
contentType := weosContext.GetContentType(ctx)
if s, ok := p.Schema[strings.Title(contentType.Name)]; ok {
schemes = s.Build().NewSliceOfStructs()
scheme := s.Build().New()

result = p.db.Table(contentType.Name).Scopes(ContentQuery()).Model(&scheme).Count(&count).Scopes(paginate(page, limit), sort(sortOptions)).Omit("weos_id, sequence_no").Find(schemes)
}
bytes, err := json.Marshal(schemes)
if err != nil {
return nil, 0, err
}
var entities []map[string]interface{}
json.Unmarshal(bytes, &entities)
return entities, count, result.Error
}

//paginate to query results
func paginate(page int, limit int) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
actualLimit := limit
actualPage := page
if actualLimit == 0 {
actualLimit = -1
}
if actualPage == 0 {
actualPage = 1
}
return db.Offset((page - 1) * limit).Limit(actualLimit)
}
}

// function that sorts the query results
func sort(order map[string]string) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
for key, value := range order {
//only support certain values since GORM doesn't protect the order function https://gorm.io/docs/security.html#SQL-injection-Methods
if (value != "asc" && value != "desc" && value != "") || (key != "id") {
return db
}
db.Order(key + " " + value)
}

return db
}
}

//query modifier for making queries to the database
type QueryModifier func() func(db *gorm.DB) *gorm.DB

Expand Down
186 changes: 186 additions & 0 deletions projections/projections_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1866,3 +1866,189 @@ components:
}
})
}

func TestProjections_List(t *testing.T) {
openAPI := `openapi: 3.0.3
info:
title: Blog
description: Blog example
version: 1.0.0
servers:
- url: https://prod1.weos.sh/blog/dev
description: WeOS Dev
- url: https://prod1.weos.sh/blog/v1
x-weos-config:
logger:
level: warn
report-caller: true
formatter: json
database:
driver: sqlite3
database: test.db
event-source:
- title: default
driver: service
endpoint: https://prod1.weos.sh/events/v1
- title: event
driver: sqlite3
database: test.db
databases:
- title: default
driver: sqlite3
database: test.db
rest:
middleware:
- RequestID
- Recover
- ZapLogger
components:
schemas:
Blog:
type: object
properties:
title:
type: string
description: blog title
description:
type: string
required:
- title
Post:
type: object
properties:
title:
type: string
description: post title
description:
type: string
blog:
$ref: "#/components/schemas/Blog"
`
loader := openapi3.NewSwaggerLoader()
swagger, err := loader.LoadSwaggerFromData([]byte(openAPI))
if err != nil {
t.Fatal(err)
}

schemes := rest.CreateSchema(context.Background(), echo.New(), swagger)
p, err := projections.NewProjection(context.Background(), app, schemes)
if err != nil {
t.Fatal(err)
}

err = p.Migrate(context.Background())
if err != nil {
t.Fatal(err)
}

gormDB := app.DB()
if !gormDB.Migrator().HasTable("Blog") {
t.Fatal("expected to get a table 'Blog'")
}

if !gormDB.Migrator().HasTable("Post") {
t.Fatal("expected to get a table 'Post'")
}

t.Run("do a basic list with page and limit", func(t *testing.T) {

blogWeosID := "abc123"
blogWeosID1 := "abc1234"
blogWeosID2 := "abc12345"
blogWeosID3 := "abc123456"
blogWeosID4 := "abc1234567"
limit := 2
page := 1
sortOptions := map[string]string{
"id": "asc",
}
ctxt := context.Background()
name := "Blog"
scheme := swagger.Components.Schemas[name]
ctxt = context.WithValue(ctxt, weosContext.CONTENT_TYPE, &weosContext.ContentType{
Name: strings.Title(name),
Schema: scheme.Value,
})
blog := map[string]interface{}{"weos_id": blogWeosID, "title": "hugs1", "sequence_no": int64(1)}
blog1 := map[string]interface{}{"weos_id": blogWeosID1, "title": "hugs2", "sequence_no": int64(1)}
blog2 := map[string]interface{}{"weos_id": blogWeosID2, "title": "hugs3", "sequence_no": int64(1)}
blog3 := map[string]interface{}{"weos_id": blogWeosID3, "title": "morehugs4", "sequence_no": int64(1)}
blog4 := map[string]interface{}{"weos_id": blogWeosID4, "title": "morehugs5", "sequence_no": int64(1)}

gormDB.Table("Blog").Create(blog)
gormDB.Table("Blog").Create(blog1)
gormDB.Table("Blog").Create(blog2)
gormDB.Table("Blog").Create(blog3)
gormDB.Table("Blog").Create(blog4)

results, total, err := p.GetContentEntities(ctxt, page, limit, "", sortOptions, nil)
if err != nil {
t.Errorf("error getting content entities: %s", err)
}
if results == nil || len(results) == 0 {
t.Errorf("expected to get results but got nil")
}
if total != int64(5) {
t.Errorf("expected total to be %d got %d", int64(5), total)
}
found := 0
for _, b := range results {
//Because it is sorted by asc order the first two blogs would be in the results
if b["title"] == blog["title"] && b["weos_id"] == nil && b["sequence_no"] == nil {
found++
}
if b["title"] == blog1["title"] && b["weos_id"] == nil && b["sequence_no"] == nil {
found++
}

}
if found != limit {
t.Errorf("expected to find %d blogs got %d", limit, found)
}

})
t.Run("get a basic list with the foreign key returned", func(t *testing.T) {

blogWeosID := "abc123fgd"
limit := 1
page := 1
sortOptions := map[string]string{
"id": "asc",
}
ctxt := context.Background()
name := "Post"
scheme := swagger.Components.Schemas[name]
ctxt = context.WithValue(ctxt, weosContext.CONTENT_TYPE, &weosContext.ContentType{
Name: strings.Title(name),
Schema: scheme.Value,
})

blog := map[string]interface{}{"weos_id": blogWeosID, "title": "hugs1", "sequence_no": int64(1)}
gormDB.Table("Blog").Create(blog)
gormDB.Table("Post").Create(map[string]interface{}{"title": "hills have eyes", "blog_id": uint(1)})
gormDB.Table("Post").Create(map[string]interface{}{"title": "hills have eyes2", "blog_id": uint(1)})

results, total, err := p.GetContentEntities(ctxt, page, limit, "", sortOptions, nil)
if err != nil {
t.Errorf("error getting content entities: %s", err)
}
if results == nil || len(results) == 0 {
t.Errorf("expected to get results but got nil")
}
if total != int64(2) {
t.Errorf("expected total to be %d got %d", int64(2), total)
}
found := 0
for _, b := range results {
//Because it is sorted by asc order the first post would be in the results
if b["blog_id"] == float64(1) {
found++
}

}
if found != limit {
t.Errorf("expected to find %d post got %d", limit, found)
}

})
}

0 comments on commit c819896

Please sign in to comment.