Skip to content

Commit

Permalink
SQL queries view, extended properties background implementation, phase 1
Browse files Browse the repository at this point in the history
  • Loading branch information
nikitaeverywhere committed Oct 5, 2015
1 parent c0a4a97 commit 70edfa2
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 59 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Cache UML Explorer
# Cache Class Explorer
An UML Class explorer for InterSystems Caché.

##### Key features
+ Build class diagrams;
+ Build diagrams for any package or subpackage;
+ Edit diagrams after build;
+ Export diagrams as an image;
+ See Class methods, properties, parameters, SQL queries and more;
+ View class methods code with syntax highlighting;
+ Zoom in and out;
+ Search on diagram or in class tree;
Expand Down
55 changes: 33 additions & 22 deletions cache/projectTemplate.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Description>
Cache UML Explorer vX.X.X/*build.replace:pkg.version*/
Class contains methods that return structured classes/packages data.</Description>
<TimeChanged>63808,84964.699928</TimeChanged>
<TimeChanged>63830,81286.756889</TimeChanged>
<TimeCreated>63653,67019.989197</TimeCreated>

<Method name="getAllNamespacesList">
Expand Down Expand Up @@ -93,6 +93,7 @@ Return structured data about class.</Description>
do oData.classes.%DispatchSetProperty(classDefinition.Name, oClass) // prevent from recursive setup
set package = $LISTTOSTRING($LIST($LISTFROMSTRING(classDefinition.Name, "."), 1, *-1),".")
set oProperties = ##class(%ZEN.proxyObject).%New()
set oQueries = ##class(%ZEN.proxyObject).%New()
set oClass.NAMESPACE = $NAMESPACE
set oClass.SYSTEM = classDefinition.System
Expand All @@ -109,57 +110,67 @@ Return structured data about class.</Description>
set oClass.properties = oProperties
set count = classDefinition.Properties.Count()
set props = ##class(%Dictionary.ClassDefinition).%OpenId("%Dictionary.PropertyDefinition")
for i=1:1:count {
set oProp = ##class(%ZEN.proxyObject).%New()
set p = classDefinition.Properties.GetAt(i)
do oProperties.%DispatchSetProperty(p.Name, oProp)
set oProp.private = p.Private
set oProp.readOnly = p.ReadOnly
set oProp.cardinality = p.Cardinality
set oProp.inverse = p.Inverse
for j=1:1:props.Properties.Count() {
set pname = props.Properties.GetAt(j).Name
set:(pname '= "parent") $PROPERTY(oProp, pname) = $PROPERTY(p, pname)
}
if (..classExists(package _ "." _ p.Type)) {
set oProp.type = package _ "." _ p.Type
set oProp.Type = package _ "." _ p.Type
do ..fillClassData(oData, package _ "." _ p.Type)
} elseif (..classExists(..extendClassFromType(p.Type))) {
set oProp.type = ..extendClassFromType(p.Type)
set oProp.Type = ..extendClassFromType(p.Type)
do ..fillClassData(oData, ..extendClassFromType(p.Type))
} else {
set oProp.type = p.Type
set oProp.Type = ..extendClassFromType(p.Type)
}
}
set oMethods = ##class(%ZEN.proxyObject).%New()
set oClass.methods = oMethods
set count = classDefinition.Methods.Count()
set props = ##class(%Dictionary.ClassDefinition).%OpenId("%Dictionary.MethodDefinition")
for i=1:1:count {
set oMeth = ##class(%ZEN.proxyObject).%New()
set met = classDefinition.Methods.GetAt(i)
do oMethods.%DispatchSetProperty(met.Name, oMeth)
set oMeth.private = met.Private
set oMeth.returns = met.ReturnType
set oMeth.classMethod = met.ClassMethod
set oMeth.clientMethod = met.ClientMethod
set oMeth.final = met.Final
set oMeth.abstract = met.Abstract
set oMeth.language = met.Language
set oMeth.notInheritable = met.NotInheritable
set oMeth.serverOnly = met.ServerOnly
set oMeth.sqlProc = met.SqlProc
set oMeth.sqlName = met.SqlName
set oMeth.webMethod = met.WebMethod
set oMeth.zenMethod = met.ZenMethod
for j=1:1:props.Properties.Count() {
set pname = props.Properties.GetAt(j).Name
set:((pname '= "parent") && (pname '= "Implementation")) $PROPERTY(oMeth, pname) = $PROPERTY(met, pname)
}
}
set oParameters = ##class(%ZEN.proxyObject).%New()
set oClass.parameters = oParameters
set count = classDefinition.Parameters.Count()
set props = ##class(%Dictionary.ClassDefinition).%OpenId("%Dictionary.ParameterDefinition")
for i=1:1:count {
set oPar = ##class(%ZEN.proxyObject).%New()
set p = classDefinition.Parameters.GetAt(i)
set oPar.type = p.Type
for j=1:1:props.Properties.Count() {
set pname = props.Properties.GetAt(j).Name
set:(pname '= "parent") $PROPERTY(oPar, pname) = $PROPERTY(p, pname)
}
do oParameters.%DispatchSetProperty(p.Name, oPar)
}
#dim q as %Dictionary.QueryDefinition
set oClass.queries = oQueries
set props = ##class(%Dictionary.ClassDefinition).%OpenId("%Dictionary.QueryDefinition")
for i=1:1:classDefinition.Queries.Count() {
set oProp = ##class(%ZEN.proxyObject).%New()
set q = classDefinition.Queries.GetAt(i)
for j=1:1:props.Properties.Count() {
set pname = props.Properties.GetAt(j).Name
set:(pname '= "parent") $PROPERTY(oProp, pname) = $PROPERTY(q, pname)
}
do oQueries.%DispatchSetProperty(q.Name, oProp)
}
do ..collectInheritance(oData, oClass.super)
quit oClass
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "CacheUMLExplorer",
"version": "1.2.0",
"version": "1.3.0",
"description": "An UML Class explorer for InterSystems Caché",
"directories": {
"test": "test"
Expand Down
8 changes: 7 additions & 1 deletion web/css/classView.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ svg {
/*fill: lightgray;*/
}

.uml-class-attrs-rect, .uml-class-methods-rect {
.uml-class-attrs-rect, .uml-class-methods-rect, .uml-class-queries-rect {
fill: white;
}

Expand Down Expand Up @@ -66,6 +66,12 @@ text {
fill: blue;
}

.uml-class-queries-label {
font-family: monospace;
font-weight: 900;
fill: #0d0;
}

.uml-class-params-label {
font-family: monospace;
font-weight: 900;
Expand Down
55 changes: 36 additions & 19 deletions web/js/ClassView.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ ClassView.prototype.renderInfoGraphic = function () {
aggregation: {
"Persistent class (one)": {
"DataType class (many)": {
left: "*",
right: 1
left: "many",
right: "one"
}
}
},
Expand Down Expand Up @@ -409,19 +409,21 @@ ClassView.prototype.getClassSigns = function (classMetaData) {
*
* @param method
*/
ClassView.prototype.getMethodIcons = function (method) {
ClassView.prototype.getPropertyIcons = function (method) {

var icons = [];

icons.push({ src: lib.image[method["private"] ? "minus" : "plus"] });
if (method["abstract"]) icons.push({ src: lib.image.crystalBall });
if (method["clientMethod"]) icons.push({ src: lib.image.user });
if (method["final"]) icons.push({ src: lib.image.blueFlag });
if (method["notInheritable"]) icons.push({ src: lib.image.redFlag });
if (method["sqlProc"]) icons.push({ src: lib.image.table });
if (method["webMethod"]) icons.push({ src: lib.image.earth });
if (method["zenMethod"]) icons.push({ src: lib.image.zed });
if (method["readOnly"]) icons.push({ src: lib.image.eye });
if (typeof method["Private"] !== "undefined") {
icons.push({ src: lib.image[method["Private"] ? "minus" : "plus"] });
}
if (method["Abstract"]) icons.push({ src: lib.image.crystalBall });
if (method["ClientMethod"]) icons.push({ src: lib.image.user });
if (method["Final"]) icons.push({ src: lib.image.blueFlag });
if (method["NotInheritable"]) icons.push({ src: lib.image.redFlag });
if (method["SqlProc"]) icons.push({ src: lib.image.table });
if (method["WebMethod"]) icons.push({ src: lib.image.earth });
if (method["ZenMethod"]) icons.push({ src: lib.image.zed });
if (method["ReadOnly"]) icons.push({ src: lib.image.eye });

return icons;

Expand All @@ -437,6 +439,7 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
var classParams = classMetaData["parameters"],
classProps = classMetaData["properties"],
classMethods = classMetaData["methods"],
classQueries = classMetaData["queries"],
keyWordsArray = [name],
self = this;

Expand All @@ -455,7 +458,8 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in params) {
keyWordsArray.push(n);
arr.push({
text: n + (params[n]["type"] ? ": " + params[n]["type"] : "")
text: n + (params[n]["Type"] ? ": " + params[n]["Type"] : ""),
icons: self.getPropertyIcons(params[n])
});
}
return arr;
Expand All @@ -465,8 +469,8 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in ps) {
keyWordsArray.push(n);
arr.push({
text: n + (ps[n]["type"] ? ": " + ps[n]["type"] : ""),
icons: self.getMethodIcons(ps[n])
text: n + (ps[n]["Type"] ? ": " + ps[n]["Type"] : ""),
icons: self.getPropertyIcons(ps[n])
});
}
return arr;
Expand All @@ -476,18 +480,29 @@ ClassView.prototype.createClassInstance = function (name, classMetaData) {
for (n in met) {
keyWordsArray.push(n);
arr.push({
text: n + (met[n]["returns"] ? ": " + met[n]["returns"] : ""),
text: n + (met[n]["ReturnType"] ? ": " + met[n]["ReturnType"] : ""),
styles: (function (t) {
return t ? { textDecoration: "underline" } : {}
})(met[n]["classMethod"]),
clickHandler: (function (n) {
return function () { self.showMethodCode(name, n); }
})(n),
icons: self.getMethodIcons(met[n])
icons: self.getPropertyIcons(met[n])
});
}
return arr;
})(classMethods),
queries: (function (qrs) {
var arr = [], n;
for (n in qrs) {
keyWordsArray.push(n);
arr.push({
text: n,
icons: self.getPropertyIcons(qrs[n])
});
}
return arr;
})(classQueries),
classSigns: this.getClassSigns(classMetaData),
classType: classMetaData.$classType,
SYMBOL_12_WIDTH: self.SYMBOL_12_WIDTH
Expand Down Expand Up @@ -591,9 +606,11 @@ ClassView.prototype.render = function (data) {
ClassView.prototype.confirmRender = function (data) {

var self = this, p, pp, className,
LINK_TEXT_MARGIN = 22,
uml = joint.shapes.uml, relFrom, relTo,
classes = {}, connector;

console.log(data);
this.filterInherits(data);

// Reset view and zoom again because it may cause visual damage to icons.
Expand Down Expand Up @@ -648,8 +665,8 @@ ClassView.prototype.confirmRender = function (data) {
}
}
};
if (link.left) arr.push(getLabel(link.left, 10));
if (link.right) arr.push(getLabel(link.right, -10));
if (link.left) arr.push(getLabel(link.left, LINK_TEXT_MARGIN));
if (link.right) arr.push(getLabel(link.right, -LINK_TEXT_MARGIN));
return arr;
})(data[type][p][pp] || {})
}));
Expand Down
26 changes: 13 additions & 13 deletions web/js/Logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,21 @@ Logic.prototype.fillAssociations = function () {
if (!properties) continue;
for (propertyName in properties) {
po = properties[propertyName];
if (po["cardinality"] === "one") {
if (!aggr[po.type]) aggr[po.type] = {};
aggr[po.type][className] = {
left: "*",
right: "1"
if (po["Cardinality"] === "one") {
if (!aggr[po["Type"]]) aggr[po["Type"]] = {};
aggr[po["Type"]][className] = {
left: "many",
right: "one"
};
} else if (po["cardinality"] === "parent") {
if (!compos[po.type]) compos[po.type] = {};
compos[po.type][className] = {
left: "*",
right: "1"
} else if (po["Cardinality"] === "parent") {
if (!compos[po["Type"]]) compos[po["Type"]] = {};
compos[po["Type"]][className] = {
left: "child",
right: "parent"
};
} else if (self.data.classes[po.type] && !po["cardinality"]) {
if (!assoc[po.type]) assoc[po.type] = {};
assoc[po.type][className] = {};
} else if (self.data.classes[po["Type"]] && !po["Cardinality"]) {
if (!assoc[po["Type"]]) assoc[po["Type"]] = {};
assoc[po["Type"]][className] = {};
}
}
}
Expand Down
18 changes: 16 additions & 2 deletions web/jsLib/joint.shapes.uml.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
'<text class="uml-class-attrs-label">Properties</text>',
'<rect class="uml-class-methods-rect"/>',
'<text class="uml-class-methods-label">Methods</text>',
'<rect class="uml-class-queries-rect"/>',
'<text class="uml-class-queries-label">Queries</text>',
'</g>',
'<text class="uml-class-name-text"/>',
'<text class="uml-class-params-text"/>',
'<text class="uml-class-attrs-text"/>',
'<text class="uml-class-methods-text"/>',
'<text class="uml-class-queries-text"/>',
'</g>'
].join(''),

Expand All @@ -46,6 +49,7 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
'.uml-class-params-rect': { 'stroke': 'black', 'stroke-width': 1, 'fill': 'white' },
'.uml-class-attrs-rect': { 'stroke': 'black', 'stroke-width': 1, 'fill': '#2980b9' },
'.uml-class-methods-rect': { 'stroke': 'black', 'stroke-width': 1, 'fill': '#2980b9' },
'.uml-class-queries-rect': { 'stroke': 'black', 'stroke-width': 1, 'fill': '#2980b9' },

'.uml-class-name-text': {
'ref': '.uml-class-name-rect', 'ref-y': .5, 'ref-x': .5, 'text-anchor': 'middle', 'y-alignment': 'middle', 'font-weight': 'bold',
Expand All @@ -63,13 +67,20 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
'ref': '.uml-class-methods-rect', 'ref-y': 5, 'ref-x': 5,
'fill': 'black', 'font-size': 12
},
'.uml-class-queries-text': {
'ref': '.uml-class-queries-rect', 'ref-y': 5, 'ref-x': 5,
'fill': 'black', 'font-size': 12
},
'.uml-class-attrs-label': {
ref: '.uml-class-attrs-label', fill: "black", 'font-size': 10,
xPos: -56
},
'.uml-class-methods-label': {
ref: '.uml-class-methods-label', fill: "black", 'font-size': 10
},
'.uml-class-queries-label': {
ref: '.uml-class-queries-label', fill: "black", 'font-size': 10
},
'.uml-class-params-label': {
ref: '.uml-class-methods-label', fill: "black", 'font-size': 10
}
Expand All @@ -79,6 +90,7 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
params: [],
attributes: [],
methods: [],
queries: [],
classSigns: []

}, joint.shapes.basic.Generic.prototype.defaults),
Expand All @@ -90,7 +102,8 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
{ type: 'name', text: this.getClassName() },
{ type: 'params', text: (o = this.get('params')) , o: o },
{ type: 'attrs', text: (o = this.get('attributes')), o: o },
{ type: 'methods', text: (o = this.get('methods')) , o: o }
{ type: 'methods', text: (o = this.get('methods')) , o: o },
{ type: 'queries', text: (o = this.get('queries')) , o: o }
],
self = this,
classSigns = this.get('classSigns'),
Expand Down Expand Up @@ -185,7 +198,8 @@ joint.shapes.uml.Class = joint.shapes.basic.Generic.extend({
{ type: 'name', text: this.getClassName() },
{ type: 'params', text: this.get('params') },
{ type: 'attrs', text: this.get('attributes') },
{ type: 'methods', text: this.get('methods') }
{ type: 'methods', text: this.get('methods') },
{ type: 'queries', text: this.get('queries') }
];

var offsetY = 0;
Expand Down

0 comments on commit 70edfa2

Please sign in to comment.