Commits

Yury Shulaev committed 2ef1e42

implement relation types (dummy, default, cascade)

  • Participants
  • Parent commits 0fc31bd

Comments (0)

Files changed (5)

File db/mysql/output.xsl

 <xsl:output method="text"/>
 
 <xsl:template name="replace-substring">
-      <xsl:param name="value" />
-      <xsl:param name="from" />
-      <xsl:param name="to" />
-      <xsl:choose>
-         <xsl:when test="contains($value,$from)">
-            <xsl:value-of select="substring-before($value,$from)" />
-            <xsl:value-of select="$to" />
-            <xsl:call-template name="replace-substring">
-               <xsl:with-param name="value" select="substring-after($value,$from)" />
-               <xsl:with-param name="from" select="$from" />
-               <xsl:with-param name="to" select="$to" />
-            </xsl:call-template>
-         </xsl:when>
-         <xsl:otherwise>
-            <xsl:value-of select="$value" />
-         </xsl:otherwise>
-      </xsl:choose>
+	<xsl:param name="value" />
+	<xsl:param name="from" />
+	<xsl:param name="to" />
+	<xsl:choose>
+		<xsl:when test="contains($value,$from)">
+			<xsl:value-of select="substring-before($value,$from)" />
+			<xsl:value-of select="$to" />
+			<xsl:call-template name="replace-substring">
+				<xsl:with-param name="value" select="substring-after($value,$from)" />
+				<xsl:with-param name="from" select="$from" />
+				<xsl:with-param name="to" select="$to" />
+			</xsl:call-template>
+		</xsl:when>
+		<xsl:otherwise>
+			<xsl:value-of select="$value" />
+		</xsl:otherwise>
+	</xsl:choose>
 </xsl:template>
 
 <xsl:template match="/sql">
 
 <!-- tables -->
 	<xsl:for-each select="table">
-    <xsl:text>-- ---
+	<xsl:text>-- ---
 -- Table '</xsl:text>
-    <xsl:value-of select="@name" />
-    <xsl:if test="comment">
-	    <xsl:call-template name="replace-substring">
-		    <xsl:with-param name="value" select="comment" />
-		    <xsl:with-param name="from" select='"&apos;"' />
-		    <xsl:with-param name="to" select='"&apos;&apos;"' />
-	    </xsl:call-template>
-    </xsl:if>
-    <xsl:text>
+	<xsl:value-of select="@name" />
+	<xsl:if test="comment">
+		<xsl:call-template name="replace-substring">
+			<xsl:with-param name="value" select="comment" />
+			<xsl:with-param name="from" select='"&apos;"' />
+			<xsl:with-param name="to" select='"&apos;&apos;"' />
+		</xsl:call-template>
+	</xsl:if>
+	<xsl:text>
 -- ---
 
 </xsl:text>
 
 
 
-    <xsl:if test="comment">
+	<xsl:if test="comment">
 <xsl-text> COMMENT '</xsl-text>
-            <xsl:call-template name="replace-substring">
-                    <xsl:with-param name="value" select="substring(comment, 1, 60)" />
-                    <xsl:with-param name="from" select='"&apos;"' />
-                    <xsl:with-param name="to" select='"&apos;&apos;"' />
-            </xsl:call-template>
+			<xsl:call-template name="replace-substring">
+					<xsl:with-param name="value" select="substring(comment, 1, 60)" />
+					<xsl:with-param name="from" select='"&apos;"' />
+					<xsl:with-param name="to" select='"&apos;&apos;"' />
+			</xsl:call-template>
 <xsl-text>'</xsl-text>
-    </xsl:if>
+	</xsl:if>
 <xsl-text>;
 
 </xsl-text>
 -- ---
 
 </xsl:text>
-    <xsl:for-each select="table">
-    <xsl:text>ALTER TABLE `</xsl:text><xsl:value-of select="@name" />
-    <xsl:text>` ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+	<xsl:for-each select="table">
+	<xsl:text>ALTER TABLE `</xsl:text><xsl:value-of select="@name" />
+	<xsl:text>` ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 </xsl:text>
-    </xsl:for-each>
+	</xsl:for-each>
 
 <xsl:text>
 -- ---
 	<xsl:for-each select="table">
 		<xsl:for-each select="row">
 			<xsl:for-each select="relation">
