using System; using System.Collections.Generic; using System.Linq; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Scaffolding.Metadata; using Xunit; namespace EntityFrameworkCore.Jet.Design.FunctionalTests { public class JetDatabaseModelFactoryTest : IClassFixture { [Fact] public void It_reads_tables() { var sql = new List { "CREATE TABLE [Everest] ( id int );", "CREATE TABLE [Denali] ( id int );" }; var dbInfo = CreateModel(sql, new List { "Everest", "Denali" }); Assert.Collection(dbInfo.Tables.OrderBy(t => t.Name), d => { Assert.Equal("Jet", d.Schema); Assert.Equal("Denali", d.Name); }, e => { Assert.Equal("Jet", e.Schema); Assert.Equal("Everest", e.Name); }); } [Fact] public void It_reads_foreign_keys() { var sql = new List { "CREATE TABLE Ranges ( Id INT IDENTITY (1,1) PRIMARY KEY);", "CREATE TABLE Mountains ( RangeId INT NOT NULL, FOREIGN KEY (RangeId) REFERENCES Ranges(Id) ON DELETE CASCADE)" }; var dbInfo = CreateModel(sql, new List { "Ranges", "Mountains" }); var fk = Assert.Single(dbInfo.Tables.Single(t => t.ForeignKeys.Count > 0).ForeignKeys); Assert.Equal("Jet", fk.Table.Schema); Assert.Equal("Mountains", fk.Table.Name); Assert.Equal("Jet", fk.PrincipalTable.Schema); Assert.Equal("Ranges", fk.PrincipalTable.Name); Assert.Equal("RangeId", fk.Columns.Single().Name); Assert.Equal("Id", fk.PrincipalColumns.Single().Name); Assert.Equal(ReferentialAction.Cascade, fk.OnDelete); } [Fact] public void It_reads_composite_foreign_keys() { var sql = new List { "CREATE TABLE Ranges1 ( Id INT IDENTITY (1,1), AltId INT, PRIMARY KEY(Id, AltId));", "CREATE TABLE Mountains1 ( RangeId INT NOT NULL, RangeAltId INT NOT NULL, FOREIGN KEY (RangeId, RangeAltId) REFERENCES Ranges1(Id, AltId) ON DELETE NO ACTION)" }; var dbInfo = CreateModel(sql, new List { "Ranges1", "Mountains1" }); var fk = Assert.Single(dbInfo.Tables.Single(t => t.ForeignKeys.Count > 0).ForeignKeys); Assert.Equal("Jet", fk.Table.Schema); Assert.Equal("Mountains1", fk.Table.Name); Assert.Equal("Jet", fk.PrincipalTable.Schema); Assert.Equal("Ranges1", fk.PrincipalTable.Name); Assert.Equal(new[] { "RangeId", "RangeAltId" }, fk.Columns.Select(c => c.Name).ToArray()); Assert.Equal(new[] { "Id", "AltId" }, fk.PrincipalColumns.Select(c => c.Name).ToArray()); Assert.Equal(ReferentialAction.NoAction, fk.OnDelete); } [Fact] public void It_reads_primary_keys() { var sql = new List { "CREATE TABLE Place1 ( Id int, Name int, Location int);", "CREATE UNIQUE INDEX IX_Name ON Place1 (Name);", "CREATE INDEX IX_Location_Name ON Place1 (Location, Name);", "CREATE INDEX IX_Location ON Place1 (Location);", "ALTER TABLE Place1 ADD CONSTRAINT PK_Place1 PRIMARY KEY (Id);" }; var dbModel = CreateModel(sql, new List { "Place1" }); var pkIndex = dbModel.Tables.Single().PrimaryKey; Assert.Equal("Jet", pkIndex.Table.Schema); Assert.Equal("Place1", pkIndex.Table.Name); Assert.StartsWith("PK_Place1", pkIndex.Name); Assert.Equal(new List { "Id" }, pkIndex.Columns.Select(ic => ic.Name).ToList()); } [Fact] public void It_reads_unique_constraints() { var sql = new List { "CREATE TABLE Place2 ( Id int PRIMARY KEY, Name int, Location int );", "CREATE UNIQUE INDEX IX_Name ON Place2 (Name);", "CREATE INDEX IX_Location ON Place2 (Location);" }; var dbModel = CreateModel(sql, new List { "Place2" }); var indexes = dbModel.Tables.Single().UniqueConstraints; Assert.All( indexes, c => { Assert.Equal("Jet", c.Table.Schema); Assert.Equal("Place2", c.Table.Name); }); Assert.Collection( indexes, unique => { Assert.Equal("Name", unique.Columns.Single().Name); }); } [Fact] public void It_reads_indexes() { var sql = new List { "CREATE TABLE Place ( Id int PRIMARY KEY, Name int, Location int );", "CREATE UNIQUE INDEX IX_Name ON Place (Name);", "CREATE INDEX IX_Location ON Place (Location);" }; var dbInfo = CreateModel(sql, new List { "Place" }); var indexes = dbInfo.Tables.Single().Indexes; Assert.All(indexes, c => { Assert.Equal("Jet", c.Table.Schema); Assert.Equal("Place", c.Table.Name); }); Assert.Collection(indexes, nonClustered => { Assert.Equal("IX_Location", nonClustered.Name); Assert.Equal("Location", nonClustered.Columns.Select(c => c.Name).Single()); }); } [Fact] public void It_reads_columns() { var sql = @" CREATE TABLE [MountainsColumns] ( Id int NOT NULL, Name varchar(100) NOT NULL, Latitude decimal( 5, 2 ) DEFAULT 0.0, Created datetime DEFAULT #09/15/1969#, DiscoveredDate datetime, Modified varbinary(8), CONSTRAINT PK_MountainsColumns PRIMARY KEY (Name, Id) );"; var dbModel = CreateModel(new List{ sql }, new List { "MountainsColumns" }); var columns = dbModel.Tables.Single().Columns; Assert.All( columns, c => { Assert.Equal("Jet", c.Table.Schema); Assert.Equal("MountainsColumns", c.Table.Name); }); Assert.Collection( columns, id => { Assert.Equal("Id", id.Name); Assert.Equal("int", id.StoreType); Assert.False(id.IsNullable); Assert.Null(id.DefaultValueSql); }, name => { Assert.Equal("Name", name.Name); Assert.Equal("varchar(100)", name.StoreType); Assert.False(name.IsNullable); Assert.Null(name.DefaultValueSql); }, lat => { Assert.Equal("Latitude", lat.Name); Assert.Equal("decimal(5, 2)", lat.StoreType); Assert.True(lat.IsNullable); Assert.Equal("0.0", lat.DefaultValueSql); }, created => { Assert.Equal("Created", created.Name); Assert.Equal("datetime", created.StoreType); Assert.True(created.IsNullable); Assert.Equal("#09/15/1969#", created.DefaultValueSql); }, discovered => { Assert.Equal("DiscoveredDate", discovered.Name); Assert.Equal("datetime", discovered.StoreType); Assert.True(discovered.IsNullable); Assert.Null(discovered.DefaultValueSql); }, modified => { Assert.Equal("Modified", modified.Name); // This is a rowversion test. Rowversion is not supported by JET //Assert.Equal(ValueGenerated.OnAddOrUpdate, modified.ValueGenerated); Assert.Equal("varbinary(8)", modified.StoreType); }); } [Theory] [InlineData("varchar(55)", 55)] [InlineData("char(14)", 14)] [InlineData("text", null)] public void It_reads_max_length(string type, int? length) { var tables = _fixture.Query("SHOW Tables WHERE Name = 'Strings'"); if (tables.Count() > 0) { _fixture.ExecuteNonQuery("DROP TABLE [Strings];"); } var sql = new List { "CREATE TABLE [Strings] ( CharColumn " + type + ");" }; var db = CreateModel(sql, new List { "Strings" }); Assert.Equal(type, db.Tables.Single().Columns.Single().StoreType); } [Theory] [InlineData(true)] [InlineData(false)] public void It_reads_identity(bool isIdentity) { var tables = _fixture.Query("SHOW Tables WHERE Name = 'Identities'"); if (tables.Count() > 0) { _fixture.ExecuteNonQuery("DROP TABLE [Identities];"); } var sql = new List { "CREATE TABLE [Identities] ( Id INT " + (isIdentity ? "IDENTITY(1,1)" : "") + ")" }; var dbModel = CreateModel(sql, new List { "Identities" }); var column = Assert.Single(dbModel.Tables.Single().Columns); // ReSharper disable once AssignNullToNotNullAttribute Assert.Equal(isIdentity ? ValueGenerated.OnAdd : default(ValueGenerated?), column.ValueGenerated); } [Fact] public void It_filters_tables() { var sql = new List { "CREATE TABLE [K2] ( Id int, A varchar, UNIQUE (A) );", "CREATE TABLE [Kilimanjaro] ( Id int,B varchar, UNIQUE (B ), FOREIGN KEY (B) REFERENCES K2 (A) );" }; var selectionSet = new List { "K2" }; var dbModel = CreateModel(sql, selectionSet); var table = Assert.Single(dbModel.Tables); // ReSharper disable once PossibleNullReferenceException Assert.Equal("K2", table.Name); Assert.Equal(2, table.Columns.Count); Assert.Equal(1, table.UniqueConstraints.Count); Assert.Empty(table.ForeignKeys); } private readonly JetDatabaseModelFixture _fixture; public DatabaseModel CreateModel(List createSql, IEnumerable tables = null) => _fixture.CreateModel(createSql, tables); public JetDatabaseModelFactoryTest(JetDatabaseModelFixture fixture) { _fixture = fixture; } } }