예제 #1
0
        private static async Task <string> ReadAsJsonString(IScenarioContext context, TableItAllColumnTypes table)
        {
            using var ms = new MemoryStream();

            using Utf8JsonWriter writer = new Utf8JsonWriter(ms);

            writer.WriteStartObject();
            writer.WriteStartArray(table.FullName.AsExprTableFullName().TableName.Name);

            await SqQueryBuilder
            .Select(table.Columns)
            .From(table)
            .Query(context.Database,
                   r =>
            {
                writer.WriteStartArray();
                foreach (var column in table.Columns)
                {
                    var readAsString = column.ReadAsString(r);
                    writer.WriteStringValue(readAsString);
                }
                writer.WriteEndArray();
            });

            writer.WriteEndArray();
            writer.WriteEndObject();
            writer.Flush();

            var jsonString = Encoding.UTF8.GetString(ms.ToArray());

            return(jsonString);
        }
예제 #2
0
        private static IExprExec?WhenNotMatchedByTarget(ExprMerge merge, TempTableBase tempTable, ExtractKeysResult keys)
        {
            IExprExec?e = null;

            if (merge.WhenNotMatchedByTarget != null)
            {
                if (merge.WhenNotMatchedByTarget is ExprExprMergeNotMatchedInsert insert)
                {
                    var filter = !SqQueryBuilder.Exists(SqQueryBuilder
                                                        .SelectOne()
                                                        .From(merge.TargetTable)
                                                        .Where(merge.On));

                    if (insert.And != null)
                    {
                        filter = filter & insert.And;
                    }

                    e = SqQueryBuilder.InsertInto(merge.TargetTable, insert.Columns)
                        .From(SqQueryBuilder.Select(insert.Values.SelectToReadOnlyList(i =>
                                                                                       i is ExprValue v
                                    ? v
                                    : throw new SqExpressException("DEFAULT value cannot be used in MERGE polyfill")))
                              .From(tempTable)
                              .Where(filter));
                }
                else if (merge.WhenNotMatchedByTarget is ExprExprMergeNotMatchedInsertDefault insertDefault)
                {
                    var filter = !SqQueryBuilder.Exists(SqQueryBuilder
                                                        .SelectOne()
                                                        .From(merge.TargetTable)
                                                        .Where(merge.On));

                    if (insertDefault.And != null)
                    {
                        filter = filter & insertDefault.And;
                    }

                    e = SqQueryBuilder.InsertInto(merge.TargetTable, keys.TargetKeys)
                        .From(SqQueryBuilder.Select(keys.SourceKeys)
                              .From(tempTable)
                              .Where(filter));
                }
                else
                {
                    throw new SqExpressException($"Unknown type: '{merge.WhenNotMatchedByTarget.GetType().Name}'");
                }
            }
            return(e);
        }
