mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-08-18 07:49:26 +02:00
Merge pull request #4030 from tomperr/feature/4009_er_multiple_constraints
feat(er): add multiple key constraints
This commit is contained in:
@@ -71,6 +71,44 @@
|
|||||||
</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 />
|
||||||
|
|
||||||
|
<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 src="./mermaid.js"></script>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
mermaid.initialize({
|
mermaid.initialize({
|
||||||
|
@@ -200,14 +200,13 @@ The `type` and `name` values must begin with an alphabetic character and may con
|
|||||||
|
|
||||||
#### Attribute Keys and Comments
|
#### 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
|
```mermaid-example
|
||||||
erDiagram
|
erDiagram
|
||||||
CAR ||--o{ NAMED-DRIVER : allows
|
CAR ||--o{ NAMED-DRIVER : allows
|
||||||
CAR {
|
CAR {
|
||||||
string allowedDriver FK "The license of the allowed driver"
|
string registrationNumber PK
|
||||||
string registrationNumber UK
|
|
||||||
string make
|
string make
|
||||||
string model
|
string model
|
||||||
string[] parts
|
string[] parts
|
||||||
@@ -217,17 +216,21 @@ erDiagram
|
|||||||
string driversLicense PK "The license #"
|
string driversLicense PK "The license #"
|
||||||
string(99) firstName "Only 99 characters are allowed"
|
string(99) firstName "Only 99 characters are allowed"
|
||||||
string lastName
|
string lastName
|
||||||
|
string phone UK
|
||||||
int age
|
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
|
```mermaid
|
||||||
erDiagram
|
erDiagram
|
||||||
CAR ||--o{ NAMED-DRIVER : allows
|
CAR ||--o{ NAMED-DRIVER : allows
|
||||||
CAR {
|
CAR {
|
||||||
string allowedDriver FK "The license of the allowed driver"
|
string registrationNumber PK
|
||||||
string registrationNumber UK
|
|
||||||
string make
|
string make
|
||||||
string model
|
string model
|
||||||
string[] parts
|
string[] parts
|
||||||
@@ -237,9 +240,14 @@ erDiagram
|
|||||||
string driversLicense PK "The license #"
|
string driversLicense PK "The license #"
|
||||||
string(99) firstName "Only 99 characters are allowed"
|
string(99) firstName "Only 99 characters are allowed"
|
||||||
string lastName
|
string lastName
|
||||||
|
string phone UK
|
||||||
int age
|
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
|
### Other Things
|
||||||
|
@@ -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();
|
||||||
|
@@ -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; }
|
||||||
;
|
;
|
||||||
|
@@ -190,6 +190,28 @@ 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 = '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 () {
|
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';
|
||||||
|
@@ -146,14 +146,13 @@ The `type` and `name` values must begin with an alphabetic character and may con
|
|||||||
|
|
||||||
#### Attribute Keys and Comments
|
#### 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
|
```mermaid-example
|
||||||
erDiagram
|
erDiagram
|
||||||
CAR ||--o{ NAMED-DRIVER : allows
|
CAR ||--o{ NAMED-DRIVER : allows
|
||||||
CAR {
|
CAR {
|
||||||
string allowedDriver FK "The license of the allowed driver"
|
string registrationNumber PK
|
||||||
string registrationNumber UK
|
|
||||||
string make
|
string make
|
||||||
string model
|
string model
|
||||||
string[] parts
|
string[] parts
|
||||||
@@ -163,9 +162,14 @@ erDiagram
|
|||||||
string driversLicense PK "The license #"
|
string driversLicense PK "The license #"
|
||||||
string(99) firstName "Only 99 characters are allowed"
|
string(99) firstName "Only 99 characters are allowed"
|
||||||
string lastName
|
string lastName
|
||||||
|
string phone UK
|
||||||
int age
|
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
|
### Other Things
|
||||||
|
Reference in New Issue
Block a user