public static DwhTableBuilder[] AutoValidityRange(this DwhTableBuilder[] builders, Action <AutoValidityRangeBuilder> customizer) { foreach (var tableBuilder in builders) { var tempBuilder = new AutoValidityRangeBuilder(tableBuilder); customizer.Invoke(tempBuilder); if (tempBuilder.MatchColumns == null) { throw new NotSupportedException("you must specify the key columns of " + nameof(AutoValidityRange) + " for table " + tableBuilder.ResilientTable.TableName); } tableBuilder.AddMutatorCreator(_ => CreateAutoValidityRangeMutators(tempBuilder)); } return(builders); }
private static IEnumerable <IMutator> CreateAutoValidityRangeMutators(AutoValidityRangeBuilder builder) { var finalValueColumns = builder.CompareValueColumns .Where(x => !builder.MatchColumns.Contains(x) && !x.IsPrimaryKey && !builder.PreviousValueColumnNameMap.ContainsValue(x)) .ToArray(); var equalityComparer = new ColumnBasedRowEqualityComparer() { Columns = finalValueColumns.Select(x => x.Name).ToArray(), }; if (builder.MatchColumns.Length == 1) { yield return(new BatchedCompareWithRowMutator(builder.TableBuilder.ResilientTable.Scope.Context) { Name = nameof(AutoValidityRange), RowFilter = row => row.HasValue(builder.MatchColumns[0].Name), LookupBuilder = new FilteredRowLookupBuilder() { ProcessCreator = filterRows => CreateAutoValidity_ExpandDeferredReaderProcess(builder, builder.MatchColumns[0], finalValueColumns, filterRows), KeyGenerator = row => row.GenerateKey(builder.MatchColumns[0].Name), }, RowKeyGenerator = row => row.GenerateKey(builder.MatchColumns[0].Name), EqualityComparer = equalityComparer, NoMatchAction = new NoMatchAction(MatchMode.Custom) { CustomAction = row => { // this is the first version row[builder.TableBuilder.ValidFromColumn.Name] = builder.TableBuilder.DwhBuilder.DefaultValidFromDateTime; row[builder.TableBuilder.ValidToColumnName] = builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime; } }, MatchButDifferentAction = new MatchAction(MatchMode.Custom) { CustomAction = (row, match) => { foreach (var kvp in builder.PreviousValueColumnNameMap) { var previousValue = match[kvp.Key.Name]; row[kvp.Value.Name] = previousValue; } row[builder.TableBuilder.ValidFromColumn.Name] = builder.TableBuilder.DwhBuilder.EtlRunIdAsDateTimeOffset.Value; row[builder.TableBuilder.ValidToColumnName] = builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime; }, }, MatchAndEqualsAction = new MatchAction(MatchMode.Remove) }); } else { var parameters = new Dictionary <string, object>(); if (builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime != null) { parameters.Add("InfiniteFuture", builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime); } yield return(new CompareWithRowMutator(builder.TableBuilder.ResilientTable.Scope.Context) { Name = nameof(AutoValidityRange), LookupBuilder = new RowLookupBuilder() { Process = new CustomSqlAdoNetDbReader(builder.TableBuilder.ResilientTable.Scope.Context) { Name = "PreviousValueReader", ConnectionString = builder.TableBuilder.DwhBuilder.ConnectionString, MainTableName = builder.TableBuilder.Table.SchemaAndName, Sql = "SELECT " + string.Join(",", builder.MatchColumns.Concat(finalValueColumns).Select(x => x.NameEscaped(builder.TableBuilder.DwhBuilder.ConnectionString))) + " FROM " + builder.TableBuilder.Table.EscapedName(builder.TableBuilder.DwhBuilder.ConnectionString) + " WHERE " + builder.TableBuilder.ValidToColumnNameEscaped + (builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime == null ? " IS NULL" : "=@InfiniteFuture"), Parameters = parameters, }, KeyGenerator = row => row.GenerateKey(builder.MatchColumnNames), }, RowKeyGenerator = row => row.GenerateKey(builder.MatchColumnNames), EqualityComparer = equalityComparer, NoMatchAction = new NoMatchAction(MatchMode.Custom) { CustomAction = row => { // this is the first version row[builder.TableBuilder.ValidFromColumn.Name] = builder.TableBuilder.DwhBuilder.DefaultValidFromDateTime; row[builder.TableBuilder.ValidToColumnName] = builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime; } }, MatchButDifferentAction = new MatchAction(MatchMode.Custom) { CustomAction = (row, match) => { foreach (var kvp in builder.PreviousValueColumnNameMap) { var previousValue = match[kvp.Key.Name]; row[kvp.Value.Name] = previousValue; } row[builder.TableBuilder.ValidFromColumn.Name] = builder.TableBuilder.DwhBuilder.EtlRunIdAsDateTimeOffset.Value; row[builder.TableBuilder.ValidToColumnName] = builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime; }, }, MatchAndEqualsAction = new MatchAction(MatchMode.Remove) }); } }
private static CustomSqlAdoNetDbReader CreateAutoValidity_ExpandDeferredReaderProcess(AutoValidityRangeBuilder builder, RelationalColumn matchColumn, RelationalColumn[] valueColumns, IReadOnlySlimRow[] rows) { var parameters = new Dictionary <string, object> { ["keyList"] = rows .Select(row => row.FormatToString(matchColumn.Name)) .Distinct() .ToArray(), }; if (builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime != null) { parameters.Add("InfiniteFuture", builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime); } return(new CustomSqlAdoNetDbReader(builder.TableBuilder.ResilientTable.Scope.Context) { Name = "PreviousValueReader", ConnectionString = builder.TableBuilder.DwhBuilder.ConnectionString, MainTableName = builder.TableBuilder.Table.SchemaAndName, Sql = "SELECT " + matchColumn.NameEscaped(builder.TableBuilder.DwhBuilder.ConnectionString) + "," + string.Join(", ", valueColumns.Select(c => c.NameEscaped(builder.TableBuilder.DwhBuilder.ConnectionString))) + " FROM " + builder.TableBuilder.Table.EscapedName(builder.TableBuilder.DwhBuilder.ConnectionString) + " WHERE " + matchColumn.NameEscaped(builder.TableBuilder.DwhBuilder.ConnectionString) + " IN (@keyList)" + " and " + builder.TableBuilder.ValidToColumnNameEscaped + (builder.TableBuilder.DwhBuilder.Configuration.InfiniteFutureDateTime == null ? " IS NULL" : "=@InfiniteFuture"), InlineArrayParameters = true, Parameters = parameters, }); }