Esempio n. 1
0
        protected override IRuleMessage BuildMessage(Option <Identifier> foreignKeyName, Identifier childTableName)
        {
            if (childTableName == null)
            {
                throw new ArgumentNullException(nameof(childTableName));
            }

            var builder = StringBuilderCache.Acquire();

            builder.Append("A foreign key");

            foreignKeyName.IfSome(fkName =>
            {
                builder.Append(" <code>")
                .Append(HttpUtility.HtmlEncode(fkName.LocalName))
                .Append("</code>");
            });

            var childTableUrl  = UrlRouter.GetTableUrl(childTableName);
            var childTableLink = $"<a href=\"{ childTableUrl }\">{ HttpUtility.HtmlEncode(childTableName.ToVisibleName()) }</a>";

            builder.Append(" on ")
            .Append(childTableLink)
            .Append(" contains the same column set as the target key.");

            var message = builder.GetStringAndRelease();

            return(new RuleMessage(RuleId, RuleTitle, Level, message));
        }
Esempio n. 2
0
        private Option <Uri> GetSynonymTargetUrl(Identifier identifier, SynonymTargets targets)
        {
            if (targets.Tables.ContainsKey(identifier))
            {
                return(new Uri(UrlRouter.GetTableUrl(identifier), UriKind.Relative));
            }

            if (targets.Views.ContainsKey(identifier))
            {
                return(new Uri(UrlRouter.GetViewUrl(identifier), UriKind.Relative));
            }

            if (targets.Sequences.ContainsKey(identifier))
            {
                return(new Uri(UrlRouter.GetSequenceUrl(identifier), UriKind.Relative));
            }

            if (targets.Synonyms.ContainsKey(identifier))
            {
                return(new Uri(UrlRouter.GetSynonymUrl(identifier), UriKind.Relative));
            }

            if (targets.Routines.ContainsKey(identifier))
            {
                return(new Uri(UrlRouter.GetRoutineUrl(identifier), UriKind.Relative));
            }

            return(Option <Uri> .None);
        }
Esempio n. 3
0
            public TableColumn(
                Identifier tableName,
                int ordinalPosition,
                string columnName,
                string typeDefinition,
                bool isNullable,
                Option <string> defaultValue,
                bool isPrimaryKeyColumn,
                bool isUniqueKeyColumn,
                bool isForeignKeyColumn
                ) : base(
                    tableName,
                    ordinalPosition,
                    columnName,
                    typeDefinition,
                    isNullable,
                    defaultValue
                    )
            {
                TableUrl = UrlRouter.GetTableUrl(tableName);

                var isKey = isPrimaryKeyColumn || isUniqueKeyColumn || isForeignKeyColumn;

                ColumnClass = isKey ? @"class=""is-key-column""" : string.Empty;

                ColumnIcon  = BuildColumnIcon(isPrimaryKeyColumn, isUniqueKeyColumn, isForeignKeyColumn);
                ColumnTitle = BuildColumnTitle(isPrimaryKeyColumn, isUniqueKeyColumn, isForeignKeyColumn);
            }
Esempio n. 4
0
            public Sequence(
                Identifier sequenceName,
                decimal start,
                decimal increment,
                Option <decimal> minValue,
                Option <decimal> maxValue,
                int cache,
                bool cycle
                )
            {
                if (sequenceName == null)
                {
                    throw new ArgumentNullException(nameof(sequenceName));
                }

                Name        = sequenceName.ToVisibleName();
                SequenceUrl = UrlRouter.GetSequenceUrl(sequenceName);

                Start        = start;
                Increment    = increment;
                MinValueText = minValue.Match(mv => mv.ToString(), () => string.Empty);
                MaxValueText = maxValue.Match(mv => mv.ToString(), () => string.Empty);
                Cache        = cache;
                CycleText    = cycle ? "✓" : "✗";
            }
Esempio n. 5
0
            public ChildKey(string constraintName, Identifier childTableName, string childColumnName, string qualifiedParentColumnName, string rootPath)
            {
                if (childTableName == null)
                {
                    throw new ArgumentNullException(nameof(childTableName));
                }
                if (childColumnName.IsNullOrWhiteSpace())
                {
                    throw new ArgumentNullException(nameof(childColumnName));
                }
                if (qualifiedParentColumnName.IsNullOrWhiteSpace())
                {
                    throw new ArgumentNullException(nameof(qualifiedParentColumnName));
                }
                if (rootPath == null)
                {
                    throw new ArgumentNullException(nameof(rootPath));
                }

                ChildTableName  = childTableName.ToVisibleName();
                ChildTableUrl   = rootPath + UrlRouter.GetTableUrl(childTableName);
                ChildColumnName = childColumnName;

                var qualifiedChildColumnName = ChildTableName + "." + ChildColumnName;
                var description = qualifiedChildColumnName + " references " + qualifiedParentColumnName;

                if (!constraintName.IsNullOrWhiteSpace())
                {
                    description += " via " + constraintName;
                }
                ConstraintDescription = description;
            }
