mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-23 09:20:03 +02:00
Alter ERD syntax for compatibility with PlantUML
This commit is contained in:
@@ -8,22 +8,15 @@ let relationships = [];
|
||||
let title = '';
|
||||
|
||||
const Cardinality = {
|
||||
ONLY_ONE_TO_ONE_OR_MORE: 'ONLY_ONE_TO_ONE_OR_MORE',
|
||||
ONLY_ONE_TO_ZERO_OR_MORE: 'ONLY_ONE_TO_ZERO_OR_MORE',
|
||||
ZERO_OR_ONE_TO_ZERO_OR_MORE: 'ZERO_OR_ONE_TO_ZERO_OR_MORE',
|
||||
ZERO_OR_ONE_TO_ONE_OR_MORE: 'ZERO_OR_ONE_TO_ONE_OR_MORE',
|
||||
ONE_OR_MORE_TO_ONLY_ONE: 'ONE_OR_MORE_TO_ONLY_ONE',
|
||||
ZERO_OR_MORE_TO_ONLY_ONE: 'ZERO_OR_MORE_TO_ONLY_ONE',
|
||||
ZERO_OR_MORE_TO_ZERO_OR_ONE: 'ZERO_OR_MORE_TO_ZERO_OR_ONE',
|
||||
ONE_OR_MORE_TO_ZERO_OR_ONE: 'ONE_OR_MORE_TO_ZERO_OR_ONE',
|
||||
ZERO_OR_ONE_TO_ONLY_ONE: 'ZERO_OR_ONE_TO_ONLY_ONE',
|
||||
ONLY_ONE_TO_ONLY_ONE: 'ONLY_ONE_TO_ONLY_ONE',
|
||||
ONLY_ONE_TO_ZERO_OR_ONE: 'ONLY_ONE_TO_ZERO_OR_ONE',
|
||||
ZERO_OR_ONE_TO_ZERO_OR_ONE: 'ZERO_OR_ONE_TO_ZERO_OR_ONE',
|
||||
ZERO_OR_MORE_TO_ZERO_OR_MORE: 'ZERO_OR_MORE_TO_ZERO_OR_MORE',
|
||||
ZERO_OR_MORE_TO_ONE_OR_MORE: 'ZERO_OR_MORE_TO_ONE_OR_MORE',
|
||||
ONE_OR_MORE_TO_ZERO_OR_MORE: 'ONE_OR_MORE_TO_ZERO_OR_MORE',
|
||||
ONE_OR_MORE_TO_ONE_OR_MORE: 'ONE_OR_MORE_TO_ONE_OR_MORE'
|
||||
ZERO_OR_ONE: 'ZERO_OR_ONE',
|
||||
ZERO_OR_MORE: 'ZERO_OR_MORE',
|
||||
ONE_OR_MORE: 'ONE_OR_MORE',
|
||||
ONLY_ONE: 'ONLY_ONE'
|
||||
};
|
||||
|
||||
const Identification = {
|
||||
NON_IDENTIFYING: 'NON_IDENTIFYING',
|
||||
IDENTIFYING: 'IDENTIFYING'
|
||||
};
|
||||
|
||||
const addEntity = function(name) {
|
||||
@@ -40,14 +33,14 @@ const getEntities = () => entities;
|
||||
* @param entA The first entity in the relationship
|
||||
* @param rolA The role played by the first entity in relation to the second
|
||||
* @param entB The second entity in the relationship
|
||||
* @param card The cardinality of the relationship between the two entities
|
||||
* @param rSpec The details of the relationship between the two entities
|
||||
*/
|
||||
const addRelationship = function(entA, rolA, entB, card) {
|
||||
const addRelationship = function(entA, rolA, entB, rSpec) {
|
||||
let rel = {
|
||||
entityA: entA,
|
||||
roleA: rolA,
|
||||
entityB: entB,
|
||||
cardinality: card
|
||||
relSpec: rSpec
|
||||
};
|
||||
|
||||
relationships.push(rel);
|
||||
@@ -73,6 +66,7 @@ const clear = function() {
|
||||
|
||||
export default {
|
||||
Cardinality,
|
||||
Identification,
|
||||
addEntity,
|
||||
getEntities,
|
||||
addRelationship,
|
||||
|
@@ -25,7 +25,7 @@ export const setConf = function(cnf) {
|
||||
* Use D3 to construct the svg elements for the entities
|
||||
* @param svgNode the svg node that contains the diagram
|
||||
* @param entities The entities to be drawn
|
||||
* @param g The graph that contains the vertex and edge definitions post-layout
|
||||
* @param graph The graph that contains the vertex and edge definitions post-layout
|
||||
* @return The first entity that was inserted
|
||||
*/
|
||||
const drawEntities = function(svgNode, entities, graph) {
|
||||
@@ -63,7 +63,7 @@ const drawEntities = function(svgNode, entities, graph) {
|
||||
const rectNode = groupNode
|
||||
.insert('rect', '#' + textId)
|
||||
.attr('fill', conf.fill)
|
||||
.attr('fill-opacity', conf.fillOpacity)
|
||||
.attr('fill-opacity', '100%')
|
||||
.attr('stroke', conf.stroke)
|
||||
.attr('x', 0)
|
||||
.attr('y', 0)
|
||||
@@ -124,6 +124,7 @@ let relCnt = 0;
|
||||
* @param svg the svg node
|
||||
* @param rel the relationship to draw in the svg
|
||||
* @param g the graph containing the edge information
|
||||
* @param insert the insertion point in the svg DOM (because relationships have markers that need to sit 'behind' opaque entity boxes)
|
||||
*/
|
||||
const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
relCnt++;
|
||||
@@ -149,6 +150,11 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
.attr('stroke', conf.stroke)
|
||||
.attr('fill', 'none');
|
||||
|
||||
// ...and with dashes if necessary
|
||||
if (rel.relSpec.relType === erDb.Identification.NON_IDENTIFYING) {
|
||||
svgPath.attr('stroke-dasharray', '8,8');
|
||||
}
|
||||
|
||||
// TODO: Understand this better
|
||||
let url = '';
|
||||
if (conf.arrowMarkerAbsolute) {
|
||||
@@ -164,106 +170,44 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
|
||||
// Decide which start and end markers it needs. It may be possible to be more concise here
|
||||
// by reversing a start marker to make an end marker...but this will do for now
|
||||
switch (rel.cardinality) {
|
||||
case erDb.Cardinality.ONLY_ONE_TO_ONE_OR_MORE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
|
||||
// Note that the 'A' entity's marker is at the end of the relationship and the 'B' entity's marker is at the start
|
||||
switch (rel.relSpec.cardA) {
|
||||
case erDb.Cardinality.ZERO_OR_ONE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_MORE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
case erDb.Cardinality.ZERO_OR_MORE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_MORE:
|
||||
case erDb.Cardinality.ONE_OR_MORE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rel.relSpec.cardB) {
|
||||
case erDb.Cardinality.ZERO_OR_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_ONE_TO_ONE_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE_TO_ONLY_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE_TO_ONLY_ONE:
|
||||
case erDb.Cardinality.ZERO_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_ONE:
|
||||
case erDb.Cardinality.ONE_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_ONE_TO_ONLY_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE_TO_ONLY_ONE:
|
||||
case erDb.Cardinality.ONLY_ONE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_ONE:
|
||||
svgPath.attr('marker-start', 'url(' + url + '#' + erMarkers.ERMarkers.ONLY_ONE_START + ')');
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_ONE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_ONE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ZERO_OR_MORE_TO_ONE_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ZERO_OR_MORE_END + ')');
|
||||
break;
|
||||
case erDb.Cardinality.ONE_OR_MORE_TO_ONE_OR_MORE:
|
||||
svgPath.attr(
|
||||
'marker-start',
|
||||
'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_START + ')'
|
||||
);
|
||||
svgPath.attr('marker-end', 'url(' + url + '#' + erMarkers.ERMarkers.ONE_OR_MORE_END + ')');
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -289,7 +233,7 @@ const drawRelationshipFromLayout = function(svg, rel, g, insert) {
|
||||
// Figure out how big the opaque 'container' rectangle needs to be
|
||||
const labelBBox = labelNode.node().getBBox();
|
||||
|
||||
// Insert the opaque rectangle in front of the text label
|
||||
// Insert the opaque rectangle before the text label
|
||||
svg
|
||||
.insert('rect', '#' + labelId)
|
||||
.attr('x', labelPoint.x - labelBBox.width / 2)
|
||||
@@ -384,28 +328,16 @@ export const draw = function(text, id) {
|
||||
drawRelationshipFromLayout(svg, rel, g, firstEntity);
|
||||
});
|
||||
|
||||
const padding = 8; // TODO: move this to config
|
||||
const padding = conf.diagramPadding;
|
||||
|
||||
const svgBounds = svg.node().getBBox();
|
||||
const width = svgBounds.width + padding * 4;
|
||||
const height = svgBounds.height + padding * 4;
|
||||
logger.debug(
|
||||
`new ViewBox 0 0 ${width} ${height}`,
|
||||
`translate(${padding - g._label.marginx}, ${padding - g._label.marginy})`
|
||||
);
|
||||
const width = svgBounds.width + padding * 2;
|
||||
const height = svgBounds.height + padding * 2;
|
||||
|
||||
if (conf.useMaxWidth) {
|
||||
svg.attr('width', '100%');
|
||||
svg.attr('style', `max-width: ${width}px;`);
|
||||
} else {
|
||||
svg.attr('height', height);
|
||||
svg.attr('width', width);
|
||||
}
|
||||
|
||||
svg.attr('viewBox', `0 0 ${width} ${height}`);
|
||||
svg
|
||||
.select('g')
|
||||
.attr('transform', `translate(${padding - g._label.marginx}, ${padding - svgBounds.y})`);
|
||||
svg.attr('height', height);
|
||||
svg.attr('width', '100%');
|
||||
svg.attr('style', `max-width: ${width}px;`);
|
||||
svg.attr('viewBox', `${svgBounds.x - padding} ${svgBounds.y - padding} ${width} ${height}`);
|
||||
}; // draw
|
||||
|
||||
export default {
|
||||
|
@@ -10,27 +10,21 @@
|
||||
<string>["] { this.popState(); }
|
||||
<string>[^"]* { return 'STR'; }
|
||||
"erDiagram" return 'ER_DIAGRAM';
|
||||
\|o return 'ZERO_OR_ONE';
|
||||
\}o return 'ZERO_OR_MORE';
|
||||
\}\| return 'ONE_OR_MORE';
|
||||
\|\| return 'ONLY_ONE';
|
||||
o\| return 'ZERO_OR_ONE';
|
||||
o\{ return 'ZERO_OR_MORE';
|
||||
\|\{ return 'ONE_OR_MORE';
|
||||
\.\. return 'NON_IDENTIFYING';
|
||||
\-\- return 'IDENTIFYING';
|
||||
\.\- return 'NON_IDENTIFYING';
|
||||
\-\. return 'NON_IDENTIFYING';
|
||||
[A-Za-z][A-Za-z0-9\-]* return 'ALPHANUM';
|
||||
\>\?\-\?\< return 'ZERO_OR_MORE_TO_ZERO_OR_MORE';
|
||||
\>\?\-\!\< return 'ZERO_OR_MORE_TO_ONE_OR_MORE';
|
||||
\>\!\-\!\< return 'ONE_OR_MORE_TO_ONE_OR_MORE';
|
||||
\>\!\-\?\< return 'ONE_OR_MORE_TO_ZERO_OR_MORE';
|
||||
\!\-\!\< return 'ONLY_ONE_TO_ONE_OR_MORE';
|
||||
\!\-\?\< return 'ONLY_ONE_TO_ZERO_OR_MORE';
|
||||
\?\-\?\< return 'ZERO_OR_ONE_TO_ZERO_OR_MORE';
|
||||
\?\-\!\< return 'ZERO_OR_ONE_TO_ONE_OR_MORE';
|
||||
\>\!\-\! return 'ONE_OR_MORE_TO_ONLY_ONE';
|
||||
\>\?\-\! return 'ZERO_OR_MORE_TO_ONLY_ONE';
|
||||
\>\?\-\? return 'ZERO_OR_MORE_TO_ZERO_OR_ONE';
|
||||
\>\!\-\? return 'ONE_OR_MORE_TO_ZERO_OR_ONE';
|
||||
\?\-\! return 'ZERO_OR_ONE_TO_ONLY_ONE';
|
||||
\!\-\! return 'ONLY_ONE_TO_ONLY_ONE';
|
||||
\!\-\? return 'ONLY_ONE_TO_ZERO_OR_ONE';
|
||||
\?\-\? return 'ZERO_OR_ONE_TO_ZERO_OR_ONE';
|
||||
. return yytext[0];
|
||||
<<EOF>> return 'EOF';
|
||||
|
||||
|
||||
/lex
|
||||
|
||||
%start start
|
||||
@@ -46,8 +40,8 @@ document
|
||||
;
|
||||
|
||||
statement
|
||||
: entityName relationship entityName ':' role
|
||||
{
|
||||
: entityName relSpec entityName ':' role
|
||||
{
|
||||
yy.addEntity($1);
|
||||
yy.addEntity($3);
|
||||
yy.addRelationship($1, $5, $3, $2);
|
||||
@@ -55,26 +49,27 @@ statement
|
||||
};
|
||||
|
||||
entityName
|
||||
: 'ALPHANUM' { $$ = $1; }
|
||||
: 'ALPHANUM' { $$ = $1; /*console.log('Entity: ' + $1);*/ }
|
||||
;
|
||||
|
||||
relationship
|
||||
: 'ONLY_ONE_TO_ONE_OR_MORE' { $$ = yy.Cardinality.ONLY_ONE_TO_ONE_OR_MORE; }
|
||||
| 'ONLY_ONE_TO_ZERO_OR_MORE' { $$ = yy.Cardinality.ONLY_ONE_TO_ZERO_OR_MORE; }
|
||||
| 'ZERO_OR_ONE_TO_ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_MORE; }
|
||||
| 'ZERO_OR_ONE_TO_ONE_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_ONE_TO_ONE_OR_MORE; }
|
||||
| 'ONE_OR_MORE_TO_ONLY_ONE' { $$ = yy.Cardinality.ONE_OR_MORE_TO_ONLY_ONE; }
|
||||
| 'ZERO_OR_MORE_TO_ONLY_ONE' { $$ = yy.Cardinality.ZERO_OR_MORE_TO_ONLY_ONE; }
|
||||
| 'ZERO_OR_MORE_TO_ZERO_OR_ONE' { $$ = yy.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_ONE; }
|
||||
| 'ONE_OR_MORE_TO_ZERO_OR_ONE' { $$ = yy.Cardinality.ONE_OR_MORE_TO_ZERO_OR_ONE; }
|
||||
| 'ZERO_OR_ONE_TO_ONLY_ONE' { $$ = yy.Cardinality.ZERO_OR_ONE_TO_ONLY_ONE; }
|
||||
| 'ONLY_ONE_TO_ONLY_ONE' { $$ = yy.Cardinality.ONLY_ONE_TO_ONLY_ONE; }
|
||||
| 'ONLY_ONE_TO_ZERO_OR_ONE' { $$ = yy.Cardinality.ONLY_ONE_TO_ZERO_OR_ONE; }
|
||||
| 'ZERO_OR_ONE_TO_ZERO_OR_ONE' { $$ = yy.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_ONE; }
|
||||
| 'ZERO_OR_MORE_TO_ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_MORE; }
|
||||
| 'ZERO_OR_MORE_TO_ONE_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE_TO_ONE_OR_MORE; }
|
||||
| 'ONE_OR_MORE_TO_ONE_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE_TO_ONE_OR_MORE; }
|
||||
| 'ONE_OR_MORE_TO_ZERO_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE_TO_ZERO_OR_MORE; }
|
||||
relSpec
|
||||
: cardinality relType cardinality
|
||||
{
|
||||
$$ = { cardA: $3, relType: $2, cardB: $1 };
|
||||
/*console.log('relSpec: ' + $3 + $2 + $1);*/
|
||||
}
|
||||
;
|
||||
|
||||
cardinality
|
||||
: 'ZERO_OR_ONE' { $$ = yy.Cardinality.ZERO_OR_ONE; }
|
||||
| 'ZERO_OR_MORE' { $$ = yy.Cardinality.ZERO_OR_MORE; }
|
||||
| 'ONE_OR_MORE' { $$ = yy.Cardinality.ONE_OR_MORE; }
|
||||
| 'ONLY_ONE' { $$ = yy.Cardinality.ONLY_ONE; }
|
||||
;
|
||||
|
||||
relType
|
||||
: 'NON_IDENTIFYING' { $$ = yy.Identification.NON_IDENTIFYING; }
|
||||
| 'IDENTIFYING' { $$ = yy.Identification.IDENTIFYING; }
|
||||
;
|
||||
|
||||
role
|
||||
|
@@ -15,7 +15,7 @@ describe('when parsing ER diagram it...', function() {
|
||||
});
|
||||
|
||||
it('should associate two entities correctly', function() {
|
||||
erDiagram.parser.parse('erDiagram\nCAR !-?< DRIVER : "insured for"');
|
||||
erDiagram.parser.parse('erDiagram\nCAR ||--o{ DRIVER : "insured for"');
|
||||
const entities = erDb.getEntities();
|
||||
const relationships = erDb.getRelationships();
|
||||
const carEntity = entities.CAR;
|
||||
@@ -24,12 +24,14 @@ describe('when parsing ER diagram it...', function() {
|
||||
expect(carEntity).toBe('CAR');
|
||||
expect(driverEntity).toBe('DRIVER');
|
||||
expect(relationships.length).toBe(1);
|
||||
expect(relationships[0].cardinality).toBe(erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_MORE);
|
||||
expect(relationships[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
expect(relationships[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
expect(relationships[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING);
|
||||
});
|
||||
|
||||
it('should not create duplicate entities', function() {
|
||||
const line1 = 'CAR !-?< DRIVER : "insured for"';
|
||||
const line2 = 'DRIVER !-! LICENSE : has';
|
||||
const line1 = 'CAR ||--o{ DRIVER : "insured for"';
|
||||
const line2 = 'DRIVER ||--|| LICENSE : has';
|
||||
erDiagram.parser.parse(`erDiagram\n${line1}\n${line2}`);
|
||||
const entities = erDb.getEntities();
|
||||
|
||||
@@ -38,7 +40,7 @@ describe('when parsing ER diagram it...', function() {
|
||||
|
||||
it('should create the role specified', function() {
|
||||
const teacherRole = 'is teacher of';
|
||||
const line1 = `TEACHER >?-?< STUDENT : "${teacherRole}"`;
|
||||
const line1 = `TEACHER }o--o{ STUDENT : "${teacherRole}"`;
|
||||
erDiagram.parser.parse(`erDiagram\n${line1}`);
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
@@ -46,13 +48,13 @@ describe('when parsing ER diagram it...', function() {
|
||||
});
|
||||
|
||||
it('should allow recursive relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nNODE !-?< NODE : "leads to"');
|
||||
erDiagram.parser.parse('erDiagram\nNODE ||--o{ NODE : "leads to"');
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(1);
|
||||
});
|
||||
|
||||
it('should allow more than one relationship between the same two entities', function() {
|
||||
const line1 = 'CAR !-?< PERSON : "insured for"';
|
||||
const line2 = 'CAR >?-! PERSON : "owned by"';
|
||||
const line1 = 'CAR ||--o{ PERSON : "insured for"';
|
||||
const line2 = 'CAR }o--|| PERSON : "owned by"';
|
||||
erDiagram.parser.parse(`erDiagram\n${line1}\n${line2}`);
|
||||
const entities = erDb.getEntities();
|
||||
const rels = erDb.getRelationships();
|
||||
@@ -69,149 +71,178 @@ describe('when parsing ER diagram it...', function() {
|
||||
/* TODO */
|
||||
});
|
||||
|
||||
|
||||
it('should handle only-one-to-one-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA !-!< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA ||--|{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONLY_ONE_TO_ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
});
|
||||
|
||||
it('should handle only-one-to-zero-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA !-?< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA ||..o{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
|
||||
});
|
||||
|
||||
it('should handle zero-or-one-to-zero-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA ?-?< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA |o..o{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-one-to-one-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA ?-!< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA |o--|{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_ONE_TO_ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
});
|
||||
|
||||
it('should handle one-or-more-to-only-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >!-! B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }|--|| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONE_OR_MORE_TO_ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-more-to-only-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >?-! B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }o--|| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_MORE_TO_ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-more-to-zero-or-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >?-? B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }o..o| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle one-or-more-to-zero-or-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >!-? B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }|..o| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-one-to-only-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA ?-! B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA |o..|| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_ONE_TO_ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
});
|
||||
|
||||
it('should handle only-one-to-only-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA !-! B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA ||..|| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONLY_ONE_TO_ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
});
|
||||
|
||||
it('should handle only-one-to-zero-or-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA !-? B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA ||--o| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONLY_ONE_TO_ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONLY_ONE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-one-to-zero-or-one relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA ?-? B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA |o..o| B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_ONE_TO_ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_ONE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-more-to-zero-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >?-?< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }o--o{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_MORE_TO_ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle one-or-more-to-one-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >!-!< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }|..|{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONE_OR_MORE_TO_ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle zero-or-more-to-one-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >?-!< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }o--|{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ZERO_OR_MORE_TO_ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
});
|
||||
|
||||
it('should handle one-or-more-to-zero-or-more relationships', function() {
|
||||
erDiagram.parser.parse('erDiagram\nA >!-?< B : has');
|
||||
erDiagram.parser.parse('erDiagram\nA }|..o{ B : has');
|
||||
const rels = erDb.getRelationships();
|
||||
|
||||
expect(Object.keys(erDb.getEntities()).length).toBe(2);
|
||||
expect(rels.length).toBe(1);
|
||||
expect(rels[0].cardinality).toBe(erDb.Cardinality.ONE_OR_MORE_TO_ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardA).toBe(erDb.Cardinality.ZERO_OR_MORE);
|
||||
expect(rels[0].relSpec.cardB).toBe(erDb.Cardinality.ONE_OR_MORE);
|
||||
});
|
||||
|
||||
it('should represent identifying relationships properly', function() {
|
||||
erDiagram.parser.parse('erDiagram\nHOUSE ||--|{ ROOM : contains');
|
||||
const rels = erDb.getRelationships();
|
||||
expect(rels[0].relSpec.relType).toBe(erDb.Identification.IDENTIFYING);
|
||||
});
|
||||
|
||||
it('should represent non-identifying relationships properly', function() {
|
||||
erDiagram.parser.parse('erDiagram\n PERSON ||..o{ POSSESSION : owns');
|
||||
const rels = erDb.getRelationships();
|
||||
expect(rels[0].relSpec.relType).toBe(erDb.Identification.NON_IDENTIFYING);
|
||||
});
|
||||
|
||||
it('should not accept a syntax error', function() {
|
||||
|
Reference in New Issue
Block a user