{* * File ERD-graphviz2.sml * Author: Manfred Jeusfeld, jeusfeld@uvt.nl * Date: 5-Jun-2008 (9-Jul-2008) *---------------------------------------------------------------- * This model file specifies the ERD notation and provides and * export filter for graphviz. * Steps: * 1- Load this model into ConceptBase * 2- Load the example model UniversityModel.sml into ConceptBase * 3- Ask the query ShowERD[UniversityModel/erd] * 4- Copy/paste the answer to a file graphviz-input.dot * 5- Call Graphviz, e.g. by * neato -Tpng graphviz-input.dot > graphviz-output.png * Use the manual pages of dot or neato to learn more about options of Graphviz. * Graphviz is available from http://graphviz.org/ * * (c) 2008 by M. Jeusfeld. * This model file is licensed under the terms of Attribution-Non-Commercial 2.0 Germany * http://creativecommons.org/licenses/by-nc/2.0/de/legalcode (German) * http://creativecommons.org/licenses/by-nc/2.0/legalcode (generic) * A summary of your rights and obligations concerning this work is available from * http://creativecommons.org/licenses/by-nc/2.0/de/deed.en_GB * Extended rights can be obtained via the author. * * Requires ConceptBase 7.1.2 released 9-Jul-2008 or later. * *} {* -------------------------------------------------------------------------- *} {* Define the ERD notation: *} {* entity types, relationship types, IsA types, cardinality tags, attributes *} {* -------------------------------------------------------------------------- *} EntityType with attribute attr: Domain; key: Domain; {* some attributes are key attributes *} superType: EntityType {* only used for defining the semaantics of the IsaType *} end RelationshipType with attribute role: EntityType; "1..n": EntityType; "1..1": EntityType; "0..1": EntityType; "0..n": EntityType; "n..m": EntityType end Proposition with attribute cardinalityTag: Proposition end RelationshipType!"1..n" in Proposition!cardinalityTag end RelationshipType!"1..1" in Proposition!cardinalityTag end RelationshipType!"0..1" in Proposition!cardinalityTag end RelationshipType!"0..n" in Proposition!cardinalityTag end RelationshipType!"n..m" in Proposition!cardinalityTag end {* This one is what Yourdan calls an associative object type *} EntityRelationshipType in Class isA EntityType,RelationshipType end IsaType in Class with attribute sub: EntityType; super: EntityType end Domain with end {* -------------------------------------------------------------------------- *} {* ERD elements are just all elements that can occur in an ER diagram *} {* -------------------------------------------------------------------------- *} ERDElement end EntityType isA ERDElement end RelationshipType isA ERDElement end RelationshipType!role isA ERDElement end IsaType isA ERDElement end IsaType!sub isA ERDElement end IsaType!super isA ERDElement end Domain isA ERDElement end EntityType!attr isA ERDElement end ERDModel in Class with attribute contains: ERDElement rule r1: $ forall e/EntityType m/ERDModel a/EntityType!attr (m contains e) and Ai(e,attr,a) ==> (m contains a) $; r2: $ forall e/IsaType m/ERDModel a/IsaType!sub (m contains e) and Ai(e,sub,a) ==> (m contains a) $; r3: $ forall e/IsaType m/ERDModel a/IsaType!super (m contains e) and Ai(e,super,a) ==> (m contains a) $; r4: $ forall e/RelationshipType m/ERDModel a/RelationshipType!role (m contains e) and Ai(e,role,a) ==> (m contains a) $ end {* -------------------------------------------------------------------------- *} {* We support the following graphical notation for ERDs: *} {* Entity types --> boxes *} {* Relationship types --> diamonds *} {* Entityrelationship types --> squared diamonds *} {* IsA types --> diamonds with grey color *} {* entity attributes --> ellipses *} {* key attributes --> ellipses with double lines *} {* roles links --> undirected links *} {* links to subtypes --> undirected links *} {* links to supertypes --> undirected links with a bar *} {* attribute links --> undirected links *} {* -------------------------------------------------------------------------- *} GraphVizType end Boxnode in GraphVizType,Class with rule r1: $ forall n/EntityType not (n in EntityRelationshipType) ==> (n in Boxnode) $ end Diamondnode in GraphVizType,Class with rule r1: $ forall n/RelationshipType not (n in EntityType) ==> (n in Diamondnode) $ end Mdiamondnode in GraphVizType,Class with rule r1: $ forall n/EntityRelationshipType (n in Mdiamondnode) $ end Filleddiamondnode in GraphVizType,Class with rule r1: $ forall n/IsaType (n in Filleddiamondnode) $ end Ellipsenode in GraphVizType,Class with rule r1: $ forall n/EntityType!attr not (n in EntityType!key) ==> (n in Ellipsenode) $ end Dellipsenode in GraphVizType,Class with rule r1: $ forall n/EntityType!key (n in Dellipsenode) $ end Link in GraphVizType,Class with rule r1: $ forall l/RelationshipType!role (l in Link) $; r2: $ forall l/IsaType!sub (l in Link) $ end LinkTee in GraphVizType,Class with rule r1: $ forall l/IsaType!super (l in LinkTee) $ end LinkAttr in GraphVizType,Class with rule r1: $ forall l/EntityType!attr (l in LinkAttr) $ end {* -------------------------------------------------------------------------- *} {* LinkLabel returns the cardinality tag of a role link; if the tag is *} {* undefined then the empty string is returned. *} {* -------------------------------------------------------------------------- *} Function LinkLabel isA Label with parameter li: Link constraint cfn: $ (exists tag1/Proposition!cardinalityTag (li in RelationshipType!role) and (li in tag1) and Label(tag1,this)) or (not exists tag2/Proposition!cardinalityTag (li in RelationshipType!role) and (li in tag2)) and (this ="") $ end {* -------------------------------------------------------------------------- *} {* ShowERD returns the parameter erd as result. This is apparently not very *} {* meaningful but is triggers the evaluation of the answer format script *} {* GraphVizErd, which coordinates the production of the answer. *} {* -------------------------------------------------------------------------- *} GenericQueryClass ShowERD isA ERDModel with required,parameter erd: ERDModel constraint c1: $ (erd = this) $ end {* -------------------------------------------------------------------------- *} {* ShowElement(erd,type) computes those elements that are contained in a *} {* given ERD diagram erd and that have the given type (e.g. Boxnode). *} {* It is used to format all elements of an ERD to their Graphviz *} {* representation. *} {* -------------------------------------------------------------------------- *} GenericQueryClass ShowElement isA ERDModel with required,parameter erd: ERDModel; type: GraphVizType computed_attribute elem: ERDElement constraint c1: $ (erd = this) and (this contains elem) and (elem in type) $ end {* -------------------------------------------------------------------------- *} {* GraphVizErd coordinates the production of all Graphviz code for an ER *} {* diagram. It does so by calling ShowElement for all supported types. *} {* -------------------------------------------------------------------------- *} GraphVizErd in AnswerFormat with forQuery q: ShowERD head h: "# Generated by ConceptBase {cb_version} at {transactiontime} # Process this file by Graphviz, e.g. # neato -Tpng thisfile.txt > thisfile.png " pattern p: "graph {this} \{ {ASKquery(ShowElement[{this}/erd,Boxnode/type],BOXNODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Diamondnode/type],DIAMONDNODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Mdiamondnode/type],MDIAMONDNODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Dellipsenode/type],DELLIPSENODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Ellipsenode/type],ELLIPSENODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Filleddiamondnode/type],FILLEDDIAMONDNODE_FORMAT)} {ASKquery(ShowElement[{this}/erd,Link/type],LINK_FORMAT)} {ASKquery(ShowElement[{this}/erd,LinkTee/type],LINKTEE_FORMAT)} {ASKquery(ShowElement[{this}/erd,LinkAttr/type],LINKATTR_FORMAT)} overlap=false label=\"ERD Model {this}\\\nExtracted from ConceptBase and layed out by Graphviz (neato) \" fontsize=12; \} " end {* -------------------------------------------------------------------------- *} {* The following answer formats are linked one-to-one to the supported *} {* Graphviz types (Boxnode,...). *} {* Note that a given ERD referenced by 'this' usually has many elements of *} {* a given type. They are scanned by the Foreach-construct. *} {* -------------------------------------------------------------------------- *} BOXNODE_FORMAT in AnswerFormat with pattern p: "node [shape=box]; {Foreach( ({this.elem}), (n), {n};)}" end DIAMONDNODE_FORMAT in AnswerFormat with pattern p: "node [shape=diamond]; {Foreach( ({this.elem}), (d), {d};)}" end FILLEDDIAMONDNODE_FORMAT in AnswerFormat with pattern p: "node [shape=diamond,style=filled,peripheries=1,color=lightgrey,label=\"isa\"]; {Foreach( ({this.elem}), (f), {f};)}" end ELLIPSENODE_FORMAT in AnswerFormat with pattern p: "{Foreach( ({this.elem}), (e),node [shape=ellipse\,peripheries=1,label=\"{Label({e})}\"]; {Oid({e})};\\n)}" end DELLIPSENODE_FORMAT in AnswerFormat with pattern p: "{Foreach( ({this.elem}), (e),node [shape=ellipse\,peripheries=2,label=\"{Label({e})}\"]; {Oid({e})};\\n)}" end MDIAMONDNODE_FORMAT in AnswerFormat with pattern p: "node [shape=Mdiamond]; {Foreach( ({this.elem}), (m), {m};)}" end LINK_FORMAT in AnswerFormat with pattern p: "{Foreach( ({this.elem}),(l),{From({l})}--{To({l})} [len=1.20,label={ASKquery(LinkLabel[{l}/li],LABEL)}];\\n)}" end LINKTEE_FORMAT in AnswerFormat with pattern p: "{Foreach( ({this.elem}),(l),{From({l})}--{To({l})} [len=1.10\,dir=forward,arrowhead=tee];\\n)}" end LINKATTR_FORMAT in AnswerFormat with pattern p: "{Foreach( ({this.elem}),(l),{From({l})}--{Oid({l})} [len=1.00];\\n)}" end