Skip to content

Adds multi-row insert with list of dictionaries (#663) #664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions QueryBuilder.Tests/InsertTests.cs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -284,6 +284,45 @@ public void InsertReadOnlyDictionary()
c[EngineCodes.Firebird]);
}

[Fact]
public void InsertDictionaryList()
{
var expensiveCars = new List<Dictionary<string, object>>
{
new Dictionary<string, object>
{
{ "name", "Chiron" },
{ "brand", "Bugatti" },
{ "year", null },
},
new Dictionary<string, object>
{
{ "name", "Huayra" },
{ "year", 2012 },
{ "brand", "Pagani" },
},
new Dictionary<string, object>
{
{ "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()
{
Expand Down
42 changes: 41 additions & 1 deletion QueryBuilder/Query.Insert.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace SqlKata
{
Expand Down Expand Up @@ -97,6 +96,47 @@ public Query AsInsert(IEnumerable<string> columns, IEnumerable<IEnumerable<objec
return this;
}

public Query AsInsert(IEnumerable<IEnumerable<KeyValuePair<string, object>>> 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<List<object>>();

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<object>();
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);
}

/// <summary>
/// Produces insert from subquery
/// </summary>
Expand Down