PlantUML is a tool I’m fond of using to create diagrams from text. While they may not give the same level of customization as a graphical editor, they’re easier to maintain/update.

The other day I was working to loosely define a schema in PlantUML and realized that it wasn’t obvious how to customize plantuml to represent this.

Skinning Components

To start, I’m using PlantUML’s class diagram to describe our schema since it provides a lot of useful relationship and attribute descriptors. We can start with a base description of offices and their employees:

class "Office" as office {
    officeCode: integer
    city: string
    phone: string
    addressLine1: string
    addressLine2: string
    state: string
    country: string
    postalCode: string
    territory: string
}

class "Employee" as employee {
    employeeId: uuid
    officeCode: integer
    lastName: string
    firstName: string
    email: string
    jobTitle: string
}

which renders as the following:

Schema Unskinned

Now this looks alright but some parts aren’t quite right. We’re not really representing a class via the ‘C’ icon. Furthermore, there’s a line at the bottom which would be used to split between class fields and methods but for our schema this isn’t needed. To make this more schema-oriented, we can spruce this up a bit by replacing the ‘C’ icon representing “class” with a ‘T’ icon representing “table”. We also can remove the bottom line delineating between the fields and methods of a ‘class’. This can be accomplished with the following changes (’ at the beginning of a line denotes a comment):

@startuml

' Define a preprocessor define to shorthand table creation
!define table(name, x) class "name" as x << (T,#FFAAAA) >>

' Ensure we hide methods and stereotypes to clean up the diagram
hide methods
hide stereotypes

table(Employee, employee) {
    officeCode: integer
    city: string
    phone: string
    addressLine1: string
    addressLine2: string
    state: string
    country: string
    postalCode: string
    territory: string
}

table(Office, office) {
    employeeId: uuid
    officeCode: integer
    lastName: string
    firstName: string
    email: string
    jobTitle: string
}

@enduml

This reads a bit cleaner in the text as well as on the diagram: Schema Skinned

Relationships Between Tables

Within our usecase, let’s say that within every office there are 0 or more employees. We can represent this in PlantUML with the following addition:

office "1" -r- "*" employee

Which renders as:

Schema With Relationships

Primary, Foreign Keys and other attribute modifiers

Now that we’ve established the relationship between the tables, it’d be nice if we could mark the attributes that show uniqueness for table elements as well as table relationships. For this example, the two things that would be helpful to mark would be the primary and foreign keys. This is done via a key icon and underlining to indicate a primary vs a foreign key. This can be accomplished with a couple more preprocessor defines:

!define primary_key(x) <&key><u>x</u>
!define foreign_key(x) <&key>x

we can then use these to wrap attributes of a table like so:

table(Employee, employee) {
    primary_key(employeeId: uuid)
    foreign_key(officeCode: integer)
    lastName: string
    firstName: string
    email: string
    jobTitle: string
}

table(Office, office) {
    primary_key(officeCode: uuid)
    city: string
    phone: string
    addressLine1: string
    addressLine2: string
    state: string
    country: string
    postalCode: string
    territory: string
}

which renders as:

Schema With Attribute Modifiers

Conclusion

While this doesn’t fully cover all the possible attributes they may need to be represented in a schema, it can give a starting point to quickly iterate until you’ve come to a better understanding of the given problem domain and how those relationships should be represented.

The full example and all the intermediate steps can be found here.