public async Task CreateRowDefaultTest() { // Setup: // ... We will have 3 columns DbColumnWrapper[] cols = { new DbColumnWrapper(new TestDbColumn("col1")), // No default new DbColumnWrapper(new TestDbColumn("col2")), // Has default (defined below) new DbColumnWrapper(new TestDbColumn("filler")) // Filler column so we can use the common code }; // ... Metadata provider will return 3 columns EditColumnMetadata[] metas = { new EditColumnMetadata // No default { DefaultValue = null, EscapedName = cols[0].ColumnName }, new EditColumnMetadata // Has default { DefaultValue = "default", EscapedName = cols[1].ColumnName }, new EditColumnMetadata { EscapedName = cols[2].ColumnName } }; var etm = new EditTableMetadata { Columns = metas, EscapedMultipartName = "tbl", IsMemoryOptimized = false }; etm.Extend(cols); // ... Create a result set var q = await Common.GetQuery(cols.Cast <DbColumn>().ToArray(), false); // ... Create a session from all this EditSession s = await Common.GetCustomSession(q, etm); // If: I add a row to the session, on a table that has defaults var result = s.CreateRow(); // Then: // ... Result should not be null, new row ID should be > 0 Assert.NotNull(result); Assert.True(result.NewRowId > 0); // ... There should be 3 default values (3 columns) Assert.NotEmpty(result.DefaultValues); Assert.Equal(3, result.DefaultValues.Length); // ... There should be specific values for each kind of default Assert.Null(result.DefaultValues[0]); Assert.Equal("default", result.DefaultValues[1]); }
public static EditTableMetadata GetCustomEditTableMetadata(DbColumn[] columns) { // Create column metadata providers and column wrappers var columnMetas = new List <EditColumnMetadata>(); var columnWrappers = new List <DbColumnWrapper>(); for (int i = 0; i < columns.Length; i++) { columnMetas.Add(new EditColumnMetadata { EscapedName = columns[i].ColumnName, Ordinal = i }); columnWrappers.Add(new DbColumnWrapper(columns[i])); } // Create the table metadata EditTableMetadata editTableMetadata = new EditTableMetadata { Columns = columnMetas.ToArray(), EscapedMultipartName = TableName, IsMemoryOptimized = false }; editTableMetadata.Extend(columnWrappers.ToArray()); return(editTableMetadata); }
public async Task GetScript(bool includeIdentity) { // Setup: Generate the parameters for the row create const long rowId = 100; DbColumn[] columns = Common.GetColumns(includeIdentity); ResultSet rs = await Common.GetResultSet(columns, includeIdentity); EditTableMetadata etm = Common.GetStandardMetadata(columns); // If: I ask for a script to be generated without an identity column RowCreate rc = new RowCreate(rowId, rs, etm); Common.AddCells(rc, includeIdentity); string script = rc.GetScript(); // Then: // ... The script should not be null, Assert.NotNull(script); // ... It should be formatted as an insert script Regex r = new Regex(@"INSERT INTO (.+)\((.*)\) VALUES \((.*)\)"); var m = r.Match(script); Assert.True(m.Success); // ... It should have 3 columns and 3 values (regardless of the presence of an identity col) string tbl = m.Groups[1].Value; string cols = m.Groups[2].Value; string vals = m.Groups[3].Value; Assert.Equal(etm.EscapedMultipartName, tbl); Assert.Equal(3, cols.Split(',').Length); Assert.Equal(3, vals.Split(',').Length); }
public static EditTableMetadata GetStandardMetadata(DbColumn[] columns, bool isMemoryOptimized = false) { // Create column metadata providers var columnMetas = columns.Select((c, i) => { var ecm = new EditColumnMetadata { EscapedName = c.ColumnName, Ordinal = i }; return(ecm); }).ToArray(); // Create column wrappers var columnWrappers = columns.Select(c => new DbColumnWrapper(c)).ToArray(); // Create the table metadata EditTableMetadata editTableMetadata = new EditTableMetadata { Columns = columnMetas, EscapedMultipartName = "tbl", IsMemoryOptimized = isMemoryOptimized }; editTableMetadata.Extend(columnWrappers); return(editTableMetadata); }
public async Task CreateRowSuccess() { // Setup: Create a session with a proper query and metadata Query q = QueryExecution.Common.GetBasicExecutedQuery(); ResultSet rs = q.Batches[0].ResultSets[0]; EditTableMetadata etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast <DbColumn>().ToArray()); EditSession s = await Common.GetCustomSession(q, etm); // If: I add a row to the session EditCreateRowResult result = s.CreateRow(); // Then: // ... The new ID should be equal to the row count Assert.Equal(rs.RowCount, result.NewRowId); // ... The next row ID should have been incremented Assert.Equal(rs.RowCount + 1, s.NextRowId); // ... There should be a new row create object in the cache Assert.Contains(result.NewRowId, s.EditCache.Keys); Assert.IsType <RowCreate>(s.EditCache[result.NewRowId]); // ... The default values should be returned (we will test this in depth below) Assert.NotEmpty(result.DefaultValues); }
public async Task CreateRowAddFailure() { // NOTE: This scenario should theoretically never occur, but is tested for completeness // Setup: // ... Create a session with a proper query and metadata Query q = QueryExecution.Common.GetBasicExecutedQuery(); ResultSet rs = q.Batches[0].ResultSets[0]; EditTableMetadata etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast <DbColumn>().ToArray()); EditSession s = await Common.GetCustomSession(q, etm); // ... Add a mock edit to the edit cache to cause the .TryAdd to fail var mockEdit = new Mock <RowEditBase>().Object; s.EditCache[rs.RowCount] = mockEdit; // If: I create a row in the session // Then: // ... An exception should be thrown Assert.Throws <InvalidOperationException>(() => s.CreateRow()); // ... The mock edit should still exist Assert.Equal(mockEdit, s.EditCache[rs.RowCount]); // ... The next row ID should not have changes Assert.Equal(rs.RowCount, s.NextRowId); }
public static async Task <EditSession> GetCustomSession(Query q, EditTableMetadata etm) { // Step 1) Create the Session object // Mock metadata factory Mock <IEditMetadataFactory> metaFactory = new Mock <IEditMetadataFactory>(); metaFactory .Setup(f => f.GetObjectMetadata(It.IsAny <DbConnection>(), It.IsAny <string[]>(), It.IsAny <string>())) .Returns(etm); EditSession session = new EditSession(metaFactory.Object); // Step 2) Initialize the Session // Mock connector that does nothing EditSession.Connector connector = () => Task.FromResult <DbConnection>(null); // Mock query runner that returns the query we were provided EditSession.QueryRunner queryRunner = (s) => Task.FromResult(new EditSession.EditSessionQueryExecutionState(q)); // Initialize session.Initialize(BasicInitializeParameters, connector, queryRunner, () => Task.FromResult(0), (e) => Task.FromResult(0)); await session.InitializeTask; return(session); }
public async Task SetCellImplicitRowRevertTests() { // Setup: Create a fake column to update DbColumn[] columns = Common.GetColumns(true); ResultSet rs = await Common.GetResultSet(columns, true); EditTableMetadata etm = Common.GetStandardMetadata(columns); // If: // ... I add updates to one cell in the row RowUpdate ru = new RowUpdate(0, rs, etm); ru.SetCell(1, "qqq"); // ... Then I update the cell to its original value var eucr = ru.SetCell(1, (string)rs.GetRow(0)[1].RawObject); // Then: // ... An edit cell should have been returned Assert.NotNull(eucr); Assert.NotNull(eucr.Cell); // ... The old value should be returned Assert.Equal(rs.GetRow(0)[1].DisplayValue, eucr.Cell.DisplayValue); Assert.False(eucr.Cell.IsNull); // ... The cell should be clean Assert.False(eucr.Cell.IsDirty); // ... The row should be clean Assert.False(eucr.IsRowDirty); // TODO: Make sure that the script and command things will return null }
private static async Task <EditSession> GetBasicSession() { Query q = QueryExecution.Common.GetBasicExecutedQuery(); ResultSet rs = q.Batches[0].ResultSets[0]; EditTableMetadata etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast <DbColumn>().ToArray()); return(await Common.GetCustomSession(q, etm)); }
public void EmptyDataTest() { EditColumnMetadata[] metas = new EditColumnMetadata[0]; DbColumnWrapper[] cols = new DbColumnWrapper[0]; EditColumnMetadata[] filteredData = EditTableMetadata.FilterColumnMetadata(metas, cols); ValidateFilteredData(filteredData, cols); }
public void LessResultColumnsTest() { EditColumnMetadata[] metas = CreateMetadataColumns(new string[] { "[col1]", "[col2]", "[col3]", "[fillerCol1]", "[fillerCol2]" }); DbColumnWrapper[] cols = CreateColumnWrappers(new string[] { metas[0].EscapedName, metas[1].EscapedName, metas[2].EscapedName }); EditColumnMetadata[] filteredData = EditTableMetadata.FilterColumnMetadata(metas, cols); ValidateFilteredData(filteredData, cols); }
public void ConstructWithoutExtendedMetadata() { // Setup: Create a table metadata that has not been extended EditTableMetadata etm = new EditTableMetadata(); // If: I construct a new EditRowBase implementation without an extended metadata // Then: I should get an exception Assert.Throws <ArgumentException>(() => new RowEditTester(null, etm)); }
/// <summary> /// Creates a new Row Creation edit to the result set /// </summary> /// <param name="rowId">Internal ID of the row that is being created</param> /// <param name="associatedResultSet">The result set for the rows in the table we're editing</param> /// <param name="associatedMetadata">The metadata for table we're editing</param> public RowCreate(long rowId, ResultSet associatedResultSet, EditTableMetadata associatedMetadata) : base(rowId, associatedResultSet, associatedMetadata) { newCells = new CellUpdate[associatedResultSet.Columns.Length]; // Process the default cell values. If the column is calculated, then the value is a placeholder DefaultValues = associatedMetadata.Columns.Select((col, index) => col.IsCalculated.HasTrue() ? SR.EditDataComputedColumnPlaceholder : col.DefaultValue).ToArray(); }
private static async Task <EditSession> GetDefaultSession() { // ... Create a session with a proper query and metadata Query q = QueryExecution.Common.GetBasicExecutedQuery(); ResultSet rs = q.Batches[0].ResultSets[0]; EditTableMetadata etm = Common.GetStandardMetadata(rs.Columns); EditSession s = await Common.GetCustomSession(q, etm); return(s); }
/// <summary> /// Base constructor for a row edit. Stores the state that should be available to all row /// edit implementations. /// </summary> /// <param name="rowId">The internal ID of the row that is being edited</param> /// <param name="associatedResultSet">The result set that will be updated</param> /// <param name="associatedMetadata">Metadata provider for the object to edit</param> protected RowEditBase(long rowId, ResultSet associatedResultSet, EditTableMetadata associatedMetadata) { if (!associatedMetadata.HasExtendedProperties) { throw new ArgumentException(SR.EditDataMetadataNotExtended); } RowId = rowId; AssociatedResultSet = associatedResultSet; AssociatedObjectMetadata = associatedMetadata; }
public async Task GetWhereClauseNoKeyColumns() { // Setup: Create a result set and metadata provider with no key columns DbColumn[] cols = { new TestDbColumn("col1"), new TestDbColumn("col2") }; ResultSet rs = await GetResultSet(cols, new object[] { "abc", "def" }); EditTableMetadata etm = Common.GetStandardMetadata(new DbColumn[] {}); RowEditTester rt = new RowEditTester(rs, etm); rt.ValidateWhereClauseNoKeys(); }
public async Task GetWhereClauseSimple(DbColumn col, object val, string nullClause) { // Setup: Create a result set and metadata provider with a single column var cols = new[] { col }; ResultSet rs = await GetResultSet(cols, new[] { val }); EditTableMetadata etm = Common.GetStandardMetadata(cols); RowEditTester rt = new RowEditTester(rs, etm); rt.ValidateWhereClauseSingleKey(nullClause); }
public void RowUpdateConstruction() { // Setup: Create the values to store const long rowId = 0; ResultSet rs = QueryExecution.Common.GetBasicExecutedBatch().ResultSets[0]; EditTableMetadata etm = Common.GetStandardMetadata(rs.Columns); // If: I create a RowUpdate instance RowUpdate rc = new RowUpdate(rowId, rs, etm); // Then: The values I provided should be available Assert.Equal(rowId, rc.RowId); Assert.Equal(rs, rc.AssociatedResultSet); Assert.Equal(etm, rc.AssociatedObjectMetadata); }
public async Task RowDeleteConstruction() { // Setup: Create the values to store DbColumn[] columns = Common.GetColumns(true); ResultSet rs = await Common.GetResultSet(columns, true); EditTableMetadata etm = Common.GetStandardMetadata(rs.Columns); // If: I create a RowCreate instance RowDelete rc = new RowDelete(100, rs, etm); // Then: The values I provided should be available Assert.Equal(100, rc.RowId); Assert.Equal(rs, rc.AssociatedResultSet); Assert.Equal(etm, rc.AssociatedObjectMetadata); }
public async Task SetCellImplicitRevertTest() { // Setup: Create a fake table to update DbColumn[] columns = Common.GetColumns(true); ResultSet rs = await Common.GetResultSet(columns, true); EditTableMetadata etm = Common.GetStandardMetadata(columns); // If: // ... I add updates to all the cells in the row RowUpdate ru = new RowUpdate(0, rs, etm); Common.AddCells(ru, true); // ... Then I update a cell back to it's old value var eucr = ru.SetCell(1, (string)rs.GetRow(0)[1].RawObject); // Then: // ... A edit cell was returned Assert.NotNull(eucr); Assert.NotNull(eucr.Cell); // ... The new value we provided should be returned Assert.Equal(rs.GetRow(0)[1].DisplayValue, eucr.Cell.DisplayValue); Assert.False(eucr.Cell.IsNull); // ... The cell should be clean Assert.False(eucr.Cell.IsDirty); // ... The row is still dirty Assert.True(eucr.IsRowDirty); // ... It should be formatted as an update script Regex r = new Regex(@"UPDATE .+ SET (.*) WHERE"); var m = r.Match(ru.GetScript()); // ... It should have 2 updates string updates = m.Groups[1].Value; string[] updateSplit = updates.Split(','); Assert.Equal(2, updateSplit.Length); Assert.All(updateSplit, s => Assert.Equal(2, s.Split('=').Length)); }
public async Task ApplyChanges(bool includeIdentity) { // Setup: // ... Generate the parameters for the row create const long rowId = 100; DbColumn[] columns = Common.GetColumns(includeIdentity); ResultSet rs = await Common.GetResultSet(columns, includeIdentity); EditTableMetadata etm = Common.GetStandardMetadata(columns); // ... Setup a db reader for the result of an insert var newRowReader = Common.GetNewRowDataReader(columns, includeIdentity); // If: I ask for the change to be applied RowCreate rc = new RowCreate(rowId, rs, etm); await rc.ApplyChanges(newRowReader); // Then: The result set should have an additional row in it Assert.Equal(2, rs.RowCount); }
public async Task GetRowsNoEdits() { // Setup: Create a session with a proper query and metadata Query q = QueryExecution.Common.GetBasicExecutedQuery(); ResultSet rs = q.Batches[0].ResultSets[0]; EditTableMetadata etm = Common.GetCustomEditTableMetadata(rs.Columns.Cast <DbColumn>().ToArray()); EditSession s = await Common.GetCustomSession(q, etm); // If: I ask for 3 rows from session skipping the first EditRow[] rows = await s.GetRows(1, 3); // Then: // ... I should get back 3 rows Assert.Equal(3, rows.Length); // ... Each row should... for (int i = 0; i < rows.Length; i++) { EditRow er = rows[i]; // ... Have properly set IDs Assert.Equal(i + 1, er.Id); // ... Have cells equal to the cells in the result set DbCellValue[] cachedRow = rs.GetRow(i + 1).ToArray(); Assert.Equal(cachedRow.Length, er.Cells.Length); for (int j = 0; j < cachedRow.Length; j++) { Assert.Equal(cachedRow[j].DisplayValue, er.Cells[j].DisplayValue); Assert.Equal(cachedRow[j].IsNull, er.Cells[j].IsNull); Assert.False(er.Cells[j].IsDirty); } // ... Be clean, since we didn't apply any updates Assert.Equal(EditRow.EditRowState.Clean, er.State); Assert.False(er.IsDirty); } }
public async Task GetScriptTest(bool isMemoryOptimized) { // Setup: Create a fake table to update DbColumn[] columns = Common.GetColumns(true); ResultSet rs = await Common.GetResultSet(columns, true); EditTableMetadata etm = Common.GetStandardMetadata(columns, isMemoryOptimized); // If: I ask for a script to be generated for update RowUpdate ru = new RowUpdate(0, rs, etm); Common.AddCells(ru, true); string script = ru.GetScript(); // Then: // ... The script should not be null Assert.NotNull(script); // ... It should be formatted as an update script string regexString = isMemoryOptimized ? @"UPDATE (.+) WITH \(SNAPSHOT\) SET (.*) WHERE .+" : @"UPDATE (.+) SET (.*) WHERE .+"; Regex r = new Regex(regexString); var m = r.Match(script); Assert.True(m.Success); // ... It should have 3 updates string tbl = m.Groups[1].Value; string updates = m.Groups[2].Value; string[] updateSplit = updates.Split(','); Assert.Equal(etm.EscapedMultipartName, tbl); Assert.Equal(3, updateSplit.Length); Assert.All(updateSplit, s => Assert.Equal(2, s.Split('=').Length)); }
public async Task GetScriptTest(bool isMemoryOptimized) { DbColumn[] columns = Common.GetColumns(true); ResultSet rs = await Common.GetResultSet(columns, true); EditTableMetadata etm = Common.GetStandardMetadata(columns, isMemoryOptimized); // If: I ask for a script to be generated for delete RowDelete rd = new RowDelete(0, rs, etm); string script = rd.GetScript(); // Then: // ... The script should not be null Assert.NotNull(script); // ... It should be formatted as a delete script string scriptStart = $"DELETE FROM {etm.EscapedMultipartName}"; if (isMemoryOptimized) { scriptStart += " WITH(SNAPSHOT)"; } Assert.StartsWith(scriptStart, script); }
public TestDbColumnsWithTableMetadata(bool isMemoryOptimized, bool identityCol, int defaultCols, int nullableCols) { List <DbColumn> dbColumns = new List <DbColumn>(); List <DbColumnWrapper> columnWrappers = new List <DbColumnWrapper>(); List <EditColumnMetadata> columnMetadatas = new List <EditColumnMetadata>(); int startingOrdinal = 0; // Add the identity column at the front of the table if (identityCol) { const string colName = "id"; DbColumn dbColumn = new TestDbColumn(colName) { IsKey = true, IsIdentity = true, IsAutoIncrement = true }; EditColumnMetadata columnMetadata = new EditColumnMetadata { EscapedName = colName, Ordinal = startingOrdinal, DefaultValue = null }; dbColumns.Add(dbColumn); columnWrappers.Add(new DbColumnWrapper(dbColumn)); columnMetadatas.Add(columnMetadata); startingOrdinal++; } // Add each column to the table for (int i = startingOrdinal; i < 3 + startingOrdinal; i++) { string colName = $"col{i}"; DbColumn dbColumn; EditColumnMetadata columnMetadata; if (i < defaultCols + startingOrdinal) { // This column will have a default value dbColumn = new TestDbColumn(colName) { AllowDBNull = false }; columnMetadata = new EditColumnMetadata { EscapedName = colName, Ordinal = i, DefaultValue = DefaultValue }; } else if (i < nullableCols + defaultCols + startingOrdinal) { // This column will be nullable dbColumn = new TestDbColumn(colName) { AllowDBNull = true }; columnMetadata = new EditColumnMetadata { EscapedName = colName, Ordinal = i, DefaultValue = null }; } else { // This column doesn't have a default value or is nullable dbColumn = new TestDbColumn(colName) { AllowDBNull = false }; columnMetadata = new EditColumnMetadata { EscapedName = colName, Ordinal = i, DefaultValue = null }; } dbColumns.Add(dbColumn); columnWrappers.Add(new DbColumnWrapper(dbColumn)); columnMetadatas.Add(columnMetadata); } // Put together the table metadata EditTableMetadata editTableMetadata = new EditTableMetadata { Columns = columnMetadatas.ToArray(), EscapedMultipartName = TableName, IsMemoryOptimized = isMemoryOptimized }; editTableMetadata.Extend(columnWrappers.ToArray()); DbColumns = dbColumns.ToArray(); TableMetadata = editTableMetadata; }
/// <summary> /// Creates a new Row Creation edit to the result set /// </summary> /// <param name="rowId">Internal ID of the row that is being created</param> /// <param name="associatedResultSet">The result set for the rows in the table we're editing</param> /// <param name="associatedMetadata">The metadata for table we're editing</param> public RowCreate(long rowId, ResultSet associatedResultSet, EditTableMetadata associatedMetadata) : base(rowId, associatedResultSet, associatedMetadata) { newCells = new CellUpdate[associatedResultSet.Columns.Length]; }
/// <summary> /// Constructs a new RowDelete object /// </summary> /// <param name="rowId">Internal ID of the row to be deleted</param> /// <param name="associatedResultSet">Result set that is being edited</param> /// <param name="associatedMetadata">Improved metadata of the object being edited</param> public RowDelete(long rowId, ResultSet associatedResultSet, EditTableMetadata associatedMetadata) : base(rowId, associatedResultSet, associatedMetadata) { }
/// <summary> /// Constructs a new RowUpdate to be added to the cache. /// </summary> /// <param name="rowId">Internal ID of the row that will be updated with this object</param> /// <param name="associatedResultSet">Result set for the rows of the object to update</param> /// <param name="associatedMetadata">Metadata provider for the object to update</param> public RowUpdate(long rowId, ResultSet associatedResultSet, EditTableMetadata associatedMetadata) : base(rowId, associatedResultSet, associatedMetadata) { cellUpdates = new ConcurrentDictionary <int, CellUpdate>(); associatedRow = associatedResultSet.GetRow(rowId); }
public RowEditTester(ResultSet rs, EditTableMetadata meta) : base(0, rs, meta) { }