Skip to content

Commit a7e08e4

Browse files
committed
Major ORM refactor. Seperate the concept of table mapping from Row to object mapping. This should allow for instance the use of a row mapper to eventually map joined select queries to an object.
1 parent 2ee58da commit a7e08e4

25 files changed

Lines changed: 682 additions & 1423 deletions

SQLitePCL.pretty.Async/AsyncDatabaseConnection.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,64 @@ 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+
}
542600
}
543601

544602
internal sealed class AsyncDatabaseConnectionImpl : IAsyncDatabaseConnection

SQLitePCL.pretty.Orm/Attributes.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ internal static string GetCollationSequence(this PropertyInfo This)
303303
return This.GetCustomAttributes<CollationAttribute>(true).Select(x => x.Name).FirstOrDefault();
304304
}
305305

306-
internal static bool Ignore(this PropertyInfo This)
306+
private static bool Ignore(this PropertyInfo This)
307307
{
308308
return This.GetCustomAttributes<IgnoreAttribute>(true).Count() > 0;
309309
}
@@ -344,5 +344,15 @@ internal static ForeignKeyConstraint GetForeignKeyConstraint(this PropertyInfo T
344344
var fkAttr = This.GetCustomAttributes<ForeignKeyAttribute>(true).FirstOrDefault();
345345
return fkAttr != null ? fkAttr.Value : null;
346346
}
347+
348+
internal static IEnumerable<PropertyInfo> GetNotIgnoredGettableProperties(this Type This)
349+
{
350+
return This.GetPublicInstanceProperties().Where(x => !x.Ignore());
351+
}
352+
353+
internal static IEnumerable<PropertyInfo> GetNotIgnoredSettableProperties(this Type This)
354+
{
355+
return This.GetPublicInstanceSettableProperties().Where(x => !x.Ignore());
356+
}
347357
}
348358
}

SQLitePCL.pretty.Orm/TableMapping.Delete.cs renamed to SQLitePCL.pretty.Orm/DatabaseConnection.Delete.cs

