diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 5aee5ea42..59bb6569d 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -12,3 +12,4 @@ - Fixes edge case where layouts with dagre show a connection from the bottom side of shapes being slightly disconnected from the shape. [#820](https://github.com/terrastruct/d2/pull/820) - Fixes rare compiler bug when using underscores in edges to create objects across containers. [#824](https://github.com/terrastruct/d2/pull/824) - Fixes rare possibility of rendered connections being hidden or cut off. [#828](https://github.com/terrastruct/d2/pull/828) +- Creating nested children within `sql_table` and `class` shapes are now prevented (caused confusion when accidentally done). [#834](https://github.com/terrastruct/d2/pull/834) diff --git a/d2compiler/compile.go b/d2compiler/compile.go index 8442e5417..3bc0f26d1 100644 --- a/d2compiler/compile.go +++ b/d2compiler/compile.go @@ -160,6 +160,17 @@ func (c *compiler) compileField(obj *d2graph.Object, f *d2ir.Field) { return } + if obj.Parent != nil { + if obj.Parent.Attributes.Shape.Value == d2target.ShapeSQLTable { + c.errorf(f.LastRef().AST(), "sql_table columns cannot have children") + return + } + if obj.Parent.Attributes.Shape.Value == d2target.ShapeClass { + c.errorf(f.LastRef().AST(), "class fields cannot have children") + return + } + } + obj = obj.EnsureChild(d2graphIDA([]string{f.Name})) if f.Primary() != nil { c.compileLabel(obj.Attributes, f) diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 1ed5b18ca..fa238a2c5 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -1483,6 +1483,36 @@ d2/testdata/d2compiler/TestCompile/errors/reserved_icon_style.d2:2:9: near key " shape: sql_table x: {p -> q} }`, + expErr: `d2/testdata/d2compiler/TestCompile/edge_in_column.d2:3:7: sql_table columns cannot have children +d2/testdata/d2compiler/TestCompile/edge_in_column.d2:3:12: sql_table columns cannot have children`, + }, + { + name: "no-nested-columns-sql", + + text: `x: { + shape: sql_table + a -- b.b +}`, + expErr: `d2/testdata/d2compiler/TestCompile/no-nested-columns-sql.d2:3:10: sql_table columns cannot have children`, + }, + { + name: "no-nested-columns-sql-2", + + text: `x: { + shape: sql_table + a +} +x.a.b`, + expErr: `d2/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.d2:5:5: sql_table columns cannot have children`, + }, + { + name: "no-nested-columns-class", + + text: `x: { + shape: class + a.a +}`, + expErr: `d2/testdata/d2compiler/TestCompile/no-nested-columns-class.d2:3:5: class fields cannot have children`, }, { name: "edge_to_style", diff --git a/testdata/d2compiler/TestCompile/edge_in_column.exp.json b/testdata/d2compiler/TestCompile/edge_in_column.exp.json index 7783ac781..4a390573c 100644 --- a/testdata/d2compiler/TestCompile/edge_in_column.exp.json +++ b/testdata/d2compiler/TestCompile/edge_in_column.exp.json @@ -1,384 +1,16 @@ { - "graph": { - "name": "", - "ast": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-3:1:39", - "nodes": [ - { - "map_key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-3:1:39", - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-0:1:1", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-0:1:1", - "value": [ - { - "string": "x", - "raw_string": "x" - } - ] - } - } - ] - }, - "primary": {}, - "value": { - "map": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:3:3-3:0:38", - "nodes": [ - { - "map_key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,1:2:7-1:18:23", - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,1:2:7-1:7:12", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,1:2:7-1:7:12", - "value": [ - { - "string": "shape", - "raw_string": "shape" - } - ] - } - } - ] - }, - "primary": {}, - "value": { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,1:9:14-1:18:23", - "value": [ - { - "string": "sql_table", - "raw_string": "sql_table" - } - ] - } - } - } - }, - { - "map_key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:2:26-2:13:37", - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:2:26-2:3:27", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:2:26-2:3:27", - "value": [ - { - "string": "x", - "raw_string": "x" - } - ] - } - } - ] - }, - "primary": {}, - "value": { - "map": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:5:29-2:12:36", - "nodes": [ - { - "map_key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:12:36", - "edges": [ - { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:12:36", - "src": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:8:32", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:7:31", - "value": [ - { - "string": "p", - "raw_string": "p" - } - ] - } - } - ] - }, - "src_arrow": "", - "dst": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:10:34-2:12:36", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:11:35-2:12:36", - "value": [ - { - "string": "q", - "raw_string": "q" - } - ] - } - } - ] - }, - "dst_arrow": ">" - } - ], - "primary": {}, - "value": {} - } - } - ] - } - } - } - } - ] - } - } - } - } - ] - }, - "root": { - "id": "", - "id_val": "", - "label_dimensions": { - "width": 0, - "height": 0 - }, - "attributes": { - "label": { - "value": "" - }, - "style": {}, - "near_key": null, - "shape": { - "value": "" - }, - "direction": { - "value": "" - }, - "constraint": { - "value": "" - } - }, - "zIndex": 0 - }, - "edges": [ + "graph": null, + "err": { + "ioerr": null, + "errs": [ { - "index": 0, - "minWidth": 0, - "minHeight": 0, - "label_dimensions": { - "width": 0, - "height": 0 - }, - "isCurve": false, - "src_arrow": false, - "dst_arrow": true, - "references": [ - { - "map_key_edge_index": 0 - } - ], - "attributes": { - "label": { - "value": "" - }, - "style": {}, - "near_key": null, - "shape": { - "value": "" - }, - "direction": { - "value": "" - }, - "constraint": { - "value": "" - } - }, - "zIndex": 0 - } - ], - "objects": [ - { - "id": "x", - "id_val": "x", - "label_dimensions": { - "width": 0, - "height": 0 - }, - "references": [ - { - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-0:1:1", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,0:0:0-0:1:1", - "value": [ - { - "string": "x", - "raw_string": "x" - } - ] - } - } - ] - }, - "key_path_index": 0, - "map_key_edge_index": -1 - } - ], - "sql_table": { - "columns": [ - { - "name": { - "label": "x", - "fontSize": 0, - "fontFamily": "", - "language": "", - "color": "", - "italic": false, - "bold": false, - "underline": false, - "labelWidth": 0, - "labelHeight": 0 - }, - "type": { - "label": "", - "fontSize": 0, - "fontFamily": "", - "language": "", - "color": "", - "italic": false, - "bold": false, - "underline": false, - "labelWidth": 0, - "labelHeight": 0 - }, - "constraint": "", - "reference": "" - } - ] - }, - "attributes": { - "label": { - "value": "x" - }, - "style": {}, - "near_key": null, - "shape": { - "value": "sql_table" - }, - "direction": { - "value": "" - }, - "constraint": { - "value": "" - } - }, - "zIndex": 0 + "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:7:31", + "errmsg": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2:3:7: sql_table columns cannot have children" }, { - "id": "p", - "id_val": "p", - "label_dimensions": { - "width": 0, - "height": 0 - }, - "references": [ - { - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:8:32", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:6:30-2:7:31", - "value": [ - { - "string": "p", - "raw_string": "p" - } - ] - } - } - ] - }, - "key_path_index": 0, - "map_key_edge_index": 0 - } - ], - "attributes": { - "label": { - "value": "p" - }, - "style": {}, - "near_key": null, - "shape": { - "value": "rectangle" - }, - "direction": { - "value": "" - }, - "constraint": { - "value": "" - } - }, - "zIndex": 0 - }, - { - "id": "q", - "id_val": "q", - "label_dimensions": { - "width": 0, - "height": 0 - }, - "references": [ - { - "key": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:10:34-2:12:36", - "path": [ - { - "unquoted_string": { - "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:11:35-2:12:36", - "value": [ - { - "string": "q", - "raw_string": "q" - } - ] - } - } - ] - }, - "key_path_index": 0, - "map_key_edge_index": 0 - } - ], - "attributes": { - "label": { - "value": "q" - }, - "style": {}, - "near_key": null, - "shape": { - "value": "rectangle" - }, - "direction": { - "value": "" - }, - "constraint": { - "value": "" - } - }, - "zIndex": 0 + "range": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2,2:11:35-2:12:36", + "errmsg": "d2/testdata/d2compiler/TestCompile/edge_in_column.d2:3:12: sql_table columns cannot have children" } ] - }, - "err": null + } } diff --git a/testdata/d2compiler/TestCompile/no-nested-columns-class.exp.json b/testdata/d2compiler/TestCompile/no-nested-columns-class.exp.json new file mode 100644 index 000000000..cc9546885 --- /dev/null +++ b/testdata/d2compiler/TestCompile/no-nested-columns-class.exp.json @@ -0,0 +1,12 @@ +{ + "graph": null, + "err": { + "ioerr": null, + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/no-nested-columns-class.d2,2:4:24-2:5:25", + "errmsg": "d2/testdata/d2compiler/TestCompile/no-nested-columns-class.d2:3:5: class fields cannot have children" + } + ] + } +} diff --git a/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.exp.json b/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.exp.json new file mode 100644 index 000000000..15bef32df --- /dev/null +++ b/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.exp.json @@ -0,0 +1,12 @@ +{ + "graph": null, + "err": { + "ioerr": null, + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.d2,4:4:34-4:5:35", + "errmsg": "d2/testdata/d2compiler/TestCompile/no-nested-columns-sql-2.d2:5:5: sql_table columns cannot have children" + } + ] + } +} diff --git a/testdata/d2compiler/TestCompile/no-nested-columns-sql.exp.json b/testdata/d2compiler/TestCompile/no-nested-columns-sql.exp.json new file mode 100644 index 000000000..782ccce94 --- /dev/null +++ b/testdata/d2compiler/TestCompile/no-nested-columns-sql.exp.json @@ -0,0 +1,12 @@ +{ + "graph": null, + "err": { + "ioerr": null, + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/no-nested-columns-sql.d2,2:9:33-2:10:34", + "errmsg": "d2/testdata/d2compiler/TestCompile/no-nested-columns-sql.d2:3:10: sql_table columns cannot have children" + } + ] + } +}