-				<xsl:text>ALTER TABLE `</xsl:text>
-				<xsl:value-of select="../../@name" />
-				<xsl:text>` ADD FOREIGN KEY (</xsl:text>
-				<xsl:value-of select="../@name" />
-				<xsl:text>) REFERENCES `</xsl:text>
-				<xsl:value-of select="@table" />
-				<xsl:text>` (`</xsl:text>
-				<xsl:value-of select="@row" />
-				<xsl:text>`);
+				<xsl:choose>
+					<xsl:when test="@type='dummy'"></xsl:when>
+					<xsl:when test="@type='cascade'">
+						<xsl:text>ALTER TABLE `</xsl:text>
+						<xsl:value-of select="../../@name" />
+						<xsl:text>` ADD FOREIGN KEY (</xsl:text>
+						<xsl:value-of select="../@name" />
+						<xsl:text>) REFERENCES `</xsl:text>
+						<xsl:value-of select="@table" />
+						<xsl:text>` (`</xsl:text>
+						<xsl:value-of select="@row" />
+						<xsl:text>`) ON DELETE CASCADE;
 </xsl:text>
+					</xsl:when>
+					<xsl:otherwise>
+						<xsl:text>ALTER TABLE `</xsl:text>
+						<xsl:value-of select="../../@name" />
+						<xsl:text>` ADD FOREIGN KEY (</xsl:text>
+						<xsl:value-of select="../@name" />
+						<xsl:text>) REFERENCES `</xsl:text>
+						<xsl:value-of select="@table" />
+						<xsl:text>` (`</xsl:text>
+						<xsl:value-of select="@row" />
+						<xsl:text>`);
+</xsl:text>
+					</xsl:otherwise>
+				</xsl:choose>
 			</xsl:for-each>
 		</xsl:for-each>
 	</xsl:for-each>

File js/config.js

 	AVAILABLE_BACKENDS: ["php-mysql+file", "php-mysql", "php-file", "php-sqlite", "php-postgresql", "php-pdo", "php-blank", "perl-file", "php-cubrid"],
 	DEFAULT_BACKEND: ["php-mysql+file"],
 
-	RELATION_THICKNESS: 2,
+	RELATION_THICKNESS: {
+		"dummy": 1,
+		"cascade": 1.5,
+		"default": 1.5
+	},
+
+	RELATION_COLORS: {
+		"dummy": "#888",
+		"cascade": "#800",
+		"default": "#008"
+	},
+
 	RELATION_SPACING: 15,
-	RELATION_COLORS: ["#000", "#800", "#080", "#008", "#088", "#808", "#088"],
 
 	STATIC_PATH: "",
 	XHR_PATH: ""