Lines changed: 37 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,27 @@
66
using System.Threading.Tasks;
77
namespace SQLitePCL.pretty.Orm
88
{
9-
public static partial class TableMapping
9+
public static partial class DatabaseConnection
1010
{
11-
1211
/// <summary>
1312
/// Prepares a SQLite statement that can be bound to an object primary key to delete row from the database.
1413
/// </summary>
1514
/// <returns>A prepared statement.</returns>
1615
/// <param name="This">The database connection</param>
1716
/// <param name="tableMapping">The table mapping.</param>
18-
/// <typeparam name="T">The mapped type</typeparam>
19-
public static IStatement PrepareDeleteStatement<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping)
17+
public static IStatement PrepareDeleteStatement(this IDatabaseConnection This, TableMapping tableMapping)
2018
{
2119
Contract.Requires(This != null);
2220
Contract.Requires(tableMapping != null);
2321

2422
return This.PrepareDelete(tableMapping.TableName, tableMapping.PrimaryKeyColumn());
2523
}
2624

27-
private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys)
25+
private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(
26+
this IDatabaseConnection This,
27+
TableMapping tableMapping,
28+
IEnumerable<long> primaryKeys,
29+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
2830
{
2931
using (var deleteStmt = This.PrepareDeleteStatement(tableMapping))
3032
using (var findStmt = This.PrepareFindStatement(tableMapping))
@@ -35,7 +37,7 @@ private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(this IDatabas
3537
{
3638
deleteStmt.Execute(primaryKey);
3739
return x;
38-
}).FirstOrDefault();
40+
}).Select(resultSelector).FirstOrDefault();
3941
yield return new KeyValuePair<long,T>(primaryKey, result);
4042
}
4143
}
@@ -50,12 +52,17 @@ private static IEnumerable<KeyValuePair<long,T>> YieldDeleteAll<T>(this IDatabas
5052
/// <param name="primaryKey">A primary key.</param>
5153
/// <param name="deleted">If found in the database, the deleted object.</param>
5254
/// <typeparam name="T">The mapped type.</typeparam>
53-
public static bool TryDelete<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, long primaryKey, out T deleted)
55+
public static bool TryDelete<T>(
56+
this IDatabaseConnection This,
57+
TableMapping tableMapping,
58+
long primaryKey,
59+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
60+
out T deleted)
5461
{
5562
Contract.Requires(This != null);
5663
Contract.Requires(tableMapping != null);
5764

58-
var result = This.YieldDeleteAll(tableMapping, new long[] { primaryKey }).FirstOrDefault();
65+
var result = This.YieldDeleteAll(tableMapping, new long[] { primaryKey }, resultSelector).FirstOrDefault();
5966
if (result.Value != null)
6067
{
6168
deleted = result.Value;
@@ -76,18 +83,25 @@ public static bool TryDelete<T>(this IDatabaseConnection This, ITableMapping<T>
7683
/// <param name="tableMapping">The table mapping.</param>
7784
/// <param name="primaryKeys">An IEnumerable of primary keys to delete.</param>
7885
/// <typeparam name="T">The mapped type.</typeparam>
79-
public static IReadOnlyDictionary<long,T> DeleteAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys)
86+
public static IReadOnlyDictionary<long,T> DeleteAll<T>(
87+
this IDatabaseConnection This,
88+
TableMapping tableMapping,
89+
IEnumerable<long> primaryKeys,
90+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
8091
{
8192
Contract.Requires(This != null);
8293
Contract.Requires(tableMapping != null);
8394
Contract.Requires(primaryKeys != null);
8495

8596
return This.RunInTransaction(_ =>
86-
This.YieldDeleteAll(tableMapping, primaryKeys)
97+
This.YieldDeleteAll(tableMapping, primaryKeys, resultSelector)
8798
.Where(kvp => kvp.Value != null)
8899
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value));
89100
}
101+
}
90102

103+
public static partial class AsyncDatabaseConnection
104+
{
91105
/// <summary>
92106
/// Deletes all object instances specified by their primary keys.
93107
/// </summary>
@@ -97,13 +111,18 @@ public static IReadOnlyDictionary<long,T> DeleteAll<T>(this IDatabaseConnection
97111
/// <param name="primaryKeys">An IEnumerable of primary keys to delete.</param>
98112
/// <param name="ct">A cancellation token that can be used to cancel the operation.</param>
99113
/// <typeparam name="T">The mapped type.</typeparam>
100-
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys, CancellationToken ct)
114+
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(
115+
this IAsyncDatabaseConnection This,
116+
TableMapping tableMapping,
117+
IEnumerable<long> primaryKeys,
118+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
119+
CancellationToken ct)
101120
{
102121
Contract.Requires(This != null);
103122
Contract.Requires(tableMapping != null);
104123
Contract.Requires(primaryKeys != null);
105124

106-
return This.Use((db,_) => db.DeleteAll<T>(tableMapping, primaryKeys), ct);
125+
return This.Use((db,_) => db.DeleteAll<T>(tableMapping, primaryKeys, resultSelector), ct);
107126
}
108127

109128
/// <summary>
@@ -114,58 +133,17 @@ public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(this IAsyncDat
114133
/// <param name="tableMapping">The table mapping.</param>
115134
/// <param name="primaryKeys">An IEnumerable of primary keys to delete.</param>
116135
/// <typeparam name="T">The mapped type.</typeparam>
117-
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys)
136+
public static Task<IReadOnlyDictionary<long,T>> DeleteAllAsync<T>(
137+
this IAsyncDatabaseConnection This,
138+
TableMapping tableMapping,
139+
IEnumerable<long> primaryKeys,
140+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
118141
{
119142
Contract.Requires(This != null);
120143
Contract.Requires(tableMapping != null);
121144
Contract.Requires(primaryKeys != null);
122145

123-
return This.DeleteAllAsync(tableMapping, primaryKeys, CancellationToken.None);
124-
}
125-
126-
/// <summary>
127-
/// Deletes all rows in a given table.
128-
/// </summary>
129-
/// <param name="This">The database connection.</param>
130-
/// <param name="tableMapping">The table mapping.</param>
131-
/// <typeparam name="T">The mapped type.</typeparam>
132-
public static void DeleteAllRows<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping)
133-
{
134-
Contract.Requires(This != null);
135-
Contract.Requires(tableMapping != null);
136-
137-
This.DeleteAll(tableMapping.TableName);
138-
}
139-
140-
/// <summary>
141-
/// Deletes all rows in a given table, asynchronously.
142-
/// </summary>
143-
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
144-
/// <param name="This">The database connection.</param>
145-
/// <param name="tableMapping">he table mapping.</param>
146-
/// <param name="ct">A cancellation token that can be used to cancel the operation.</param>
147-
/// <typeparam name="T">The mapped type.</typeparam>
148-
public static Task DeleteAllRowsAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping, CancellationToken ct)
149-
{
150-
Contract.Requires(This != null);
151-
Contract.Requires(tableMapping != null);
152-
153-
return This.Use((db, _) => db.DeleteAllRows(tableMapping), ct);
154-
}
155-
156-
/// <summary>
157-
/// Deletes all rows in a given table, asynchronously.
158-
/// </summary>
159-
/// <returns>A task that completes when all rows are deleted succesfully.</returns>
160-
/// <param name="This">The database connection.</param>
161-
/// <param name="tableMapping">he table mapping.</param>
162-
/// <typeparam name="T">The mapped type.</typeparam>
163-
public static Task DeleteAllRowsAsync<T>(this IAsyncDatabaseConnection This, ITableMapping<T> tableMapping)
164-
{
165-
Contract.Requires(This != null);
166-
Contract.Requires(tableMapping != null);
167-
168-
return This.DeleteAllRowsAsync(tableMapping, CancellationToken.None);
146+
return This.DeleteAllAsync(tableMapping, primaryKeys, resultSelector, CancellationToken.None);
169147
}
170148
}
171149
}

