Fix typo 'compact' --> 'graph' for output
[erdiag.git] / parser.js
index 65ac9ec..0ab6a43 100644 (file)
--- a/parser.js
+++ b/parser.js
@@ -1,7 +1,7 @@
 // ER diagram description parser
 class ErDiags
 {
-       constructor(description)
+       constructor(description, output, image)
        {
                this.entities = { };
                this.inheritances = [ ];
@@ -9,10 +9,8 @@ class ErDiags
                this.tables = { };
                this.mcdParsing(description);
                this.mldParsing();
-               // Cache SVG graphs returned by server (in addition to server cache = good perfs)
-               this.mcdGraph = "";
-               this.mldGraph = "";
-               this.sqlText = "";
+               this.output = output || "graph";
+               this.image = image || "svg";
        }
 
        static CARDINAL(symbol)
@@ -170,10 +168,12 @@ class ErDiags
                                        name: attr.name,
                                        type: attr.type,
                                        isKey: attr.isKey,
-                                       qualifiers: attr.qualifiers,
                                };
-                               if (!!attr.qualifiers && !!attr.qualifiers.match(/foreign/i))
+                               if (!!attr.qualifiers && !!attr.qualifiers.match(/references/i))
+                               {
                                        Object.assign(newField, {ref: attr.qualifiers.match(/references ([^\s]+)/i)[1]});
+                                       newField.qualifiers = attr.qualifiers.replace(/references [^\s]+/i, "");
+                               }
                                newTable.push(newField);
                        });
                        this.tables[name] = newTable;
@@ -187,8 +187,8 @@ class ErDiags
                                        name: inh.parent + "_id",
                                        type: this.tables[inh.parent][idx].type,
                                        isKey: true,
-                                       qualifiers: (this.tables[inh.parent][idx].qualifiers || "") + " foreign key references " + inh.parent,
-                                       ref: inh.parent,
+                                       qualifiers: this.tables[inh.parent][idx].qualifiers || "",
+                                       ref: inh.parent + "(" + this.tables[inh.parent][idx].name + ")",
                                });
                        });
                });
@@ -213,8 +213,8 @@ class ErDiags
                                                                        isKey: isKey,
                                                                        name: e2.name + "_" + attr.name,
                                                                        type: attr.type,
-                                                                       qualifiers: "foreign key references " + e2.name + " " + (!isKey && e.card[0]=='1' ? "not null" : ""),
-                                                                       ref: e2.name, //easier drawMld function (fewer regexps)
+                                                                       qualifiers: !isKey && e.card[0]=='1' ? "not null" : "",
+                                                                       ref: e2.name + "(" + attr.name + ")",
                                                                });
                                                        }
                                                });
@@ -243,8 +243,8 @@ class ErDiags
                                                        name: item.entity + "_" + f.name,
                                                        isKey: true,
                                                        type: f.type,
-                                                       qualifiers: (f.qualifiers || "") + " foreign key references " + item.entity,
-                                                       ref: item.entity,
+                                                       qualifiers: f.qualifiers || "",
+                                                       ref: item.entity + "(" + f.name + ")",
                                                });
                                        });
                                });
@@ -282,28 +282,12 @@ class ErDiags
        // DRAWING + GET SQL FROM PARSING
        /////////////////////////////////
 
-       static AjaxGet(dotInput, callback)
-       {
-               let xhr = new XMLHttpRequest();
-               xhr.onreadystatechange = function() {
-                       if (this.readyState == 4 && this.status == 200)
-                               callback(this.responseText);
-               };
-               xhr.open("GET", "scripts/getGraphSvg.php?dot=" + encodeURIComponent(dotInput), true);
-               xhr.send();
-       }
-
        // "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);
                mcdStyle = mcdStyle || "compact";
-               if (this.mcdGraph.length > 0)
-               {
-                       element.innerHTML = this.mcdGraph;
-                       return;
-               }
                // Build dot graph input
                let mcdDot = 'graph {\n';
                mcdDot += 'rankdir="LR";\n';
@@ -417,23 +401,16 @@ class ErDiags
                        });
                });
                mcdDot += '}';
