Skip to content

Commit b01c77b

Browse files
Add SelectAll method.
1 parent aea0d23 commit b01c77b

12 files changed

Lines changed: 210 additions & 82 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

77
## [0.6.0]
8+
### Added
9+
- New SelectAll method that returns a typed SelectBuilder that is awaitable.
810
### Changed
911
- Renamed DbCommandBuilder to CommandBuilder
1012
- Renamed DbTransactionWrapper to Transaction
1113
- Renamed DbConnectionWrapper to Connection
14+
### Removed
15+
- Removed SelectAsync override with a callback.
1216

1317
## [0.5.3]
1418
### Added

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,24 +125,24 @@ public class StockItem
125125
}
126126

127127
// SELECT all rows from stock_items and map them to a list of StockItem
128-
var stockItems = await database.SelectAsync<StockItem>();
128+
var stockItems = await database.SelectAll<StockItem>().ToListAsync();
129129

130130
// SELECT the row where stock_item_id = 1 and map it to a StockItem (or null.)
131131
var stockItem = await database.SelectAsync<StockItem>(1);
132132

133133
// SELECT the rows where stock_item_name = "USB missile launcher (Green)" and map it to a list of StockItem
134-
var results = await database.SelectAsync<StockItemAnnotated>(_ =>
135-
_.Where("stock_item_name").EqualTo("USB missile launcher (Green)")
136-
);
134+
var results = await database
135+
.SelectAll<StockItem>()
136+
.Where("stock_item_name").EqualTo("USB missile launcher (Green)");
137137

138138
// INSERT a row into stock_items, using the fields on the stockItem model.
139-
var rowsAffected = await database.InsertAsync<StockItem>(stockItem);
139+
var insertedStockItem = await database.InsertAsync<StockItem>(stockItem);
140140

141141
// INSERT a row in stock_items, using the fields on the stockItem model.
142-
var rowsAffected = await database.UpdateAsync<StockItem>(stockItem);
142+
var updatedStockItem = await database.UpdateAsync<StockItem>(stockItem);
143143

