X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=parser.js;h=0d52ee00005bb6889b298d40ee312ab0c68a4956;hb=4ef6cdeda1d92848df61a92f8fa4af20761b99bb;hp=6caf0a9f5a3f0dfdc4f153a5d8e4ffd54dba02df;hpb=006d95a3942660083d2c957afea5338c2de8642d;p=erdiag.git diff --git a/parser.js b/parser.js index 6caf0a9..0d52ee0 100644 --- a/parser.js +++ b/parser.js @@ -3,11 +3,10 @@ class ErDiags { constructor(description) { - this.entities = {}; - this.inheritances = []; - this.associations = []; + this.entities = { }; + this.inheritances = [ ]; + this.associations = [ ]; this.txt2json(description); - this.tables = []; // Cache SVG graphs returned by server (in addition to server cache = good perfs) this.mcdGraph = ""; this.mldGraph = ""; @@ -26,7 +25,9 @@ class ErDiags "*": "0,n", "+": "1,n", "?": "0,1", - "1": "1,1" + "1": "1,1", + "?R": "(0,1)", + "1R": "(1,1)", }; } @@ -136,7 +137,10 @@ class ErDiags return inheritance; } - // Association (parsed here): { entities: ArrayOf entity names + cardinality, [attributes: ArrayOf {name, [isKey], [type], [qualifiers]}] } + // Association (parsed here): { + // entities: ArrayOf entity names + cardinality, + // [attributes: ArrayOf {name, [isKey], [type], [qualifiers]}] + // } parseAssociation(lines, start, end) { let assoce = { }; @@ -192,7 +196,7 @@ class ErDiags mcdDot += 'rankdir="LR";\n'; // Nodes: if (mcdStyle == "compact") - mcdDot += "node [shape=plaintext];\n"; + mcdDot += 'node [shape=plaintext];\n'; _.shuffle(Object.keys(this.entities)).forEach( name => { if (mcdStyle == "bubble") { @@ -202,7 +206,7 @@ class ErDiags mcdDot += '];\n'; if (!!this.entities[name].attributes) { - _.shuffle(this.entities[name].attributes).forEach( a => { + this.entities[name].attributes.forEach( a => { let label = (a.isKey ? '#' : '') + a.name; let attrName = name + '_' + a.name; mcdDot += '"' + attrName + '" [shape=ellipse, label="' + label + '"];\n'; @@ -226,7 +230,7 @@ class ErDiags mcdDot += '' + name + '\n'; if (!!this.entities[name].attributes) { - _.shuffle(this.entities[name].attributes).forEach( a => { + this.entities[name].attributes.forEach( a => { let label = (a.isKey ? '' : '') + a.name + (a.isKey ? '' : ''); mcdDot += '' + label + '\n'; }); @@ -239,6 +243,10 @@ class ErDiags }); // Inheritances: _.shuffle(this.inheritances).forEach( i => { + // TODO: node shape = triangle fill yellow. See + // https://merise.developpez.com/faq/?page=MCD#CIF-ou-dependance-fonctionnelle-de-A-a-Z + // https://merise.developpez.com/faq/?page=MLD#Comment-transformer-un-MCD-en-MLD + // https://www.developpez.net/forums/d1088964/general-developpement/alm/modelisation/structure-agregation-l-association-d-association/ _.shuffle(i.children).forEach( c => { if (Math.random() < 0.5) mcdDot += '"' + c + '":name -- "' + i.parent; @@ -248,15 +256,47 @@ class ErDiags }); }); // Relationships: + if (mcdStyle == "compact") + mcdDot += 'node [shape=rectangle, style=rounded];\n'; let assoceCounter = 0; _.shuffle(this.associations).forEach( a => { let name = !!a.name && a.name.length > 0 ? a.name : '_assoce' + assoceCounter++; - mcdDot += '"' + name + '" [shape="diamond", style="filled", color="lightgrey", label="' + name + '"'; - if (a.weak) - mcdDot += ', peripheries=2'; - mcdDot += '];\n'; + if (mcdStyle == "bubble") + { + mcdDot += '"' + name + '" [shape="diamond", style="filled", color="lightgrey", label="' + name + '"'; + if (a.weak) + mcdDot += ', peripheries=2'; + mcdDot += '];\n'; + if (!!a.attributes) + { + a.attributes.forEach( attr => { + let label = (attr.isKey ? '#' : '') + attr.name; + mcdDot += '"' + name + '_' + attr.name + '" [shape=ellipse, label="' + label + '"];\n'; + let attrName = name + '_' + attr.name; + if (Math.random() < 0.5) + mcdDot += '"' + attrName + '" -- "' + name + '";\n'; + else + mcdDot += '"' + name + '" -- "' + attrName + '";\n'; + }); + } + } + else + { + let label = '<' + name + '>'; + if (!!a.attributes) + { + a.attributes.forEach( attr => { + let attrLabel = (attr.isKey ? '#' : '') + attr.name; + label += '\\n' + attrLabel; + }); + } + mcdDot += '"' + name + '" [color="lightgrey", label="' + label + '"'; + if (a.weak) + mcdDot += ', peripheries=2'; + mcdDot += '];\n'; + } _.shuffle(a.entities).forEach( e => { if (Math.random() < 0.5) mcdDot += '"' + e.name + '":name -- "' + name + '"'; @@ -264,18 +304,6 @@ class ErDiags mcdDot += '"' + name + '" -- "' + e.name + '":name'; mcdDot += '[label="' + ErDiags.CARDINAL[e.card] + '"];\n'; }); - if (!!a.attributes) - { - _.shuffle(a.attributes).forEach( attr => { - let label = (attr.isKey ? '#' : '') + attr.name; - mcdDot += '"' + name + '_' + attr.name + '" [shape=ellipse, label="' + label + '"];\n'; - let attrName = name + '_' + attr.name; - if (Math.random() < 0.5) - mcdDot += '"' + attrName + '" -- "' + name + '";\n'; - else - mcdDot += '"' + name + '" -- "' + attrName + '";\n'; - }); - } }); mcdDot += '}'; console.log(mcdDot); @@ -295,18 +323,21 @@ class ErDiags element.innerHTML = this.mcdGraph; return; } - // Build dot graph input + // Build dot graph input (assuming foreign keys not already present...) let mldDot = 'graph {\n'; - // Nodes: + // Pass 1: initialize tables + let tables = [ ]; Object.keys(this.entities).forEach( name => { - //mld. ... --> devient table - // mldDot = ... + tables.push({ name: this.entities[name] }); //TODO: should be a (deep) copy }); - // Relationships: + // Pass 2: parse associations, add foreign keys + new tables this.associations.forEach( a => { a.entities.forEach( e => { // e.card e.name ... - // Pass 1 : entites deviennent tables - // Pass 2 : sur les assoces + switch (e.card) + { + case '?': + case '?R': //"weak tables" foreign keys become part of the key + // TODO // multi-arite : sub-loop si 0,1 ou 1,1 : aspiré comme attribut de l'association (phase 1) // ensuite, que du 0,n ou 1,n : si == 1, OK une table // si 2 ou + : n tables + 1 pour l'assoce, avec attrs clés étrangères