-
Notifications
You must be signed in to change notification settings - Fork 0
/
descriptor.go
182 lines (153 loc) · 5.3 KB
/
descriptor.go
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package resource
import (
"sort"
"github.com/iancoleman/strcase"
"github.com/cloudwan/goten-sdk/runtime/object"
)
// Descriptor allows writing code operating on resources without knowing exact type.
// It can be used to create Resource instance, all derivative types, access information
// about name type.
type Descriptor interface {
NewResource() Resource
NewResourceChange() ResourceChange
NewResourceName() Name
NewResourceCursor() Cursor
NewResourceFilter() Filter
NewResourceOrderBy() OrderBy
NewResourcePager() PagerQuery
NewResourceFieldMask() object.FieldMask
NewGetQuery() GetQuery
NewListQuery() ListQuery
NewSearchQuery() SearchQuery
NewWatchQuery() WatchQuery
NewQueryResultSnapshot() QueryResultSnapshot
NewQueryResultChange() QueryResultChange
NewResourceList(size, reserved int) ResourceList
NewResourceChangeList(size, reserved int) ResourceChangeList
NewNameList(size, reserved int) NameList
NewReferenceList(size, reserved int) ReferenceList
NewParentNameList(size, reserved int) ParentNameList
NewParentReferenceList(size, reserved int) ParentReferenceList
NewResourceMap(reserved int) ResourceMap
NewResourceChangeMap(reserved int) ResourceChangeMap
GetResourceTypeName() *TypeName
GetNameDescriptor() *NameDescriptor
CanBeParentless() bool
GetParentResDescriptors() []Descriptor
SupportsMetadata() bool
// ParseFieldPath returns a field path matching given string. If does not exist, error
// is returned and returned interface is None.
ParseFieldPath(raw string) (object.FieldPath, error)
ParseResourceName(raw string) (Name, error)
}
type NameDescriptor struct {
fieldPath object.FieldPath
patternFieldName string
idFieldName string
parentIdFieldNames []string
namePatterns []NamePattern
}
func NewNameDescriptor(fp object.FieldPath, patternFieldName, idFieldName string,
parentIdFieldNames []string, namePatterns []NamePattern) *NameDescriptor {
return &NameDescriptor{
fieldPath: fp,
patternFieldName: patternFieldName,
idFieldName: idFieldName,
parentIdFieldNames: parentIdFieldNames,
namePatterns: namePatterns,
}
}
func (d *NameDescriptor) GetFieldPath() object.FieldPath {
return d.fieldPath
}
func (d *NameDescriptor) GetPatternFieldName() string {
return d.patternFieldName
}
func (d *NameDescriptor) GetIdFieldName() string {
return d.idFieldName
}
func (d *NameDescriptor) GetParentIdFieldNames() []string {
return d.parentIdFieldNames
}
func (d *NameDescriptor) GetAllSegmentIdFieldNames() []string {
res := d.parentIdFieldNames
return append(res, d.idFieldName)
}
func (d *NameDescriptor) GetNamePatterns() []NamePattern {
return d.namePatterns
}
type TypeName struct {
singular string
plural string
domain string
version string
}
func NewTypeName(singular, plural, domain, version string) *TypeName {
return &TypeName{singular: singular, plural: plural, domain: domain, version: version}
}
func (rtn *TypeName) Singular() string {
return rtn.singular
}
func (rtn *TypeName) Plural() string {
return rtn.plural
}
func (rtn *TypeName) Version() string {
return rtn.version
}
func (rtn *TypeName) JSONSingular() string {
return strcase.ToLowerCamel(rtn.singular)
}
func (rtn *TypeName) JSONPlural() string {
return strcase.ToLowerCamel(rtn.plural)
}
func (rtn *TypeName) FullyQualifiedTypeName() string {
return rtn.domain + "/" + rtn.singular
}
func (rtn *TypeName) ServiceDomain() string {
return rtn.domain
}
func SortedResourceIdRefNameSegments(descriptor Descriptor) []string {
nameToSegment := make(map[string]NameSegmentPattern)
havingOnTheLeftSide := make(map[string]map[string]NameSegmentPattern)
havingOnTheRightSide := make(map[string]map[string]NameSegmentPattern)
for _, namePattern := range descriptor.GetNameDescriptor().GetNamePatterns() {
segmentPatterns := namePattern.SegmentPatterns()
for i, segmentPattern := range segmentPatterns {
collection := segmentPattern.CollectionLowerJson
nameToSegment[collection] = segmentPattern
if havingOnTheLeftSide[collection] == nil {
havingOnTheLeftSide[collection] = make(map[string]NameSegmentPattern)
}
if havingOnTheRightSide[collection] == nil {
havingOnTheRightSide[collection] = make(map[string]NameSegmentPattern)
}
onTheLeftSide := segmentPatterns[0:i]
for _, segmentOnTheLeftSide := range onTheLeftSide {
leftCollection := segmentOnTheLeftSide.CollectionLowerJson
havingOnTheRightSide[leftCollection][collection] = segmentPattern
havingOnTheLeftSide[collection][leftCollection] = segmentOnTheLeftSide
}
}
}
result := make([]string, 0)
for len(havingOnTheLeftSide) > 0 {
toAppend := make([]NameSegmentPattern, 0)
for segmentName, remainingLeftNeighbours := range havingOnTheLeftSide {
if len(remainingLeftNeighbours) == 0 {
toAppend = append(toAppend, nameToSegment[segmentName])
}
}
sort.Slice(toAppend, func(i, j int) bool {
return toAppend[i].IdFieldName() < toAppend[j].IdFieldName()
})
for _, nameSegment := range toAppend {
delete(havingOnTheLeftSide, nameSegment.CollectionLowerJson)
neighboursOnRight := havingOnTheRightSide[nameSegment.CollectionLowerJson]
for rightNeighbourName := range neighboursOnRight {
delete(havingOnTheLeftSide[rightNeighbourName], nameSegment.CollectionLowerJson)
}
result = append(result, nameSegment.IdFieldName())
}
}
return result
}