Esempio n. 1
0
        public ColumnDefinition(string columnName, IEnumerable <Token <SqliteToken> > typeDefinition, IEnumerable <ColumnConstraint> columnConstraints)
        {
            if (columnName.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(columnName));
            }

            Name           = columnName;
            TypeDefinition = typeDefinition?.ToList() ?? Enumerable.Empty <Token <SqliteToken> >();

            var        nullable            = true;
            var        autoIncrement       = false;
            var        collation           = SqliteCollation.None;
            var        defaultValue        = new List <Token <SqliteToken> >();
            PrimaryKey?primaryKey          = null;
            UniqueKey? uniqueKey           = null;
            var        foreignKeys         = new List <ForeignKey>();
            var        checks              = new List <Check>();
            var        generatedDefinition = new List <Token <SqliteToken> >();
            var        generatedColumnType = SqliteGeneratedColumnType.None;

            columnConstraints = columnConstraints?.ToList() ?? Enumerable.Empty <ColumnConstraint>();
            foreach (var constraint in columnConstraints)
            {
                switch (constraint.ConstraintType)
                {
                case ColumnConstraint.ColumnConstraintType.Check:
                    if (constraint is ColumnConstraint.Check ck)
                    {
                        checks.Add(new Check(ck.Name, ck.Definition));
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.Collation:
                    if (constraint is ColumnConstraint.Collation col)
                    {
                        collation = col.CollationType;
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.Default:
                    if (constraint is ColumnConstraint.DefaultConstraint def)
                    {
                        defaultValue.AddRange(def.DefaultValue);
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.ForeignKey:
                    if (constraint is ColumnConstraint.ForeignKey fk)
                    {
                        foreignKeys.Add(new ForeignKey(fk.Name, Name, fk.ParentTable, fk.ParentColumnNames));
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.Nullable:
                    if (constraint is ColumnConstraint.Nullable nullableCons)
                    {
                        nullable = nullableCons.IsNullable;
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.PrimaryKey:
                    if (constraint is ColumnConstraint.PrimaryKey pk)
                    {
                        autoIncrement = pk.AutoIncrement;
                        primaryKey    = new PrimaryKey(pk.Name, new IndexedColumn(Name).WithColumnOrder(pk.ColumnOrder).ToEnumerable());
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.UniqueKey:
                    if (constraint is ColumnConstraint.UniqueKey uk)
                    {
                        uniqueKey = new UniqueKey(uk.Name, Name);
                    }
                    break;

                case ColumnConstraint.ColumnConstraintType.GeneratedAlways:
                    if (constraint is ColumnConstraint.GeneratedAlways generated)
                    {
                        generatedDefinition.AddRange(generated.Definition);
                        generatedColumnType = generated.GeneratedColumnType;
                    }
                    break;
                }
            }

            if (primaryKey != null && uniqueKey != null)
            {
                uniqueKey = null; // prefer primary key to unique key
            }
            Nullable        = nullable;
            IsAutoIncrement = autoIncrement;
            Collation       = collation;
            DefaultValue    = defaultValue;
            PrimaryKey      = primaryKey != null ? Option <PrimaryKey> .Some(primaryKey) : Option <PrimaryKey> .None;

            UniqueKey = uniqueKey != null ? Option <UniqueKey> .Some(uniqueKey) : Option <UniqueKey> .None;

            ForeignKeys = foreignKeys;
            Checks      = checks;
            GeneratedColumnDefinition = generatedDefinition;
            GeneratedColumnType       = generatedColumnType;
        }
Esempio n. 2
0
        /// <summary>
        /// Parses the tokens into structured table definition.
        /// </summary>
        /// <param name="definition">The textual definition of the <c>CREATE TABLE</c> statement.</param>
        /// <param name="tokens">A collection of tokens from the table definition.</param>
        /// <returns>Parsed data for a <c>CREATE TABLE</c> definition.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="tokens"/> is empty.</exception>
        public ParsedTableData ParseTokens(string definition, TokenList <SqliteToken> tokens)
        {
            if (definition.IsNullOrWhiteSpace())
            {
                throw new ArgumentNullException(nameof(definition));
            }
            if (tokens == default || tokens.Empty())
            {
                throw new ArgumentNullException(nameof(tokens));
            }

            var next = tokens.ConsumeToken();
            var createTablePrefix = SqliteTokenParsers.CreateTablePrefix(next.Location);

            if (!createTablePrefix.HasValue)
            {
                throw new ArgumentException("Token list does not start with a CREATE TABLE statement.", nameof(tokens));
            }

            next = createTablePrefix.Remainder.ConsumeToken();
            var ifNotExists = SqliteTokenParsers.IfNotExistsClause(next.Location);

            if (ifNotExists.HasValue)
            {
                next = ifNotExists.Remainder.ConsumeToken();
            }

            var tableName = SqliteTokenParsers.QualifiedName(next.Location);

            if (!tableName.HasValue)
            {
                throw new ArgumentException("Unable to determine the name of the table being parsed.", nameof(tokens));
            }

            next = tableName.Remainder.ConsumeToken();
            var isSelectBasedTable = !next.HasValue || next.Value.Kind != SqliteToken.LParen;

            // skipping because we cannot parse extra information from a select-based table
            if (isSelectBasedTable)
            {
                return(ParsedTableData.Empty(definition));
            }

            next = next.Remainder.ConsumeToken(); // consume LParen

            var tableMembers = SqliteTokenParsers.TableMembers(next.Location);

            if (!tableMembers.HasValue)
            {
                var errMessage = "Unable to parse columns and/or constraints from the table definition. Error: " + tableMembers.ErrorMessage;
                throw new ArgumentException(errMessage, nameof(tokens));
            }

            var columns     = new List <Column>();
            var primaryKey  = Option <PrimaryKey> .None;
            var uniqueKeys  = new List <UniqueKey>();
            var foreignKeys = new List <ForeignKey>();
            var checks      = new List <Check>();

            var parsedColumns     = tableMembers.Value.SelectMany(m => m.Columns);
            var parsedConstraints = tableMembers.Value.SelectMany(m => m.Constraints);

            foreach (var parsedColumn in parsedColumns)
            {
                var column = new Column(
                    parsedColumn.Name,
                    parsedColumn.TypeDefinition,
                    parsedColumn.Nullable,
                    parsedColumn.IsAutoIncrement,
                    parsedColumn.Collation,
                    parsedColumn.DefaultValue,
                    parsedColumn.GeneratedColumnDefinition,
                    parsedColumn.GeneratedColumnType
                    );

                columns.Add(column);

                if (primaryKey.IsNone && parsedColumn.PrimaryKey.IsSome)
                {
                    primaryKey = parsedColumn.PrimaryKey;
                }

                parsedColumn.UniqueKey.IfSome(uk => uniqueKeys.Add(uk));
                foreignKeys.AddRange(parsedColumn.ForeignKeys);
                checks.AddRange(parsedColumn.Checks);
            }

            foreach (var parsedConstraint in parsedConstraints)
            {
                switch (parsedConstraint.ConstraintType)
                {
                case TableConstraint.TableConstraintType.PrimaryKey:
                    if (parsedConstraint is TableConstraint.PrimaryKey pk)
                    {
                        primaryKey = new PrimaryKey(pk.Name, pk.Columns);
                    }
                    break;

                case TableConstraint.TableConstraintType.UniqueKey:
                    if (parsedConstraint is TableConstraint.UniqueKey uk)
                    {
                        uniqueKeys.Add(new UniqueKey(uk.Name, uk.Columns));
                    }
                    break;

                case TableConstraint.TableConstraintType.ForeignKey:
                    if (parsedConstraint is TableConstraint.ForeignKey fk)
                    {
                        foreignKeys.Add(new ForeignKey(fk.Name, fk.Columns, fk.ParentTable, fk.ParentColumnNames));
                    }
                    break;

                case TableConstraint.TableConstraintType.Check:
                    if (parsedConstraint is TableConstraint.Check ck)
                    {
                        checks.Add(new Check(ck.Name, ck.Definition));
                    }
                    break;
                }
            }

            return(new ParsedTableData(
                       definition,
                       columns,
                       primaryKey,
                       uniqueKeys,
                       foreignKeys,
                       checks
                       ));
        }