SQLitePCL.pretty.Orm/TableMapping.Find.cs renamed to SQLitePCL.pretty.Orm/DatabaseConnection.Find.cs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
namespace SQLitePCL.pretty.Orm
1010
{
11-
public static partial class TableMapping
11+
public static partial class DatabaseConnection
1212
{
13-
private static readonly ConditionalWeakTable<ITableMapping, string> find =
14-
new ConditionalWeakTable<ITableMapping, string>();
13+
private static readonly ConditionalWeakTable<TableMapping, string> find =
14+
new ConditionalWeakTable<TableMapping, string>();
1515

16-
private static string Find(this ITableMapping This)
16+
private static string Find(this TableMapping This)
1717
{
1818
return find.GetValue(This, mapping =>
1919
{
@@ -28,22 +28,25 @@ private static string Find(this ITableMapping This)
2828
/// <returns>A prepared statement.</returns>
2929
/// <param name="This">The database connection</param>
3030
/// <param name="tableMapping">The table mapping.</param>
31-
/// <typeparam name="T">The mapped type</typeparam>
32-
public static ITableMappedStatement<T> PrepareFindStatement<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping)
31+
public static IStatement PrepareFindStatement(this IDatabaseConnection This, TableMapping tableMapping)
3332
{
3433
Contract.Requires(This != null);
3534
Contract.Requires(tableMapping != null);
3635

37-
return new TableMappedStatement<T>(This.PrepareStatement(tableMapping.Find()), tableMapping);
36+
return This.PrepareStatement(tableMapping.Find());
3837
}
3938

40-
private static IEnumerable<KeyValuePair<long,T>> YieldFindAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys)
39+
private static IEnumerable<KeyValuePair<long,T>> YieldFindAll<T>(
40+
this IDatabaseConnection This,
41+
TableMapping tableMapping,
42+
IEnumerable<long> primaryKeys,
43+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
4144
{
4245
using (var findStmt = This.PrepareFindStatement(tableMapping))
4346
{
4447
foreach (var primaryKey in primaryKeys)
4548
{
46-
var result = findStmt.Query(primaryKey).FirstOrDefault();
49+
var result = findStmt.Query(primaryKey).Select(resultSelector).FirstOrDefault();
4750
yield return new KeyValuePair<long,T>(primaryKey, result);
4851
}
4952
}
@@ -58,12 +61,17 @@ private static IEnumerable<KeyValuePair<long,T>> YieldFindAll<T>(this IDatabaseC
5861
/// <param name="primaryKey">A primary key.</param>
5962
/// <param name="value">If found in the database, the found object.</param>
6063
/// <typeparam name="T">The mapped type.</typeparam>
61-
public static bool TryFind<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, long primaryKey, out T value)
64+
public static bool TryFind<T>(
65+
this IDatabaseConnection This,
66+
TableMapping tableMapping,
67+
long primaryKey,
68+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
69+
out T value)
6270
{
6371
Contract.Requires(This != null);
6472
Contract.Requires(tableMapping != null);
6573

66-
var result = This.YieldFindAll(tableMapping, new long[] { primaryKey }).FirstOrDefault();
74+
var result = This.YieldFindAll(tableMapping, new long[] { primaryKey }, resultSelector).FirstOrDefault();
6775

6876
if (result.Value != null)
6977
{
@@ -83,17 +91,24 @@ public static bool TryFind<T>(this IDatabaseConnection This, ITableMapping<T> ta
8391
/// <param name="tableMapping">The table mapping.</param>
8492
/// <param name="primaryKeys">An IEnumerable of primary keys to find.</param>
8593
/// <typeparam name="T">The mapped type.</typeparam>
86-
public static IReadOnlyDictionary<long,T> FindAll<T>(this IDatabaseConnection This, ITableMapping<T> tableMapping, IEnumerable<long> primaryKeys)
94+
public static IReadOnlyDictionary<long,T> FindAll<T>(
95+
this IDatabaseConnection This,
96+
TableMapping tableMapping,
97+
IEnumerable<long> primaryKeys,
98+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
8799
{
88100
Contract.Requires(This != null);
89101
Contract.Requires(tableMapping != null);
90102
Contract.Requires(primaryKeys != null);
91103

92-
return This.YieldFindAll(tableMapping, primaryKeys)
104+
return This.YieldFindAll(tableMapping, primaryKeys, resultSelector)
93105
.Where(kvp => kvp.Value != null)
94106
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
95107
}
108+
}
96109

110+
public static partial class AsyncDatabaseConnection
111+
{
97112
/// <summary>
98113
/// Finds all object instances specified by their primary keys.
99114
/// </summary>
@@ -105,15 +120,16 @@ public static IReadOnlyDictionary<long,T> FindAll<T>(this IDatabaseConnection Th
105120
/// <typeparam name="T">The mapped type.</typeparam>
106121
public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
107122
this IAsyncDatabaseConnection This,
108-
ITableMapping<T> tableMapping,
123+
TableMapping tableMapping,
109124
IEnumerable<long> primaryKeys,
125+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector,
110126
CancellationToken ct)
111127
{
112128
Contract.Requires(This != null);
113129
Contract.Requires(tableMapping != null);
114130
Contract.Requires(primaryKeys != null);
115131

116-
return This.Use((db,_) => db.FindAll(tableMapping, primaryKeys), ct);
132+
return This.Use((db,_) => db.FindAll(tableMapping, primaryKeys, resultSelector), ct);
117133
}
118134

119135
/// <summary>
@@ -126,14 +142,15 @@ public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
126142
/// <typeparam name="T">The mapped type.</typeparam>
127143
public static Task<IReadOnlyDictionary<long,T>> FindAllAsync<T>(
128144
this IAsyncDatabaseConnection This,
129-
ITableMapping<T> tableMapping,
130-
IEnumerable<long> primaryKeys)
145+
TableMapping tableMapping,
146+
IEnumerable<long> primaryKeys,
147+
Func<IReadOnlyList<IResultSetValue>,T> resultSelector)
131148
{
132149
Contract.Requires(This != null);
133150
Contract.Requires(tableMapping != null);
134151
Contract.Requires(primaryKeys != null);
135152

136-
return This.FindAllAsync(tableMapping, primaryKeys, CancellationToken.None);
153+
return This.FindAllAsync(tableMapping, primaryKeys, resultSelector, CancellationToken.None);
137154
}
138155
}
139156
}

0 commit comments

Comments
 (0)