Beispiel #1
0
        void GetEnums(NpgsqlConnection connection, DatabaseModel databaseModel)
        {
            _enums.Clear();
            using (var command = connection.CreateCommand())
            {
                command.CommandText = @"
SELECT nspname, typname, array_agg(enumlabel ORDER BY enumsortorder) AS labels
FROM pg_enum
JOIN pg_type ON pg_type.oid=enumtypid
JOIN pg_namespace ON pg_namespace.oid=pg_type.typnamespace
GROUP BY nspname, typname";
                using (var reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        var schema = reader.GetValueOrDefault <string>("nspname");
                        var name   = reader.GetValueOrDefault <string>("typname");
                        var labels = reader.GetValueOrDefault <string[]>("labels");

                        if (schema == "public")
                        {
                            schema = null;
                        }
                        PostgresEnum.GetOrAddPostgresEnum(databaseModel, schema, name, labels);
                        _enums.Add(name);
                    }
                }
            }
        }
Beispiel #2
0
 protected virtual void GenerateDropEnum(PostgresEnum @enum, MigrationCommandListBuilder builder)
 {
     builder
     .Append("DROP TYPE ")
     .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(@enum.Name, @enum.Schema))
     .AppendLine(";");
 }
Beispiel #3
0
        public override void CreateTables()
        {
            var operations = Dependencies.ModelDiffer.GetDifferences(null, Dependencies.Model);
            var commands   = Dependencies.MigrationsSqlGenerator.Generate(operations, Dependencies.Model);

            // If a PostgreSQL extension or enum was added, we want Npgsql to reload all types at the ADO.NET level.
            var reloadTypes = operations.Any(o => o is AlterDatabaseOperation &&
                                             (PostgresExtension.GetPostgresExtensions(o).Any() ||
                                              PostgresEnum.GetPostgresEnums(o).Any()));

            try
            {
                Dependencies.MigrationCommandExecutor.ExecuteNonQuery(commands, _connection);
            }
            catch (PostgresException e) when(
                e.SqlState == "23505" && e.ConstraintName == "pg_type_typname_nsp_index"
                )
            {
                // This occurs when two connections are trying to create the same database concurrently
                // (happens in the tests). Simply ignore the error.
            }

            if (reloadTypes)
            {
                _connection.Open();
                try
                {
                    ((NpgsqlConnection)_connection.DbConnection).ReloadTypes();
                }
                catch
                {
                    _connection.Close();
                }
            }
        }
Beispiel #4
0
        protected virtual void GenerateCreateEnum(
            PostgresEnum enumType,
            IModel model,
            MigrationCommandListBuilder builder)
        {
            // Schemas are normally created (or rather ensured) by the model differ, which scans all tables, sequences
            // and other database objects. However, it isn't aware of enums, so we always ensure schema on enum creation.
            if (enumType.Schema != null)
            {
                Generate(new EnsureSchemaOperation {
                    Name = enumType.Schema
                }, model, builder);
            }

            builder
            .Append("CREATE TYPE ")
            .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(enumType.Name, enumType.Schema))
            .Append(" AS ENUM (");

            var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));

            var labels = enumType.Labels;

            for (var i = 0; i < labels.Length; i++)
            {
                builder.Append(stringTypeMapping.GenerateSqlLiteral(labels[i]));
                if (i < labels.Length - 1)
                {
                    builder.Append(", ");
                }
            }

            builder.AppendLine(");");
        }
