Skip to content

Commit c5476f5

Browse files
committed
Cache the TableMapping on the type T instance, therefore allowing for its use to be inferred by type, instead of passing it explicitly. Lots of refactors fall out of that decision.
1 parent 35c4c0e commit c5476f5

24 files changed

Lines changed: 478 additions & 567 deletions

SQLitePCL.pretty.Async/AsyncDatabaseConnection.cs

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -539,64 +539,6 @@ public static IObservable<T> Use<T>(this IAsyncDatabaseConnection This, Func<IDa
539539
Contract.Requires(f != null);
540540
return This.Use((conn, ct) => f(conn));
541541
}
542-
543-
/// <summary>
544-
/// Drops the table if exists async.
545-
/// </summary>
546-
/// <returns>The table if exists async.</returns>
547-
/// <param name="This">This.</param>
548-
/// <param name="table">The table name.</param>
549-
/// <param name="ct">Ct.</param>
550-
public static Task DropTableIfExistsAsync(this IAsyncDatabaseConnection This, string table, CancellationToken ct)
551-
{
552-
Contract.Requires(This != null);
553-
Contract.Requires(table != null);
554-
555-
return This.Use((db, _) => db.DropTableIfExists(table), ct);
556-
}
557-
558-
/// <summary>
559-
/// Drops the table if exists async.
560-
/// </summary>
561-
/// <returns>The table if exists async.</returns>
562-
/// <param name="This">This.</param>
563-
/// <param name="table">The table name.</param>
564-
public static Task DropTableIfExistsAsync(this IAsyncDatabaseConnection This, string table)
565-
{
566-
Contract.Requires(This != null);
567-
Contract.Requires(table != null);
568-
569-
return This.DropTableIfExistsAsync(table, CancellationToken.None);
570-
}
571-
572-
/// <summary>
573-
/// Deletes all rows in a given table, asynchronously.
574-
/// </summary>
575-
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
576-
/// <param name="This">The database connection.</param>
577-
/// <param name="table">The table name.</param>
578-
/// <param name="ct">A cancellation token that can be used to cancel the operation.</param>
579-
public static Task DeleteAllRowsAsync(this IAsyncDatabaseConnection This, string table, CancellationToken ct)
580-
{
581-
Contract.Requires(This != null);
582-
Contract.Requires(table != null);
583-
584-
return This.Use((db, _) => db.DeleteAllRows(table), ct);
585-
}
586-
587-
/// <summary>
588-
/// Deletes all rows in a given table, asynchronously.
589-
/// </summary>
590-
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
591-
/// <param name="This">The database connection.</param>
592-
/// <param name="table">The table name.</param>
593-
public static Task DeleteAllRowsAsync(this IAsyncDatabaseConnection This, string table)
594-
{
595-
Contract.Requires(This != null);
596-
Contract.Requires(table != null);
597-
598-
return This.DeleteAllRowsAsync(table, CancellationToken.None);
599-
}
600542
}
601543

602544
internal sealed class AsyncDatabaseConnectionImpl : IAsyncDatabaseConnection

SQLitePCL.pretty.Orm/DatabaseConnection.Delete.cs

