Skip to content

Commit

Permalink
Merge pull request #4030 from tomperr/feature/4009_er_multiple_constr…
Browse files Browse the repository at this point in the history
…aints

feat(er): add multiple key constraints
  • Loading branch information
sidharthv96 authored Jan 25, 2023
2 parents c76728b + dc0a46f commit c51f6df
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 15 deletions.
38 changes: 38 additions & 0 deletions demos/er.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,44 @@
</pre>
<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 />

<pre class="mermaid">
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string registrationNumber PK
string make
string model
string[] parts
}
PERSON ||--o{ NAMED-DRIVER : is
PERSON {
string driversLicense PK "The license #"
string(99) firstName "Only 99 characters are allowed"
string lastName
string phone UK
int age
}
NAMED-DRIVER {
string carRegistrationNumber PK, FK
string driverLicence PK,FK
}
MANUFACTURER only one to zero or more CAR : makes
</pre>

<script src="./mermaid.js"></script>
<script type="module">
mermaid.initialize({
Expand Down
22 changes: 15 additions & 7 deletions docs/syntax/entityRelationshipDiagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,13 @@ The `type` and `name` values must begin with an alphabetic character and may con

#### Attribute Keys and Comments

Attributes may also have a `key` or comment defined. Keys can be "PK", "FK" or "UK", for Primary Key, Foreign Key or Unique Key. And a `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.

```mermaid-example
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string allowedDriver FK "The license of the allowed driver"
string registrationNumber UK
string registrationNumber PK
string make
string model
string[] parts
Expand All @@ -217,17 +216,21 @@ erDiagram
string driversLicense PK "The license #"
string(99) firstName "Only 99 characters are allowed"
string lastName
string phone UK
int age
}
MANUFACTURER only one to zero or more CAR
NAMED-DRIVER {
string carRegistrationNumber PK, FK
string driverLicence PK, FK
}
MANUFACTURER only one to zero or more CAR : makes
```

```mermaid
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string allowedDriver FK "The license of the allowed driver"
string registrationNumber UK
string registrationNumber PK
string make
string model
string[] parts
Expand All @@ -237,9 +240,14 @@ erDiagram
string driversLicense PK "The license #"
string(99) firstName "Only 99 characters are allowed"
string lastName
string phone UK
int age
}
MANUFACTURER only one to zero or more CAR
NAMED-DRIVER {
string carRegistrationNumber PK, FK
string driverLicence PK, FK
}
MANUFACTURER only one to zero or more CAR : makes
```

### Other Things
Expand Down
7 changes: 5 additions & 2 deletions packages/mermaid/src/diagrams/er/erRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {

// Check to see if any of the attributes has a key or a comment
attributes.forEach((item) => {
if (item.attributeKeyType !== undefined) {
if (item.attributeKeyTypeList !== undefined && item.attributeKeyTypeList.length > 0) {
hasKeyType = true;
}

Expand Down Expand Up @@ -112,6 +112,9 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
nodeHeight = Math.max(typeBBox.height, nameBBox.height);

if (hasKeyType) {
const keyTypeNodeText =
item.attributeKeyTypeList !== undefined ? item.attributeKeyTypeList.join(',') : '';

const keyTypeNode = groupNode
.append('text')
.classed('er entityLabel', true)
Expand All @@ -122,7 +125,7 @@ const drawAttributes = (groupNode, entityTextNode, attributes) => {
.style('text-anchor', 'left')
.style('font-family', getConfig().fontFamily)
.style('font-size', attrFontSize + 'px')
.text(item.attributeKeyType || '');
.text(keyTypeNodeText);

attributeNode.kn = keyTypeNode;
const keyTypeBBox = keyTypeNode.node().getBBox();
Expand Down
11 changes: 9 additions & 2 deletions packages/mermaid/src/diagrams/er/parser/erDiagram.jison
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ accDescr\s*"{"\s* { this.begin("acc_descr_multili
\"[^"]*\" return 'WORD';
"erDiagram" return 'ER_DIAGRAM';
"{" { this.begin("block"); return 'BLOCK_START'; }
<block>"," return 'COMMA';
<block>\s+ /* skip whitespace in block */
<block>\b((?:PK)|(?:FK)|(?:UK))\b return 'ATTRIBUTE_KEY'
<block>(.*?)[~](.*?)*[~] return 'ATTRIBUTE_WORD';
Expand Down Expand Up @@ -131,11 +132,12 @@ attributes

attribute
: 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 attributeKeyType attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyType: $3, attributeComment: $4 }; }
| attributeType attributeName attributeKeyTypeList attributeComment { $$ = { attributeType: $1, attributeName: $2, attributeKeyTypeList: $3, attributeComment: $4 }; }
;


attributeType
: ATTRIBUTE_WORD { $$=$1; }
;
Expand All @@ -144,6 +146,11 @@ attributeName
: ATTRIBUTE_WORD { $$=$1; }
;

attributeKeyTypeList
: attributeKeyType { $$ = [$1]; }
| attributeKeyTypeList COMMA attributeKeyType { $1.push($3); $$ = $1; }
;

attributeKeyType
: ATTRIBUTE_KEY { $$=$1; }
;
Expand Down
22 changes: 22 additions & 0 deletions packages/mermaid/src/diagrams/er/parser/erDiagram.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,28 @@ describe('when parsing ER diagram it...', function () {
expect(entities[entity].attributes.length).toBe(4);
});

it('should allow an entity with attributes that have many constraints and comments', function () {
const entity = 'CUSTOMER';
const attribute1 = 'int customer_number PK, FK "comment1"';
const attribute2 = 'datetime customer_status_start_datetime PK,UK, FK';
const attribute3 = 'datetime customer_status_end_datetime PK , UK "comment3"';
const attribute4 = 'string customer_firstname';
const attribute5 = 'string customer_lastname "comment5"';

erDiagram.parser.parse(
`erDiagram\n${entity} {\n${attribute1}\n${attribute2}\n${attribute3}\n${attribute4}\n${attribute5}\n}`
);
const entities = erDb.getEntities();
expect(entities[entity].attributes[0].attributeKeyTypeList).toEqual(['PK', 'FK']);
expect(entities[entity].attributes[0].attributeComment).toBe('comment1');
expect(entities[entity].attributes[1].attributeKeyTypeList).toEqual(['PK', 'UK', 'FK']);
expect(entities[entity].attributes[2].attributeKeyTypeList).toEqual(['PK', 'UK']);
expect(entities[entity].attributes[2].attributeComment).toBe('comment3');
expect(entities[entity].attributes[3].attributeKeyTypeList).toBeUndefined();
expect(entities[entity].attributes[4].attributeKeyTypeList).toBeUndefined();
expect(entities[entity].attributes[4].attributeComment).toBe('comment5');
});

it('should allow an entity with attribute that has a generic type', function () {
const entity = 'BOOK';
const attribute1 = 'type~T~ type';
Expand Down
12 changes: 8 additions & 4 deletions packages/mermaid/src/docs/syntax/entityRelationshipDiagram.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,14 +146,13 @@ The `type` and `name` values must begin with an alphabetic character and may con

#### Attribute Keys and Comments

Attributes may also have a `key` or comment defined. Keys can be "PK", "FK" or "UK", for Primary Key, Foreign Key or Unique Key. And a `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.
Attributes may also have a `key` or comment defined. Keys can be `PK`, `FK` or `UK`, for Primary Key, Foreign Key or Unique Key. To specify multiple key constraints on a single attribute, separate them with a comma (e.g., `PK, FK`).. A `comment` is defined by double quotes at the end of an attribute. Comments themselves cannot have double-quote characters in them.

```mermaid-example
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string allowedDriver FK "The license of the allowed driver"
string registrationNumber UK
string registrationNumber PK
string make
string model
string[] parts
Expand All @@ -163,9 +162,14 @@ erDiagram
string driversLicense PK "The license #"
string(99) firstName "Only 99 characters are allowed"
string lastName
string phone UK
int age
}
MANUFACTURER only one to zero or more CAR
NAMED-DRIVER {
string carRegistrationNumber PK, FK
string driverLicence PK, FK
}
MANUFACTURER only one to zero or more CAR : makes
```

### Other Things
Expand Down

0 comments on commit c51f6df

Please sign in to comment.