private IExprMergeMatched?BuildWhenMatched(IReadOnlyList <ExprColumnName> keys, IReadOnlyList <ExprColumnName> allColumns)
        {
            if (!this._whenMatched.HasValue)
            {
                return(null);
            }
            var when = this._whenMatched.Value;

            if (!when.IsDelete)
            {
                IReadOnlyList <ColumnValueUpdateMap>?extraMaps = null;
                if (when.Mapping != null)
                {
                    var mergeUpdateSetter = new MergerUpdateSetter <TTable>(this._table, this._sourceTableAlias);
                    when.Mapping.Invoke(mergeUpdateSetter);
                    extraMaps = mergeUpdateSetter.Maps;
                }

                var updateColNum = allColumns.Count - keys.Count;

                if (updateColNum == 0 && extraMaps == null)
                {
                    throw new SqExpressException("'WHEN MATCH THEN UPDATE..' should have at least one assignment");
                }

                ExprColumnSetClause[] sets = new ExprColumnSetClause[updateColNum + (extraMaps?.Count ?? 0)];

                for (int i = keys.Count; i < allColumns.Count; i++)
                {
                    sets[i - keys.Count] = new ExprColumnSetClause(allColumns[i].WithSource(this._table.Alias), allColumns[i].WithSource(this._sourceTableAlias));
                }
                if (extraMaps != null && extraMaps.Count > 0)
                {
                    for (int i = updateColNum; i < sets.Length; i++)
                    {
                        var extraMap = extraMaps[i - updateColNum];
                        sets[i] = new ExprColumnSetClause(extraMap.Column.WithSource(this._table.Alias), extraMap.Value);
                    }
                }

                HashSet <ExprColumn> duplicateChecker = new HashSet <ExprColumn>();
                for (int i = 0; i < sets.Length; i++)
                {
                    if (!duplicateChecker.Add(sets[i].Column))
                    {
                        throw new SqExpressException($"The column name '{sets[i].Column.ColumnName.Name}' is specified more than once in the SET clause");
                    }
                }

                return(new ExprMergeMatchedUpdate(when.And, sets));
            }

            return(new ExprMergeMatchedDelete(when.And));
        }
        private IExprMergeNotMatched?BuildWhenNotMatchedByTarget(IReadOnlyList <ExprColumnName> keys, IReadOnlyList <ExprColumnName> allColumns)
        {
            if (!this._whenNotMatchedByTarget.HasValue)
            {
                return(null);
            }
            var when = this._whenNotMatchedByTarget.Value;

            if (!when.IsDefaultValues)
            {
                IReadOnlyList <ColumnValueUpdateMap>?extraMaps = null;
                if (when.Mapping != null)
                {
                    var mergeUpdateSetter = new MergerUpdateSetter <TTable>(this._table, this._sourceTableAlias);
                    when.Mapping(mergeUpdateSetter);
                    extraMaps = mergeUpdateSetter.Maps;
                }

                var actualColumns = when.ExcludeKeys
                    ? new ReadOnlyListSegment <ExprColumnName>(allColumns, keys.Count)
                    : new ReadOnlyListSegment <ExprColumnName>(allColumns);

                int totalCount = actualColumns.Count + (extraMaps?.Count ?? 0);

                var insertColumns = new List <ExprColumnName>(totalCount);
                var insertValues  = new List <IExprAssigning>(totalCount);

                for (int i = 0; i < actualColumns.Count; i++)
                {
                    var coll = actualColumns[i];

                    if (when.Exclude != null && when.Exclude.Contains(coll))
                    {
                        continue;
                    }

                    insertColumns.Add(coll);
                    insertValues.Add(coll.WithSource(this._sourceTableAlias));
                }

                if (extraMaps != null && extraMaps.Count > 0)
                {
                    for (int i = actualColumns.Count; i < totalCount; i++)
                    {
                        var m = extraMaps[i - actualColumns.Count];
                        insertColumns.Add(m.Column);
                        insertValues.Add(m.Value);
                    }
                }

                HashSet <ExprColumnName> duplicateChecker = new HashSet <ExprColumnName>();
                for (int i = 0; i < insertColumns.Count; i++)
                {
                    if (!duplicateChecker.Add(insertColumns[i]))
                    {
                        throw new SqExpressException($"The column name '{insertColumns[i].Name}' is specified more than once in the column list of an INSERT");
                    }
                }

                return(new ExprExprMergeNotMatchedInsert(when.And, insertColumns, insertValues));
            }

            return(new ExprExprMergeNotMatchedInsertDefault(when.And));
        }