Lines changed: 103 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,44 @@
44
using System.Linq;
55
using System.Threading;
66
using System.Threading.Tasks;
7+
using System.Runtime.CompilerServices;
8+
9+
710
namespace SQLitePCL.pretty.Orm
811
{
912
public static partial class DatabaseConnection
1013
{
14+
private static readonly ConditionalWeakTable<TableMapping, string> deleteQueries =
15+
new ConditionalWeakTable<TableMapping, string>();
16+
1117
/// <summary>
1218
/// Prepares a SQLite statement that can be bound to an object primary key to delete row from the database.
1319
/// </summary>
1420
/// <returns>A prepared statement.</returns>
1521
/// <param name="This">The database connection</param>
1622
/// <param name="tableMapping">The table mapping.</param>
17-
public static IStatement PrepareDeleteStatement(this IDatabaseConnection This, TableMapping tableMapping)
23+
public static IStatement PrepareDeleteStatement<T>(this IDatabaseConnection This)
1824
{
1925
Contract.Requires(This != null);
20-
Contract.Requires(tableMapping != null);
26+
27+
var tableMapping = TableMapping.Create<T>();
28+
var sql = deleteQueries.GetValue(tableMapping, mapping =>
29+
{
30+
var primaryKeyColumn = mapping.PrimaryKeyColumn();
31+
return SQLBuilder.DeleteUsingPrimaryKey(mapping.TableName, primaryKeyColumn);
32+
});
33+
2134

22-
return This.PrepareDelete(tableMapping.TableName, tableMapping.PrimaryKeyColumn());
35+
return This.PrepareStatement(sql);
2336
}
2437

2538
private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(
2639
this IDatabaseConnection This,
27-
TableMapping tableMapping,
2840
IEnumerable<long> primaryKeys,
2941
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
3042
{
31-
using (var deleteStmt = This.PrepareDeleteStatement(tableMapping))
32-
using (var findStmt = This.PrepareFindStatement(tableMapping))
43+
using (var deleteStmt = This.PrepareDeleteStatement<T>())
44+
using (var findStmt = This.PrepareFindStatement<T>())
3345
{
3446
foreach (var primaryKey in primaryKeys)
3547
{
@@ -54,16 +66,14 @@ private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(
5466
/// <typeparam name="T">The mapped type.</typeparam>
5567
public static bool TryDelete<T>(
5668
this IDatabaseConnection This,
57-
TableMapping tableMapping,
5869
long primaryKey,
5970
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
6071
out T deleted)
6172
{
6273
Contract.Requires(This != null);
63-
Contract.Requires(tableMapping != null);
6474
Contract.Requires(resultSelector != null);
6575

66-
var result = This.YieldDeleteAll(tableMapping, new long[] { primaryKey }, resultSelector).FirstOrDefault();
76+
var result = This.YieldDeleteAll(new long[] { primaryKey }, resultSelector).FirstOrDefault();
6777
if (result.Value != null)
6878
{
6979
deleted = result.Value;
@@ -85,21 +95,47 @@ public static bool TryDelete<T>(
8595
/// <param name="primaryKeys">An IEnumerable of primary keys to delete.</param>
8696
/// <typeparam name="T">The mapped type.</typeparam>
8797
public static IReadOnlyDictionary<long,T> DeleteAll<T>(
88-
this IDatabaseConnection This,
89-
TableMapping tableMapping,
98+
this IDatabaseConnection This,
9099
IEnumerable<long> primaryKeys,
91100
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
92101
{
93102
Contract.Requires(This != null);
94-
Contract.Requires(tableMapping != null);
95103
Contract.Requires(primaryKeys != null);
96104
Contract.Requires(resultSelector != null);
97105

98106
return This.RunInTransaction(_ =>
99-
This.YieldDeleteAll(tableMapping, primaryKeys, resultSelector)
107+
This.YieldDeleteAll(primaryKeys, resultSelector)
100108
.Where(kvp => kvp.Value != null)
101109
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
102110
}
111+
112+
/// <summary>
113+
/// Drops the table if it exists. Otherwise this is a no-op.
114+
/// </summary>
115+
/// <param name="This">The database connection.</param>
116+
/// <param name="table">The table name.</param>
117+
/// <seealso href="https://www.sqlite.org/lang_droptable.html"/>
118+
public static void DropTableIfExists<T>(this IDatabaseConnection This)
119+
{
120+
Contract.Requires(This != null);
121+
122+
var tableMapping = TableMapping.Create<T>();
123+
This.Execute(SQLBuilder.DropTableIfExists(tableMapping.TableName));
124+
}
125+
126+
127+
/// <summary>
128+
/// Deletes all rows in a given table.
129+
/// </summary>
130+
/// <param name="This">The database connection.</param>
131+
/// <param name="table">The table name.</param>
132+
public static void DeleteAllRows<T>(this IDatabaseConnection This)
133+
{
134+
Contract.Requires(This != null);
135+
136+
var tableMapping = TableMapping.Create<T>();
137+
This.Execute(SQLBuilder.DeleteAll(tableMapping.TableName));
138+
}
103139
}
104140

105141
public static partial class AsyncDatabaseConnection
@@ -115,17 +151,15 @@ public static partial class AsyncDatabaseConnection
115151
/// <typeparam name="T">The mapped type.</typeparam>
116152
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(
117153
this IAsyncDatabaseConnection This,
118-
TableMapping tableMapping,
119154
IEnumerable<long> primaryKeys,
120155
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
121156
CancellationToken ct)
122157
{
123158
Contract.Requires(This != null);
124-
Contract.Requires(tableMapping != null);
125159
Contract.Requires(primaryKeys != null);
126160
Contract.Requires(resultSelector != null);
127161

128-
return This.Use((db,_) => db.DeleteAll<T>(tableMapping, primaryKeys, resultSelector), ct);
162+
return This.Use((db,_) => db.DeleteAll<T>(primaryKeys, resultSelector), ct);
129163
}
130164

131165
/// <summary>
@@ -138,16 +172,66 @@ public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(
138172
/// <typeparam name="T">The mapped type.</typeparam>
139173
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(
140174
this IAsyncDatabaseConnection This,
141-
TableMapping tableMapping,
142175
IEnumerable<long> primaryKeys,
143176
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
144177
{
145178
Contract.Requires(This != null);
146-
Contract.Requires(tableMapping != null);
147179
Contract.Requires(primaryKeys != null);
148180
Contract.Requires(resultSelector != null);
149181

150-
return This.DeleteAllAsync(tableMapping, primaryKeys, resultSelector, CancellationToken.None);
182+
return This.DeleteAllAsync(primaryKeys, resultSelector, CancellationToken.None);
183+
}
184+
185+
186+
/// <summary>
187+
/// Drops the table if exists async.
188+
/// </summary>
189+
/// <returns>The table if exists async.</returns>
190+
/// <param name="This">This.</param>
191+
/// <param name="table">The table name.</param>
192+
/// <param name="ct">Ct.</param>
193+
public static Task DropTableIfExistsAsync<T>(this IAsyncDatabaseConnection This, CancellationToken ct)
194+
{
195+
Contract.Requires(This != null);
196+
197+
return This.Use((db, _) => db.DropTableIfExists<T>(), ct);
198+
}
199+
200+
/// <summary>
201+
/// Drops the table if exists async.
202+
/// </summary>
203+
/// <returns>The table if exists async.</returns>
204+
/// <param name="This">This.</param>
205+
/// <param name="table">The table name.</param>
206+
public static Task DropTableIfExistsAsync<T>(this IAsyncDatabaseConnection This)
207+
{
208+
Contract.Requires(This != null);
209+
return This.DropTableIfExistsAsync<T>(CancellationToken.None);
210+
}
211+
212+
/// <summary>
213+
/// Deletes all rows in a given table, asynchronously.
214+
/// </summary>
215+
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
216+
/// <param name="This">The database connection.</param>
217+
/// <param name="table">The table name.</param>
218+
/// <param name="ct">A cancellation token that can be used to cancel the operation.</param>
219+
public static Task DeleteAllRowsAsync<T>(this IAsyncDatabaseConnection This, CancellationToken ct)
220+
{
221+
Contract.Requires(This != null);
222+
return This.Use((db, _) => db.DeleteAllRows<T>(), ct);
223+
}
224+
225+
/// <summary>
226+
/// Deletes all rows in a given table, asynchronously.
227+
/// </summary>
228+
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
229+
/// <param name="This">The database connection.</param>
230+
/// <param name="table">The table name.</param>
231+
public static Task DeleteAllRowsAsync<T>(this IAsyncDatabaseConnection This)
232+
{
233+
Contract.Requires(This != null);
234+
return This.DeleteAllRowsAsync<T>(CancellationToken.None);
151235
}
152236
}
153237
}

SQLitePCL.pretty.Orm/DatabaseConnection.Find.cs

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,35 @@ namespace SQLitePCL.pretty.Orm
1010
{
1111
public static partial class DatabaseConnection
1212
{
13-
private static readonly ConditionalWeakTable<TableMapping, string> find =
13+
private static readonly ConditionalWeakTable<TableMapping, string> findQueries =
1414
new ConditionalWeakTable<TableMapping, string>();
1515

16-
private static string Find(this TableMapping This)
17-
{
18-
return find.GetValue(This, mapping =>
19-
{
20-
var column = This.PrimaryKeyColumn();
21-
return SQLBuilder.SelectWhereColumnEquals(This.TableName, column);
22-
});
23-
}
24-
2516
/// <summary>
2617
/// Prepares a SQLite statement that can be bound to an object primary key to retrieve an instance from the database.
2718
/// </summary>
2819
/// <returns>A prepared statement.</returns>
2920
/// <param name="This">The database connection</param>
3021
/// <param name="tableMapping">The table mapping.</param>
31-
public static IStatement PrepareFindStatement(this IDatabaseConnection This, TableMapping tableMapping)
22+
public static IStatement PrepareFindStatement<T>(this IDatabaseConnection This)
3223
{
3324
Contract.Requires(This != null);
34-
Contract.Requires(tableMapping != null);
3525

36-
return This.PrepareStatement(tableMapping.Find());
26+
var tableMapping = TableMapping.Create<T>();
27+
var sql = findQueries.GetValue(tableMapping, mapping =>
28+
{
29+
var column = mapping.PrimaryKeyColumn();
30+
return SQLBuilder.SelectWhereColumnEquals(tableMapping.TableName, column);
31+
});
32+
33+
return This.PrepareStatement(sql);
3734
}
3835

3936
private static IEnumerable<KeyValuePair<long,T>> YieldFindAll<T>(
40-
this IDatabaseConnection This,
41-
TableMapping tableMapping,
37+
this IDatabaseConnection This,
4238
IEnumerable<long> primaryKeys,
4339
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
4440
{
45-
using (var findStmt = This.PrepareFindStatement(tableMapping))
41+
using (var findStmt = This.PrepareFindStatement<T>())
4642
{
4743
foreach (var primaryKey in primaryKeys)
4844
{
@@ -63,16 +59,14 @@ private static IEnumerable<KeyValuePair<long,T>> YieldFindAll<T>(
6359
/// <typeparam name="T">The mapped type.</typeparam>
6460
public static bool TryFind<T>(
6561
this IDatabaseConnection This,
66-
TableMapping tableMapping,
6762
long primaryKey,
6863
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
6964
out T value)
7065
{
7166
Contract.Requires(This != null);
72-
Contract.Requires(tableMapping != null);
7367
Contract.Requires(resultSelector != null);
7468

75-
var result = This.YieldFindAll(tableMapping, new long[] { primaryKey }, resultSelector).FirstOrDefault();
69+
var result = This.YieldFindAll(new long[] { primaryKey }, resultSelector).FirstOrDefault();
7670

7771
if (result.Value != null)
7872
{
@@ -94,16 +88,14 @@ public static bool TryFind<T>(
9488
/// <typeparam name="T">The mapped type.</typeparam>
9589
public static IReadOnlyDictionary<long,T> FindAll<T>(
9690
this IDatabaseConnection This,
97-
TableMapping tableMapping,
9891
IEnumerable<long> primaryKeys,
9992
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
10093
{
10194
Contract.Requires(This != null);
102-
Contract.Requires(tableMapping != null);
10395
Contract.Requires(primaryKeys != null);
10496
Contract.Requires(resultSelector != null);
10597

106-
return This.YieldFindAll(tableMapping, primaryKeys, resultSelector)
98+
return This.YieldFindAll(primaryKeys, resultSelector)
10799
.Where(kvp => kvp.Value != null)
108100
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
109101
}
@@ -122,17 +114,15 @@ public static partial class AsyncDatabaseConnection
122114
/// <typeparam name="T">The mapped type.</typeparam>
123115
public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
124116
this IAsyncDatabaseConnection This,
125-
TableMapping tableMapping,
126117
IEnumerable<long> primaryKeys,
127118
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
128119
CancellationToken ct)
129120
{
130121
Contract.Requires(This != null);
131-
Contract.Requires(tableMapping != null);
132122
Contract.Requires(primaryKeys != null);
133123
Contract.Requires(resultSelector != null);
134124

135-
return This.Use((db,_) => db.FindAll(tableMapping, primaryKeys, resultSelector), ct);
125+
return This.Use((db,_) => db.FindAll(primaryKeys, resultSelector), ct);
136126
}
137127

138128
/// <summary>
@@ -145,16 +135,14 @@ public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
145135
/// <typeparam name="T">The mapped type.</typeparam>
146136
public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
147137
this IAsyncDatabaseConnection This,
148-
TableMapping tableMapping,
149138
IEnumerable<long> primaryKeys,
150139
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
151140
{
152141
Contract.Requires(This != null);
153-
Contract.Requires(tableMapping != null);
154142
Contract.Requires(primaryKeys != null);
155143
Contract.Requires(resultSelector != null);
156144

157-
return This.FindAllAsync(tableMapping, primaryKeys, resultSelector, CancellationToken.None);
145+
return This.FindAllAsync(primaryKeys, resultSelector, CancellationToken.None);
158146
}
159147
}
160148
}

0 commit comments

Comments
 (0)