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 = "";
static get TYPES()
{
- // SQLite types without null (TODO: be more general)
+ // SQLite storage classes without null
return ["integer","real","text","blob"];
}
{
case '[':
// Entity = { name: { attributes, [weak] } }
- let name = lines[start].match(/\w+/)[0];
+ let name = lines[start].match(/[^\[\]"\s]+/)[0];
let entity = { attributes: this.parseAttributes(lines, start+1, end) };
if (lines[start].charAt(1) == '[')
entity.weak = true;
case '{': //association
// Association = { [name], [attributes], [weak], entities: ArrayOf entity indices }
let relationship = { };
- let nameRes = lines[start].match(/\w+/);
+ let nameRes = lines[start].match(/[^{}"\s]+/);
if (nameRes !== null)
relationship.name = nameRes[0];
if (lines[start].charAt(1) == '{')
let attributes = [];
for (let i=start; i<end; i++)
{
- let field = { name: lines[i].match(/\w+/)[0] };
- if (lines[i].charAt(0) == '#')
+ let field = { };
+ let line = lines[i];
+ if (line.charAt(0) == '#')
+ {
field.isKey = true;
- let parenthesis = lines[i].match(/\((.+)\)/);
+ line = line.slice(1);
+ }
+ field.name = line.match(/[^()"\s]+/)[0];
+ let parenthesis = line.match(/\((.+)\)/);
if (parenthesis !== null)
{
let sqlClues = parenthesis[1];
let qualifiers = sqlClues;
- let firstWord = sqlClues.match(/\w+/)[0];
+ let firstWord = sqlClues.match(/[^\s]+/)[0];
if (ErDiags.TYPES.includes(firstWord))
{
field.type = firstWord;
}
// "Modèle conceptuel des données". TODO: option for graph size
+ // NOTE: randomizing helps to obtain better graphs (sometimes)
drawMcd(id, mcdStyle) //mcdStyle: bubble, or compact
{
let element = document.getElementById(id);
}
// Build dot graph input
let mcdDot = 'graph {\n';
+ mcdDot += 'rankdir="LR";\n';
// Nodes:
- Object.keys(this.entities).forEach( name => {
+ if (mcdStyle == "compact")
+ mcdDot += "node [shape=plaintext];\n";
+ _.shuffle(Object.keys(this.entities)).forEach( name => {
if (mcdStyle == "bubble")
{
- mcdDot += name + '[shape=rectangle, label="' + name + '"';
+ mcdDot += '"' + name + '" [shape=rectangle, label="' + name + '"';
if (this.entities[name].weak)
mcdDot += ', peripheries=2';
mcdDot += '];\n';
{
this.entities[name].attributes.forEach( a => {
let label = (a.isKey ? '#' : '') + a.name;
- mcdDot += name + '_' + a.name + '[shape=ellipse, label="' + label + '"];\n';
- mcdDot += name + '_' + a.name + ' -- ' + name + ';\n';
+ let attrName = name + '_' + a.name;
+ mcdDot += '"' + attrName + '" [shape=ellipse, label="' + label + '"];\n';
+ if (Math.random() < 0.5)
+ mcdDot += '"' + attrName + '" -- "' + name + '";\n';
+ else
+ mcdDot += '"' + name + '" -- "' + attrName + '";\n';
});
}
}
else
{
- mcdDot += name + '[shape=plaintext, label=<';
+ mcdDot += '"' + name + '" [label=<';
if (this.entities[name].weak)
{
mcdDot += '<table port="name" BORDER="1" ALIGN="LEFT" CELLPADDING="0" CELLSPACING="3" CELLBORDER="0">' +
}
});
// Inheritances:
- this.inheritances.forEach( i => {
- i.children.forEach( c => {
- mcdDot += c + ':name -- ' + i.parent + ':name [len="1.00", dir="forward", arrowhead="vee", style="dashed"];\n';
+ _.shuffle(this.inheritances).forEach( i => {
+ _.shuffle(i.children).forEach( c => {
+ if (Math.random() < 0.5)
+ mcdDot += '"' + c + '":name -- "' + i.parent;
+ else
+ mcdDot += '"' + i.parent + '":name -- "' + c;
+ mcdDot += '":name [dir="forward", arrowhead="vee", style="dashed"];\n';
});
});
// Relationships:
let assoceCounter = 0;
- this.associations.forEach( a => {
+ _.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="' + (!!a.name ? a.name : '') + '"';
+ mcdDot += '"' + name + '" [shape="diamond", style="filled", color="lightgrey", label="' + name + '"';
if (a.weak)
mcdDot += ', peripheries=2';
mcdDot += '];\n';
- a.entities.forEach( e => {
- mcdDot += e.name + ':name -- ' + name + '[len="1.00", label="' + ErDiags.CARDINAL[e.card] + '"];\n';
+ _.shuffle(a.entities).forEach( e => {
+ if (Math.random() < 0.5)
+ mcdDot += '"' + e.name + '":name -- "' + name + '"';
+ else
+ mcdDot += '"' + name + '" -- "' + e.name + '":name';
+ mcdDot += '[label="' + ErDiags.CARDINAL[e.card] + '"];\n';
});
if (!!a.attributes)
{
a.attributes.forEach( attr => {
let label = (attr.isKey ? '#' : '') + attr.name;
- mcdDot += name + '_' + attr.name + '[len="1.00", shape=ellipse, label="' + label + '"];\n';
- mcdDot += name + '_' + attr.name + ' -- ' + name + ';\n';
+ 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);
+ console.log(mcdDot);
ErDiags.AjaxGet(mcdDot, graphSvg => {
this.mcdGraph = graphSvg;
element.innerHTML = graphSvg;
- })
+ });
}
// "Modèle logique des données"
+ // TODO: this one should draw links from foreign keys to keys (port=... in <TD>)
drawMld(id)
{
let element = document.getElementById(id);
element.innerHTML = this.mcdGraph;
return;
}
- //UNIMPLEMENTED
- // TODO: analyze cardinalities (eat attributes, create new tables...)
- // mldDot = ...
+ // Build dot graph input
+ let mldDot = 'graph {\n';
+ // Nodes:
+ Object.keys(this.entities).forEach( name => {
+ //mld. ... --> devient table
+ // mldDot = ...
+ });
+ // Relationships:
+ this.associations.forEach( a => {
+ a.entities.forEach( e => { // e.card e.name ...
+ // Pass 1 : entites deviennent tables
+ // Pass 2 : sur les assoces
+ // 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
+ // clé étrangère NOT NULL si 1,1
+ });
+ });
// this.graphMld = ...
+ //console.log(mldDot);
+ ErDiags.AjaxGet(mldDot, graphSvg => {
+ this.mldGraph = graphSvg;
+ element.innerHTML = graphSvg;
+ });
}
fillSql(id)