Files
ziti/controller/models/base_model.go
T
Paul Lorenz 2f94fe061f Update for foundation API change. Support list by roles. (#68)
* Update for foundation API change. Support list by roles.
2020-03-27 12:42:42 -04:00

220 lines
5.6 KiB
Go

/*
Copyright NetFoundry, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package models
import (
"github.com/netfoundry/ziti-foundation/storage/ast"
"github.com/netfoundry/ziti-foundation/storage/boltz"
"github.com/pkg/errors"
"go.etcd.io/bbolt"
"time"
)
const (
ListLimitMax = 500
ListOffsetMax = 100000
ListLimitDefault = 10
ListOffsetDefault = 0
)
type EntityRetriever interface {
BaseLoad(id string) (Entity, error)
BaseLoadInTx(tx *bbolt.Tx, id string) (Entity, error)
BaseList(query string) (*EntityListResult, error)
BasePreparedList(query ast.Query) (*EntityListResult, error)
BasePreparedListAssociated(id string, typeLoader EntityRetriever, query ast.Query) (*EntityListResult, error)
GetStore() boltz.CrudStore
}
type Entity interface {
GetId() string
SetId(string)
GetCreatedAt() time.Time
GetUpdatedAt() time.Time
GetTags() map[string]interface{}
}
type BaseEntity struct {
Id string
CreatedAt time.Time
UpdatedAt time.Time
Tags map[string]interface{}
}
func (entity *BaseEntity) GetId() string {
return entity.Id
}
func (entity *BaseEntity) SetId(id string) {
entity.Id = id
}
func (entity *BaseEntity) GetCreatedAt() time.Time {
return entity.CreatedAt
}
func (entity *BaseEntity) GetUpdatedAt() time.Time {
return entity.UpdatedAt
}
func (entity *BaseEntity) GetTags() map[string]interface{} {
return entity.Tags
}
func (entity *BaseEntity) FillCommon(boltEntity boltz.ExtEntity) {
entity.Id = boltEntity.GetId()
entity.CreatedAt = boltEntity.GetCreatedAt()
entity.UpdatedAt = boltEntity.GetUpdatedAt()
entity.Tags = boltEntity.GetTags()
}
type EntityListResult struct {
Loader EntityRetriever
Entities []Entity
QueryMetaData
}
func (result *EntityListResult) GetEntities() []Entity {
return result.Entities
}
func (result *EntityListResult) GetMetaData() *QueryMetaData {
return &result.QueryMetaData
}
func (result *EntityListResult) Collect(tx *bbolt.Tx, ids []string, queryMetaData *QueryMetaData) error {
result.QueryMetaData = *queryMetaData
for _, key := range ids {
entity, err := result.Loader.BaseLoadInTx(tx, key)
if err != nil {
return err
}
result.Entities = append(result.Entities, entity)
}
return nil
}
type QueryMetaData struct {
Count int64
Limit int64
Offset int64
FilterableFields []string
}
type BaseController struct {
Store boltz.CrudStore
}
func (ctrl *BaseController) GetStore() boltz.CrudStore {
return ctrl.Store
}
type ListResultHandler func(tx *bbolt.Tx, ids []string, qmd *QueryMetaData) error
func (ctrl *BaseController) checkLimits(query ast.Query) {
if query.GetLimit() == nil || *query.GetLimit() < -1 || *query.GetLimit() == 0 {
query.SetLimit(ListLimitDefault)
} else if *query.GetLimit() > ListLimitMax {
query.SetLimit(ListLimitMax)
}
if query.GetSkip() == nil || *query.GetSkip() < 0 {
query.SetSkip(ListOffsetDefault)
} else if *query.GetSkip() > ListOffsetMax {
query.SetSkip(ListOffsetMax)
}
}
func (ctrl *BaseController) ListWithTx(tx *bbolt.Tx, queryString string, resultHandler ListResultHandler) error {
query, err := ast.Parse(ctrl.Store, queryString)
if err != nil {
return err
}
return ctrl.PreparedListWithTx(tx, query, resultHandler)
}
func (ctrl *BaseController) PreparedListWithTx(tx *bbolt.Tx, query ast.Query, resultHandler ListResultHandler) error {
ctrl.checkLimits(query)
keys, count, err := ctrl.Store.QueryIdsC(tx, query)
if err != nil {
return err
}
qmd := &QueryMetaData{
Count: count,
Limit: *query.GetLimit(),
Offset: *query.GetSkip(),
FilterableFields: ctrl.Store.GetPublicSymbols(),
}
return resultHandler(tx, keys, qmd)
}
func (ctrl *BaseController) PreparedListAssociatedWithTx(tx *bbolt.Tx, id, association string, query ast.Query, resultHandler ListResultHandler) error {
ctrl.checkLimits(query)
var count int64
var keys []string
var err error
symbol := ctrl.GetStore().GetSymbol(association)
if symbol == nil {
return errors.Errorf("invalid association: '%v'", association)
}
linkedType := symbol.GetLinkedType()
if linkedType == nil {
return errors.Errorf("invalid association: '%v'", association)
}
cursorProvider := func(tx *bbolt.Tx, forward bool) ast.SetCursor {
return symbol.GetStore().GetRelatedEntitiesCursor(tx, id, association, forward)
}
if keys, count, err = linkedType.QueryWithCursorC(tx, cursorProvider, query); err != nil {
return err
}
qmd := &QueryMetaData{
Count: count,
Limit: *query.GetLimit(),
Offset: *query.GetSkip(),
FilterableFields: linkedType.GetPublicSymbols(),
}
return resultHandler(tx, keys, qmd)
}
func (ctrl *BaseController) PreparedListIndexedWithTx(tx *bbolt.Tx, cursorProvider ast.SetCursorProvider, query ast.Query, resultHandler ListResultHandler) error {
ctrl.checkLimits(query)
keys, count, err := ctrl.Store.QueryWithCursorC(tx, cursorProvider, query)
if err != nil {
return err
}
qmd := &QueryMetaData{
Count: count,
Limit: *query.GetLimit(),
Offset: *query.GetSkip(),
FilterableFields: ctrl.Store.GetPublicSymbols(),
}
return resultHandler(tx, keys, qmd)
}