Skip to content

Commit a60cd18

Browse files
committed
add SqlInsertValuesCollection.cs
1 parent ad3fc07 commit a60cd18

1 file changed

Lines changed: 136 additions & 0 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright (C) 2023 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System;
6+
using System.Collections;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using Xtensive.Core;
10+
11+
namespace Xtensive.Sql.Dml.Collections
12+
{
13+
/// <summary>
14+
/// Collection of values of <see cref="SqlInsert"/>.
15+
/// </summary>
16+
public sealed class SqlInsertValuesCollection : IReadOnlyList<SqlRow>
17+
{
18+
private IReadOnlyList<SqlColumn> columns;
19+
private List<SqlRow> rows = new();
20+
21+
/// <summary>
22+
/// The columns collection has values for.
23+
/// </summary>
24+
public IReadOnlyList<SqlColumn> Columns => columns ?? Array.Empty<SqlColumn>();
25+
26+
/// <summary>
27+
/// Count of rows.
28+
/// </summary>
29+
public int Count => rows.Count;
30+
31+
/// <summary>
32+
/// Gets row by index.
33+
/// </summary>
34+
/// <param name="index"></param>
35+
/// <returns></returns>
36+
public SqlRow this[int index] => rows[index];
37+
38+
/// <summary>
39+
/// Adds column-to-value mapped collection of values as row.
40+
/// </summary>
41+
/// <param name="row">column-to-value mapped collection of values</param>
42+
/// <exception cref="ArgumentNullException"><paramref name="row"/> value is null.</exception>
43+
/// <exception cref="ArgumentException">Count of values between already added rows and <paramref name="row"/>
44+
/// -or- particular column in <paramref name="row"/> is not presented in already added rows
45+
/// -or- <paramref name="row"/> is empty.</exception>
46+
public void Add(Dictionary<SqlColumn, SqlExpression> row)
47+
{
48+
#if NET6_0_OR_GREATER
49+
ArgumentNullException.ThrowIfNull(row, nameof(row));
50+
#else
51+
ArgumentValidator.EnsureArgumentNotNull(row, nameof(row));
52+
#endif
53+
if (row.Count == 0) {
54+
throw new ArgumentException("Empty row is not allowed.");
55+
}
56+
57+
if (rows.Count == 0) {
58+
// save columns order as header for further rows to match;
59+
columns = row.Keys.ToList();
60+
rows.Add(SqlDml.Row(row.Values.ToList()));
61+
}
62+
else {
63+
if (columns.Count != row.Count)
64+
throw new ArgumentException("Inconsistent row length.");
65+
if (row.Keys.SequenceEqual(columns)) {
66+
//fast addition
67+
rows.Add(SqlDml.Row(row.Values.ToList()));
68+
}
69+
else {
70+
//re-arrange values to be the same order
71+
//and also make sure all columns exist
72+
var rowList = new List<SqlExpression>();
73+
foreach (var column in columns) {
74+
if (row.TryGetValue(column, out var value)) {
75+
rowList.Add(value);
76+
}
77+
else {
78+
throw new ArgumentException(string.Format("There is no mentioning of column '{0}' in previously added rows.", column.Name));
79+
}
80+
}
81+
82+
rows.Add(SqlDml.Row(rowList));
83+
}
84+
}
85+
}
86+
87+
/// <summary>
88+
/// Removes row by index.
89+
/// </summary>
90+
/// <param name="index">The index of row to remove.</param>
91+
public void RemoveAt(int index)
92+
{
93+
rows.RemoveAt(index);
94+
if (rows.Count == 0) {
95+
columns = null;
96+
}
97+
}
98+
99+
/// <summary>
100+
/// Clears rows and columns.
101+
/// </summary>
102+
public void Clear()
103+
{
104+
rows = new List<SqlRow>();
105+
columns = null;
106+
}
107+
108+
/// <inheritdoc/>
109+
public IEnumerator<SqlRow> GetEnumerator() => rows.GetEnumerator();
110+
111+
/// <inheritdoc/>
112+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
113+
114+
internal SqlInsertValuesCollection Clone(SqlNodeCloneContext context)
115+
{
116+
var clone = new SqlInsertValuesCollection();
117+
118+
if (rows.Count == 0) {
119+
return clone;
120+
}
121+
122+
var clonedList = new List<SqlColumn>(columns.Count);
123+
foreach (var oldColumn in columns) {
124+
clonedList.Add((SqlColumn) context.NodeMapping[oldColumn]);
125+
}
126+
clone.columns = clonedList;
127+
128+
clone.rows = new List<SqlRow>(rows.Count);
129+
foreach(var oldRow in rows) {
130+
clone.rows.Add((SqlRow) oldRow.Clone());
131+
}
132+
133+
return clone;
134+
}
135+
}
136+
}

0 commit comments

Comments
 (0)