1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
package model
import (
"fmt"
"reflect"
"github.com/ovn-org/libovsdb/mapper"
"github.com/ovn-org/libovsdb/ovsdb"
)
// A DatabaseModel represents libovsdb's metadata about the database.
// It's the result of combining the client's ClientDBModel and the server's Schema
type DatabaseModel struct {
client ClientDBModel
Schema ovsdb.DatabaseSchema
Mapper mapper.Mapper
metadata map[reflect.Type]mapper.Metadata
}
// NewDatabaseModel returns a new DatabaseModel
func NewDatabaseModel(schema ovsdb.DatabaseSchema, client ClientDBModel) (DatabaseModel, []error) {
dbModel := &DatabaseModel{
Schema: schema,
client: client,
}
errs := client.validate(schema)
if len(errs) > 0 {
return DatabaseModel{}, errs
}
dbModel.Mapper = mapper.NewMapper(schema)
var metadata map[reflect.Type]mapper.Metadata
metadata, errs = generateModelInfo(schema, client.types)
if len(errs) > 0 {
return DatabaseModel{}, errs
}
dbModel.metadata = metadata
return *dbModel, nil
}
// NewPartialDatabaseModel returns a DatabaseModel what does not have a schema yet
func NewPartialDatabaseModel(client ClientDBModel) DatabaseModel {
return DatabaseModel{
client: client,
}
}
// Valid returns whether the DatabaseModel is fully functional
func (db DatabaseModel) Valid() bool {
return !reflect.DeepEqual(db.Schema, ovsdb.DatabaseSchema{})
}
// Client returns the DatabaseModel's client dbModel
func (db DatabaseModel) Client() ClientDBModel {
return db.client
}
// NewModel returns a new instance of a model from a specific string
func (db DatabaseModel) NewModel(table string) (Model, error) {
mtype, ok := db.client.types[table]
if !ok {
return nil, fmt.Errorf("table %s not found in database model", string(table))
}
model := reflect.New(mtype.Elem())
return model.Interface().(Model), nil
}
// Types returns the DatabaseModel Types
// the DatabaseModel types is a map of reflect.Types indexed by string
// The reflect.Type is a pointer to a struct that contains 'ovs' tags
// as described above. Such pointer to struct also implements the Model interface
func (db DatabaseModel) Types() map[string]reflect.Type {
return db.client.types
}
// FindTable returns the string associated with a reflect.Type or ""
func (db DatabaseModel) FindTable(mType reflect.Type) string {
for table, tType := range db.client.types {
if tType == mType {
return table
}
}
return ""
}
// generateModelMetadata creates metadata objects from all models included in the
// database and caches them for future re-use
func generateModelInfo(dbSchema ovsdb.DatabaseSchema, modelTypes map[string]reflect.Type) (map[reflect.Type]mapper.Metadata, []error) {
errors := []error{}
metadata := make(map[reflect.Type]mapper.Metadata, len(modelTypes))
for tableName, tType := range modelTypes {
tableSchema := dbSchema.Table(tableName)
if tableSchema == nil {
errors = append(errors, fmt.Errorf("database Model contains model for table %s which is not present in schema", tableName))
continue
}
obj := reflect.New(tType.Elem()).Interface().(Model)
info, err := mapper.NewInfo(tableName, tableSchema, obj)
if err != nil {
errors = append(errors, err)
continue
}
metadata[tType] = info.Metadata
}
return metadata, errors
}
// NewModelInfo returns a mapper.Info object based on a provided model
func (db DatabaseModel) NewModelInfo(obj interface{}) (*mapper.Info, error) {
meta, ok := db.metadata[reflect.TypeOf(obj)]
if !ok {
return nil, ovsdb.NewErrWrongType("NewModelInfo", "type that is part of the DatabaseModel", obj)
}
return &mapper.Info{
Obj: obj,
Metadata: meta,
}, nil
}
|