File: model.go

package info (click to toggle)
golang-github-ovn-org-libovsdb 0.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 1,440 kB
  • sloc: makefile: 52; sh: 14
file content (130 lines) | stat: -rw-r--r-- 3,556 bytes parent folder | download | duplicates (2)
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
119
120
121
122
123
124
125
126
127
128
129
130
package model

import (
	"encoding/json"
	"fmt"
	"reflect"

	"github.com/ovn-org/libovsdb/ovsdb"
)

// A Model is the base interface used to build Database Models. It is used
// to express how data from a specific Database Table shall be translated into structs
// A Model is a struct with at least one (most likely more) field tagged with the 'ovs' tag
// The value of 'ovs' field must be a valid column name in the OVS Database
// A field associated with the "_uuid" column mandatory. The rest of the columns are optional
// The struct may also have non-tagged fields (which will be ignored by the API calls)
// The Model interface must be implemented by the pointer to such type
// Example:
//type MyLogicalRouter struct {
//	UUID          string            `ovsdb:"_uuid"`
//	Name          string            `ovsdb:"name"`
//	ExternalIDs   map[string]string `ovsdb:"external_ids"`
//	LoadBalancers []string          `ovsdb:"load_balancer"`
//}
type Model interface{}

type CloneableModel interface {
	CloneModel() Model
	CloneModelInto(Model)
}

type ComparableModel interface {
	EqualsModel(Model) bool
}

// Clone creates a deep copy of a model
func Clone(a Model) Model {
	if cloner, ok := a.(CloneableModel); ok {
		return cloner.CloneModel()
	}

	val := reflect.Indirect(reflect.ValueOf(a))
	b := reflect.New(val.Type()).Interface()
	aBytes, _ := json.Marshal(a)
	_ = json.Unmarshal(aBytes, b)
	return b
}

// CloneInto deep copies a model into another one
func CloneInto(src, dst Model) {
	if cloner, ok := src.(CloneableModel); ok {
		cloner.CloneModelInto(dst)
		return
	}

	aBytes, _ := json.Marshal(src)
	_ = json.Unmarshal(aBytes, dst)
}

func Equal(l, r Model) bool {
	if comparator, ok := l.(ComparableModel); ok {
		return comparator.EqualsModel(r)
	}

	return reflect.DeepEqual(l, r)
}

func modelSetUUID(model Model, uuid string) error {
	modelVal := reflect.ValueOf(model).Elem()
	for i := 0; i < modelVal.NumField(); i++ {
		if field := modelVal.Type().Field(i); field.Tag.Get("ovsdb") == "_uuid" &&
			field.Type.Kind() == reflect.String {
			modelVal.Field(i).Set(reflect.ValueOf(uuid))
			return nil
		}
	}
	return fmt.Errorf("model is expected to have a string field mapped to column _uuid")
}

// Condition is a model-based representation of an OVSDB Condition
type Condition struct {
	// Pointer to the field of the model where the operation applies
	Field interface{}
	// Condition function
	Function ovsdb.ConditionFunction
	// Value to use in the condition
	Value interface{}
}

// Mutation is a model-based representation of an OVSDB Mutation
type Mutation struct {
	// Pointer to the field of the model that shall be mutated
	Field interface{}
	// String representing the mutator (as per RFC7047)
	Mutator ovsdb.Mutator
	// Value to use in the mutation
	Value interface{}
}

// CreateModel creates a new Model instance based on an OVSDB Row information
func CreateModel(dbModel DatabaseModel, tableName string, row *ovsdb.Row, uuid string) (Model, error) {
	if !dbModel.Valid() {
		return nil, fmt.Errorf("database model not valid")
	}

	table := dbModel.Schema.Table(tableName)
	if table == nil {
		return nil, fmt.Errorf("table %s not found", tableName)
	}
	model, err := dbModel.NewModel(tableName)
	if err != nil {
		return nil, err
	}
	info, err := dbModel.NewModelInfo(model)
	if err != nil {
		return nil, err
	}
	err = dbModel.Mapper.GetRowData(row, info)
	if err != nil {
		return nil, err
	}

	if uuid != "" {
		if err := info.SetField("_uuid", uuid); err != nil {
			return nil, err
		}
	}

	return model, nil
}