예제 #3
0
        public ExprInsert Done()
        {
            var checkExistence = this._checkExistenceByColumns != null && this._checkExistenceByColumns.Count > 0;

            var useDerivedTable = this._targetInsertSelectMapping != null || checkExistence;

            var mapping = this._dataMapping.AssertFatalNotNull(nameof(this._dataMapping));

            int?capacity = this._data.TryToCheckLength(out var c) ? c : (int?)null;

            if (capacity != null && capacity.Value < 1)
            {
                throw new SqExpressException("Input data should not be empty");
            }


            List <ExprValueRow>?      recordsS = null;
            List <ExprInsertValueRow>?recordsI = null;

            if (useDerivedTable)
            {
                recordsS = capacity.HasValue ? new List <ExprValueRow>(capacity.Value) : new List <ExprValueRow>();
            }
            else
            {
                recordsI = capacity.HasValue ? new List <ExprInsertValueRow>(capacity.Value) : new List <ExprInsertValueRow>();
            }

            DataMapSetter <TTable, TItem>? dataMapSetter = null;
            IReadOnlyList <ExprColumnName>?columns       = null;

            foreach (var item in this._data)
            {
                dataMapSetter ??= new DataMapSetter <TTable, TItem>(this._target, item);

                dataMapSetter.NextItem(item, columns?.Count);
                mapping(dataMapSetter);

                columns ??= dataMapSetter.Columns;

                dataMapSetter.EnsureRecordLength();

                recordsS?.Add(new ExprValueRow(dataMapSetter.Record.AssertFatalNotNull(nameof(dataMapSetter.Record))));
                recordsI?.Add(new ExprInsertValueRow(dataMapSetter.Record.AssertFatalNotNull(nameof(dataMapSetter.Record))));
            }

            if ((recordsS?.Count ?? 0 + recordsI?.Count ?? 0) < 1 || columns == null)
            {
                //In case of empty IEnumerable
                throw new SqExpressException("Input data should not be empty");
            }

            IExprInsertSource insertSource;

            if (recordsI != null)
            {
                insertSource = new ExprInsertValues(recordsI);
            }
            else if (recordsS != null && useDerivedTable)
            {
                var valuesConstructor = new ExprTableValueConstructor(recordsS);
                var values            = new ExprDerivedTableValues(
                    valuesConstructor,
                    new ExprTableAlias(Alias.Auto.BuildAliasExpression().AssertNotNull("Alias cannot be null")),
                    columns);

                IReadOnlyList <ColumnValueInsertSelectMap>?additionalMaps = null;
                if (this._targetInsertSelectMapping != null)
                {
                    var targetUpdateSetter = new TargetInsertSelectSetter <TTable>(this._target);

                    this._targetInsertSelectMapping.Invoke(targetUpdateSetter);

                    additionalMaps = targetUpdateSetter.Maps;
                    if (additionalMaps.Count < 1)
                    {
                        throw new SqExpressException("Additional insertion cannot be null");
                    }
                }

                var selectValues = new List <IExprSelecting>(columns.Count + (additionalMaps?.Count ?? 0));

                foreach (var exprColumnName in values.Columns)
                {
                    selectValues.Add(exprColumnName);
                }

                if (additionalMaps != null)
                {
                    foreach (var m in additionalMaps)
                    {
                        selectValues.Add(m.Value);
                    }
                }

                IExprQuery query;
                var        queryBuilder = SqQueryBuilder.Select(selectValues).From(values);

                if (checkExistence && this._checkExistenceByColumns != null)
                {
                    var tbl = this._target.WithAlias(new ExprTableAlias(Alias.Auto.BuildAliasExpression() !));

                    var existsFilter = !SqQueryBuilder.Exists(SqQueryBuilder
                                                              .SelectOne()
                                                              .From(tbl)
                                                              .Where(this._checkExistenceByColumns
                                                                     .Select(column => column.WithSource(tbl.Alias) == column.WithSource(values.Alias))
                                                                     .JoinAsAnd()));

                    query = queryBuilder.Where(existsFilter).Done();
                }
                else
                {
                    query = queryBuilder.Done();
                }

                insertSource = new ExprInsertQuery(query);

                if (additionalMaps != null)
                {
                    var extraInsertCols = additionalMaps.SelectToReadOnlyList(m => m.Column);
                    columns = Helpers.Combine(columns, extraInsertCols);
                }
            }
            else
            {
                //Actually C# should have detected that this brunch cannot be invoked
                throw new SqExpressException("Fatal logic error!");
            }

            return(new ExprInsert(this._target.FullName, columns, insertSource));
        }
예제 #4
0
        public async Task Exec(IScenarioContext context)
        {
            var tUser = AllTables.GetItUser();

            var users = await SqQueryBuilder.Select(UserName.GetColumns(tUser))
                        .From(tUser)
                        .OrderBy(tUser.FirstName)
                        .OffsetFetch(0, 10)
                        .QueryList(context.Database, r => UserName.Read(r, tUser));

            var modifiedUsers = users.Select(u => u.WithFirstName(u.FirstName + "Modified")).ToList();

            await SqQueryBuilder.UpdateData(tUser, modifiedUsers)
            .MapDataKeys(UserName.GetUpdateKeyMapping)
            .MapData(UserName.GetUpdateMapping)
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .Exec(context.Database);

            var usersAfterMod = await SqQueryBuilder.Select(UserName.GetColumns(tUser))
                                .From(tUser)
                                .OrderBy(tUser.FirstName)
                                .OffsetFetch(0, 10)
                                .QueryList(context.Database, r => UserName.Read(r, tUser));

            for (var index = 0; index < usersAfterMod.Count; index++)
            {
                if (usersAfterMod[index].FirstName != modifiedUsers[index].FirstName)
                {
                    throw new Exception("Name was not updated");
                }
                if (usersAfterMod[index].LastName != modifiedUsers[index].LastName)
                {
                    throw new Exception("Name was not updated");
                }
            }

            await SqQueryBuilder.UpdateData(tUser, users)
            .MapDataKeys(UserName.GetUpdateKeyMapping)
            .MapData(UserName.GetUpdateMapping)
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .Done()
            .Exec(context.Database);

            var usersAfterMod2 = await SqQueryBuilder.Select(UserName.GetColumns(tUser))
                                 .From(tUser)
                                 .OrderBy(tUser.FirstName)
                                 .OffsetFetch(0, 10)
                                 .QueryList(context.Database, r => UserName.Read(r, tUser));

            for (var index = 0; index < usersAfterMod2.Count; index++)
            {
                if (usersAfterMod2[index].FirstName != users[index].FirstName)
                {
                    throw new Exception("Name was not updated");
                }
                if (usersAfterMod2[index].LastName != users[index].LastName)
                {
                    throw new Exception("Name was not updated");
                }
            }
        }