Beispiel #5
0
        public override MethodCallCodeFragment GenerateFluentApi(IModel model, IAnnotation annotation)
        {
            Check.NotNull(model, nameof(model));
            Check.NotNull(annotation, nameof(annotation));

            if (annotation.Name.StartsWith(NpgsqlAnnotationNames.PostgresExtensionPrefix))
            {
                var extension = new PostgresExtension(model, annotation.Name);

                return(new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.HasPostgresExtension),
                                                  extension.Name));
            }

            if (annotation.Name.StartsWith(NpgsqlAnnotationNames.EnumPrefix))
            {
                var enumTypeDef = new PostgresEnum(model, annotation.Name);

                return(enumTypeDef.Schema == "public"
                    ? new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasEnum),
                                                 enumTypeDef.Name, enumTypeDef.Labels)
                    : new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasEnum),
                                                 enumTypeDef.Schema, enumTypeDef.Name, enumTypeDef.Labels));
            }

            return(null);
        }
        protected override void Generate(
            AlterDatabaseOperation operation,
            IModel model,
            MigrationCommandListBuilder builder)
        {
            Check.NotNull(operation, nameof(operation));
            Check.NotNull(builder, nameof(builder));

            foreach (var extension in PostgresExtension.GetPostgresExtensions(operation))
            {
                GenerateCreateExtension(extension, model, builder);
            }

            foreach (var enumTypeToCreate in PostgresEnum.GetPostgresEnums(operation)
                     .Where(ne => PostgresEnum.GetPostgresEnums(operation.OldDatabase).All(oe => oe.Name != ne.Name)))
            {
                GenerateCreateEnum(enumTypeToCreate, model, builder);
            }

            foreach (var enumTypeToDrop in PostgresEnum.GetPostgresEnums(operation.OldDatabase)
                     .Where(oe => PostgresEnum.GetPostgresEnums(operation).All(ne => ne.Name != oe.Name)))
            {
                GenerateDropEnum(enumTypeToDrop, builder);
            }

            foreach (var enumTypeToAlter in from newEnum in PostgresEnum.GetPostgresEnums(operation)
                     join oldEnum in PostgresEnum.GetPostgresEnums(operation.OldDatabase) on newEnum.Name equals oldEnum.Name
                     select new { newEnum.Name, OldLabels = oldEnum.Labels, newLabels = newEnum.Labels })
            {
                // TODO: Some forms of enum alterations are actually supported... At least log...
            }

            builder.EndCommand();
        }
        public void DropPostgresEnum()
        {
            var op = new AlterDatabaseOperation();

            PostgresEnum.GetOrAddPostgresEnum(op.OldDatabase, "public", "my_enum", new[] { "value1", "value2" });
            Generate(op);

            Assert.Equal(@"DROP TYPE public.my_enum;" + EOL, Sql);
        }
        public void CreatePostgresEnum()
        {
            var op = new AlterDatabaseOperation();

            PostgresEnum.GetOrAddPostgresEnum(op, "public", "my_enum", new[] { "value1", "value2" });
            Generate(op);

            Assert.Equal(@"CREATE TYPE public.my_enum AS ENUM ('value1', 'value2');" + EOL, Sql);
        }
Beispiel #9
0
        protected virtual void GenerateDropEnum(
            [NotNull] PostgresEnum enumType,
            [NotNull] IModel model,
            [NotNull] MigrationCommandListBuilder builder)
        {
            var schema = enumType.Schema ?? model.Relational().DefaultSchema;

            builder
            .Append("DROP TYPE ")
            .Append(Dependencies.SqlGenerationHelper.DelimitIdentifier(enumType.Name, schema))
            .AppendLine(";");
        }
        public void CreatePostgresEnumWithSchema()
        {
            var op = new AlterDatabaseOperation();

            PostgresEnum.GetOrAddPostgresEnum(op, "some_schema", "my_enum", new[] { "value1", "value2" });
            Generate(op);

            Assert.Equal(
                @"CREATE SCHEMA IF NOT EXISTS some_schema;" + EOL +
                @"GO" + EOL + EOL +
                @"CREATE TYPE some_schema.my_enum AS ENUM ('value1', 'value2');" + EOL,
                Sql);
        }
