d2compiler: Integrate d2ir (wip)
This commit is contained in:
parent
3e7bdc5468
commit
154c7e8947
5 changed files with 149 additions and 112 deletions
|
|
@ -111,13 +111,13 @@ func (c *compiler) compileMap(obj *d2graph.Object, m *d2ir.Map) {
|
|||
|
||||
switch obj.Attributes.Shape.Value {
|
||||
case d2target.ShapeClass:
|
||||
c.compileClass(obj, m)
|
||||
c.compileClass(obj)
|
||||
case d2target.ShapeSQLTable:
|
||||
c.compileSQLTable(obj, m)
|
||||
c.compileSQLTable(obj)
|
||||
}
|
||||
|
||||
for _, e := range m.Edges {
|
||||
c.compileEdge(obj, m, e)
|
||||
c.compileEdge(obj, e)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) {
|
|||
|
||||
obj = obj.EnsureChild([]string{f.Name})
|
||||
if f.Primary() != nil {
|
||||
c.compileLabel(obj, f)
|
||||
c.compileLabel(obj.Attributes, f)
|
||||
}
|
||||
if f.Map() != nil {
|
||||
c.compileMap(obj, f.Map())
|
||||
|
|
@ -167,11 +167,11 @@ func (c *compiler) compileLabel(attrs *d2graph.Attributes, f d2ir.Node) {
|
|||
attrs.Label.MapKey = f.LastPrimaryKey()
|
||||
}
|
||||
|
||||
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||
func (c *compiler) compileReserved(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||
scalar := f.Primary().Value
|
||||
switch f.Name {
|
||||
case "label":
|
||||
c.compileLabel(obj, f)
|
||||
c.compileLabel(attrs, f)
|
||||
case "shape":
|
||||
in := d2target.IsShape(scalar.ScalarString())
|
||||
if !in {
|
||||
|
|
@ -233,7 +233,13 @@ func (c *compiler) compileReserved(attrs *d2graph.Attributes, f d2ir.Node) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileStyle(attrs *d2graph.Attributes, f d2ir.Node) {
|
||||
func (c *compiler) compileStyle(attrs *d2graph.Attributes, m *d2ir.Map) {
|
||||
for _, f := range m.Fields {
|
||||
c.compileStyleField(attrs, f)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileStyleField(attrs *d2graph.Attributes, f *d2ir.Field) {
|
||||
scalar := f.Primary().Value
|
||||
err := attrs.Style.Apply(f.Name, scalar.ScalarString())
|
||||
if err != nil {
|
||||
|
|
@ -286,7 +292,7 @@ func (c *compiler) compileStyle(attrs *d2graph.Attributes, f d2ir.Node) {
|
|||
func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
||||
edge, err := obj.Connect(e.ID.SrcPath, e.ID.DstPath, e.ID.SrcArrow, e.ID.DstArrow, "")
|
||||
if err != nil {
|
||||
c.errorf(e, err.Error())
|
||||
c.errorf(e.References[0].AST(), err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -297,7 +303,7 @@ func (c *compiler) compileEdge(obj *d2graph.Object, e *d2ir.Edge) {
|
|||
for _, f := range e.Map().Fields {
|
||||
_, ok := d2graph.ReservedKeywords[f.Name]
|
||||
if !ok {
|
||||
c.errorf(mk, `edge map keys must be reserved keywords`)
|
||||
c.errorf(f.References[0].AST(), `edge map keys must be reserved keywords`)
|
||||
continue
|
||||
}
|
||||
c.compileEdgeField(edge, f)
|
||||
|
|
@ -320,7 +326,7 @@ func (c *compiler) compileEdgeField(edge *d2graph.Edge, f *d2ir.Field) {
|
|||
}
|
||||
|
||||
if f.Primary() != nil {
|
||||
c.compileLabel(edge, f)
|
||||
c.compileLabel(edge.Attributes, f)
|
||||
}
|
||||
|
||||
if f.Name == "source-arrowhead" || f.Name == "target-arrowhead" {
|
||||
|
|
@ -341,6 +347,7 @@ func (c *compiler) compileArrowheads(edge *d2graph.Edge, f *d2ir.Field) {
|
|||
}
|
||||
|
||||
for _, f2 := range f.Map().Fields {
|
||||
keyword := strings.ToLower(f2.Name)
|
||||
_, isReserved := d2graph.ReservedKeywords[keyword]
|
||||
if isReserved {
|
||||
c.compileReserved(attrs, f2)
|
||||
|
|
@ -352,7 +359,7 @@ func (c *compiler) compileArrowheads(edge *d2graph.Edge, f *d2ir.Field) {
|
|||
c.compileStyle(attrs, f2.Map())
|
||||
continue
|
||||
} else {
|
||||
c.errorf(mk, `source-arrowhead/target-arrowhead map keys must be reserved keywords`)
|
||||
c.errorf(f2.LastRef().AST(), `source-arrowhead/target-arrowhead map keys must be reserved keywords`)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
|
@ -370,24 +377,7 @@ var ShortToFullLanguageAliases = map[string]string{
|
|||
}
|
||||
var FullToShortLanguageAliases map[string]string
|
||||
|
||||
func (c *compiler) compileShapes(obj *d2graph.Object) {
|
||||
for _, obj := range obj.ChildrenArray {
|
||||
switch obj.Attributes.Shape.Value {
|
||||
case d2target.ShapeClass:
|
||||
c.compileClass(obj)
|
||||
case d2target.ShapeSQLTable:
|
||||
c.compileSQLTable(obj)
|
||||
}
|
||||
c.compileShapes(obj)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) compileClass(obj *d2graph.Object) {
|
||||
if len(m.Edges) > 0 {
|
||||
c.errorf(m.Edges[0].LastAST(), "class shapes cannot have edges inside")
|
||||
return
|
||||
}
|
||||
|
||||
obj.Class = &d2target.Class{}
|
||||
for _, f := range obj.ChildrenArray {
|
||||
visiblity := "public"
|
||||
|
|
@ -436,15 +426,7 @@ func (c *compiler) compileClass(obj *d2graph.Object) {
|
|||
}
|
||||
|
||||
func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
||||
if len(m.Edges) > 0 {
|
||||
c.errorf(m.Edges[0].LastAST(), "sql_table shapes cannot have edges inside")
|
||||
return
|
||||
}
|
||||
|
||||
obj.SQLTable = &d2target.SQLTable{}
|
||||
|
||||
parentID := obj.Parent.AbsID()
|
||||
tableIDPrefix := obj.AbsID() + "."
|
||||
for _, col := range obj.ChildrenArray {
|
||||
typ := col.Attributes.Label.Value
|
||||
if typ == col.IDVal {
|
||||
|
|
@ -480,12 +462,13 @@ func (c *compiler) compileSQLTable(obj *d2graph.Object) {
|
|||
}
|
||||
|
||||
func (c *compiler) validateKeys(obj *d2graph.Object, m *d2ir.Map) {
|
||||
for _, n := range m.Fields {
|
||||
for _, f := range m.Fields {
|
||||
c.validateKey(obj, f)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
||||
keyword := strings.ToLower(f.Name)
|
||||
_, isReserved := d2graph.ReservedKeywords[keyword]
|
||||
if isReserved {
|
||||
switch obj.Attributes.Shape.Value {
|
||||
|
|
@ -526,7 +509,7 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
|||
}
|
||||
default:
|
||||
if len(obj.Children) > 0 && (f.Name == "width" || f.Name == "height") {
|
||||
c.errorf(f.LastPrimaryKey(), mk.Range.End, fmt.Sprintf("%s cannot be used on container: %s", f.Name, obj.AbsID()))
|
||||
c.errorf(f.LastPrimaryKey(), fmt.Sprintf("%s cannot be used on container: %s", f.Name, obj.AbsID()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -540,12 +523,12 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
|
|||
}
|
||||
|
||||
if obj.Attributes.Shape.Value == d2target.ShapeImage {
|
||||
c.errorf(mk, "image shapes cannot have children.")
|
||||
c.errorf(obj.Attributes.Shape.MapKey, "image shapes cannot have children.")
|
||||
return
|
||||
}
|
||||
|
||||
obj = obj.HasChild([]string{f.Name})
|
||||
if f.Map() != nil {
|
||||
obj, ok := obj.HasChild([]string{f.Name})
|
||||
if ok && f.Map() != nil {
|
||||
c.validateKeys(obj, f.Map())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -973,7 +973,18 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
|
|||
}
|
||||
e.initIndex()
|
||||
|
||||
addSQLTableColumnIndexes(e, srcID, dstID, obj, src, dst)
|
||||
|
||||
obj.Graph.Edges = append(obj.Graph.Edges, e)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func addSQLTableColumnIndexes(e *Edge, srcID, dstID []string, obj, src, dst *Object) {
|
||||
if src.Attributes.Shape.Value == d2target.ShapeSQLTable {
|
||||
if src == dst {
|
||||
// Ignore edge to column inside table.
|
||||
return
|
||||
}
|
||||
objAbsID := obj.AbsIDArray()
|
||||
srcAbsID := src.AbsIDArray()
|
||||
if len(objAbsID) + len(srcID) > len(srcAbsID) {
|
||||
|
|
@ -1001,10 +1012,6 @@ func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
obj.Graph.Edges = append(obj.Graph.Edges, e)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// TODO: Treat undirectional/bidirectional edge here and in HasEdge flipped. Same with
|
||||
|
|
|
|||
|
|
@ -15,7 +15,16 @@ func (c *compiler) errorf(n d2ast.Node, f string, v ...interface{}) {
|
|||
|
||||
func Compile(ast *d2ast.Map) (*Map, error) {
|
||||
c := &compiler{}
|
||||
m := &Map{}
|
||||
m := &Map{
|
||||
parent: &Field{
|
||||
Name: "",
|
||||
References: []*FieldReference{{
|
||||
Context: &RefContext{
|
||||
Scope: ast,
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
c.compileMap(m, ast)
|
||||
c.compileScenarios(m)
|
||||
c.compileSteps(m)
|
||||
|
|
@ -160,7 +169,7 @@ func (c *compiler) compileEdges(dst *Map, refctx *RefContext) {
|
|||
continue
|
||||
}
|
||||
e = ea[0]
|
||||
e.References = append(e.References, EdgeReference{
|
||||
e.References = append(e.References, &EdgeReference{
|
||||
Context: refctx,
|
||||
})
|
||||
dst.appendFieldReferences(0, refctx.Edge.Src, refctx)
|
||||
|
|
|
|||
166
d2ir/d2ir.go
166
d2ir/d2ir.go
|
|
@ -30,11 +30,6 @@ type Node interface {
|
|||
LastPrimaryKey() *d2ast.Key
|
||||
}
|
||||
|
||||
type Reference interface {
|
||||
reference()
|
||||
AST() d2ast.Node
|
||||
}
|
||||
|
||||
var _ Node = &Scalar{}
|
||||
var _ Node = &Field{}
|
||||
var _ Node = &Edge{}
|
||||
|
|
@ -109,6 +104,26 @@ func (n *Edge) String() string { return d2format.Format(n.ast()) }
|
|||
func (n *Array) String() string { return d2format.Format(n.ast()) }
|
||||
func (n *Map) String() string { return d2format.Format(n.ast()) }
|
||||
|
||||
func (n *Scalar) LastRef() Reference { return parentRef(n) }
|
||||
func (n *Map) LastRef() Reference { return parentRef(n) }
|
||||
func (n *Array) LastRef() Reference { return parentRef(n) }
|
||||
|
||||
func (n *Scalar) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||
func (n *Map) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||
func (n *Array) LastPrimaryKey() *d2ast.Key { return parentPrimaryKey(n) }
|
||||
|
||||
type Reference interface {
|
||||
reference()
|
||||
// Most specific AST node for the reference.
|
||||
AST() d2ast.Node
|
||||
}
|
||||
|
||||
var _ Reference = &FieldReference{}
|
||||
var _ Reference = &EdgeReference{}
|
||||
|
||||
func (r *FieldReference) reference() {}
|
||||
func (r *EdgeReference) reference() {}
|
||||
|
||||
type Scalar struct {
|
||||
parent Node
|
||||
Value d2ast.Scalar `json:"value"`
|
||||
|
|
@ -174,18 +189,14 @@ func (m *Map) CopyBase(newParent Node) *Map {
|
|||
|
||||
// Root reports whether the Map is the root of the D2 tree.
|
||||
func (m *Map) Root() bool {
|
||||
return m.parent == nil
|
||||
}
|
||||
|
||||
func (f *Map) LastRef() *MapReference {
|
||||
if f.parent == nil {
|
||||
return nil
|
||||
// m.parent exists even on the root map as we store the root AST in
|
||||
// m.parent.References[0].Context.Map for reporting error messages about the whole IR.
|
||||
// Or if otherwise needed.
|
||||
f, ok := m.parent.(*Field)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return f.References[len(f.References)-1]
|
||||
}
|
||||
|
||||
func (f *Map) LastAST() d2ast.Node {
|
||||
return f.LastRef().String
|
||||
return f.Name == ""
|
||||
}
|
||||
|
||||
type LayerKind string
|
||||
|
|
@ -199,25 +210,26 @@ const (
|
|||
// NodeLayerKind reports whether n represents the root of a layer.
|
||||
// n should be *Field or *Map
|
||||
func NodeLayerKind(n Node) LayerKind {
|
||||
var f *Field
|
||||
switch n := n.(type) {
|
||||
case *Field:
|
||||
n = ParentField(n)
|
||||
if n != nil {
|
||||
switch n.Name {
|
||||
case "layers":
|
||||
return LayerLayer
|
||||
case "scenarios":
|
||||
return LayerScenario
|
||||
case "steps":
|
||||
return LayerStep
|
||||
}
|
||||
}
|
||||
f = ParentField(n)
|
||||
case *Map:
|
||||
f := ParentField(n)
|
||||
if f == nil {
|
||||
return LayerLayer
|
||||
}
|
||||
return NodeLayerKind(f)
|
||||
f = ParentField(n)
|
||||
}
|
||||
if f == nil {
|
||||
return ""
|
||||
}
|
||||
switch f.Name {
|
||||
case "layers":
|
||||
return LayerLayer
|
||||
case "scenarios":
|
||||
return LayerScenario
|
||||
case "steps":
|
||||
return LayerStep
|
||||
case "":
|
||||
// root
|
||||
return LayerLayer
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
@ -230,7 +242,7 @@ type Field struct {
|
|||
Primary_ *Scalar `json:"primary,omitempty"`
|
||||
Composite Composite `json:"composite,omitempty"`
|
||||
|
||||
References []FieldReference `json:"references,omitempty"`
|
||||
References []*FieldReference `json:"references,omitempty"`
|
||||
}
|
||||
|
||||
func (f *Field) Copy(newParent Node) Node {
|
||||
|
|
@ -238,7 +250,7 @@ func (f *Field) Copy(newParent Node) Node {
|
|||
f = &tmp
|
||||
|
||||
f.parent = newParent.(*Map)
|
||||
f.References = append([]FieldReference(nil), f.References...)
|
||||
f.References = append([]*FieldReference(nil), f.References...)
|
||||
if f.Primary_ != nil {
|
||||
f.Primary_ = f.Primary_.Copy(f).(*Scalar)
|
||||
}
|
||||
|
|
@ -248,7 +260,7 @@ func (f *Field) Copy(newParent Node) Node {
|
|||
return f
|
||||
}
|
||||
|
||||
func (f *Field) LastPrimaryRef() *FieldReference {
|
||||
func (f *Field) lastPrimaryRef() *FieldReference {
|
||||
inEdge := ParentEdge(f) != nil
|
||||
for i := len(f.References) - 1; i >= 0; i-- {
|
||||
fr := f.References[i]
|
||||
|
|
@ -266,21 +278,17 @@ func (f *Field) LastPrimaryRef() *FieldReference {
|
|||
}
|
||||
|
||||
func (f *Field) LastPrimaryKey() *d2ast.Key {
|
||||
fr := f.LastModification()
|
||||
fr := f.lastPrimaryRef()
|
||||
if fr == nil {
|
||||
return nil
|
||||
}
|
||||
return fr.Context.Key
|
||||
}
|
||||
|
||||
func (f *Field) LastRef() *FieldReference {
|
||||
func (f *Field) LastRef() Reference {
|
||||
return f.References[len(f.References)-1]
|
||||
}
|
||||
|
||||
func (f *Field) LastAST() d2ast.Node {
|
||||
return f.LastRef().String
|
||||
}
|
||||
|
||||
type EdgeID struct {
|
||||
SrcPath []string `json:"src_path"`
|
||||
SrcArrow bool `json:"src_arrow"`
|
||||
|
|
@ -396,7 +404,7 @@ type Edge struct {
|
|||
Primary_ *Scalar `json:"primary,omitempty"`
|
||||
Map_ *Map `json:"map,omitempty"`
|
||||
|
||||
References []EdgeReference `json:"references,omitempty"`
|
||||
References []*EdgeReference `json:"references,omitempty"`
|
||||
}
|
||||
|
||||
func (e *Edge) Copy(newParent Node) Node {
|
||||
|
|
@ -404,7 +412,7 @@ func (e *Edge) Copy(newParent Node) Node {
|
|||
e = &tmp
|
||||
|
||||
e.parent = newParent.(*Map)
|
||||
e.References = append([]EdgeReference(nil), e.References...)
|
||||
e.References = append([]*EdgeReference(nil), e.References...)
|
||||
if e.Primary_ != nil {
|
||||
e.Primary_ = e.Primary_.Copy(e).(*Scalar)
|
||||
}
|
||||
|
|
@ -414,7 +422,7 @@ func (e *Edge) Copy(newParent Node) Node {
|
|||
return e
|
||||
}
|
||||
|
||||
func (e *Edge) LastPrimaryRef() *EdgeReference {
|
||||
func (e *Edge) lastPrimaryRef() *EdgeReference {
|
||||
for i := len(e.References) - 1; i >= 0; i-- {
|
||||
fr := e.References[i]
|
||||
if fr.Context.Key.EdgeKey == nil {
|
||||
|
|
@ -425,21 +433,17 @@ func (e *Edge) LastPrimaryRef() *EdgeReference {
|
|||
}
|
||||
|
||||
func (e *Edge) LastPrimaryKey() *d2ast.Key {
|
||||
fr := f.LastModification()
|
||||
if fr == nil {
|
||||
er := e.lastPrimaryRef()
|
||||
if er == nil {
|
||||
return nil
|
||||
}
|
||||
return fr.Context.Key
|
||||
return er.Context.Key
|
||||
}
|
||||
|
||||
func (e *Edge) LastRef() *EdgeReference {
|
||||
func (e *Edge) LastRef() Reference {
|
||||
return e.References[len(e.References)-1]
|
||||
}
|
||||
|
||||
func (e *Edge) LastAST() d2ast.Node {
|
||||
return e.LastRef().Context.Edge
|
||||
}
|
||||
|
||||
type Array struct {
|
||||
parent Node
|
||||
Values []Value `json:"values"`
|
||||
|
|
@ -464,27 +468,39 @@ type FieldReference struct {
|
|||
Context *RefContext `json:"context"`
|
||||
}
|
||||
|
||||
func (kr FieldReference) KeyPathIndex() int {
|
||||
for i, sb := range kr.KeyPath.Path {
|
||||
if sb.Unbox() == kr.String {
|
||||
func (fr *FieldReference) KeyPathIndex() int {
|
||||
for i, sb := range fr.KeyPath.Path {
|
||||
if sb.Unbox() == fr.String {
|
||||
return i
|
||||
}
|
||||
}
|
||||
panic("d2ir.KeyReference.KeyPathIndex: String not in KeyPath?")
|
||||
}
|
||||
|
||||
func (kr FieldReference) EdgeDest() bool {
|
||||
return kr.KeyPath == kr.Context.Edge.Dst
|
||||
func (fr *FieldReference) EdgeDest() bool {
|
||||
return fr.KeyPath == fr.Context.Edge.Dst
|
||||
}
|
||||
|
||||
func (kr FieldReference) InEdge() bool {
|
||||
return kr.Context.Edge != nil
|
||||
func (fr *FieldReference) InEdge() bool {
|
||||
return fr.Context.Edge != nil
|
||||
}
|
||||
|
||||
func (fr *FieldReference) AST() d2ast.Node {
|
||||
if fr.String == nil {
|
||||
// Root map.
|
||||
return fr.Context.Scope
|
||||
}
|
||||
return fr.String
|
||||
}
|
||||
|
||||
type EdgeReference struct {
|
||||
Context *RefContext `json:"context"`
|
||||
}
|
||||
|
||||
func (er *EdgeReference) AST() d2ast.Node {
|
||||
return er.Context.Edge
|
||||
}
|
||||
|
||||
type RefContext struct {
|
||||
Edge *d2ast.Edge `json:"edge"`
|
||||
Key *d2ast.Key `json:"key"`
|
||||
|
|
@ -628,7 +644,7 @@ func (m *Map) ensureField(i int, kp *d2ast.KeyPath, refctx *RefContext) (*Field,
|
|||
continue
|
||||
}
|
||||
|
||||
f.References = append(f.References, FieldReference{
|
||||
f.References = append(f.References, &FieldReference{
|
||||
String: kp.Path[i].Unbox(),
|
||||
KeyPath: kp,
|
||||
Context: refctx,
|
||||
|
|
@ -651,7 +667,7 @@ func (m *Map) ensureField(i int, kp *d2ast.KeyPath, refctx *RefContext) (*Field,
|
|||
f := &Field{
|
||||
parent: m,
|
||||
Name: head,
|
||||
References: []FieldReference{{
|
||||
References: []*FieldReference{{
|
||||
String: kp.Path[i].Unbox(),
|
||||
KeyPath: kp,
|
||||
Context: refctx,
|
||||
|
|
@ -773,7 +789,7 @@ func (m *Map) CreateEdge(eid *EdgeID, refctx *RefContext) (*Edge, error) {
|
|||
e := &Edge{
|
||||
parent: m,
|
||||
ID: eid,
|
||||
References: []EdgeReference{{
|
||||
References: []*EdgeReference{{
|
||||
Context: refctx,
|
||||
}},
|
||||
}
|
||||
|
|
@ -868,7 +884,7 @@ func (m *Map) appendFieldReferences(i int, kp *d2ast.KeyPath, refctx *RefContext
|
|||
return
|
||||
}
|
||||
|
||||
f.References = append(f.References, FieldReference{
|
||||
f.References = append(f.References, &FieldReference{
|
||||
String: sb.Unbox(),
|
||||
KeyPath: kp,
|
||||
Context: refctx,
|
||||
|
|
@ -945,3 +961,27 @@ func hasLayerKeywords(ida ...string) int {
|
|||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func parentRef(n Node) Reference {
|
||||
f := ParentField(n)
|
||||
if f != nil {
|
||||
return f.LastRef()
|
||||
}
|
||||
e := ParentEdge(n)
|
||||
if e != nil {
|
||||
return e.LastRef()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parentPrimaryKey(n Node) *d2ast.Key {
|
||||
f := ParentField(n)
|
||||
if f != nil {
|
||||
return f.LastPrimaryKey()
|
||||
}
|
||||
e := ParentEdge(n)
|
||||
if e != nil {
|
||||
return e.LastPrimaryKey()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,10 @@ func TestCopy(t *testing.T) {
|
|||
Composite: a,
|
||||
}
|
||||
e := &d2ir.Edge{
|
||||
|
||||
Primary_: s,
|
||||
Map_: m2,
|
||||
}
|
||||
m := &d2ir.Map{
|
||||
|
||||
Fields: []*d2ir.Field{f},
|
||||
Edges: []*d2ir.Edge{e},
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue