Skip to content

Commit

Permalink
Naïve implementation of more operations via rebuild for SQLite. Needs…
Browse files Browse the repository at this point in the history
… validation and better testing. See #329
  • Loading branch information
Nate McMaster committed Jul 8, 2015
1 parent f8216a1 commit 70e2b39
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ namespace Microsoft.Data.Entity.Sqlite.Migrations
{
public class SqliteOperationTransformer
{
// TODO detect current schema and optimize based on existing table structure, not just the target model

private readonly IModelDiffer _differ;
private readonly IDictionary<string, TableRebuildOperation> _tableRebuilds = new Dictionary<string, TableRebuildOperation>();

Expand Down Expand Up @@ -42,7 +44,11 @@ private IList<MigrationOperation> TransformOperation(RenameColumnOperation opera
}

private IList<MigrationOperation> TransformOperation(AlterColumnOperation operation, IModel model)
=> FilterRedudantOperation(operation.Table, operation);
{
// Because of loose typing in SQLite, it may be possible to skip rebuilds for certain types of alters.
GetOrAddRebuild(operation.Table, model);
return null;
}

private IList<MigrationOperation> TransformOperation(AddColumnOperation operation, IModel model)
{
Expand All @@ -61,7 +67,28 @@ private IList<MigrationOperation> TransformOperation(AddColumnOperation operatio
}

private IList<MigrationOperation> TransformOperation(AddPrimaryKeyOperation operation, IModel model)
=> FilterRedudantOperation(operation.Table, operation);
{
GetOrAddRebuild(operation.Table, model);
return null;
}

private IList<MigrationOperation> TransformOperation(DropPrimaryKeyOperation operation, IModel model)
{
GetOrAddRebuild(operation.Table, model);
return null;
}

private IList<MigrationOperation> TransformOperation(AddForeignKeyOperation operation, IModel model)
{
GetOrAddRebuild(operation.Table, model);
return null;
}

private IList<MigrationOperation> TransformOperation(DropForeignKeyOperation operation, IModel model)
{
GetOrAddRebuild(operation.Table, model);
return null;
}

private IList<MigrationOperation> TransformOperation(CreateIndexOperation operation, IModel model)
=> FilterRedudantOperation(operation.Table, operation);
Expand Down Expand Up @@ -92,7 +119,7 @@ private TableRebuildOperation CreateTableRebuild(string tableName, IModel model)
var differences = _differ.GetDifferences(null, model);
var createTableOperation = differences
.OfType<CreateTableOperation>()
.FirstOrDefault(o => o.Name == tableName);
.First(o => o.Name == tableName);

var rebuild = new TableRebuildOperation
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.Data.Entity.Migrations.Builders;
using Microsoft.Data.Entity.Migrations.Infrastructure;
using Microsoft.Data.Entity.Sqlite.Metadata;
using Microsoft.Data.Entity.Sqlite.Migrations.Operations;
Expand All @@ -10,6 +12,72 @@ namespace Microsoft.Data.Entity.Sqlite.Migrations
{
public class SqliteOperationTransformTest : SqliteOperationTransformBase
{
[Fact]
public void AlterColumn_to_TableRebuild()
{
SimpleRebuildTest(migrate => { migrate.AlterColumn("ZipCode", "Address", "TEXT"); });
}

[Fact]
public void AddPrimaryKey_to_TableRebuild()
{
SimpleRebuildTest(migrate => { migrate.AddPrimaryKey("PK_Address", "Address", new []{"Id"}); });
}

[Fact]
public void DropColumn_to_TableRebuild()
{
SimpleRebuildTest(migrate=> migrate.DropColumn("HouseNumber","Address"));
}

[Fact]
public void DropPrimaryKey_to_TableRebuild()
{
SimpleRebuildTest(migrate => { migrate.DropPrimaryKey("PK_Address", "Address"); });
}

[Fact]
public void AddForeignKey_to_TableRebuild()
{
SimpleRebuildTest(migrate => { migrate.AddForeignKey("FK_Contact", "Address", new []{"Contact_Id"}, "Contacts"); });
}

[Fact]
public void DropForeignKey_to_TableRebuild()
{
SimpleRebuildTest(migrate => { migrate.DropForeignKey("FK_Owner", "Address"); });
}

private void SimpleRebuildTest(Action<MigrationBuilder> migration)
{
var t = "Address";
var operations = Transform(migration, model =>
{
model.Entity("Contacts", b =>
{
b.Property<int>("Id");
b.Key("Id");
});
model.Entity(t, b =>
{
b.Property<string>("ZipCode").Required();
b.Property<int>("Contact_Id");
b.Property<int>("Id");
b.Reference("Contacts").InverseCollection().ForeignKey("Contact_Id");
b.Key("Id");
});
});

var steps = Assert.IsType<TableRebuildOperation>(operations[0]);

var columns = new[] { "Id", "Contact_Id", "ZipCode" };
Assert.Collection(steps.Operations,
AssertRenameTemp(t),
AssertCreateTable(t, columns),
AssertMoveData(t, columns, columns),
AssertDropTemp(t));
}

[Fact]
public void RenameColumn_to_TableRebuild()
{
Expand Down Expand Up @@ -65,26 +133,6 @@ public void Rebuild_filters_obviated_operations()
AssertCreateIndex(t, new[] { "Indexed" }, unique: true));
}

[Fact]
public void DropColumn_to_TableRebuild()
{
var operations = Transform(migrate => { migrate.DropColumn("OldCol", "A"); }, model =>
{
model.Entity("A", b =>
{
b.Property<string>("Col");
b.Key("Col");
});
});

var steps = Assert.IsType<TableRebuildOperation>(operations[0]);
Assert.Collection(steps.Operations,
AssertRenameTemp("A"),
AssertCreateTable("A", new[] { "Col" }, new[] { "Col" }),
AssertMoveData("A", new[] { "Col" }, new[] { "Col" }),
AssertDropTemp("A"));
}

protected override SqliteOperationTransformer CreateTransformer()
=> new SqliteOperationTransformer(
new ModelDiffer(
Expand Down

0 comments on commit 70e2b39

Please sign in to comment.