-               //console.log(mcdDot);
-               ErDiags.AjaxGet(mcdDot, graphSvg => {
-                       this.mcdGraph = graphSvg;
-                       element.innerHTML = graphSvg;
-               });
+               if (this.output == "graph") //draw graph in element
+                       element.innerHTML = "<img src='scripts/getGraph_" + this.image + ".php?dot=" + encodeURIComponent(mcdDot) + "'/>";
+               else //output = "text": just show dot input
+                       element.innerHTML = mcdDot.replace(/</g,"&lt;").replace(/>/g,"&gt;");
        }
 
        // "Modèle logique des données", from MCD without anomalies
-       // TODO: this one should draw links from foreign keys to keys (port=... in <TD>)
        drawMld(id)
        {
                let element = document.getElementById(id);
-               if (this.mldGraph.length > 0)
-               {
-                       element.innerHTML = this.mcdGraph;
-                       return;
-               }
                // Build dot graph input (assuming foreign keys not already present...)
                let mldDot = 'graph {\n';
                mldDot += 'rankdir="LR";\n';
@@ -447,38 +424,28 @@ class ErDiags
                                mldDot += '<tr><td port="' + f.name + '"' + ' BGCOLOR="#FFFFFF" BORDER="0" ALIGN="LEFT"><font COLOR="#000000" >' + label + '</font></td></tr>\n';
                                if (!!f.ref)
                                {
-                                       // Need to find a key attribute in reference entity (the first...)
-                                       let keyInRef = "";
-                                       for (let field of this.tables[f.ref])
-                                       {
-                                               if (field.isKey)
-                                               {
-                                                       keyInRef = field.name;
-                                                       break;
-                                               }
-                                       }
+                                       const refPort = f.ref.slice(0,-1).replace('(',':');
                                        if (Math.random() < 0.5)
-                                               links += '"' + f.ref + '":"' + keyInRef + '" -- "' + name+'":"'+f.name + '" [dir="forward",arrowhead="dot"';
+                                               links += refPort + ' -- "' + name+'":"'+f.name + '" [dir="forward",arrowhead="dot"';
                                        else
-                                               links += '"'+name+'":"'+f.name+'" -- "' + f.ref + '":"' + keyInRef + '" [dir="back",arrowtail="dot"';
+                                               links += '"'+name+'":"'+f.name+'" -- ' + refPort + ' [dir="back",arrowtail="dot"';
                                        links += ']\n;';
                                }
                        });
                        mldDot += '</table>>];\n';
                });
                mldDot += links + '\n';
-               mldDot += '}\n';
-               //console.log(mldDot);
-               ErDiags.AjaxGet(mldDot, graphSvg => {
-                       this.mldGraph = graphSvg;
-                       element.innerHTML = graphSvg;
-               });
+               mldDot += '}';
+               if (this.output == "graph")
+                       element.innerHTML = "<img src='scripts/getGraph_" + this.image + ".php?dot=" + encodeURIComponent(mldDot) + "'/>";
+               else
+                       element.innerHTML = mldDot.replace(/</g,"&lt;").replace(/>/g,"&gt;");
        }
 
        fillSql(id)
        {
                let element = document.getElementById(id);
-               if (this.sqlText.length > 0)
+               if (!!this.sqlText)
                {
                        element.innerHTML = this.sqlText;
                        return;
@@ -487,16 +454,24 @@ class ErDiags
                Object.keys(this.tables).forEach( name => {
                        sqlText += "CREATE TABLE " + name + " (\n";
                        let key = "";
+                       let foreignKey = [ ];
                        this.tables[name].forEach( f => {
                                let type = f.type || (f.isKey ? "INTEGER" : "TEXT");
+                               if (!!f.ref)
+                                       foreignKey.push({name: f.name, ref: f.ref});
                                sqlText += "\t" + f.name + " " + type + " " + (f.qualifiers || "") + ",\n";
                                if (f.isKey)
                                        key += (key.length>0 ? "," : "") + f.name;
                        });
-                       sqlText += "\tPRIMARY KEY (" + key + ")\n";
-                       sqlText += ");\n";
+                       sqlText += "\tPRIMARY KEY (" + key + ")";
+                       foreignKey.forEach( f => {
+                               let refParts = f.ref.split("(");
+                               const table = refParts[0];
+                               const field = refParts[1].slice(0,-1); //remove last parenthesis
+                               sqlText += ",\n\tFOREIGN KEY (" + f.name + ") REFERENCES " + table + "(" + field + ")";
+                       });
+                       sqlText += "\n);\n";
                });
-               //console.log(sqlText);
                this.sqlText = sqlText;
                element.innerHTML = "<pre><code>" + sqlText + "</code></pre>";
        }