예제 #5
0
        public async Task Exec(IScenarioContext context)
        {
            var tt = new TestMergeTmpTable();
            await context.Database.Statement(tt.Script.Create());

            var testData = new List <TestMergeData>
            {
                new TestMergeData(1, 10),
                new TestMergeData(2, 11)
            };

            //Insert
            context.WriteLine("Inserting using MERGE..");
            await SqQueryBuilder.MergeDataInto(tt, testData)
            .MapDataKeys(TestMergeData.GetUpdateKeyMapping)
            .MapData(TestMergeData.GetUpdateMapping)
            .WhenMatchedThenUpdate()
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .WhenNotMatchedByTargetThenInsert()
            .Done()
            .Exec(context.Database);

            var dataFromDb = await SqQueryBuilder.Select(TestMergeDataRow.GetColumns(tt))
                             .From(tt)
                             .OrderBy(tt.Id)
                             .QueryList(context.Database, r => TestMergeDataRow.Read(r, tt));

            if (RowDataToString(dataFromDb) != "1,10,0;2,11,0")
            {
                throw new Exception("Incorrect data");
            }

            context.WriteLine("Updating using MERGE..");

            testData.Add(new TestMergeData(3, 12));
            testData[0] = testData[0].WithValue(100);

            await SqQueryBuilder.MergeDataInto(tt, testData)
            .MapDataKeys(TestMergeData.GetUpdateKeyMapping)
            .MapData(TestMergeData.GetUpdateMapping)
            .WhenMatchedThenUpdate((s, t) => tt.Value.WithSource(t) != s.Value.WithSource(s.Alias))
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .WhenNotMatchedByTargetThenInsert()
            .Done()
            .Exec(context.Database);

            dataFromDb = await SqQueryBuilder.Select(TestMergeDataRow.GetColumns(tt))
                         .From(tt)
                         .OrderBy(tt.Id)
                         .QueryList(context.Database, r => TestMergeDataRow.Read(r, tt));

            if (RowDataToString(dataFromDb) != "1,100,1;2,11,0;3,12,0")
            {
                throw new Exception("Incorrect data");
            }


            context.WriteLine("Updating (BY SOURCE) using MERGE..");

            testData = new List <TestMergeData>
            {
                new TestMergeData(1, 17),
            };

            await SqQueryBuilder.MergeDataInto(tt, testData)
            .MapDataKeys(TestMergeData.GetUpdateKeyMapping)
            .MapData(TestMergeData.GetUpdateMapping)
            .WhenMatchedThenUpdate((s, t) => tt.Value.WithSource(t) != s.Value.WithSource(s.Alias))
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .WhenNotMatchedBySourceThenUpdate(t => t.Value == 12).Set(s => s.Set(s.Target.Version, s.Target.Version + 10))
            .Done()
            .Exec(context.Database);

            dataFromDb = await SqQueryBuilder.Select(TestMergeDataRow.GetColumns(tt))
                         .From(tt)
                         .OrderBy(tt.Id)
                         .QueryList(context.Database, r => TestMergeDataRow.Read(r, tt));

            if (RowDataToString(dataFromDb) != "1,17,2;2,11,0;3,12,10")
            {
                throw new Exception("Incorrect data");
            }

            context.WriteLine("Deleting (BY SOURCE) using MERGE..");

            await SqQueryBuilder.MergeDataInto(tt, testData)
            .MapDataKeys(TestMergeData.GetUpdateKeyMapping)
            .MapData(TestMergeData.GetUpdateMapping)
            .WhenMatchedThenUpdate()
            .AlsoSet(s => s.Set(s.Target.Version, s.Target.Version + 1))
            .WhenNotMatchedBySourceThenDelete(t => t.Value == 12)
            .Done()
            .Exec(context.Database);

            dataFromDb = await SqQueryBuilder.Select(TestMergeDataRow.GetColumns(tt))
                         .From(tt)
                         .OrderBy(tt.Id)
                         .QueryList(context.Database, r => TestMergeDataRow.Read(r, tt));

            if (RowDataToString(dataFromDb) != "1,17,3;2,11,0")
            {
                throw new Exception("Incorrect data");
            }

            context.WriteLine("Deleting ON MATCH using MERGE..");

            await SqQueryBuilder.MergeDataInto(tt, testData)
            .MapDataKeys(TestMergeData.GetUpdateKeyMapping)
            .MapData(TestMergeData.GetUpdateMapping)
            .WhenMatchedThenDelete()
            .Done()
            .Exec(context.Database);

            dataFromDb = await SqQueryBuilder.Select(TestMergeDataRow.GetColumns(tt))
                         .From(tt)
                         .OrderBy(tt.Id)
                         .QueryList(context.Database, r => TestMergeDataRow.Read(r, tt));

            if (RowDataToString(dataFromDb) != "2,11,0")
            {
                throw new Exception("Incorrect data");
            }

            await context.Database.Statement(tt.Script.Drop());
        }