144144
// DELETE a row from stock_items
145-
var rowsAffected = await database.DeleteAsync<StockItemAnnotated>(stockItem);
145+
var rowsAffected = await database.DeleteAsync<StockItem>(stockItem);
146146
```
147147

148148
### Custom Commands

src/Normal.Abstractions/ICommandExecutor.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,16 @@ public interface ICommandExecutor
1515
Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken = default);
1616
Task<T> ExecuteScalarAsync<T>(CancellationToken cancellationToken = default);
1717
}
18+
19+
public interface ICommandExecutor<T>
20+
{
21+
Task<IEnumerable<T>> ToEnumerableAsync(CancellationToken cancellationToken = default);
22+
Task<IList<T>> ToListAsync(CancellationToken cancellationToken = default);
23+
Task<T> FirstAsync(CancellationToken cancellationToken = default);
24+
Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default);
25+
Task<T> SingleAsync(CancellationToken cancellationToken = default);
26+
Task<T> SingleOrDefaultAsync(CancellationToken cancellationToken = default);
27+
Task<int> ExecuteNonQueryAsync(CancellationToken cancellationToken = default);
28+
Task<T> ExecuteScalarAsync(CancellationToken cancellationToken = default);
29+
}
1830
}

src/Normal/IDatabaseExtensions.cs

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.IO;
43
using System.Linq;
54
using System.Reflection;
@@ -16,30 +15,21 @@ public static ISelectBuilder Select(this IDatabase database, params string[] sel
1615
return new SelectBuilder(database).WithColumns(selectList);
1716
}
1817

19-
public static async Task<IEnumerable<T>> SelectAsync<T>(this IDatabase database, CancellationToken cancellationToken = default)
18+
public static ISelectBuilder<T> SelectAll<T>(this IDatabase database)
2019
{
21-
return await database.Select<T>().ToEnumerableAsync<T>(cancellationToken);
22-
}
23-
24-
public static async Task<IEnumerable<T>> SelectAsync<T>(
25-
this IDatabase database,
26-
Action<ISelectBuilder> builderCallback,
27-
CancellationToken cancellationToken = default)
28-
{
29-
var selectBuilder = database.Select<T>();
30-
builderCallback(selectBuilder);
31-
return await selectBuilder.ToEnumerableAsync<T>(cancellationToken);
20+
var table = Table.FromType(typeof(T));
21+
return new SelectBuilder<T>(database)
22+
.WithColumns(table.Columns.Select(c => c.Name).ToArray())
23+
.From(table.Name);
3224
}
3325

3426
public static async Task<T> SelectAsync<T>(
35-
this IDatabase database,
36-
object id,
37-
CancellationToken cancellationToken = default)
27+
this IDatabase database, object id, CancellationToken cancellationToken = default)
3828
{
3929
var table = Table.FromType(typeof(T));
40-
return await database.Select<T>()
30+
return await database.SelectAll<T>()
4131
.Where(table.PrimaryKey.Name).EqualTo(id)
42-
.FirstOrDefaultAsync<T>(cancellationToken);
32+
.FirstOrDefaultAsync(cancellationToken);
4333
}
4434

4535
public static IInsertBuilder InsertInto(this IDatabase database, string tableName)
@@ -60,7 +50,7 @@ public static Task<T> InsertAsync<T>(
6050
.Columns(columnsWithoutPrimaryKey.Select(c => c.Name).ToArray())
6151
.Values(columnsWithoutPrimaryKey.Select(c => c.GetValue(model)).ToArray()) as InsertBuilder;
6252

63-
ISelectBuilder select;
53+
ISelectBuilder<T> select;
6454
if (primaryKey.IsAutoIncrement)
6555
{
6656
var identityExpression = database.Variant switch
@@ -71,22 +61,19 @@ public static Task<T> InsertAsync<T>(
7161
_ => throw new NotSupportedException("Unknown database variant: " + database.Variant)
7262
};
7363

74-
select = Select(database, columns.Select(c => c.Name).ToArray())
75-
.From(table.Name)
64+
select = SelectAll<T>(database)
7665
.Where($"{primaryKey.Name} = {identityExpression}")
77-
.End() as SelectBuilder;
66+
.End();
7867
}
7968
else
8069
{
81-
select = Select(database, columns.Select(c => c.Name).ToArray())
82-
.From(table.Name)
70+
select = SelectAll<T>(database)
8371
.Where($"{primaryKey.Name}").EqualTo(primaryKey.GetValue(model));
8472
}
8573

8674
insertBuilder.AddLine(";");
8775
insertBuilder.AddLine(select.Build());
8876

89-
9077
return insertBuilder
9178
.SingleAsync<T>(cancellationToken);
9279
}
@@ -97,9 +84,7 @@ public static IUpdateBuilder Update(this IDatabase database, string tableName)
9784
}
9885

9986
public static Task<int> UpdateAsync<T>(
100-
this IDatabase database,
101-
T model,
102-
CancellationToken cancellationToken = default)
87+
this IDatabase database, T model, CancellationToken cancellationToken = default)
10388
{
10489
var table = Table.FromType(typeof(T));
10590
var columns = table.Columns.ToList();
@@ -116,7 +101,8 @@ public static IDeleteBuilder DeleteFrom(this IDatabase database, string tableNam
116101
return new DeleteBuilder(database).WithTableName(tableName);
117102
}
118103

119-
public static Task<int> DeleteAsync<T>(this IDatabase database, T model, CancellationToken cancellationToken = default)
104+
public static Task<int> DeleteAsync<T>(
105+
this IDatabase database, T model, CancellationToken cancellationToken = default)
120106
{
121107
var table = Table.FromType(typeof(T));
122108
var primaryKey = table.PrimaryKey;
@@ -125,7 +111,8 @@ public static Task<int> DeleteAsync<T>(this IDatabase database, T model, Cancell
125111
.ExecuteNonQueryAsync(cancellationToken);
126112
}
127113

128-
public static ICommandBuilder CreateCommandFromFile(this IDatabase database, string fileName, Encoding encoding = default)
114+
public static ICommandBuilder CreateCommandFromFile(
115+
this IDatabase database, string fileName, Encoding encoding = default)
129116
{
130117
encoding ??= Encoding.Default;
131118
var file = File.ReadAllText(fileName, encoding);
@@ -170,13 +157,5 @@ private static Stream FindResourceFromAssemblies(string resourceName, params Ass
170157
}
171158
return null;
172159
}
173-
174-
175-
// TODO: make this public, and return an ISelectBuilder with a Generic type?
176-
private static ISelectBuilder Select<T>(this IDatabase database)
177-
{
178-
var table = Table.FromType(typeof(T));
179-
return database.Select(table.Columns.Select(c => c.Name).ToArray()).From(table.Name);
180-
}
181160
}
182161
}

src/Normal/StatementBuilder/IDeleteBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Normal
22
{
3-
public interface IDeleteBuilder : IStatementBuilder
3+
public interface IDeleteBuilder : IStatementBuilder, ICommandExecutor
44
{
55
IConditionBuilder<IDeleteBuilder> Where(string columnName);
66
IConditionBuilder<IDeleteBuilder> And(string columnName);

src/Normal/StatementBuilder/IInsertBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
namespace Normal
22
{
3-
public interface IInsertBuilder : IStatementBuilder
3+
public interface IInsertBuilder : IStatementBuilder, ICommandExecutor
44
{
55
IInsertBuilder Columns(params string[] columnNames);
66
IInsertBuilder Values(params object[] valueRow);

src/Normal/StatementBuilder/ISelectBuilder.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
using System.Collections.Generic;
2+
using System.Runtime.CompilerServices;
3+
14
namespace Normal
25
{
3-
public interface ISelectBuilder : IStatementBuilder
6+
public interface ISelectBuilder : IStatementBuilder, ICommandExecutor
47
{
58
ISelectBuilder From(params string[] fromList);
69
ISelectBuilder Join(string tableName);
@@ -15,4 +18,21 @@ public interface ISelectBuilder : IStatementBuilder
1518
ISelectBuilder Limit(int limit);
1619
ISelectBuilder Offset(int offset);
1720
}
21+
22+
public interface ISelectBuilder<T> : IStatementBuilder, ICommandExecutor<T>
23+
{
24+
ISelectBuilder<T> From(params string[] fromList);
25+
ISelectBuilder<T> Join(string tableName);
26+
ISelectBuilder<T> LeftJoin(string tableName);
27+
ISelectBuilder<T> On(string clause);
28+
IConditionBuilder<ISelectBuilder<T>> Where(string columnName);
29+
IConditionBuilder<ISelectBuilder<T>> And(string columnName);
30+
IConditionBuilder<ISelectBuilder<T>> Or(string columnName);
31+
ISelectBuilder<T> GroupBy(params string[] groupingElements);
32+
ISelectBuilder<T> Having(string having);
33+
ISelectBuilder<T> OrderBy(string orderBy);
34+
ISelectBuilder<T> Limit(int limit);
35+
ISelectBuilder<T> Offset(int offset);
36+
TaskAwaiter<IEnumerable<T>> GetAwaiter();
37+
}
1838
}

src/Normal/StatementBuilder/IStatementBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace Normal
55
{
6-
public interface IStatementBuilder : ICommandExecutor
6+
public interface IStatementBuilder
77
{
88
string Build();
99
}

src/Normal/StatementBuilder/IUpdateBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Normal
44
{
5-
public interface IUpdateBuilder : IStatementBuilder
5+
public interface IUpdateBuilder : IStatementBuilder, ICommandExecutor
66
{
77
IConditionBuilder<IUpdateBuilder> Set(string columnName);
88
IUpdateBuilder Set(object setBuilder);

src/Normal/StatementBuilder/SelectBuilder.cs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
using System.Collections.Generic;
2+
using System.Runtime.CompilerServices;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
16
namespace Normal
27
{
38
internal class SelectBuilder : StatementBuilder, ISelectBuilder
@@ -82,4 +87,110 @@ public ISelectBuilder Offset(int offset)
8287
return base.AddLine(keyword, columnNames) as ISelectBuilder;
8388
}
8489
}
90+
91+
internal partial class SelectBuilder<T> : StatementBuilder, ISelectBuilder<T>
92+
{
93+
public SelectBuilder(IDatabase database)
94+
{
95+
_database = database;
96+
}
97+
98+
public SelectBuilder(params string[] selectList)
99+
{
100+
WithColumns(selectList);
101+
}
102+
103+
public ISelectBuilder<T> WithColumns(params string[] selectList)
104+
{
105+
return AddLine("SELECT", selectList);
106+
}
107+
108+
public ISelectBuilder<T> From(params string[] fromList)
109+
{
110+
return AddLine("FROM", fromList);
111+
}
112+
113+
public ISelectBuilder<T> Join(string tableName)
114+
{
115+
return AddLine("JOIN", tableName);
116+
}
117+
118+
public ISelectBuilder<T> LeftJoin(string tableName)
119+
{
120+
return AddLine("LEFT JOIN", tableName);
121+
}
122+
123+
public ISelectBuilder<T> On(string clause)
124+
{
125+
return AddLine("ON", clause);
126+
}
127+
128+
public IConditionBuilder<ISelectBuilder<T>> Where(string columnName)
129+
{
130+
return new ConditionBuilder<ISelectBuilder<T>>(this, "WHERE", columnName);
131+
}
132+
133+
public IConditionBuilder<ISelectBuilder<T>> And(string columnName)
134+
{
135+
return new ConditionBuilder<ISelectBuilder<T>>(this, "AND", columnName);
136+
}
137+
138+
public IConditionBuilder<ISelectBuilder<T>> Or(string columnName)
139+
{
140+
return new ConditionBuilder<ISelectBuilder<T>>(this, "OR", columnName);
141+
}
142+
143+
public ISelectBuilder<T> GroupBy(params string[] groupingElements)
144+
{
145+
return AddLine("GROUP BY", groupingElements);
146+
}
147+
148+
public ISelectBuilder<T> Having(string having)
149+
{
150+
return AddLine("HAVING", having);
151+
}
152+
153+
public ISelectBuilder<T> OrderBy(string orderBy)
154+
{
155+
return AddLine("ORDER BY", orderBy);
156+
}
157+
158+
public ISelectBuilder<T> Limit(int limit)
159+
{
160+
return AddLine("LIMIT", limit.ToString());
161+
}
162+
163+
public ISelectBuilder<T> Offset(int offset)
164+
{
165+
return AddLine("OFFSET", offset.ToString());
166+
}
167+
168+
public TaskAwaiter<IEnumerable<T>> GetAwaiter()
169+
{
170+
return ToEnumerableAsync<T>().GetAwaiter();
171+
}
172+
173+
private new ISelectBuilder<T> AddLine(string keyword, params string[] columnNames)
174+
{
175+
return base.AddLine(keyword, columnNames) as ISelectBuilder<T>;
176+
}
177+
}
178+
179+
internal partial class SelectBuilder<T> : ICommandExecutor<T>
180+
{
181+
public Task<T> ExecuteScalarAsync(CancellationToken cancellationToken = default)
182+
=> ExecuteScalarAsync<T>(cancellationToken);
183+
public Task<T> FirstAsync(CancellationToken cancellationToken = default)
184+
=> FirstAsync<T>(cancellationToken);
185+
public Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default)
186+
=> FirstOrDefaultAsync<T>(cancellationToken);
187+
public Task<T> SingleAsync(CancellationToken cancellationToken = default)
188+
=> SingleAsync<T>(cancellationToken);
189+
public Task<T> SingleOrDefaultAsync(CancellationToken cancellationToken = default)
190+
=> SingleOrDefaultAsync<T>(cancellationToken);
191+
public Task<IEnumerable<T>> ToEnumerableAsync(CancellationToken cancellationToken = default)
192+
=> ToEnumerableAsync<T>(cancellationToken);
193+
public Task<IList<T>> ToListAsync(CancellationToken cancellationToken = default)
194+
=> ToListAsync<T>(cancellationToken);
195+
}
85196
}

0 commit comments

Comments
 (0)