diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go
index 6fbe5268f..3fb25014b 100644
--- a/d2layouts/d2elklayout/layout.go
+++ b/d2layouts/d2elklayout/layout.go
@@ -41,10 +41,38 @@ type ELKNode struct {
Width float64 `json:"width"`
Height float64 `json:"height"`
Children []*ELKNode `json:"children,omitempty"`
+ Ports []*ELKPort `json:"ports,omitempty"`
Labels []*ELKLabel `json:"labels,omitempty"`
LayoutOptions *elkOpts `json:"layoutOptions,omitempty"`
}
+type PortSide string
+
+const (
+ South PortSide = "SOUTH"
+ North PortSide = "NORTH"
+ East PortSide = "EAST"
+ West PortSide = "WEST"
+)
+
+type Direction string
+
+const (
+ Down Direction = "DOWN"
+ Up Direction = "UP"
+ Right Direction = "RIGHT"
+ Left Direction = "LEFT"
+)
+
+type ELKPort struct {
+ ID string `json:"id"`
+ X float64 `json:"x"`
+ Y float64 `json:"y"`
+ Width float64 `json:"width"`
+ Height float64 `json:"height"`
+ LayoutOptions *elkOpts `json:"layoutOptions,omitempty"`
+}
+
type ELKLabel struct {
Text string `json:"text"`
X float64 `json:"x"`
@@ -101,16 +129,16 @@ var port_spacing = 40.
var edge_node_spacing = 40
type elkOpts struct {
- EdgeNode int `json:"elk.spacing.edgeNode,omitempty"`
- FixedAlignment string `json:"elk.layered.nodePlacement.bk.fixedAlignment,omitempty"`
- Thoroughness int `json:"elk.layered.thoroughness,omitempty"`
- EdgeEdgeBetweenLayersSpacing int `json:"elk.layered.spacing.edgeEdgeBetweenLayers,omitempty"`
- Direction string `json:"elk.direction"`
- HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"`
- InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"`
- ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"`
- ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"`
- CycleBreakingStrategy string `json:"elk.layered.cycleBreaking.strategy,omitempty"`
+ EdgeNode int `json:"elk.spacing.edgeNode,omitempty"`
+ FixedAlignment string `json:"elk.layered.nodePlacement.bk.fixedAlignment,omitempty"`
+ Thoroughness int `json:"elk.layered.thoroughness,omitempty"`
+ EdgeEdgeBetweenLayersSpacing int `json:"elk.layered.spacing.edgeEdgeBetweenLayers,omitempty"`
+ Direction Direction `json:"elk.direction"`
+ HierarchyHandling string `json:"elk.hierarchyHandling,omitempty"`
+ InlineEdgeLabels bool `json:"elk.edgeLabels.inline,omitempty"`
+ ForceNodeModelOrder bool `json:"elk.layered.crossingMinimization.forceNodeModelOrder,omitempty"`
+ ConsiderModelOrder string `json:"elk.layered.considerModelOrder.strategy,omitempty"`
+ CycleBreakingStrategy string `json:"elk.layered.cycleBreaking.strategy,omitempty"`
SelfLoopDistribution string `json:"elk.layered.edgeRouting.selfLoopDistribution,omitempty"`
@@ -118,6 +146,9 @@ type elkOpts struct {
ContentAlignment string `json:"elk.contentAlignment,omitempty"`
NodeSizeMinimum string `json:"elk.nodeSize.minimum,omitempty"`
+ PortSide PortSide `json:"elk.port.side,omitempty"`
+ PortConstraints string `json:"elk.portConstraints,omitempty"`
+
ConfigurableOpts
}
@@ -171,15 +202,15 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
switch g.Root.Direction.Value {
case "down":
- elkGraph.LayoutOptions.Direction = "DOWN"
+ elkGraph.LayoutOptions.Direction = Down
case "up":
- elkGraph.LayoutOptions.Direction = "UP"
+ elkGraph.LayoutOptions.Direction = Up
case "right":
- elkGraph.LayoutOptions.Direction = "RIGHT"
+ elkGraph.LayoutOptions.Direction = Right
case "left":
- elkGraph.LayoutOptions.Direction = "LEFT"
+ elkGraph.LayoutOptions.Direction = Left
default:
- elkGraph.LayoutOptions.Direction = "DOWN"
+ elkGraph.LayoutOptions.Direction = Down
}
// set label and icon positions for ELK
@@ -257,9 +288,9 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
switch elkGraph.LayoutOptions.Direction {
- case "DOWN", "UP":
+ case Down, Up:
n.LayoutOptions.NodeSizeMinimum = fmt.Sprintf("(%d, %d)", int(math.Ceil(height)), int(math.Ceil(width)))
- case "RIGHT", "LEFT":
+ case Right, Left:
n.LayoutOptions.NodeSizeMinimum = fmt.Sprintf("(%d, %d)", int(math.Ceil(width)), int(math.Ceil(height)))
}
} else {
@@ -287,6 +318,33 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
} else {
elkNodes[parent].Children = append(elkNodes[parent].Children, n)
}
+
+ if obj.SQLTable != nil {
+ n.LayoutOptions.PortConstraints = "FIXED_POS"
+ columns := obj.SQLTable.Columns
+ colHeight := n.Height / float64(len(columns)+1)
+ n.Ports = make([]*ELKPort, 0, len(columns)*2)
+ var srcSide, dstSide PortSide
+ switch elkGraph.LayoutOptions.Direction {
+ case Left:
+ srcSide, dstSide = West, East
+ default:
+ srcSide, dstSide = East, West
+ }
+ for i, col := range columns {
+ n.Ports = append(n.Ports, &ELKPort{
+ ID: srcPortID(obj, col.Name.Label),
+ Y: float64(i+1)*colHeight + colHeight/2,
+ LayoutOptions: &elkOpts{PortSide: srcSide},
+ })
+ n.Ports = append(n.Ports, &ELKPort{
+ ID: dstPortID(obj, col.Name.Label),
+ Y: float64(i+1)*colHeight + colHeight/2,
+ LayoutOptions: &elkOpts{PortSide: dstSide},
+ })
+ }
+ }
+
elkNodes[obj] = n
})
@@ -325,11 +383,64 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
- for _, edge := range g.Edges {
+ var srcSide, dstSide PortSide
+ switch elkGraph.LayoutOptions.Direction {
+ case Up:
+ srcSide, dstSide = North, South
+ default:
+ srcSide, dstSide = South, North
+ }
+
+ ports := map[struct {
+ obj *d2graph.Object
+ side PortSide
+ }][]*ELKPort{}
+
+ for ei, edge := range g.Edges {
+ var src, dst string
+
+ switch {
+ case edge.SrcTableColumnIndex != nil:
+ src = srcPortID(edge.Src, edge.Src.SQLTable.Columns[*edge.SrcTableColumnIndex].Name.Label)
+ case edge.Src.SQLTable != nil:
+ p := &ELKPort{
+ ID: fmt.Sprintf("%s.%d", srcPortID(edge.Src, "__root__"), ei),
+ LayoutOptions: &elkOpts{PortSide: srcSide},
+ }
+ src = p.ID
+ elkNodes[edge.Src].Ports = append(elkNodes[edge.Src].Ports, p)
+ k := struct {
+ obj *d2graph.Object
+ side PortSide
+ }{edge.Src, srcSide}
+ ports[k] = append(ports[k], p)
+ default:
+ src = edge.Src.AbsID()
+ }
+
+ switch {
+ case edge.DstTableColumnIndex != nil:
+ dst = dstPortID(edge.Dst, edge.Dst.SQLTable.Columns[*edge.DstTableColumnIndex].Name.Label)
+ case edge.Dst.SQLTable != nil:
+ p := &ELKPort{
+ ID: fmt.Sprintf("%s.%d", dstPortID(edge.Dst, "__root__"), ei),
+ LayoutOptions: &elkOpts{PortSide: dstSide},
+ }
+ dst = p.ID
+ elkNodes[edge.Dst].Ports = append(elkNodes[edge.Dst].Ports, p)
+ k := struct {
+ obj *d2graph.Object
+ side PortSide
+ }{edge.Dst, dstSide}
+ ports[k] = append(ports[k], p)
+ default:
+ dst = edge.Dst.AbsID()
+ }
+
e := &ELKEdge{
ID: edge.AbsID(),
- Sources: []string{edge.Src.AbsID()},
- Targets: []string{edge.Dst.AbsID()},
+ Sources: []string{src},
+ Targets: []string{dst},
}
if edge.Label.Value != "" {
e.Labels = append(e.Labels, &ELKLabel{
@@ -345,6 +456,14 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
elkEdges[edge] = e
}
+ for k, ports := range ports {
+ width := elkNodes[k.obj].Width
+ spacing := width / float64(len(ports)+1)
+ for i, p := range ports {
+ p.X = float64(i+1) * spacing
+ }
+ }
+
raw, err := json.Marshal(elkGraph)
if err != nil {
return err
@@ -507,6 +626,14 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
return nil
}
+func srcPortID(obj *d2graph.Object, column string) string {
+ return fmt.Sprintf("%s.%s.src", obj.AbsID(), column)
+}
+
+func dstPortID(obj *d2graph.Object, column string) string {
+ return fmt.Sprintf("%s.%s.dst", obj.AbsID(), column)
+}
+
// deleteBends is a shim for ELK to delete unnecessary bends
// see https://github.com/terrastruct/d2/issues/1030
func deleteBends(g *d2graph.Graph) {
@@ -525,30 +652,42 @@ func deleteBends(g *d2graph.Graph) {
var corner *geo.Point
var end *geo.Point
+ var columnIndex *int
if isSource {
start = e.Route[0]
corner = e.Route[1]
end = e.Route[2]
endpoint = e.Src
+ columnIndex = e.SrcTableColumnIndex
} else {
start = e.Route[len(e.Route)-1]
corner = e.Route[len(e.Route)-2]
end = e.Route[len(e.Route)-3]
endpoint = e.Dst
+ columnIndex = e.DstTableColumnIndex
}
isHorizontal := math.Ceil(start.Y) == math.Ceil(corner.Y)
dx, dy := endpoint.GetModifierElementAdjustments()
// Make sure it's still attached
- if isHorizontal {
+ switch {
+ case columnIndex != nil:
+ rowHeight := endpoint.Height / float64(len(endpoint.SQLTable.Columns)+1)
+ rowCenter := endpoint.TopLeft.Y + rowHeight*float64(*columnIndex+1) + rowHeight/2
+
+ // for row connections new Y coordinate should be within 1/3 row height from the row center
+ if math.Abs(end.Y-rowCenter) > rowHeight/3 {
+ continue
+ }
+ case isHorizontal:
if end.Y <= endpoint.TopLeft.Y+10-dy {
continue
}
if end.Y >= endpoint.TopLeft.Y+endpoint.Height-10 {
continue
}
- } else {
+ default:
if end.X <= endpoint.TopLeft.X+10 {
continue
}
@@ -610,12 +749,21 @@ func deleteBends(g *d2graph.Graph) {
}
}
}
+
// Get rid of ladders
// ELK likes to do these for some reason
// . ┌─
// . ┌─┘
// . │
// We want to transform these into L-shapes
+
+ points := map[geo.Point]int{}
+ for _, e := range g.Edges {
+ for _, p := range e.Route {
+ points[*p]++
+ }
+ }
+
for ei, e := range g.Edges {
if len(e.Route) < 6 {
continue
@@ -631,6 +779,11 @@ func deleteBends(g *d2graph.Graph) {
end := e.Route[i+2]
after := e.Route[i+3]
+ if c, _ := points[*corner]; c > 1 {
+ // If corner is shared with another edge, they merge
+ continue
+ }
+
// S-shape on sources only concerned one segment, since the other was just along the bound of endpoint
// These concern two segments
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index c9fdfc0dc..c62d1d625 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -1190,18 +1190,21 @@ a -> md -> b
`,
}, {
name: "sql_tables",
- script: `users: {
+ script: `
+direction: left
+
+users: {
shape: sql_table
- id: int
+ id: int { constraint: primary_key }
name: string
email: string
password: string
- last_login: datetime { constraint: primary_key }
+ last_login: datetime
}
products: {
shape: sql_table
- id: int
+ id: int { constraint: primary_key }
price: decimal
sku: string
name: string
@@ -1209,22 +1212,41 @@ products: {
orders: {
shape: sql_table
- id: int
- user_id: int
- product_id: int
+ id: int { constraint: primary_key }
+ user_id: int { constraint: foreign_key }
+ product_id: int { constraint: foreign_key }
}
shipments: {
shape: sql_table
- id: int
- order_id: int
+ id: int { constraint: primary_key }
+ order_id: int { constraint: foreign_key }
tracking_number: string
status: string
}
-users.id <-> orders.user_id
-products.id <-> orders.product_id
-shipments.order_id <-> orders.id`,
+orders.user_id -> users.id
+orders.product_id -> products.id
+shipments.order_id -> orders.id`,
+ }, {
+ name: "sql_table_row_connections",
+ script: `
+direction: left
+
+a: {
+ shape: sql_table
+ id: int { constraint: primary_key }
+}
+
+b: {
+ shape: sql_table
+ id: int { constraint: primary_key }
+ a_1: int { constraint: foreign_key }
+ a_2: int { constraint: foreign_key }
+}
+
+b.a_1 -> a.id
+b.a_2 -> a.id`,
}, {
name: "images",
script: `a: {
@@ -2364,20 +2386,27 @@ a -> b
{
name: "sql_table_tooltip_animated",
script: `
+direction: left
+
x: {
shape: sql_table
- y
+ y { constraint: primary_key }
tooltip: I like turtles
}
a: {
shape: sql_table
- b
+ b { constraint: foreign_key }
}
-x.y -> a.b: {
+a.b <-> x.y: {
style.animated: true
- target-arrowhead.shape: cf-many
+ source-arrowhead: {
+ shape: cf-many
+ }
+ target-arrowhead: {
+ shape: cf-one
+ }
}
`,
},
diff --git a/e2etests/testdata/stable/ent2d2_basic/elk/board.exp.json b/e2etests/testdata/stable/ent2d2_basic/elk/board.exp.json
index 9fd0bdcae..296c132a9 100644
--- a/e2etests/testdata/stable/ent2d2_basic/elk/board.exp.json
+++ b/e2etests/testdata/stable/ent2d2_basic/elk/board.exp.json
@@ -7,8 +7,8 @@
"id": "User",
"type": "sql_table",
"pos": {
- "x": 411,
- "y": 12
+ "x": 376,
+ "y": 110
},
"width": 280,
"height": 144,
@@ -142,7 +142,7 @@
"type": "sql_table",
"pos": {
"x": 12,
- "y": 377
+ "y": 573
},
"width": 194,
"height": 108,
@@ -246,7 +246,7 @@
"type": "sql_table",
"pos": {
"x": 226,
- "y": 377
+ "y": 573
},
"width": 194,
"height": 108,
@@ -350,7 +350,7 @@
"type": "sql_table",
"pos": {
"x": 440,
- "y": 377
+ "y": 573
},
"width": 222,
"height": 144,
@@ -482,7 +482,7 @@
"type": "sql_table",
"pos": {
"x": 682,
- "y": 377
+ "y": 573
},
"width": 146,
"height": 108,
@@ -584,7 +584,7 @@
"type": "sql_table",
"pos": {
"x": 848,
- "y": 377
+ "y": 573
},
"width": 308,
"height": 108,
@@ -709,19 +709,27 @@
"route": [
{
"x": 411,
- "y": 60
- },
- {
- "x": 323,
- "y": 60
- },
- {
- "x": 323,
- "y": 108
+ "y": 254
},
{
"x": 411,
- "y": 108
+ "y": 342
+ },
+ {
+ "x": 288,
+ "y": 342
+ },
+ {
+ "x": 288,
+ "y": 22
+ },
+ {
+ "x": 469.3330078125,
+ "y": 22
+ },
+ {
+ "x": 469.3330078125,
+ "y": 110
}
],
"animated": false,
@@ -754,20 +762,28 @@
"labelPercentage": 0,
"route": [
{
- "x": 691,
- "y": 108
+ "x": 446,
+ "y": 254
},
{
- "x": 779,
- "y": 108
+ "x": 446,
+ "y": 352
},
{
- "x": 779,
- "y": 60
+ "x": 228,
+ "y": 352
},
{
- "x": 691,
- "y": 60
+ "x": 228,
+ "y": 12
+ },
+ {
+ "x": 562.666015625,
+ "y": 12
+ },
+ {
+ "x": 562.666015625,
+ "y": 110
}
],
"animated": false,
@@ -800,20 +816,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 457.6659851074219,
- "y": 156
+ "x": 481,
+ "y": 254
},
{
- "x": 457.6659851074219,
- "y": 196
+ "x": 481,
+ "y": 392
},
{
"x": 109,
- "y": 196
+ "y": 392
},
{
"x": 109,
- "y": 377
+ "y": 573
}
],
"animated": false,
@@ -846,20 +862,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 504.3330078125,
- "y": 156
+ "x": 516,
+ "y": 254
},
{
- "x": 504.3330078125,
- "y": 246
+ "x": 516,
+ "y": 442
},
{
"x": 323,
- "y": 246
+ "y": 442
},
{
"x": 323,
- "y": 377
+ "y": 573
}
],
"animated": false,
@@ -893,11 +909,11 @@
"route": [
{
"x": 551,
- "y": 156
+ "y": 254
},
{
"x": 551,
- "y": 377
+ "y": 573
}
],
"animated": false,
@@ -930,20 +946,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 597.666015625,
- "y": 156
+ "x": 586,
+ "y": 254
},
{
- "x": 597.666015625,
- "y": 246
+ "x": 586,
+ "y": 442
},
{
"x": 755,
- "y": 246
+ "y": 442
},
{
"x": 755,
- "y": 377
+ "y": 573
}
],
"animated": false,
@@ -976,20 +992,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 644.3330078125,
- "y": 156
+ "x": 621,
+ "y": 254
},
{
- "x": 644.3330078125,
- "y": 196
+ "x": 621,
+ "y": 392
},
{
"x": 1002,
- "y": 196
+ "y": 392
},
{
"x": 1002,
- "y": 377
+ "y": 573
}
],
"animated": false,
diff --git a/e2etests/testdata/stable/ent2d2_basic/elk/sketch.exp.svg b/e2etests/testdata/stable/ent2d2_basic/elk/sketch.exp.svg
index a6d2b2cf3..42a3641ab 100644
--- a/e2etests/testdata/stable/ent2d2_basic/elk/sketch.exp.svg
+++ b/e2etests/testdata/stable/ent2d2_basic/elk/sketch.exp.svg
@@ -1,16 +1,16 @@
-
\ No newline at end of file
diff --git a/e2etests/testdata/stable/ent2d2_right/elk/board.exp.json b/e2etests/testdata/stable/ent2d2_right/elk/board.exp.json
index 31085175a..498bfb706 100644
--- a/e2etests/testdata/stable/ent2d2_right/elk/board.exp.json
+++ b/e2etests/testdata/stable/ent2d2_right/elk/board.exp.json
@@ -7,8 +7,8 @@
"id": "User",
"type": "sql_table",
"pos": {
- "x": 12,
- "y": 200
+ "x": 72,
+ "y": 198
},
"width": 201,
"height": 280,
@@ -141,8 +141,8 @@
"id": "Pet",
"type": "sql_table",
"pos": {
- "x": 514,
- "y": 12
+ "x": 571,
+ "y": 1406
},
"width": 194,
"height": 108,
@@ -245,8 +245,8 @@
"id": "Card",
"type": "sql_table",
"pos": {
- "x": 514,
- "y": 140
+ "x": 571,
+ "y": 618
},
"width": 194,
"height": 108,
@@ -349,8 +349,8 @@
"id": "Post",
"type": "sql_table",
"pos": {
- "x": 514,
- "y": 268
+ "x": 557,
+ "y": 1182
},
"width": 222,
"height": 144,
@@ -481,8 +481,8 @@
"id": "Metadata",
"type": "sql_table",
"pos": {
- "x": 514,
- "y": 432
+ "x": 595,
+ "y": 806
},
"width": 146,
"height": 108,
@@ -584,7 +584,7 @@
"type": "sql_table",
"pos": {
"x": 514,
- "y": 560
+ "y": 994
},
"width": 308,
"height": 108,
@@ -708,20 +708,28 @@
"labelPercentage": 0,
"route": [
{
- "x": 79,
- "y": 200
+ "x": 97.125,
+ "y": 478
},
{
- "x": 79,
- "y": 150
+ "x": 97.125,
+ "y": 528
},
{
- "x": 146,
- "y": 150
+ "x": 22,
+ "y": 528
},
{
- "x": 146,
- "y": 200
+ "x": 22,
+ "y": 148
+ },
+ {
+ "x": 139,
+ "y": 148
+ },
+ {
+ "x": 139,
+ "y": 198
}
],
"animated": false,
@@ -754,20 +762,28 @@
"labelPercentage": 0,
"route": [
{
- "x": 146,
- "y": 480
+ "x": 122.25,
+ "y": 478
},
{
- "x": 146,
- "y": 530
+ "x": 122.25,
+ "y": 538
},
{
- "x": 79,
- "y": 530
+ "x": 12,
+ "y": 538
},
{
- "x": 79,
- "y": 480
+ "x": 12,
+ "y": 99
+ },
+ {
+ "x": 206,
+ "y": 99
+ },
+ {
+ "x": 206,
+ "y": 198
}
],
"animated": false,
@@ -800,20 +816,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 213,
- "y": 246.66600036621094
+ "x": 147.375,
+ "y": 478
},
{
- "x": 253,
- "y": 246.66600036621094
+ "x": 147.375,
+ "y": 1366
},
{
- "x": 253,
- "y": 66
+ "x": 668,
+ "y": 1366
},
{
- "x": 514,
- "y": 66
+ "x": 668,
+ "y": 1406
}
],
"animated": false,
@@ -846,20 +862,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 213,
- "y": 293.3330078125
+ "x": 172.5,
+ "y": 478
},
{
- "x": 303,
- "y": 293.3330078125
+ "x": 172.5,
+ "y": 578
},
{
- "x": 303,
- "y": 194
+ "x": 668,
+ "y": 578
},
{
- "x": 514,
- "y": 194
+ "x": 668,
+ "y": 618
}
],
"animated": false,
@@ -892,12 +908,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 213,
- "y": 340
+ "x": 197.625,
+ "y": 478
},
{
- "x": 514,
- "y": 340
+ "x": 197.625,
+ "y": 1142
+ },
+ {
+ "x": 668,
+ "y": 1142
+ },
+ {
+ "x": 668,
+ "y": 1182
}
],
"animated": false,
@@ -930,20 +954,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 213,
- "y": 386.6659851074219
+ "x": 222.75,
+ "y": 478
},
{
- "x": 303,
- "y": 386.6659851074219
+ "x": 222.75,
+ "y": 766
},
{
- "x": 303,
- "y": 486
+ "x": 668,
+ "y": 766
},
{
- "x": 514,
- "y": 486
+ "x": 668,
+ "y": 806
}
],
"animated": false,
@@ -976,20 +1000,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 213,
- "y": 433.3330078125
+ "x": 247.875,
+ "y": 478
},
{
- "x": 253,
- "y": 433.3330078125
+ "x": 247.875,
+ "y": 954
},
{
- "x": 253,
- "y": 614
+ "x": 668,
+ "y": 954
},
{
- "x": 514,
- "y": 614
+ "x": 668,
+ "y": 994
}
],
"animated": false,
diff --git a/e2etests/testdata/stable/ent2d2_right/elk/sketch.exp.svg b/e2etests/testdata/stable/ent2d2_right/elk/sketch.exp.svg
index 0da128f47..518245911 100644
--- a/e2etests/testdata/stable/ent2d2_right/elk/sketch.exp.svg
+++ b/e2etests/testdata/stable/ent2d2_right/elk/sketch.exp.svg
@@ -1,16 +1,16 @@
-UseridintPKparent_idintFKspouse_idintFKPetidintPKowner_idintFKCardidintPKowner_idintFKPostidintPKtextstringauthor_idintFKMetadataidintPKageintInfoidintPKcontentjson.RawMessage spousespouse childrenparentyowhoaheypets/ownercard/ownerposts/authormetadata/userinfo/user
-
-
-
-
-
-
-
-
+ .d2-1743102802 .fill-N1{fill:#0A0F25;}
+ .d2-1743102802 .fill-N2{fill:#676C7E;}
+ .d2-1743102802 .fill-N3{fill:#9499AB;}
+ .d2-1743102802 .fill-N4{fill:#CFD2DD;}
+ .d2-1743102802 .fill-N5{fill:#DEE1EB;}
+ .d2-1743102802 .fill-N6{fill:#EEF1F8;}
+ .d2-1743102802 .fill-N7{fill:#FFFFFF;}
+ .d2-1743102802 .fill-B1{fill:#0D32B2;}
+ .d2-1743102802 .fill-B2{fill:#0D32B2;}
+ .d2-1743102802 .fill-B3{fill:#E3E9FD;}
+ .d2-1743102802 .fill-B4{fill:#E3E9FD;}
+ .d2-1743102802 .fill-B5{fill:#EDF0FD;}
+ .d2-1743102802 .fill-B6{fill:#F7F8FE;}
+ .d2-1743102802 .fill-AA2{fill:#4A6FF3;}
+ .d2-1743102802 .fill-AA4{fill:#EDF0FD;}
+ .d2-1743102802 .fill-AA5{fill:#F7F8FE;}
+ .d2-1743102802 .fill-AB4{fill:#EDF0FD;}
+ .d2-1743102802 .fill-AB5{fill:#F7F8FE;}
+ .d2-1743102802 .stroke-N1{stroke:#0A0F25;}
+ .d2-1743102802 .stroke-N2{stroke:#676C7E;}
+ .d2-1743102802 .stroke-N3{stroke:#9499AB;}
+ .d2-1743102802 .stroke-N4{stroke:#CFD2DD;}
+ .d2-1743102802 .stroke-N5{stroke:#DEE1EB;}
+ .d2-1743102802 .stroke-N6{stroke:#EEF1F8;}
+ .d2-1743102802 .stroke-N7{stroke:#FFFFFF;}
+ .d2-1743102802 .stroke-B1{stroke:#0D32B2;}
+ .d2-1743102802 .stroke-B2{stroke:#0D32B2;}
+ .d2-1743102802 .stroke-B3{stroke:#E3E9FD;}
+ .d2-1743102802 .stroke-B4{stroke:#E3E9FD;}
+ .d2-1743102802 .stroke-B5{stroke:#EDF0FD;}
+ .d2-1743102802 .stroke-B6{stroke:#F7F8FE;}
+ .d2-1743102802 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-1743102802 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-1743102802 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-1743102802 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-1743102802 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-1743102802 .background-color-N1{background-color:#0A0F25;}
+ .d2-1743102802 .background-color-N2{background-color:#676C7E;}
+ .d2-1743102802 .background-color-N3{background-color:#9499AB;}
+ .d2-1743102802 .background-color-N4{background-color:#CFD2DD;}
+ .d2-1743102802 .background-color-N5{background-color:#DEE1EB;}
+ .d2-1743102802 .background-color-N6{background-color:#EEF1F8;}
+ .d2-1743102802 .background-color-N7{background-color:#FFFFFF;}
+ .d2-1743102802 .background-color-B1{background-color:#0D32B2;}
+ .d2-1743102802 .background-color-B2{background-color:#0D32B2;}
+ .d2-1743102802 .background-color-B3{background-color:#E3E9FD;}
+ .d2-1743102802 .background-color-B4{background-color:#E3E9FD;}
+ .d2-1743102802 .background-color-B5{background-color:#EDF0FD;}
+ .d2-1743102802 .background-color-B6{background-color:#F7F8FE;}
+ .d2-1743102802 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-1743102802 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-1743102802 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-1743102802 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-1743102802 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-1743102802 .color-N1{color:#0A0F25;}
+ .d2-1743102802 .color-N2{color:#676C7E;}
+ .d2-1743102802 .color-N3{color:#9499AB;}
+ .d2-1743102802 .color-N4{color:#CFD2DD;}
+ .d2-1743102802 .color-N5{color:#DEE1EB;}
+ .d2-1743102802 .color-N6{color:#EEF1F8;}
+ .d2-1743102802 .color-N7{color:#FFFFFF;}
+ .d2-1743102802 .color-B1{color:#0D32B2;}
+ .d2-1743102802 .color-B2{color:#0D32B2;}
+ .d2-1743102802 .color-B3{color:#E3E9FD;}
+ .d2-1743102802 .color-B4{color:#E3E9FD;}
+ .d2-1743102802 .color-B5{color:#EDF0FD;}
+ .d2-1743102802 .color-B6{color:#F7F8FE;}
+ .d2-1743102802 .color-AA2{color:#4A6FF3;}
+ .d2-1743102802 .color-AA4{color:#EDF0FD;}
+ .d2-1743102802 .color-AA5{color:#F7F8FE;}
+ .d2-1743102802 .color-AB4{color:#EDF0FD;}
+ .d2-1743102802 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>UseridintPKparent_idintFKspouse_idintFKPetidintPKowner_idintFKCardidintPKowner_idintFKPostidintPKtextstringauthor_idintFKMetadataidintPKageintInfoidintPKcontentjson.RawMessage spousespouse childrenparentyowhoaheypets/ownercard/ownerposts/authormetadata/userinfo/user
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_table_row_connections/dagre/board.exp.json b/e2etests/testdata/stable/sql_table_row_connections/dagre/board.exp.json
new file mode 100644
index 000000000..e9050aa8e
--- /dev/null
+++ b/e2etests/testdata/stable/sql_table_row_connections/dagre/board.exp.json
@@ -0,0 +1,351 @@
+{
+ "name": "",
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "sql_table",
+ "pos": {
+ "x": 0,
+ "y": 36
+ },
+ "width": 131,
+ "height": 72,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N1",
+ "stroke": "N7",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": [
+ {
+ "name": {
+ "label": "id",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 15,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "primary_key"
+ ],
+ "reference": ""
+ }
+ ],
+ "label": "a",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 11,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "B2",
+ "secondaryAccentColor": "AA2",
+ "neutralAccentColor": "N2"
+ },
+ {
+ "id": "b",
+ "type": "sql_table",
+ "pos": {
+ "x": 231,
+ "y": 0
+ },
+ "width": 146,
+ "height": 144,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N1",
+ "stroke": "N7",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": [
+ {
+ "name": {
+ "label": "id",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 15,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "primary_key"
+ ],
+ "reference": ""
+ },
+ {
+ "name": {
+ "label": "a_1",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 29,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "foreign_key"
+ ],
+ "reference": ""
+ },
+ {
+ "name": {
+ "label": "a_2",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 30,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "foreign_key"
+ ],
+ "reference": ""
+ }
+ ],
+ "label": "b",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "B2",
+ "secondaryAccentColor": "AA2",
+ "neutralAccentColor": "N2"
+ }
+ ],
+ "connections": [
+ {
+ "id": "(b -> a)[0]",
+ "src": "b",
+ "srcArrow": "none",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 231,
+ "y": 66
+ },
+ {
+ "x": 191,
+ "y": 62.79999923706055
+ },
+ {
+ "x": 171,
+ "y": 62.79999923706055
+ },
+ {
+ "x": 131,
+ "y": 66
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(b -> a)[1]",
+ "src": "b",
+ "srcArrow": "none",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 231,
+ "y": 78
+ },
+ {
+ "x": 191,
+ "y": 81.19999694824219
+ },
+ {
+ "x": 171,
+ "y": 81.19999694824219
+ },
+ {
+ "x": 131,
+ "y": 78
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ],
+ "root": {
+ "id": "",
+ "type": "",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 0,
+ "height": 0,
+ "opacity": 0,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "N7",
+ "stroke": "",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 0
+ }
+}
diff --git a/e2etests/testdata/stable/sql_table_row_connections/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_table_row_connections/dagre/sketch.exp.svg
new file mode 100644
index 000000000..3ea05b0f9
--- /dev/null
+++ b/e2etests/testdata/stable/sql_table_row_connections/dagre/sketch.exp.svg
@@ -0,0 +1,95 @@
+aidintPKbidintPKa_1intFKa_2intFK
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_table_row_connections/elk/board.exp.json b/e2etests/testdata/stable/sql_table_row_connections/elk/board.exp.json
new file mode 100644
index 000000000..d6757f931
--- /dev/null
+++ b/e2etests/testdata/stable/sql_table_row_connections/elk/board.exp.json
@@ -0,0 +1,341 @@
+{
+ "name": "",
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "sql_table",
+ "pos": {
+ "x": 12,
+ "y": 42
+ },
+ "width": 131,
+ "height": 80,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N1",
+ "stroke": "N7",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": [
+ {
+ "name": {
+ "label": "id",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 15,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "primary_key"
+ ],
+ "reference": ""
+ }
+ ],
+ "label": "a",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 11,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "B2",
+ "secondaryAccentColor": "AA2",
+ "neutralAccentColor": "N2"
+ },
+ {
+ "id": "b",
+ "type": "sql_table",
+ "pos": {
+ "x": 223,
+ "y": 12
+ },
+ "width": 146,
+ "height": 144,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N1",
+ "stroke": "N7",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": [
+ {
+ "name": {
+ "label": "id",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 15,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "primary_key"
+ ],
+ "reference": ""
+ },
+ {
+ "name": {
+ "label": "a_1",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 29,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "foreign_key"
+ ],
+ "reference": ""
+ },
+ {
+ "name": {
+ "label": "a_2",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 30,
+ "labelHeight": 26
+ },
+ "type": {
+ "label": "int",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 23,
+ "labelHeight": 26
+ },
+ "constraint": [
+ "foreign_key"
+ ],
+ "reference": ""
+ }
+ ],
+ "label": "b",
+ "fontSize": 20,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 31,
+ "zIndex": 0,
+ "level": 1,
+ "primaryAccentColor": "B2",
+ "secondaryAccentColor": "AA2",
+ "neutralAccentColor": "N2"
+ }
+ ],
+ "connections": [
+ {
+ "id": "(b -> a)[0]",
+ "src": "b",
+ "srcArrow": "none",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 223,
+ "y": 102
+ },
+ {
+ "x": 143,
+ "y": 102
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(b -> a)[1]",
+ "src": "b",
+ "srcArrow": "none",
+ "dst": "a",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 223,
+ "y": 138
+ },
+ {
+ "x": 183,
+ "y": 138
+ },
+ {
+ "x": 183,
+ "y": 102
+ },
+ {
+ "x": 143,
+ "y": 102
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ],
+ "root": {
+ "id": "",
+ "type": "",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 0,
+ "height": 0,
+ "opacity": 0,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "N7",
+ "stroke": "",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 0
+ }
+}
diff --git a/e2etests/testdata/stable/sql_table_row_connections/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_row_connections/elk/sketch.exp.svg
new file mode 100644
index 000000000..56d388b65
--- /dev/null
+++ b/e2etests/testdata/stable/sql_table_row_connections/elk/sketch.exp.svg
@@ -0,0 +1,95 @@
+aidintPKbidintPKa_1intFKa_2intFK
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json
index 9e4967a4c..f64da567a 100644
--- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json
+++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/board.exp.json
@@ -10,7 +10,7 @@
"x": 0,
"y": 0
},
- "width": 60,
+ "width": 103,
"height": 72,
"opacity": 1,
"strokeDash": 0,
@@ -55,7 +55,9 @@
"labelWidth": 0,
"labelHeight": 0
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
}
],
@@ -79,10 +81,10 @@
"id": "a",
"type": "sql_table",
"pos": {
- "x": 0,
- "y": 172
+ "x": 203,
+ "y": 0
},
- "width": 60,
+ "width": 101,
"height": 72,
"opacity": 1,
"strokeDash": 0,
@@ -127,7 +129,9 @@
"labelWidth": 0,
"labelHeight": 0
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
}
],
@@ -150,11 +154,11 @@
],
"connections": [
{
- "id": "(x -> a)[0]",
- "src": "x",
- "srcArrow": "none",
- "dst": "a",
- "dstArrow": "cf-many",
+ "id": "(a <-> x)[0]",
+ "src": "a",
+ "srcArrow": "cf-many",
+ "dst": "x",
+ "dstArrow": "cf-one",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -174,20 +178,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 30,
- "y": 72
+ "x": 203,
+ "y": 36
},
{
- "x": 30,
- "y": 112
+ "x": 163,
+ "y": 36
},
{
- "x": 30,
- "y": 132
+ "x": 143,
+ "y": 36
},
{
- "x": 30,
- "y": 172
+ "x": 103,
+ "y": 36
}
],
"isCurve": true,
diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg
index ef9161f73..d4eb1e2bf 100644
--- a/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/sql_table_tooltip_animated/dagre/sketch.exp.svg
@@ -1,10 +1,10 @@
-xyab I like turtles
+ .d2-3096218097 .fill-N1{fill:#0A0F25;}
+ .d2-3096218097 .fill-N2{fill:#676C7E;}
+ .d2-3096218097 .fill-N3{fill:#9499AB;}
+ .d2-3096218097 .fill-N4{fill:#CFD2DD;}
+ .d2-3096218097 .fill-N5{fill:#DEE1EB;}
+ .d2-3096218097 .fill-N6{fill:#EEF1F8;}
+ .d2-3096218097 .fill-N7{fill:#FFFFFF;}
+ .d2-3096218097 .fill-B1{fill:#0D32B2;}
+ .d2-3096218097 .fill-B2{fill:#0D32B2;}
+ .d2-3096218097 .fill-B3{fill:#E3E9FD;}
+ .d2-3096218097 .fill-B4{fill:#E3E9FD;}
+ .d2-3096218097 .fill-B5{fill:#EDF0FD;}
+ .d2-3096218097 .fill-B6{fill:#F7F8FE;}
+ .d2-3096218097 .fill-AA2{fill:#4A6FF3;}
+ .d2-3096218097 .fill-AA4{fill:#EDF0FD;}
+ .d2-3096218097 .fill-AA5{fill:#F7F8FE;}
+ .d2-3096218097 .fill-AB4{fill:#EDF0FD;}
+ .d2-3096218097 .fill-AB5{fill:#F7F8FE;}
+ .d2-3096218097 .stroke-N1{stroke:#0A0F25;}
+ .d2-3096218097 .stroke-N2{stroke:#676C7E;}
+ .d2-3096218097 .stroke-N3{stroke:#9499AB;}
+ .d2-3096218097 .stroke-N4{stroke:#CFD2DD;}
+ .d2-3096218097 .stroke-N5{stroke:#DEE1EB;}
+ .d2-3096218097 .stroke-N6{stroke:#EEF1F8;}
+ .d2-3096218097 .stroke-N7{stroke:#FFFFFF;}
+ .d2-3096218097 .stroke-B1{stroke:#0D32B2;}
+ .d2-3096218097 .stroke-B2{stroke:#0D32B2;}
+ .d2-3096218097 .stroke-B3{stroke:#E3E9FD;}
+ .d2-3096218097 .stroke-B4{stroke:#E3E9FD;}
+ .d2-3096218097 .stroke-B5{stroke:#EDF0FD;}
+ .d2-3096218097 .stroke-B6{stroke:#F7F8FE;}
+ .d2-3096218097 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-3096218097 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-3096218097 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-3096218097 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-3096218097 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-3096218097 .background-color-N1{background-color:#0A0F25;}
+ .d2-3096218097 .background-color-N2{background-color:#676C7E;}
+ .d2-3096218097 .background-color-N3{background-color:#9499AB;}
+ .d2-3096218097 .background-color-N4{background-color:#CFD2DD;}
+ .d2-3096218097 .background-color-N5{background-color:#DEE1EB;}
+ .d2-3096218097 .background-color-N6{background-color:#EEF1F8;}
+ .d2-3096218097 .background-color-N7{background-color:#FFFFFF;}
+ .d2-3096218097 .background-color-B1{background-color:#0D32B2;}
+ .d2-3096218097 .background-color-B2{background-color:#0D32B2;}
+ .d2-3096218097 .background-color-B3{background-color:#E3E9FD;}
+ .d2-3096218097 .background-color-B4{background-color:#E3E9FD;}
+ .d2-3096218097 .background-color-B5{background-color:#EDF0FD;}
+ .d2-3096218097 .background-color-B6{background-color:#F7F8FE;}
+ .d2-3096218097 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-3096218097 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-3096218097 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-3096218097 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-3096218097 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-3096218097 .color-N1{color:#0A0F25;}
+ .d2-3096218097 .color-N2{color:#676C7E;}
+ .d2-3096218097 .color-N3{color:#9499AB;}
+ .d2-3096218097 .color-N4{color:#CFD2DD;}
+ .d2-3096218097 .color-N5{color:#DEE1EB;}
+ .d2-3096218097 .color-N6{color:#EEF1F8;}
+ .d2-3096218097 .color-N7{color:#FFFFFF;}
+ .d2-3096218097 .color-B1{color:#0D32B2;}
+ .d2-3096218097 .color-B2{color:#0D32B2;}
+ .d2-3096218097 .color-B3{color:#E3E9FD;}
+ .d2-3096218097 .color-B4{color:#E3E9FD;}
+ .d2-3096218097 .color-B5{color:#EDF0FD;}
+ .d2-3096218097 .color-B6{color:#F7F8FE;}
+ .d2-3096218097 .color-AA2{color:#4A6FF3;}
+ .d2-3096218097 .color-AA4{color:#EDF0FD;}
+ .d2-3096218097 .color-AA5{color:#F7F8FE;}
+ .d2-3096218097 .color-AB4{color:#EDF0FD;}
+ .d2-3096218097 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>xyPKabFK I like turtles
@@ -111,7 +111,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json
index 613062453..17929a530 100644
--- a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json
+++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/board.exp.json
@@ -10,7 +10,7 @@
"x": 12,
"y": 12
},
- "width": 60,
+ "width": 103,
"height": 72,
"opacity": 1,
"strokeDash": 0,
@@ -55,7 +55,9 @@
"labelWidth": 0,
"labelHeight": 0
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
}
],
@@ -79,10 +81,10 @@
"id": "a",
"type": "sql_table",
"pos": {
- "x": 12,
- "y": 154
+ "x": 185,
+ "y": 12
},
- "width": 60,
+ "width": 101,
"height": 72,
"opacity": 1,
"strokeDash": 0,
@@ -127,7 +129,9 @@
"labelWidth": 0,
"labelHeight": 0
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
}
],
@@ -150,11 +154,11 @@
],
"connections": [
{
- "id": "(x -> a)[0]",
- "src": "x",
- "srcArrow": "none",
- "dst": "a",
- "dstArrow": "cf-many",
+ "id": "(a <-> x)[0]",
+ "src": "a",
+ "srcArrow": "cf-many",
+ "dst": "x",
+ "dstArrow": "cf-one",
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -174,12 +178,12 @@
"labelPercentage": 0,
"route": [
{
- "x": 42,
- "y": 84
+ "x": 185,
+ "y": 66
},
{
- "x": 42,
- "y": 154
+ "x": 115,
+ "y": 66
}
],
"animated": true,
diff --git a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg
index 33df82d73..3f7f76b1a 100644
--- a/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg
+++ b/e2etests/testdata/stable/sql_table_tooltip_animated/elk/sketch.exp.svg
@@ -1,10 +1,10 @@
-xyab I like turtles
+ .d2-3579465052 .fill-N1{fill:#0A0F25;}
+ .d2-3579465052 .fill-N2{fill:#676C7E;}
+ .d2-3579465052 .fill-N3{fill:#9499AB;}
+ .d2-3579465052 .fill-N4{fill:#CFD2DD;}
+ .d2-3579465052 .fill-N5{fill:#DEE1EB;}
+ .d2-3579465052 .fill-N6{fill:#EEF1F8;}
+ .d2-3579465052 .fill-N7{fill:#FFFFFF;}
+ .d2-3579465052 .fill-B1{fill:#0D32B2;}
+ .d2-3579465052 .fill-B2{fill:#0D32B2;}
+ .d2-3579465052 .fill-B3{fill:#E3E9FD;}
+ .d2-3579465052 .fill-B4{fill:#E3E9FD;}
+ .d2-3579465052 .fill-B5{fill:#EDF0FD;}
+ .d2-3579465052 .fill-B6{fill:#F7F8FE;}
+ .d2-3579465052 .fill-AA2{fill:#4A6FF3;}
+ .d2-3579465052 .fill-AA4{fill:#EDF0FD;}
+ .d2-3579465052 .fill-AA5{fill:#F7F8FE;}
+ .d2-3579465052 .fill-AB4{fill:#EDF0FD;}
+ .d2-3579465052 .fill-AB5{fill:#F7F8FE;}
+ .d2-3579465052 .stroke-N1{stroke:#0A0F25;}
+ .d2-3579465052 .stroke-N2{stroke:#676C7E;}
+ .d2-3579465052 .stroke-N3{stroke:#9499AB;}
+ .d2-3579465052 .stroke-N4{stroke:#CFD2DD;}
+ .d2-3579465052 .stroke-N5{stroke:#DEE1EB;}
+ .d2-3579465052 .stroke-N6{stroke:#EEF1F8;}
+ .d2-3579465052 .stroke-N7{stroke:#FFFFFF;}
+ .d2-3579465052 .stroke-B1{stroke:#0D32B2;}
+ .d2-3579465052 .stroke-B2{stroke:#0D32B2;}
+ .d2-3579465052 .stroke-B3{stroke:#E3E9FD;}
+ .d2-3579465052 .stroke-B4{stroke:#E3E9FD;}
+ .d2-3579465052 .stroke-B5{stroke:#EDF0FD;}
+ .d2-3579465052 .stroke-B6{stroke:#F7F8FE;}
+ .d2-3579465052 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-3579465052 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-3579465052 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-3579465052 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-3579465052 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-3579465052 .background-color-N1{background-color:#0A0F25;}
+ .d2-3579465052 .background-color-N2{background-color:#676C7E;}
+ .d2-3579465052 .background-color-N3{background-color:#9499AB;}
+ .d2-3579465052 .background-color-N4{background-color:#CFD2DD;}
+ .d2-3579465052 .background-color-N5{background-color:#DEE1EB;}
+ .d2-3579465052 .background-color-N6{background-color:#EEF1F8;}
+ .d2-3579465052 .background-color-N7{background-color:#FFFFFF;}
+ .d2-3579465052 .background-color-B1{background-color:#0D32B2;}
+ .d2-3579465052 .background-color-B2{background-color:#0D32B2;}
+ .d2-3579465052 .background-color-B3{background-color:#E3E9FD;}
+ .d2-3579465052 .background-color-B4{background-color:#E3E9FD;}
+ .d2-3579465052 .background-color-B5{background-color:#EDF0FD;}
+ .d2-3579465052 .background-color-B6{background-color:#F7F8FE;}
+ .d2-3579465052 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-3579465052 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-3579465052 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-3579465052 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-3579465052 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-3579465052 .color-N1{color:#0A0F25;}
+ .d2-3579465052 .color-N2{color:#676C7E;}
+ .d2-3579465052 .color-N3{color:#9499AB;}
+ .d2-3579465052 .color-N4{color:#CFD2DD;}
+ .d2-3579465052 .color-N5{color:#DEE1EB;}
+ .d2-3579465052 .color-N6{color:#EEF1F8;}
+ .d2-3579465052 .color-N7{color:#FFFFFF;}
+ .d2-3579465052 .color-B1{color:#0D32B2;}
+ .d2-3579465052 .color-B2{color:#0D32B2;}
+ .d2-3579465052 .color-B3{color:#E3E9FD;}
+ .d2-3579465052 .color-B4{color:#E3E9FD;}
+ .d2-3579465052 .color-B5{color:#EDF0FD;}
+ .d2-3579465052 .color-B6{color:#F7F8FE;}
+ .d2-3579465052 .color-AA2{color:#4A6FF3;}
+ .d2-3579465052 .color-AA4{color:#EDF0FD;}
+ .d2-3579465052 .color-AA5{color:#F7F8FE;}
+ .d2-3579465052 .color-AB4{color:#EDF0FD;}
+ .d2-3579465052 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>xyPKabFK I like turtles
@@ -111,7 +111,7 @@
-
-
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_tables/dagre/board.exp.json b/e2etests/testdata/stable/sql_tables/dagre/board.exp.json
index c400a4c67..51aa78d86 100644
--- a/e2etests/testdata/stable/sql_tables/dagre/board.exp.json
+++ b/e2etests/testdata/stable/sql_tables/dagre/board.exp.json
@@ -55,7 +55,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -167,9 +169,7 @@
"labelWidth": 77,
"labelHeight": 26
},
- "constraint": [
- "primary_key"
- ],
+ "constraint": null,
"reference": ""
}
],
@@ -193,10 +193,10 @@
"id": "products",
"type": "sql_table",
"pos": {
- "x": 311,
- "y": 18
+ "x": 22,
+ "y": 276
},
- "width": 164,
+ "width": 207,
"height": 180,
"opacity": 1,
"strokeDash": 0,
@@ -241,7 +241,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -349,10 +351,10 @@
"id": "orders",
"type": "sql_table",
"pos": {
- "x": 311,
- "y": 316
+ "x": 351,
+ "y": 165
},
- "width": 164,
+ "width": 207,
"height": 144,
"opacity": 1,
"strokeDash": 0,
@@ -397,7 +399,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -425,7 +429,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
},
{
@@ -453,7 +459,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
}
],
@@ -477,10 +485,10 @@
"id": "shipments",
"type": "sql_table",
"pos": {
- "x": 535,
- "y": 18
+ "x": 658,
+ "y": 147
},
- "width": 244,
+ "width": 287,
"height": 180,
"opacity": 1,
"strokeDash": 0,
@@ -525,7 +533,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -553,7 +563,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
},
{
@@ -632,10 +644,10 @@
],
"connections": [
{
- "id": "(users <-> orders)[0]",
- "src": "users",
- "srcArrow": "triangle",
- "dst": "orders",
+ "id": "(orders -> users)[0]",
+ "src": "orders",
+ "srcArrow": "none",
+ "dst": "users",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
@@ -656,20 +668,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 125.5,
- "y": 216
+ "x": 369,
+ "y": 165
},
{
- "x": 125.5,
- "y": 256
+ "x": 314.6000061035156,
+ "y": 119.4000015258789
},
{
- "x": 162.6999969482422,
- "y": 283
+ "x": 291,
+ "y": 108
},
{
- "x": 311.5,
- "y": 351
+ "x": 251,
+ "y": 108
}
],
"isCurve": true,
@@ -679,10 +691,10 @@
"zIndex": 0
},
{
- "id": "(products <-> orders)[0]",
- "src": "products",
- "srcArrow": "triangle",
- "dst": "orders",
+ "id": "(orders -> products)[0]",
+ "src": "orders",
+ "srcArrow": "none",
+ "dst": "products",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
@@ -703,20 +715,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 393,
- "y": 198
+ "x": 369,
+ "y": 309
},
{
- "x": 393,
- "y": 252.39999389648438
+ "x": 314.6000061035156,
+ "y": 354.6000061035156
},
{
- "x": 393,
- "y": 276
+ "x": 286.6000061035156,
+ "y": 366
},
{
- "x": 393,
- "y": 316
+ "x": 229,
+ "y": 366
}
],
"isCurve": true,
@@ -726,9 +738,9 @@
"zIndex": 0
},
{
- "id": "(shipments <-> orders)[0]",
+ "id": "(shipments -> orders)[0]",
"src": "shipments",
- "srcArrow": "triangle",
+ "srcArrow": "none",
"dst": "orders",
"dstArrow": "triangle",
"opacity": 1,
@@ -750,20 +762,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 657,
- "y": 198
+ "x": 658,
+ "y": 237
},
{
- "x": 657,
- "y": 252.39999389648438
+ "x": 618,
+ "y": 237
},
{
- "x": 620.5999755859375,
- "y": 282.79998779296875
+ "x": 598,
+ "y": 237
},
{
- "x": 475,
- "y": 350
+ "x": 558,
+ "y": 237
}
],
"isCurve": true,
diff --git a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg
index fb4818f76..393a9e13c 100644
--- a/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/sql_tables/dagre/sketch.exp.svg
@@ -1,10 +1,10 @@
-usersidintnamestringemailstringpasswordstringlast_logindatetimePKproductsidintpricedecimalskustringnamestringordersidintuser_idintproduct_idintshipmentsidintorder_idinttracking_numberstringstatusstring
-
+ .d2-1770468726 .fill-N1{fill:#0A0F25;}
+ .d2-1770468726 .fill-N2{fill:#676C7E;}
+ .d2-1770468726 .fill-N3{fill:#9499AB;}
+ .d2-1770468726 .fill-N4{fill:#CFD2DD;}
+ .d2-1770468726 .fill-N5{fill:#DEE1EB;}
+ .d2-1770468726 .fill-N6{fill:#EEF1F8;}
+ .d2-1770468726 .fill-N7{fill:#FFFFFF;}
+ .d2-1770468726 .fill-B1{fill:#0D32B2;}
+ .d2-1770468726 .fill-B2{fill:#0D32B2;}
+ .d2-1770468726 .fill-B3{fill:#E3E9FD;}
+ .d2-1770468726 .fill-B4{fill:#E3E9FD;}
+ .d2-1770468726 .fill-B5{fill:#EDF0FD;}
+ .d2-1770468726 .fill-B6{fill:#F7F8FE;}
+ .d2-1770468726 .fill-AA2{fill:#4A6FF3;}
+ .d2-1770468726 .fill-AA4{fill:#EDF0FD;}
+ .d2-1770468726 .fill-AA5{fill:#F7F8FE;}
+ .d2-1770468726 .fill-AB4{fill:#EDF0FD;}
+ .d2-1770468726 .fill-AB5{fill:#F7F8FE;}
+ .d2-1770468726 .stroke-N1{stroke:#0A0F25;}
+ .d2-1770468726 .stroke-N2{stroke:#676C7E;}
+ .d2-1770468726 .stroke-N3{stroke:#9499AB;}
+ .d2-1770468726 .stroke-N4{stroke:#CFD2DD;}
+ .d2-1770468726 .stroke-N5{stroke:#DEE1EB;}
+ .d2-1770468726 .stroke-N6{stroke:#EEF1F8;}
+ .d2-1770468726 .stroke-N7{stroke:#FFFFFF;}
+ .d2-1770468726 .stroke-B1{stroke:#0D32B2;}
+ .d2-1770468726 .stroke-B2{stroke:#0D32B2;}
+ .d2-1770468726 .stroke-B3{stroke:#E3E9FD;}
+ .d2-1770468726 .stroke-B4{stroke:#E3E9FD;}
+ .d2-1770468726 .stroke-B5{stroke:#EDF0FD;}
+ .d2-1770468726 .stroke-B6{stroke:#F7F8FE;}
+ .d2-1770468726 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-1770468726 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-1770468726 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-1770468726 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-1770468726 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-1770468726 .background-color-N1{background-color:#0A0F25;}
+ .d2-1770468726 .background-color-N2{background-color:#676C7E;}
+ .d2-1770468726 .background-color-N3{background-color:#9499AB;}
+ .d2-1770468726 .background-color-N4{background-color:#CFD2DD;}
+ .d2-1770468726 .background-color-N5{background-color:#DEE1EB;}
+ .d2-1770468726 .background-color-N6{background-color:#EEF1F8;}
+ .d2-1770468726 .background-color-N7{background-color:#FFFFFF;}
+ .d2-1770468726 .background-color-B1{background-color:#0D32B2;}
+ .d2-1770468726 .background-color-B2{background-color:#0D32B2;}
+ .d2-1770468726 .background-color-B3{background-color:#E3E9FD;}
+ .d2-1770468726 .background-color-B4{background-color:#E3E9FD;}
+ .d2-1770468726 .background-color-B5{background-color:#EDF0FD;}
+ .d2-1770468726 .background-color-B6{background-color:#F7F8FE;}
+ .d2-1770468726 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-1770468726 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-1770468726 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-1770468726 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-1770468726 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-1770468726 .color-N1{color:#0A0F25;}
+ .d2-1770468726 .color-N2{color:#676C7E;}
+ .d2-1770468726 .color-N3{color:#9499AB;}
+ .d2-1770468726 .color-N4{color:#CFD2DD;}
+ .d2-1770468726 .color-N5{color:#DEE1EB;}
+ .d2-1770468726 .color-N6{color:#EEF1F8;}
+ .d2-1770468726 .color-N7{color:#FFFFFF;}
+ .d2-1770468726 .color-B1{color:#0D32B2;}
+ .d2-1770468726 .color-B2{color:#0D32B2;}
+ .d2-1770468726 .color-B3{color:#E3E9FD;}
+ .d2-1770468726 .color-B4{color:#E3E9FD;}
+ .d2-1770468726 .color-B5{color:#EDF0FD;}
+ .d2-1770468726 .color-B6{color:#F7F8FE;}
+ .d2-1770468726 .color-AA2{color:#4A6FF3;}
+ .d2-1770468726 .color-AA4{color:#EDF0FD;}
+ .d2-1770468726 .color-AA5{color:#F7F8FE;}
+ .d2-1770468726 .color-AB4{color:#EDF0FD;}
+ .d2-1770468726 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>usersidintPKnamestringemailstringpasswordstringlast_logindatetimeproductsidintPKpricedecimalskustringnamestringordersidintPKuser_idintFKproduct_idintFKshipmentsidintPKorder_idintFKtracking_numberstringstatusstring
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/sql_tables/elk/board.exp.json b/e2etests/testdata/stable/sql_tables/elk/board.exp.json
index fece8e814..6592421bd 100644
--- a/e2etests/testdata/stable/sql_tables/elk/board.exp.json
+++ b/e2etests/testdata/stable/sql_tables/elk/board.exp.json
@@ -55,7 +55,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -167,9 +169,7 @@
"labelWidth": 77,
"labelHeight": 26
},
- "constraint": [
- "primary_key"
- ],
+ "constraint": null,
"reference": ""
}
],
@@ -193,10 +193,10 @@
"id": "products",
"type": "sql_table",
"pos": {
- "x": 283,
- "y": 48
+ "x": 56,
+ "y": 248
},
- "width": 164,
+ "width": 207,
"height": 180,
"opacity": 1,
"strokeDash": 0,
@@ -241,7 +241,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -349,10 +351,10 @@
"id": "orders",
"type": "sql_table",
"pos": {
- "x": 283,
- "y": 308
+ "x": 343,
+ "y": 76
},
- "width": 164,
+ "width": 207,
"height": 144,
"opacity": 1,
"strokeDash": 0,
@@ -397,7 +399,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -425,7 +429,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
},
{
@@ -453,7 +459,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
}
],
@@ -477,10 +485,10 @@
"id": "shipments",
"type": "sql_table",
"pos": {
- "x": 467,
- "y": 48
+ "x": 620,
+ "y": 40
},
- "width": 244,
+ "width": 287,
"height": 180,
"opacity": 1,
"strokeDash": 0,
@@ -525,7 +533,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "primary_key"
+ ],
"reference": ""
},
{
@@ -553,7 +563,9 @@
"labelWidth": 23,
"labelHeight": 26
},
- "constraint": null,
+ "constraint": [
+ "foreign_key"
+ ],
"reference": ""
},
{
@@ -632,10 +644,10 @@
],
"connections": [
{
- "id": "(users <-> orders)[0]",
- "src": "users",
- "srcArrow": "triangle",
- "dst": "orders",
+ "id": "(orders -> users)[0]",
+ "src": "orders",
+ "srcArrow": "none",
+ "dst": "users",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
@@ -656,20 +668,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 137.5,
- "y": 228
+ "x": 343,
+ "y": 166
},
{
- "x": 137.5,
- "y": 268
+ "x": 303,
+ "y": 166
},
{
- "x": 324,
- "y": 268
+ "x": 303,
+ "y": 66
},
{
- "x": 324,
- "y": 308
+ "x": 263,
+ "y": 66
}
],
"animated": false,
@@ -678,10 +690,10 @@
"zIndex": 0
},
{
- "id": "(products <-> orders)[0]",
- "src": "products",
- "srcArrow": "triangle",
- "dst": "orders",
+ "id": "(orders -> products)[0]",
+ "src": "orders",
+ "srcArrow": "none",
+ "dst": "products",
"dstArrow": "triangle",
"opacity": 1,
"strokeDash": 0,
@@ -702,12 +714,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 365,
- "y": 228
+ "x": 343,
+ "y": 202
},
{
- "x": 365,
- "y": 308
+ "x": 303,
+ "y": 202
+ },
+ {
+ "x": 303,
+ "y": 302
+ },
+ {
+ "x": 263,
+ "y": 302
}
],
"animated": false,
@@ -716,9 +736,9 @@
"zIndex": 0
},
{
- "id": "(shipments <-> orders)[0]",
+ "id": "(shipments -> orders)[0]",
"src": "shipments",
- "srcArrow": "triangle",
+ "srcArrow": "none",
"dst": "orders",
"dstArrow": "triangle",
"opacity": 1,
@@ -740,20 +760,12 @@
"labelPercentage": 0,
"route": [
{
- "x": 589,
- "y": 228
+ "x": 620,
+ "y": 130
},
{
- "x": 589,
- "y": 268
- },
- {
- "x": 406,
- "y": 268
- },
- {
- "x": 406,
- "y": 308
+ "x": 550,
+ "y": 130
}
],
"animated": false,
diff --git a/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg b/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg
index 30dfab403..bcc2129f1 100644
--- a/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg
+++ b/e2etests/testdata/stable/sql_tables/elk/sketch.exp.svg
@@ -1,10 +1,10 @@
-usersidintnamestringemailstringpasswordstringlast_logindatetimePKproductsidintpricedecimalskustringnamestringordersidintuser_idintproduct_idintshipmentsidintorder_idinttracking_numberstringstatusstring
-
+ .d2-2764772137 .fill-N1{fill:#0A0F25;}
+ .d2-2764772137 .fill-N2{fill:#676C7E;}
+ .d2-2764772137 .fill-N3{fill:#9499AB;}
+ .d2-2764772137 .fill-N4{fill:#CFD2DD;}
+ .d2-2764772137 .fill-N5{fill:#DEE1EB;}
+ .d2-2764772137 .fill-N6{fill:#EEF1F8;}
+ .d2-2764772137 .fill-N7{fill:#FFFFFF;}
+ .d2-2764772137 .fill-B1{fill:#0D32B2;}
+ .d2-2764772137 .fill-B2{fill:#0D32B2;}
+ .d2-2764772137 .fill-B3{fill:#E3E9FD;}
+ .d2-2764772137 .fill-B4{fill:#E3E9FD;}
+ .d2-2764772137 .fill-B5{fill:#EDF0FD;}
+ .d2-2764772137 .fill-B6{fill:#F7F8FE;}
+ .d2-2764772137 .fill-AA2{fill:#4A6FF3;}
+ .d2-2764772137 .fill-AA4{fill:#EDF0FD;}
+ .d2-2764772137 .fill-AA5{fill:#F7F8FE;}
+ .d2-2764772137 .fill-AB4{fill:#EDF0FD;}
+ .d2-2764772137 .fill-AB5{fill:#F7F8FE;}
+ .d2-2764772137 .stroke-N1{stroke:#0A0F25;}
+ .d2-2764772137 .stroke-N2{stroke:#676C7E;}
+ .d2-2764772137 .stroke-N3{stroke:#9499AB;}
+ .d2-2764772137 .stroke-N4{stroke:#CFD2DD;}
+ .d2-2764772137 .stroke-N5{stroke:#DEE1EB;}
+ .d2-2764772137 .stroke-N6{stroke:#EEF1F8;}
+ .d2-2764772137 .stroke-N7{stroke:#FFFFFF;}
+ .d2-2764772137 .stroke-B1{stroke:#0D32B2;}
+ .d2-2764772137 .stroke-B2{stroke:#0D32B2;}
+ .d2-2764772137 .stroke-B3{stroke:#E3E9FD;}
+ .d2-2764772137 .stroke-B4{stroke:#E3E9FD;}
+ .d2-2764772137 .stroke-B5{stroke:#EDF0FD;}
+ .d2-2764772137 .stroke-B6{stroke:#F7F8FE;}
+ .d2-2764772137 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-2764772137 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-2764772137 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-2764772137 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-2764772137 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-2764772137 .background-color-N1{background-color:#0A0F25;}
+ .d2-2764772137 .background-color-N2{background-color:#676C7E;}
+ .d2-2764772137 .background-color-N3{background-color:#9499AB;}
+ .d2-2764772137 .background-color-N4{background-color:#CFD2DD;}
+ .d2-2764772137 .background-color-N5{background-color:#DEE1EB;}
+ .d2-2764772137 .background-color-N6{background-color:#EEF1F8;}
+ .d2-2764772137 .background-color-N7{background-color:#FFFFFF;}
+ .d2-2764772137 .background-color-B1{background-color:#0D32B2;}
+ .d2-2764772137 .background-color-B2{background-color:#0D32B2;}
+ .d2-2764772137 .background-color-B3{background-color:#E3E9FD;}
+ .d2-2764772137 .background-color-B4{background-color:#E3E9FD;}
+ .d2-2764772137 .background-color-B5{background-color:#EDF0FD;}
+ .d2-2764772137 .background-color-B6{background-color:#F7F8FE;}
+ .d2-2764772137 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-2764772137 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-2764772137 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-2764772137 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-2764772137 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-2764772137 .color-N1{color:#0A0F25;}
+ .d2-2764772137 .color-N2{color:#676C7E;}
+ .d2-2764772137 .color-N3{color:#9499AB;}
+ .d2-2764772137 .color-N4{color:#CFD2DD;}
+ .d2-2764772137 .color-N5{color:#DEE1EB;}
+ .d2-2764772137 .color-N6{color:#EEF1F8;}
+ .d2-2764772137 .color-N7{color:#FFFFFF;}
+ .d2-2764772137 .color-B1{color:#0D32B2;}
+ .d2-2764772137 .color-B2{color:#0D32B2;}
+ .d2-2764772137 .color-B3{color:#E3E9FD;}
+ .d2-2764772137 .color-B4{color:#E3E9FD;}
+ .d2-2764772137 .color-B5{color:#EDF0FD;}
+ .d2-2764772137 .color-B6{color:#F7F8FE;}
+ .d2-2764772137 .color-AA2{color:#4A6FF3;}
+ .d2-2764772137 .color-AA4{color:#EDF0FD;}
+ .d2-2764772137 .color-AA5{color:#F7F8FE;}
+ .d2-2764772137 .color-AB4{color:#EDF0FD;}
+ .d2-2764772137 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>usersidintPKnamestringemailstringpasswordstringlast_logindatetimeproductsidintPKpricedecimalskustringnamestringordersidintPKuser_idintFKproduct_idintFKshipmentsidintPKorder_idintFKtracking_numberstringstatusstring
+
\ No newline at end of file