Skip to content
Snippets Groups Projects
Select Git revision
  • efc59f343ce6a209853e9470e5129e1ef6e326f7
  • main default protected
2 results

main.py

Blame
  • models.py 5.52 KiB
    import re
    
    class Theme:
        def __init__(self, color, fillcolor, fillcolorC,
                bgcolor, icolor, tcolor, style, shape, pencolor, penwidth):
            self.color = color
            self.fillcolor = fillcolor
            self.fillcolorC = fillcolorC
            self.bgcolor = bgcolor
            self.icolor = icolor
            self.tcolor = tcolor
            self.style = style
            self.shape = shape
            self.pencolor = pencolor
            self.penwidth = penwidth
    
    
    class Table():
        def __init__(self, name, comment):
            self.name = name
            self.comment = comment if comment is not None and comment != 'None' else ''
            self.label = None
    
            self.columns = []           # list of all columns
            self.uniques = {}           # dictionary with UNIQUE constraints, by name + list of columns
            self.pks = []               # list of PK columns (if any)
            self.fks = {}               # dictionary with FK constraints, by name + list of FK columns
    
    
        @classmethod
        def getClassName(cls, name, useUpperCase, withQuotes=True):
            if re.match("^[A-Z_0-9]*$", name) == None:
                return f'"{name}"' if withQuotes else name
            return name.upper() if useUpperCase else name.lower()
    
        def getName(self, useUpperCase, withQuotes=True):
            return Table.getClassName(self.name, useUpperCase, withQuotes)
    
        def getColumn(self, name):
            for column in self.columns:
                if column.name == name:
                    return column
            return None
    
        def getDotShape(self, theme, showColumns, showTypes, useUpperCase):
            fillcolor = theme.fillcolorC if showColumns else theme.fillcolor
            colspan = "2" if showTypes else "1"
            tableName = self.getName(useUpperCase, False)
    
            s = (f'  {self.label} [\n'
                + f'    fillcolor="{fillcolor}" color="{theme.color}" penwidth="1"\n'
                + f'    label=<<table style="{theme.style}" border="0" cellborder="0" cellspacing="0" cellpadding="1">\n'
                + f'      <tr><td bgcolor="{theme.bgcolor}" align="center"'
                + f' colspan="{colspan}"><font color="{theme.tcolor}"><b>{tableName}</b></font></td></tr>\n')
    
            if showColumns:
                for column in self.columns:
                    name = column.getName(useUpperCase, False)
                    if column.ispk: name = f"<u>{name}</u>"
                    if column.fkof != None: name = f"<i>{name}</i>"
                    if column.nullable: name = f"{name}*"
                    if column.identity: name = f"{name} I"
                    if column.isunique: name = f"{name} U"
                    datatype = column.datatype
                    if useUpperCase: datatype = datatype.upper()
    
                    if showTypes:
                        s += (f'      <tr><td align="left"><font color="{theme.icolor}">{name}&nbsp;</font></td>\n'
                            + f'        <td align="left"><font color="{theme.icolor}">{datatype}</font></td></tr>\n')
                    else:
                        s += f'      <tr><td align="left"><font color="{theme.icolor}">{name}</font></td></tr>\n'
    
            return s + '    </table>>\n  ]\n'
    
    
        def getDotLinks(self, theme):
            s = ""
            for constraint in self.fks:
                fks = self.fks[constraint]
                fk1 = fks[0]
                dashed = "" if not fk1.nullable else ' style="dashed"'
                arrow = "" if fk1.ispk and len(self.pks) == len(fk1.fkof.table.pks) else ' arrowtail="crow"'
                s += (f'  {self.label} -> {fk1.fkof.table.label}'
                    + f' [ penwidth="{theme.penwidth}" color="{theme.pencolor}"{dashed}{arrow} ]\n')
            return s
    
    
    class Column:
        def __init__(self, table, name, comment):
            self.table = table
            self.name = name
            self.comment = comment if comment is not None and comment != 'None' else ''
            self.nullable = True
            self.datatype = None        # with (length, or precision/scale)
            self.identity = False
    
            self.isunique = False
            self.ispk = False
            self.pkconstraint = None
            self.fkof = None            # points to the PK column on the other side
    
    
        def getName(self, useUpperCase, withQuotes=True):
            return Table.getClassName(self.name, useUpperCase, withQuotes)
    
    
        def setDataType(self, datatype):
            self.datatype = datatype["type"]
            self.nullable = bool(datatype["nullable"])
    
            if self.datatype == "FIXED":
                self.datatype = "NUMBER"
            elif "fixed" in datatype:
                fixed = bool(datatype["fixed"])
                if self.datatype == "TEXT":
                    self.datatype = "CHAR" if fixed else "VARCHAR"
    
            if "length" in datatype:
                self.datatype += f"({str(datatype['length'])})"
            elif "scale" in datatype:
                if int(datatype['precision']) == 0:
                    self.datatype += f"({str(datatype['scale'])})"
                    if self.datatype == "TIMESTAMP_NTZ(9)":
                        self.datatype = "TIMESTAMP"
                elif "scale" in datatype and int(datatype['scale']) == 0:
                    self.datatype += f"({str(datatype['precision'])})"
                    if self.datatype == "NUMBER(38)":
                        self.datatype = "INT"
                    elif self.datatype.startswith("NUMBER("):
                        self.datatype = f"INT({str(datatype['precision'])})"
                elif "scale" in datatype:
                    self.datatype += f"({str(datatype['precision'])},{str(datatype['scale'])})"
                    #if column.datatype.startswith("NUMBER("):
                    #    column.datatype = f"FLOAT({str(datatype['precision'])},{str(datatype['scale'])})"
            self.datatype = self.datatype.lower()