-
Notifications
You must be signed in to change notification settings - Fork 45
/
entity.go
162 lines (148 loc) · 4.39 KB
/
entity.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
package relgom
import (
"strings"
. "github.com/anz-bank/sysl/language/go/pkg/ast" //nolint:golint,stylecheck
"github.com/anz-bank/sysl/language/go/pkg/codegen"
sysl "github.com/anz-bank/sysl/pkg/sysl"
"github.com/anz-bank/sysl/pkg/syslutil"
)
func maskForField(i int) Expr {
return Index(Dot(I(builderRecv), "mask"), Int(i/64))
}
type entityGenerator struct {
*sourceGenerator
*modelScope
*commonModules
relation *sysl.Type_Relation
namedAttrs syslutil.NamedTypes
nAttrs int
haveKeys bool
t *sysl.Type
tname string
pkName string
dataName string
relationDataName string
builderName string
autoinc syslutil.StrSet
pkey syslutil.StrSet
patterns syslutil.StrSet
attrPatterns map[string]syslutil.StrSet
fkCount map[string]int
pkMask []uint64
requiredMask []uint64
}
func genFileForSyslTypeDecl(s *modelScope, tname string, t *sysl.Type) error {
relation := t.Type.(*sysl.Type_Relation_).Relation
nAttrs := len(relation.AttrDefs)
ename := ExportedName(tname)
g := &entityGenerator{
sourceGenerator: s.newSourceGenerator(),
modelScope: s,
relation: relation,
namedAttrs: syslutil.NamedTypesInSourceOrder(relation.AttrDefs),
nAttrs: nAttrs,
haveKeys: relation.PrimaryKey != nil,
t: t,
tname: ename,
pkName: NonExportedName(tname + "PK"),
dataName: NonExportedName(tname + "Data"),
relationDataName: NonExportedName(tname + "RelationData"),
builderName: ename + "Builder",
autoinc: syslutil.MakeStrSet(),
pkey: syslutil.MakeStrSet(),
patterns: syslutil.MakeStrSetFromAttr("patterns", t.Attrs),
attrPatterns: map[string]syslutil.StrSet{},
fkCount: map[string]int{},
pkMask: make([]uint64, (nAttrs+63)/64),
requiredMask: make([]uint64, (nAttrs+63)/64),
}
g.commonModules = newCommonModules(g.sourceGenerator)
if g.haveKeys {
for _, pk := range g.relation.PrimaryKey.AttrName {
g.pkey.Insert(pk)
}
}
for i, nt := range g.namedAttrs {
mask := uint64(1) << uint(i%64)
patterns := syslutil.MakeStrSetFromAttr("patterns", nt.Type.Attrs)
g.attrPatterns[nt.Name] = patterns
if g.pkey.Contains(nt.Name) {
g.pkMask[i/64] |= mask
}
info := g.typeInfoForSyslType(nt.Type)
if !info.opt {
g.requiredMask[i/64] |= mask
}
if g.attrPatterns[nt.Name].Contains("autoinc") {
g.autoinc.Insert(nt.Name)
g.requiredMask[i/64] &= ^mask
}
if fkey := info.fkey; fkey != nil {
path := strings.Join(fkey.Ref.Path, ".")
if n, has := g.fkCount[path]; has {
g.fkCount[path] = n + 1
} else {
g.fkCount[path] = 1
}
}
}
if len(g.autoinc) > 1 {
panic("> 1 autoinc field not supported")
}
decls := []Decl{}
decls = g.goAppendPKDecls(decls)
decls = g.goAppendTupleDataDecls(decls)
decls = g.goAppendTupleDecls(decls)
decls = g.goAppendBuilderDecls(decls)
decls = g.goAppendRelationDataDecls(decls)
decls = g.goAppendRelationDecls(decls)
decls = g.appendIterDecls(decls)
return g.genSourceForDecls(g.tname, decls...)
}
func (g *entityGenerator) isPkeyAttr(nt syslutil.NamedType) bool {
_, has := g.pkey[nt.Name]
return has
}
func (g *entityGenerator) goFieldsForSyslAttrDefs(
include syslutil.NamedTypePredicate,
export bool,
staging bool,
computeTagMap func(nt syslutil.NamedType) map[string]string,
) []Field {
fields := []Field{}
for _, nt := range g.namedAttrs.Where(include) {
field := g.goFieldForSyslAttrDef(nt.Name, nt.Type, export, staging)
if computeTagMap != nil {
field.Tag = codegen.Tag(computeTagMap(nt))
}
fields = append(fields, field)
}
return fields
}
func (g *entityGenerator) goFieldForSyslAttrDef(attrName string, attr *sysl.Type, export, staging bool) Field {
var id *Ident
if export {
id = ExportedID(attrName)
} else {
id = NonExportedID(attrName)
}
ti := g.typeInfoForSyslType(attr)
var typ Expr
if staging && ti.staging != nil {
typ = ti.staging
} else {
typ = ti.final
}
return Field{Names: []Ident{*id}, Type: typ}
}
type dotter = func(id string, ids ...string) Expr
func method(recv string, typ Expr, f func(recv string, dot dotter) FuncDecl) *FuncDecl {
fd := f(recv, func(id string, ids ...string) Expr {
return Dot(I(recv), id, ids...)
})
fd.Recv = Fields(Field{
Names: Idents(recv),
Type: typ,
}).Parens()
return &fd
}