File js/wwwsqldesigner.js

 	for (var i=0;i<this.relations.length;i++) {
 		var r = this.relations[i];
 		if (r.row2 != this) { continue; }
-		xml += '<relation table="'+r.row1.owner.getTitle()+'" row="'+r.row1.getTitle()+'" />\n';
+		xml += '<relation table="'+r.row1.owner.getTitle()+'" row="'+r.row1.getTitle()+'" type="'+r.type+'" />\n';
 	}
 
 	if (this.data.comment) {
 
 SQL.Relation = OZ.Class().extend(SQL.Visual);
 SQL.Relation._counter = 0;
-SQL.Relation.prototype.init = function(owner, row1, row2) {
+SQL.Relation.prototype.init = function(owner, row1, row2, type) {
+	type = type ? type : 'default';
 	this.constructor._counter++;
 	this.owner = owner;
 	this.row1 = row1;
 	this.row2 = row2;
+	this.type = type;
 	this.hidden = false;
 	SQL.Visual.prototype.init.apply(this);
 
 	this.row2.addRelation(this);
 
 	this.dom = [];
-	if (CONFIG.RELATION_COLORS) {
-		var colorIndex = this.constructor._counter - 1;
-		var color = CONFIG.RELATION_COLORS[colorIndex % CONFIG.RELATION_COLORS.length];
-	} else {
-		var color = "#000";
-	}
+
+	var color = CONFIG.RELATION_COLORS[type];
 
 	if (this.owner.vector) {
 		var path = document.createElementNS(this.owner.svgNS, "path");
 		path.setAttribute("stroke", color);
-		path.setAttribute("stroke-width", CONFIG.RELATION_THICKNESS);
+		path.setAttribute("stroke-width", CONFIG.RELATION_THICKNESS[type]);
 		path.setAttribute("fill", "none");
 		this.owner.dom.svg.appendChild(path);
 		this.dom.push(path);
 			var div = OZ.DOM.elm("div",{position:"absolute",className:"relation",backgroundColor:color});
 			this.dom.push(div);
 			if (i & 1) { /* middle */
-				OZ.Style.set(div,{width:CONFIG.RELATION_THICKNESS+"px"});
+				OZ.Style.set(div,{width:CONFIG.RELATION_THICKNESS[type]+"px"});
 			} else { /* first & last */
-				OZ.Style.set(div,{height:CONFIG.RELATION_THICKNESS+"px"});
+				OZ.Style.set(div,{height:CONFIG.RELATION_THICKNESS[type]+"px"});
 			}
 			this.owner.dom.container.appendChild(div);
 		}
 
 		this.dom[1].style.left = (p1[0] + half) + "px";
 		this.dom[1].style.top = Math.min(p1[1],p2[1]) + "px";
-		this.dom[1].style.height = (Math.abs(p1[1] - p2[1])+CONFIG.RELATION_THICKNESS)+"px";
+		this.dom[1].style.height = (Math.abs(p1[1] - p2[1])+CONFIG.RELATION_THICKNESS[this.type])+"px";
 
 		this.dom[2].style.left = (p1[0]+half+1)+"px";
 		this.dom[2].style.top = p2[1]+"px";
 
 		this.dom[1].style.left = x+"px";
 		this.dom[1].style.top = Math.min(p1[1],p2[1]) + "px";
-		this.dom[1].style.height = (Math.abs(p1[1] - p2[1])+CONFIG.RELATION_THICKNESS)+"px";
+		this.dom[1].style.height = (Math.abs(p1[1] - p2[1])+CONFIG.RELATION_THICKNESS[this.type])+"px";
 
 		this.dom[2].style.left = Math.min(x,p2[0])+"px";
 		this.dom[2].style.top = p2[1]+"px";
 SQL.RowManager.prototype.tableClick = function(e) { /* create relation after clicking target table */
 	if (!this.creating) { return; }
 
+	var type = this.owner.promptRelationType();
+	if (!type) { return; }
+
 	var r1 = this.selected;
 	var t2 = e.target;
 
 	var r2 = t2.addRow(p, r1.data);
 	r2.update({"type":SQL.Designer.getFKTypeFor(r1.data.type)});
 	r2.update({"ai":false});
-	this.owner.addRelation(r1, r2);
+	this.owner.addRelation(r1, r2, type);
 }
 
 SQL.RowManager.prototype.rowClick = function(e) { /* draw relation after clicking target row */
 	if (!this.connecting) { return; }
 
+	var type = this.owner.promptRelationType();
+	if (!type) { return; }
+
 	var r1 = this.selected;
 	var r2 = e.target;
 
 	if (r1 == r2) { return; }
 
-	this.owner.addRelation(r1, r2);
+	this.owner.addRelation(r1, r2, type);
 }
 
 SQL.RowManager.prototype.foreigncreate = function(e) { /* start creating fk */
 			OZ.Event.prevent(e);
 		break;
 		case 13:
-		case 27:
 			if (this.selected.expanded) {
 				this.selected.collapse();
 			} else {
 			}
 			OZ.Event.prevent(e);
 		break;
+		case 27:
+			this.selected.collapse();
+			OZ.Event.prevent(e);
+		break;
 	}
 }
 
 	this.tables.splice(idx,1);
 }
 
-SQL.Designer.prototype.addRelation = function(row1, row2) {
+SQL.Designer.prototype.addRelation = function(row1, row2, type) {
 	for (var i = 0; i < this.relations.length; i++) {
 		if (this.relations[i].row1 == row1 && this.relations[i].row2 == row2) {
-			return this.relations[i];
+			this.removeRelation(this.relations[i]);
 		}
 	}
 
-	var r = new SQL.Relation(this, row1, row2);
+	var r = new SQL.Relation(this, row1, row2, type);
 	this.relations.push(r);
 	return r;
 }
 		var rel = rs[i];
 		var tname = rel.getAttribute("table");
 		var rname = rel.getAttribute("row");
+		var type = rel.getAttribute("type");
 
 		var t1 = this.findNamedTable(tname);
 		if (!t1) { continue; }
 		var r2 = t2.findNamedRow(rname);
 		if (!r2) { continue; }
 
-		this.addRelation(r1, r2);
+		this.addRelation(r1, r2, type);
 	}
 }
 
 	}
 	return this.fkTypeFor[typeIndex];
 }
+
+SQL.Designer.prototype.promptRelationType = function () {
+	return prompt(_("relationtype"), "dummy");
+}

File locale/en.xml

 	<string name="foreignpending">click target table</string>
 	<string name="foreignconnect">Connect foreign key</string>
 	<string name="foreignconnectpending">click target row</string>
+	<string name="relationtype">Relation type (dummy, default, cascade)</string>
 	<string name="foreigndisconnect">Remove foreign key</string>
 	<string name="confirmtable">Really delete table</string>
 	<string name="confirmrow">Really delete field</string>

File locale/ru.xml

 	<string name="foreignpending">щелкните по целевой таблице</string>
 	<string name="foreignconnect">Связать внешний ключ</string>
 	<string name="foreignconnectpending">выберите целевое поле</string>
+	<string name="relationtype">Тип связи (dummy, default, cascade)</string>
 	<string name="foreigndisconnect">Удалить внешний ключ</string>
 	<string name="confirmtable">Действительно удалить таблицу</string>
 	<string name="confirmrow">Действительно удалить поле</string>