Beispiel #11
0
        public override MethodCallCodeFragment GenerateFluentApi(IModel model, IAnnotation annotation)
        {
            Check.NotNull(model, nameof(model));
            Check.NotNull(annotation, nameof(annotation));

            if (annotation.Name.StartsWith(NpgsqlAnnotationNames.PostgresExtensionPrefix, StringComparison.Ordinal))
            {
                var extension = new PostgresExtension(model, annotation.Name);

                return(new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.HasPostgresExtension),
                                                  extension.Name));
            }

            if (annotation.Name.StartsWith(NpgsqlAnnotationNames.EnumPrefix, StringComparison.Ordinal))
            {
                var enumTypeDef = new PostgresEnum(model, annotation.Name);

                return(enumTypeDef.Schema == "public"
                    ? new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasEnum),
                                                 enumTypeDef.Name, enumTypeDef.Labels)
                    : new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasEnum),
                                                 enumTypeDef.Schema, enumTypeDef.Name, enumTypeDef.Labels));
            }

            if (annotation.Name.StartsWith(NpgsqlAnnotationNames.RangePrefix, StringComparison.Ordinal))
            {
                var rangeTypeDef = new PostgresRange(model, annotation.Name);

                if (rangeTypeDef.CanonicalFunction == null &&
                    rangeTypeDef.SubtypeOpClass == null &&
                    rangeTypeDef.Collation == null &&
                    rangeTypeDef.SubtypeDiff == null)
                {
                    return(new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasRange),
                                                      rangeTypeDef.Schema == "public" ? null : rangeTypeDef.Schema,
                                                      rangeTypeDef.Name,
                                                      rangeTypeDef.Subtype));
                }

                return(new MethodCallCodeFragment(nameof(NpgsqlModelBuilderExtensions.ForNpgsqlHasRange),
                                                  rangeTypeDef.Schema == "public" ? null : rangeTypeDef.Schema,
                                                  rangeTypeDef.Name,
                                                  rangeTypeDef.Subtype,
                                                  rangeTypeDef.CanonicalFunction,
                                                  rangeTypeDef.SubtypeOpClass,
                                                  rangeTypeDef.Collation,
                                                  rangeTypeDef.SubtypeDiff));
            }

            return(null);
        }
Beispiel #12
0
        protected override void Generate(
            AlterDatabaseOperation operation,
            IModel model,
            MigrationCommandListBuilder builder)
        {
            Check.NotNull(operation, nameof(operation));
            Check.NotNull(builder, nameof(builder));

            foreach (var extension in PostgresExtension.GetPostgresExtensions(operation))
            {
                GenerateCreateExtension(extension, model, builder);
            }

            foreach (var enumType in PostgresEnum.GetPostgresEnums(operation))
            {
                GenerateCreateEnum(enumType, model, builder);
            }
            // TODO: Some forms of enum alterations are actually supported...
            foreach (var enumType in PostgresEnum.GetPostgresEnums(operation.OldDatabase))
            {
                GenerateDropEnum(enumType, builder);
            }
            builder.EndCommand();
        }
 public static IReadOnlyList <PostgresEnum> GetPostgresEnums(this IReadOnlyModel model)
 => PostgresEnum.GetPostgresEnums(model).ToArray();
 public static PostgresEnum GetOrAddPostgresEnum(
     this IMutableModel model,
     string?schema,
     string name,
     string[] labels)
 => PostgresEnum.GetOrAddPostgresEnum(model, schema, name, labels);
 public static IReadOnlyList <PostgresEnum> GetOldPostgresEnums([NotNull] this AlterDatabaseOperation operation)
 => PostgresEnum.GetPostgresEnums(operation.OldDatabase).ToArray();
Beispiel #16
0
 public static PostgresEnum GetOrAddPostgresEnum(
     [NotNull] this IMutableModel model,
     [CanBeNull] string schema,
     [NotNull] string name,
     [NotNull] string[] labels)
 => PostgresEnum.GetOrAddPostgresEnum(model, schema, name, labels);
 public static IReadOnlyList <PostgresEnum> GetPostgresEnums([NotNull] this DatabaseModel model)
 => PostgresEnum.GetPostgresEnums(model).ToArray();
Beispiel #18
0
 public static IReadOnlyList <PostgresEnum> GetPostgresEnums(this AlterDatabaseOperation operation)
 => PostgresEnum.GetPostgresEnums(operation).ToArray();