From 45a2aed716dcf8cf7c811c89dfc665a155c956ff Mon Sep 17 00:00:00 2001 From: lilacse Date: Sun, 26 Feb 2023 21:58:17 +0800 Subject: [PATCH] Adds multi-row insert with list of dictionaries (sqlkata/querybuilder#663) --- QueryBuilder.Tests/InsertTests.cs | 43 +++++++++++++++++++++++++++++-- QueryBuilder/Query.Insert.cs | 42 +++++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/QueryBuilder.Tests/InsertTests.cs b/QueryBuilder.Tests/InsertTests.cs index 926e18b2..c639060b 100644 --- a/QueryBuilder.Tests/InsertTests.cs +++ b/QueryBuilder.Tests/InsertTests.cs @@ -1,10 +1,10 @@ +using SqlKata.Compilers; +using SqlKata.Tests.Infrastructure; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Dynamic; using System.Linq; -using SqlKata.Compilers; -using SqlKata.Tests.Infrastructure; using Xunit; namespace SqlKata.Tests @@ -284,6 +284,45 @@ public void InsertReadOnlyDictionary() c[EngineCodes.Firebird]); } + [Fact] + public void InsertDictionaryList() + { + var expensiveCars = new List> + { + new Dictionary + { + { "name", "Chiron" }, + { "brand", "Bugatti" }, + { "year", null }, + }, + new Dictionary + { + { "name", "Huayra" }, + { "year", 2012 }, + { "brand", "Pagani" }, + }, + new Dictionary + { + { "year", 2009 }, + { "brand", "Lamborghini" }, + { "name", "Reventon roadster" }, + }, + }; + + var query = new Query("expensive_cars") + .AsInsert(expensiveCars); + + var c = Compile(query); + + Assert.Equal( + "INSERT INTO [expensive_cars] ([brand], [name], [year]) VALUES ('Bugatti', 'Chiron', NULL), ('Pagani', 'Huayra', 2012), ('Lamborghini', 'Reventon roadster', 2009)", + c[EngineCodes.SqlServer]); + + Assert.Equal( + "INSERT INTO \"EXPENSIVE_CARS\" (\"BRAND\", \"NAME\", \"YEAR\") SELECT 'Bugatti', 'Chiron', NULL FROM RDB$DATABASE UNION ALL SELECT 'Pagani', 'Huayra', 2012 FROM RDB$DATABASE UNION ALL SELECT 'Lamborghini', 'Reventon roadster', 2009 FROM RDB$DATABASE", + c[EngineCodes.Firebird]); + } + [Fact] public void InsertExpandoObject() { diff --git a/QueryBuilder/Query.Insert.cs b/QueryBuilder/Query.Insert.cs index dbec60af..0287dca0 100644 --- a/QueryBuilder/Query.Insert.cs +++ b/QueryBuilder/Query.Insert.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace SqlKata { @@ -97,6 +96,47 @@ public Query AsInsert(IEnumerable columns, IEnumerable>> values) + { + if (values == null || !values.Any()) + { + throw new InvalidOperationException($"{values} argument cannot be null or empty"); + } + + var columnsList = values.First().Select(x => x.Key).OrderBy(x => x).ToList(); + if (!columnsList.Any()) + { + throw new InvalidOperationException($"Elements in {values} argument cannot be empty"); + } + + var rowsValuesList = new List>(); + + foreach (var rowValues in values) + { + int rowValuesCount = rowValues.Count(); + if (rowValuesCount != columnsList.Count()) + { + throw new InvalidOperationException($"Not all elements in {values} contain the same columns."); + } + + var valuesList = new List(); + var sortedRowValuesList = rowValues.OrderBy(x => x.Key).ToList(); + for (int i = 0; i < rowValuesCount; i++) + { + if (columnsList[i] != sortedRowValuesList[i].Key) + { + throw new InvalidOperationException($"Not all elements in {values} contain the same columns."); + } + + valuesList.Add(sortedRowValuesList[i].Value); + } + + rowsValuesList.Add(valuesList); + } + + return AsInsert(columnsList, rowsValuesList); + } + /// /// Produces insert from subquery ///