feat(er): allow multiple constraints on attributes

little changes in grammar to get a list of constraints (PK, FK or UK), so little changes in renderer to handle this list
This commit is contained in:
Tom PERRILLAT-COLLOMB
2023-01-24 21:20:11 +01:00
parent 549483d19b
commit 26e9b1790b
4 changed files with 44 additions and 4 deletions

View File

@@ -71,6 +71,20 @@
</pre> </pre>
<hr /> <hr />
<pre class="mermaid">
erDiagram
"HOSPITAL" {
int id PK
int doctor_id PK,FK
string address UK
string name
string phone_number
string fax_number
}
</pre
>
<hr />
<script src="./mermaid.js"></script> <script src="./mermaid.js"></script>
<script type="module"> <script type="module">
mermaid.initialize({ mermaid.initialize({

View File

@@ -59,7 +59,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
// Check to see if any of the attributes has a key or a comment // Check to see if any of the attributes has a key or a comment
attributes.forEach((item) => { attributes.forEach((item) => {
if (item.attributeKeyType !== undefined) { if (item.attributeKeyTypeList !== undefined && item.attributeKeyTypeList.length > 0) {
hasKeyType = true; hasKeyType = true;
} }
@@ -112,6 +112,9 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
nodeHeight = Math.max(typeBBox.height, nameBBox.height); nodeHeight = Math.max(typeBBox.height, nameBBox.height);
if (hasKeyType) { if (hasKeyType) {
const keyTypeNodeText =
item.attributeKeyTypeList !== undefined ? item.attributeKeyTypeList.join(',') : '';
const keyTypeNode = groupNode const keyTypeNode = groupNode
.append('text') .append('text')
.classed('er entityLabel', true) .classed('er entityLabel', true)
@@ -122,7 +125,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
.style('text-anchor', 'left') .style('text-anchor', 'left')
.style('font-family', getConfig().fontFamily) .style('font-family', getConfig().fontFamily)
.style('font-size', attrFontSize + 'px') .style('font-size', attrFontSize + 'px')
.text(item.attributeKeyType || ''); .text(keyTypeNodeText);
attributeNode.kn = keyTypeNode; attributeNode.kn = keyTypeNode;
const keyTypeBBox = keyTypeNode.node().getBBox(); const keyTypeBBox = keyTypeNode.node().getBBox();

View File

@@ -28,6 +28,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
\"[^"]*\" return 'WORD'; \"[^"]*\" return 'WORD';
"erDiagram" return 'ER_DIAGRAM'; "erDiagram" return 'ER_DIAGRAM';
"{" { this.begin("block"); return 'BLOCK_START'; } "{" { this.begin("block"); return 'BLOCK_START'; }
<block>"," return 'COMMA';
<block>\s+ /* skip whitespace in block */ <block>\s+ /* skip whitespace in block */
<block>\b((?:PK)|(?:FK)|(?:UK))\b return 'ATTRIBUTE_KEY' <block>\b((?:PK)|(?:FK)|(?:UK))\b return 'ATTRIBUTE_KEY'
<block>(.*?)[~](.*?)*[~] return 'ATTRIBUTE_WORD'; <block>(.*?)[~](.*?)*[~] return 'ATTRIBUTE_WORD';
@@ -131,11 +132,12 @@ attributes
attribute attribute
: attributeType attributeName { $$ = { attributeType: $1, attributeName: $2 }; } : attributeType attributeName { $$ = { attributeType: $1, attributeName: $2 }; }
| attributeType attributeName attributeKeyType { $$ = { attributeType: $1, attributeName: $2, attributeKeyType: $3 }; } | attributeType attributeName attributeKeyTypeList { $$ = { attributeType: $1, attributeName: $2, attributeKeyTypeList: $3 }; }
| attributeType attributeName attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeComment: $3 }; } | attributeType attributeName attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeComment: $3 }; }
| attributeType attributeName attributeKeyType attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyType: $3, attributeComment: $4 }; } | attributeType attributeName attributeKeyTypeList attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyTypeList: $3, attributeComment: $4 }; }
; ;
attributeType attributeType
: ATTRIBUTE_WORD { $$=$1; } : ATTRIBUTE_WORD { $$=$1; }
; ;
@@ -144,6 +146,11 @@ attributeName
: ATTRIBUTE_WORD { $$=$1; } : ATTRIBUTE_WORD { $$=$1; }
; ;
attributeKeyTypeList
: attributeKeyType { $$ = [$1]; }
| attributeKeyTypeList COMMA attributeKeyType { $1.push($3); $$ = $1; }
;
attributeKeyType attributeKeyType
: ATTRIBUTE_KEY { $$=$1; } : ATTRIBUTE_KEY { $$=$1; }
; ;

View File

@@ -190,6 +190,22 @@ describe('when parsing ER diagram it...', function () {
expect(entities[entity].attributes.length).toBe(4); expect(entities[entity].attributes.length).toBe(4);
}); });
it('should allow an entity with attributes that have many constraints and comments', function () {
const entity = 'BOOK';
const attribute1 = 'int customer_number PK,FK "comment"';
const attribute2 = 'datetime customer_status_start_datetime PK,UK';
const attribute3 = 'string customer_name';
erDiagram.parser.parse(
`erDiagram\n${entity} {\n${attribute1} \n\n${attribute2}\n${attribute3}\n}`
);
const entities = erDb.getEntities();
expect(entities[entity].attributes[0].attributeKeyTypeList).toEqual(['PK', 'FK']);
expect(entities[entity].attributes[0].attributeComment).toBe('comment');
expect(entities[entity].attributes[1].attributeKeyTypeList).toEqual(['PK', 'UK']);
expect(entities[entity].attributes[2].attributeKeyTypeList).toBeUndefined();
});
it('should allow an entity with attribute that has a generic type', function () { it('should allow an entity with attribute that has a generic type', function () {
const entity = 'BOOK'; const entity = 'BOOK';
const attribute1 = 'type~T~ type'; const attribute1 = 'type~T~ type';