Esempio n. 6
0
        protected override IRuleMessage BuildMessage(string columnName, Identifier tableName, Identifier targetTableName)
        {
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (targetTableName == null)
            {
                throw new ArgumentNullException(nameof(targetTableName));
            }

            var builder = StringBuilderCache.Acquire();

            var tableUrl        = UrlRouter.GetTableUrl(tableName);
            var tableLink       = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var targetTableUrl  = UrlRouter.GetTableUrl(targetTableName);
            var targetTableLink = $"<a href=\"{ targetTableUrl }\">{ HttpUtility.HtmlEncode(targetTableName.ToVisibleName()) }</a>";

            builder.Append("The table ")
            .Append(tableLink)
            .Append(" has a column <code>")
            .Append(columnName)
            .Append("</code> implying a relationship to ")
            .Append(targetTableLink)
            .Append(" which is missing a foreign key constraint.");

            var messageText = builder.GetStringAndRelease();

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 7
0
            public Routine(Identifier routineName)
            {
                if (routineName == null)
                {
                    throw new ArgumentNullException(nameof(routineName));
                }

                Name       = routineName.ToVisibleName();
                RoutineUrl = UrlRouter.GetRoutineUrl(routineName);
            }
Esempio n. 8
0
            protected TableConstraint(Identifier tableName, string constraintName)
            {
                if (tableName == null)
                {
                    throw new ArgumentNullException(nameof(tableName));
                }

                TableName      = tableName.ToVisibleName();
                TableUrl       = UrlRouter.GetTableUrl(tableName);
                ConstraintName = constraintName ?? string.Empty;
            }
Esempio n. 9
0
            public Table(Identifier tableName, uint columnCount, ulong rowCount)
            {
                if (tableName == null)
                {
                    throw new ArgumentNullException(nameof(tableName));
                }

                Name        = tableName.ToVisibleName();
                TableUrl    = UrlRouter.GetTableUrl(tableName);
                ColumnCount = columnCount;
                RowCount    = rowCount;
            }
        private IReadOnlyCollection <Link> GetReferenceTargetLinks(string rootPath, Identifier objectName, Identifier referenceName)
        {
            if (rootPath == null)
            {
                throw new ArgumentNullException(nameof(rootPath));
            }
            if (objectName == null)
            {
                throw new ArgumentNullException(nameof(objectName));
            }
            if (referenceName == null)
            {
                throw new ArgumentNullException(nameof(referenceName));
            }

            var qualifiedReference = QualifyReferenceName(objectName, referenceName);
            var isSelfReference    = string.Equals(objectName.Schema, qualifiedReference.Schema, StringComparison.OrdinalIgnoreCase) &&
                                     string.Equals(objectName.LocalName, qualifiedReference.LocalName, StringComparison.OrdinalIgnoreCase);

            if (isSelfReference)
            {
                return(Array.Empty <Link>());
            }

            var result = new List <Link>();

            var matchingTables = GetMatchingObjects(TableNames, qualifiedReference)
                                 .Select(name => new Link(name, new Uri(rootPath + UrlRouter.GetTableUrl(name), UriKind.Relative)));

            result.AddRange(matchingTables);

            var matchingViews = GetMatchingObjects(ViewNames, qualifiedReference)
                                .Select(name => new Link(name, new Uri(rootPath + UrlRouter.GetViewUrl(name), UriKind.Relative)));

            result.AddRange(matchingViews);

            var matchingSequences = GetMatchingObjects(SequenceNames, qualifiedReference)
                                    .Select(name => new Link(name, new Uri(rootPath + UrlRouter.GetSequenceUrl(name), UriKind.Relative)));

            result.AddRange(matchingSequences);

            var matchingSynonyms = GetMatchingObjects(SynonymNames, qualifiedReference)
                                   .Select(name => new Link(name, new Uri(rootPath + UrlRouter.GetSynonymUrl(name), UriKind.Relative)));

            result.AddRange(matchingSynonyms);

            var matchingRoutines = GetMatchingObjects(RoutineNames, qualifiedReference)
                                   .Select(name => new Link(name, new Uri(rootPath + UrlRouter.GetRoutineUrl(name), UriKind.Relative)));

            result.AddRange(matchingRoutines);

            return(result);
        }
Esempio n. 11
0
            public View(Identifier viewName, uint columnCount, bool isMaterialized)
            {
                if (viewName == null)
                {
                    throw new ArgumentNullException(nameof(viewName));
                }

                Name             = viewName.ToVisibleName();
                ViewUrl          = UrlRouter.GetViewUrl(viewName);
                ColumnCount      = columnCount;
                MaterializedText = isMaterialized ? "✓" : "✗";
            }
Esempio n. 12
0
        protected override IRuleMessage BuildMessage(Identifier tableName, int columnCount)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has too many columns. It has { columnCount } columns.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has a multi-column primary key. Consider introducing a surrogate primary key.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 14
0
        protected override IRuleMessage BuildDisabledUniqueKeyMessage(Identifier tableName, Option <Identifier> uniqueKeyName)
        {
            var messageKeyName = uniqueKeyName.Match(
                name => " <code>" + HttpUtility.HtmlEncode(name.LocalName) + "</code>",
                () => string.Empty
                );

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } contains a disabled unique key{ messageKeyName }. Consider enabling or removing the unique key.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has a primary key whose column is not the first column in the table.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has no candidate (primary or unique) keys. Consider adding one to ensure records are unique.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildSequenceMessage(Identifier sequenceName)
        {
            if (sequenceName == null)
            {
                throw new ArgumentNullException(nameof(sequenceName));
            }

            var sequenceUrl  = UrlRouter.GetSequenceUrl(sequenceName);
            var sequenceLink = $"<a href=\"{ sequenceUrl }\">{ HttpUtility.HtmlEncode(sequenceName.ToVisibleName()) }</a>";
            var messageText  = $"The sequence { sequenceLink } is also a database keyword and may require quoting to be used. Consider renaming to a non-keyword name.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 18
0
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has no not-nullable columns present. Consider adding one to ensure that each record contains data.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 19
0
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } is not related to any other table. Consider adding relations or removing the table.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildMessage(Identifier viewName)
        {
            if (viewName == null)
            {
                throw new ArgumentNullException(nameof(viewName));
            }

            var viewUrl     = UrlRouter.GetViewUrl(viewName);
            var viewLink    = $"<a href=\"{ viewUrl }\">{ HttpUtility.HtmlEncode(viewName.ToVisibleName()) }</a>";
            var messageText = $"The view { viewLink } was unable to be queried. This may indicate an incorrect view definition.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 21
0
        protected override IRuleMessage BuildMessage(Identifier tableName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } does not have any indexes present, requiring table scans to access records. Consider introducing an index or a primary key or a unique key constraint.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 22
0
        protected override IRuleMessage BuildSynonymMessage(Identifier synonymName)
        {
            if (synonymName == null)
            {
                throw new ArgumentNullException(nameof(synonymName));
            }

            var synonymUrl  = UrlRouter.GetSynonymUrl(synonymName);
            var synonymLink = $"<a href=\"{ synonymUrl }\">{ HttpUtility.HtmlEncode(synonymName.ToVisibleName()) }</a>";
            var messageText = $"The synonym { synonymLink } contains whitespace and requires quoting to be used. Consider renaming to remove any whitespace.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 23
0
        protected override IRuleMessage BuildMessage(Identifier tableName, string indexName, IEnumerable <string> redundantIndexColumnNames, string otherIndexName, IEnumerable <string> otherIndexColumnNames)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (indexName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(indexName));
            }
            if (redundantIndexColumnNames == null || redundantIndexColumnNames.Empty())
            {
                throw new ArgumentNullException(nameof(redundantIndexColumnNames));
            }
            if (otherIndexName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(otherIndexName));
            }
            if (otherIndexColumnNames == null || otherIndexColumnNames.Empty())
            {
                throw new ArgumentNullException(nameof(otherIndexColumnNames));
            }

            var tableUrl  = UrlRouter.GetTableUrl(tableName);
            var tableLink = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";

            var columnNames = redundantIndexColumnNames
                              .Select(columnName => "<code>" + HttpUtility.HtmlEncode(columnName) + "</code>");
            var otherColumnNames = otherIndexColumnNames
                                   .Select(columnName => "<code>" + HttpUtility.HtmlEncode(columnName) + "</code>");

            var builder = StringBuilderCache.Acquire();

            builder.Append("The table ")
            .Append(tableLink)
            .Append(" has an index <code>")
            .Append(HttpUtility.HtmlEncode(indexName))
            .Append("</code> which may be redundant, as its column set (")
            .AppendJoin(", ", columnNames)
            .Append(") is the prefix of another index <code>")
            .Append(HttpUtility.HtmlEncode(otherIndexName))
            .Append("</code> (")
            .AppendJoin(", ", otherColumnNames)
            .Append(").");

            var messageText = builder.GetStringAndRelease();

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
        protected override IRuleMessage BuildTableColumnMessage(Identifier tableName, string columnName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } contains a column <code>{ HttpUtility.HtmlEncode(columnName) }</code> which is also a database keyword and may require quoting to be used. Consider renaming to a non-keyword name.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 25
0
        protected override IRuleMessage BuildMessage(Identifier tableName, string columnName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has a column <code>{ HttpUtility.HtmlEncode(columnName) }</code> with a numeric suffix, indicating denormalization.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 26
0
        protected override IRuleMessage BuildViewColumnMessage(Identifier viewName, string columnName)
        {
            if (viewName == null)
            {
                throw new ArgumentNullException(nameof(viewName));
            }
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }

            var viewUrl     = UrlRouter.GetViewUrl(viewName);
            var viewLink    = $"<a href=\"{ viewUrl }\">{ HttpUtility.HtmlEncode(viewName.ToVisibleName()) }</a>";
            var messageText = $"The view { viewLink } contains a column <code>{ HttpUtility.HtmlEncode(columnName) }</code> which contains whitespace and requires quoting to be used. Consider renaming to remove any whitespace.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 27
0
        protected override IRuleMessage BuildMessage(Identifier tableName, string columnName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } has a column <code>{ HttpUtility.HtmlEncode(columnName) }</code> whose default value is <code>NULL</code>. Consider removing the default value on the column.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 28
0
 public ViewColumn(
     Identifier viewName,
     int ordinalPosition,
     string columnName,
     string typeDefinition,
     bool isNullable
     ) : base(
         viewName,
         ordinalPosition,
         columnName,
         typeDefinition,
         isNullable,
         string.Empty
         )
 {
     TableUrl = UrlRouter.GetViewUrl(viewName);
 }
Esempio n. 29
0
        protected override IRuleMessage BuildDisabledTriggerMessage(Identifier tableName, string?triggerName)
        {
            if (tableName == null)
            {
                throw new ArgumentNullException(nameof(tableName));
            }

            var messageTriggerName = !triggerName.IsNullOrWhiteSpace()
                ? " <code>" + HttpUtility.HtmlEncode(triggerName) + "</code>"
                : string.Empty;

            var tableUrl    = UrlRouter.GetTableUrl(tableName);
            var tableLink   = $"<a href=\"{ tableUrl }\">{ HttpUtility.HtmlEncode(tableName.ToVisibleName()) }</a>";
            var messageText = $"The table { tableLink } contains a disabled trigger{ messageTriggerName }. Consider enabling or removing the trigger.";

            return(new RuleMessage(RuleId, RuleTitle, Level, messageText));
        }
Esempio n. 30
0
            public ForeignKey(
                string constraintName,
                IEnumerable <string> columnNames,
                Identifier parentTableName,
                string parentConstraintName,
                IEnumerable <string> parentColumnNames,
                ReferentialAction deleteAction,
                ReferentialAction updateAction,
                string rootPath
                ) : base(constraintName)
            {
                if (columnNames == null || columnNames.Empty())
                {
                    throw new ArgumentNullException(nameof(columnNames));
                }
                if (parentTableName == null)
                {
                    throw new ArgumentNullException(nameof(parentTableName));
                }
                if (parentColumnNames == null || parentColumnNames.Empty())
                {
                    throw new ArgumentNullException(nameof(parentColumnNames));
                }
                if (!deleteAction.IsValid())
                {
                    throw new ArgumentException($"The { nameof(ReferentialAction) } provided must be a valid enum.", nameof(deleteAction));
                }
                if (!updateAction.IsValid())
                {
                    throw new ArgumentException($"The { nameof(ReferentialAction) } provided must be a valid enum.", nameof(updateAction));
                }
                if (rootPath == null)
                {
                    throw new ArgumentNullException(nameof(rootPath));
                }

                ChildColumnNames     = columnNames.Join(", ");
                ParentConstraintName = parentConstraintName;
                ParentTableName      = parentTableName.ToVisibleName();
                ParentTableUrl       = rootPath + UrlRouter.GetTableUrl(parentTableName);
                ParentColumnNames    = parentColumnNames.Join(", ");

                DeleteActionDescription = _actionDescription[deleteAction];
                UpdateActionDescription = _actionDescription[updateAction];
            }