-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #373 from mk3008/372-i-want-to-convert-ienumerable…
…t-to-a-query Added query conversion functionality for IEnumerable<T>.
- Loading branch information
Showing
5 changed files
with
209 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using Carbunql.Analysis.Parser; | ||
using Carbunql.Clauses; | ||
using Carbunql.Values; | ||
|
||
namespace Carbunql.Building; | ||
|
||
public static class IEnumerableExtension | ||
{ | ||
public static ValuesQuery ToValuesQuery<T>(this IEnumerable<T> source) | ||
{ | ||
return ToValuesQuery(source, DbmsConfiguration.PlaceholderIdentifier); | ||
} | ||
|
||
public static ValuesQuery ToValuesQuery<T>(this IEnumerable<T> source, string placeholderIndentifer) | ||
{ | ||
var vq = new ValuesQuery(); | ||
var r = 0; | ||
foreach (var row in source) | ||
{ | ||
var lst = new List<ValueBase>(); | ||
var c = 0; | ||
foreach (var column in typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite).Select(x => x.GetValue(row))) | ||
{ | ||
var name = $"r{r}c{c}"; | ||
var v = placeholderIndentifer + name; | ||
lst.Add(ValueParser.Parse(v)); | ||
vq.AddParameter(name, column); | ||
c++; | ||
} | ||
vq.Rows.Add(new ValueCollection(lst)); | ||
r++; | ||
} | ||
return vq; | ||
} | ||
|
||
public static SelectQuery ToSelectQuery<T>(this IEnumerable<T> source) | ||
{ | ||
return source.ToSelectQuery(DbmsConfiguration.PlaceholderIdentifier, x => x.ToLowerSnakeCase()); | ||
} | ||
|
||
public static SelectQuery ToSelectQuery<T>(this IEnumerable<T> source, string placeholderIndentifer, Func<string, string> propertyNameConverter) | ||
{ | ||
var columns = typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite).Select(x => propertyNameConverter(x.Name)).ToList(); | ||
var vq = source.ToValuesQuery(placeholderIndentifer); | ||
var sq = vq.ToSelectQuery(columns); | ||
|
||
return sq; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
using Xunit.Abstractions; | ||
|
||
namespace Carbunql.Building.Test; | ||
|
||
public class IEnumerableTest | ||
{ | ||
private readonly QueryCommandMonitor Monitor; | ||
|
||
public IEnumerableTest(ITestOutputHelper output) | ||
{ | ||
Monitor = new QueryCommandMonitor(output); | ||
Output = output; | ||
} | ||
|
||
private ITestOutputHelper Output { get; set; } | ||
|
||
[Fact] | ||
public void ToValuesQuery() | ||
{ | ||
var results = new List<ApiResult>() | ||
{ | ||
new (){ ResultId = 1 , ResultText = "a", ResultValue = 10, ResultDate = new DateTime(2000,1,1), ResultBool= true }, | ||
new (){ ResultId = 2 , ResultText = "b", ResultValue = 20, ResultDate = new DateTime(2010,10,10), ResultBool= false }, | ||
new (){ ResultId = 3 , ResultText = null, ResultValue = null, ResultDate = null, ResultBool= null}, | ||
}; | ||
|
||
var q = results.ToValuesQuery(); | ||
|
||
var actual = q.ToText(true); | ||
Output.WriteLine(actual); | ||
|
||
var expect = @"/* | ||
r0c0 = 1 | ||
r0c1 = 'a' | ||
r0c2 = 10 | ||
r0c3 = 2000/01/01 0:00:00 | ||
r0c4 = True | ||
r1c0 = 2 | ||
r1c1 = 'b' | ||
r1c2 = 20 | ||
r1c3 = 2010/10/10 0:00:00 | ||
r1c4 = False | ||
r2c0 = 3 | ||
r2c1 is NULL | ||
r2c2 is NULL | ||
r2c3 is NULL | ||
r2c4 is NULL | ||
*/ | ||
VALUES | ||
(:r0c0, :r0c1, :r0c2, :r0c3, :r0c4), | ||
(:r1c0, :r1c1, :r1c2, :r1c3, :r1c4), | ||
(:r2c0, :r2c1, :r2c2, :r2c3, :r2c4)"; | ||
|
||
Assert.Equal(expect, actual, true, true, true); | ||
} | ||
|
||
[Fact] | ||
public void ToSelectQuery() | ||
{ | ||
var results = new List<ApiResult>() | ||
{ | ||
new (){ ResultId = 1 , ResultText = "a", ResultValue = 10, ResultDate = new DateTime(2000,1,1), ResultBool= true }, | ||
new (){ ResultId = 2 , ResultText = "b", ResultValue = 20, ResultDate = new DateTime(2010,10,10), ResultBool= false }, | ||
new (){ ResultId = 3 , ResultText = null, ResultValue = null, ResultDate = null, ResultBool= null}, | ||
}; | ||
|
||
var q = results.ToSelectQuery(); | ||
|
||
var actual = q.ToText(true); | ||
Output.WriteLine(actual); | ||
|
||
var expect = @"/* | ||
r0c0 = 1 | ||
r0c1 = 'a' | ||
r0c2 = 10 | ||
r0c3 = 2000/01/01 0:00:00 | ||
r0c4 = True | ||
r1c0 = 2 | ||
r1c1 = 'b' | ||
r1c2 = 20 | ||
r1c3 = 2010/10/10 0:00:00 | ||
r1c4 = False | ||
r2c0 = 3 | ||
r2c1 is NULL | ||
r2c2 is NULL | ||
r2c3 is NULL | ||
r2c4 is NULL | ||
*/ | ||
SELECT | ||
v.result_id, | ||
v.result_text, | ||
v.result_value, | ||
v.result_date, | ||
v.result_bool | ||
FROM | ||
( | ||
VALUES | ||
(:r0c0, :r0c1, :r0c2, :r0c3, :r0c4), | ||
(:r1c0, :r1c1, :r1c2, :r1c3, :r1c4), | ||
(:r2c0, :r2c1, :r2c2, :r2c3, :r2c4) | ||
) AS v ( | ||
result_id, result_text, result_value, result_date, result_bool | ||
)"; | ||
|
||
Assert.Equal(expect, actual, true, true, true); | ||
} | ||
|
||
[Fact] | ||
public void ToSelectQuery_50k() | ||
{ | ||
var results = GenerateDummyResults(50000); | ||
|
||
var q = results.ToSelectQuery(); | ||
|
||
var actual = q.ToText(false); | ||
Output.WriteLine(actual); | ||
} | ||
|
||
private static List<ApiResult> GenerateDummyResults(int count) | ||
{ | ||
var dummyResults = new List<ApiResult>(); | ||
|
||
for (int i = 0; i < count; i++) | ||
{ | ||
var result = new ApiResult | ||
{ | ||
ResultId = i + 1, | ||
ResultText = "dummy", | ||
ResultValue = i * 10, | ||
ResultDate = DateTime.Now.AddDays(i), | ||
ResultBool = i % 2 == 0 | ||
}; | ||
|
||
dummyResults.Add(result); | ||
} | ||
|
||
return dummyResults; | ||
} | ||
|
||
public class ApiResult | ||
{ | ||
public int ResultId { get; set; } | ||
public string? ResultText { get; set; } | ||
public long? ResultValue { get; set; } | ||
public DateTime? ResultDate { get; set; } | ||
public bool? ResultBool { get; set; } | ||
} | ||
} |