* AVIMConversationQuery.cs: chore: 抽象 QueryCondition

* AVQuery.cs:
* AVRelation.cs:
* AVQueryExtensions.cs:
* AVQueryExtensions.cs:
* QueryCompositionalCondition.cs:
oneRain 2019-09-16 18:25:05 +08:00
parent 6252a06b72
commit 06707f75fe
6 changed files with 99 additions and 128 deletions

View File

@ -12,7 +12,7 @@ namespace LeanCloud.Realtime
/// <summary> /// <summary>
/// 对话查询类 /// 对话查询类
/// </summary> /// </summary>
public class AVIMConversationQuery : AVQuery<AVObject> public class AVIMConversationQuery
{ {
internal AVIMClient CurrentClient { get; set; } internal AVIMClient CurrentClient { get; set; }
internal AVIMConversationQuery(AVIMClient _currentClient) internal AVIMConversationQuery(AVIMClient _currentClient)

View File

@ -1,4 +1,7 @@
using System.Collections.Generic; using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace LeanCloud.Storage.Internal { namespace LeanCloud.Storage.Internal {
internal class QueryCompositionalCondition : IQueryCondition { internal class QueryCompositionalCondition : IQueryCondition {
@ -8,9 +11,18 @@ namespace LeanCloud.Storage.Internal {
readonly List<IQueryCondition> conditions; readonly List<IQueryCondition> conditions;
readonly string composition; readonly string composition;
internal ReadOnlyCollection<string> orderBy;
internal HashSet<string> includes;
internal HashSet<string> selectedKeys;
internal string redirectClassNameForKey;
internal int skip;
internal int limit;
internal QueryCompositionalCondition(string composition = AND) { internal QueryCompositionalCondition(string composition = AND) {
conditions = new List<IQueryCondition>(); conditions = new List<IQueryCondition>();
this.composition = composition; this.composition = composition;
skip = 0;
limit = 30;
} }
public bool Equals(IQueryCondition other) { public bool Equals(IQueryCondition other) {
@ -33,6 +45,73 @@ namespace LeanCloud.Storage.Internal {
}; };
} }
/// <summary>
/// 构建查询字符串
/// </summary>
/// <returns></returns>
public IDictionary<string, object> BuildParameters(string className) {
Dictionary<string, object> result = new Dictionary<string, object>();
if (conditions != null) {
result["where"] = ToJSON();
}
if (orderBy != null) {
result["order"] = string.Join(",", orderBy.ToArray());
}
if (includes != null) {
result["include"] = string.Join(",", includes.ToArray());
}
if (selectedKeys != null) {
result["keys"] = string.Join(",", selectedKeys.ToArray());
}
if (!string.IsNullOrEmpty(className)) {
result["className"] = className;
}
if (redirectClassNameForKey != null) {
result["redirectClassNameForKey"] = redirectClassNameForKey;
}
result["skip"] = skip;
result["limit"] = limit;
return result;
}
internal void OrderBy(string key) {
orderBy = new ReadOnlyCollection<string>(new List<string> { key });
}
internal void OrderByDescending(string key) {
orderBy = new ReadOnlyCollection<string>(new List<string> { "-" + key });
}
internal void Include(string key) {
if (includes == null) {
includes = new HashSet<string>();
}
try {
includes.Add(key);
} catch (Exception e) {
AVClient.PrintLog(e.Message);
}
}
internal void Select(string key) {
if (selectedKeys == null) {
selectedKeys = new HashSet<string>();
}
try {
selectedKeys.Add(key);
} catch (Exception e) {
AVClient.PrintLog(e.Message);
}
}
internal void Skip(int count) {
skip = count;
}
internal void Limit(int count) {
limit = count;
}
internal void AddCondition(IQueryCondition condition) { internal void AddCondition(IQueryCondition condition) {
if (condition == null) { if (condition == null) {
return; return;

View File

@ -17,10 +17,6 @@ namespace LeanCloud.Storage.Internal {
return query.ClassName; return query.ClassName;
} }
public static IDictionary<string, object> BuildParameters<T>(this AVQuery<T> query) where T: AVObject {
return query.BuildParameters(false);
}
public static object GetConstraint<T>(this AVQuery<T> query, string key) where T : AVObject { public static object GetConstraint<T>(this AVQuery<T> query, string key) where T : AVObject {
return query.GetConstraint(key); return query.GetConstraint(key);
} }

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
@ -31,13 +30,6 @@ namespace LeanCloud {
internal QueryCompositionalCondition condition; internal QueryCompositionalCondition condition;
internal ReadOnlyCollection<string> orderBy;
internal ReadOnlyCollection<string> includes;
internal ReadOnlyCollection<string> selectedKeys;
internal string redirectClassNameForKey;
internal int? skip;
internal int? limit;
internal static AVQueryController QueryController { internal static AVQueryController QueryController {
get { get {
return AVPlugins.Instance.QueryController; return AVPlugins.Instance.QueryController;
@ -121,12 +113,9 @@ namespace LeanCloud {
} }
public virtual async Task<T> GetAsync(string objectId, CancellationToken cancellationToken) { public virtual async Task<T> GetAsync(string objectId, CancellationToken cancellationToken) {
AVQuery<T> singleItemQuery = new AVQuery<T>(ClassName) WhereEqualTo("objectId", objectId);
.WhereEqualTo("objectId", objectId); Limit(1);
singleItemQuery.includes = includes; var result = await FindAsync(cancellationToken);
singleItemQuery.selectedKeys = selectedKeys;
singleItemQuery.limit = 1;
var result = await singleItemQuery.FindAsync(cancellationToken);
var first = result.FirstOrDefault(); var first = result.FirstOrDefault();
if (first == null) { if (first == null) {
throw new AVException(AVException.ErrorCode.ObjectNotFound, throw new AVException(AVException.ErrorCode.ObjectNotFound,
@ -179,40 +168,6 @@ namespace LeanCloud {
#endregion #endregion
/// <summary>
/// 构建查询字符串
/// </summary>
/// <param name="includeClassName">是否包含 ClassName </param>
/// <returns></returns>
public IDictionary<string, object> BuildParameters(bool includeClassName = false) {
Dictionary<string, object> result = new Dictionary<string, object>();
if (condition != null) {
result["where"] = condition.ToJSON();
}
if (orderBy != null) {
result["order"] = string.Join(",", orderBy.ToArray());
}
if (skip != null) {
result["skip"] = skip.Value;
}
if (limit != null) {
result["limit"] = limit.Value;
}
if (includes != null) {
result["include"] = string.Join(",", includes.ToArray());
}
if (selectedKeys != null) {
result["keys"] = string.Join(",", selectedKeys.ToArray());
}
if (includeClassName) {
result["className"] = ClassName;
}
if (redirectClassNameForKey != null) {
result["redirectClassNameForKey"] = redirectClassNameForKey;
}
return result;
}
/// <summary> /// <summary>
/// Determines whether the specified object is equal to the current object. /// Determines whether the specified object is equal to the current object.
/// </summary> /// </summary>
@ -225,12 +180,7 @@ namespace LeanCloud {
var other = obj as AVQuery<T>; var other = obj as AVQuery<T>;
return ClassName.Equals(other.ClassName) && return ClassName.Equals(other.ClassName) &&
condition.Equals(other.condition) && condition.Equals(other.condition);
orderBy.CollectionsEqual(other.orderBy) &&
includes.CollectionsEqual(other.includes) &&
selectedKeys.CollectionsEqual(other.selectedKeys) &&
Equals(skip, other.skip) &&
Equals(limit, other.limit);
} }
public override int GetHashCode() { public override int GetHashCode() {
@ -240,59 +190,34 @@ namespace LeanCloud {
#region Order By #region Order By
public AVQuery<T> OrderBy(string key) { public AVQuery<T> OrderBy(string key) {
orderBy = new ReadOnlyCollection<string>(new List<string> { key }); condition.OrderBy(key);
return this; return this;
} }
public AVQuery<T> OrderByDescending(string key) { public AVQuery<T> OrderByDescending(string key) {
orderBy = new ReadOnlyCollection<string>(new List<string> { "-" + key }); condition.OrderByDescending(key);
return this;
}
public AVQuery<T> ThenBy(string key) {
if (orderBy == null) {
throw new ArgumentException("You must call OrderBy before calling ThenBy");
}
List<string> newOrderBy = orderBy.ToList();
newOrderBy.Add(key);
orderBy = new ReadOnlyCollection<string>(newOrderBy);
return this;
}
public AVQuery<T> ThenByDescending(string key) {
if (orderBy == null) {
throw new ArgumentException("You must call OrderBy before calling ThenBy");
}
List<string> newOrderBy = orderBy.ToList();
newOrderBy.Add($"-{key}");
orderBy = new ReadOnlyCollection<string>(newOrderBy);
return this; return this;
} }
#endregion #endregion
public AVQuery<T> Include(string key) { public AVQuery<T> Include(string key) {
includes = new ReadOnlyCollection<string>(new List<string> { key }); condition.Include(key);
return this; return this;
} }
public AVQuery<T> Select(string key) { public AVQuery<T> Select(string key) {
selectedKeys = new ReadOnlyCollection<string>(new List<string> { key }); condition.Select(key);
return this; return this;
} }
public AVQuery<T> Skip(int count) { public AVQuery<T> Skip(int count) {
skip = count; condition.Skip(count);
return this; return this;
} }
public AVQuery<T> Limit(int count) { public AVQuery<T> Limit(int count) {
limit = count; condition.Limit(count);
return this;
}
internal AVQuery<T> RedirectClassName(string key) {
redirectClassNameForKey = key;
return this; return this;
} }
@ -320,7 +245,7 @@ namespace LeanCloud {
public AVQuery<T> WhereDoesNotMatchQuery<TOther>(string key, AVQuery<TOther> query) public AVQuery<T> WhereDoesNotMatchQuery<TOther>(string key, AVQuery<TOther> query)
where TOther : AVObject { where TOther : AVObject {
AddCondition(key, "$notInQuery", query.BuildParameters(true)); AddCondition(key, "$notInQuery", query.BuildParameters(query.ClassName));
return this; return this;
} }
@ -389,7 +314,7 @@ namespace LeanCloud {
public AVQuery<T> WhereMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query) public AVQuery<T> WhereMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query)
where TOther : AVObject { where TOther : AVObject {
var parameters = new Dictionary<string, object> { var parameters = new Dictionary<string, object> {
{ "query", query.BuildParameters(true)}, { "query", query.BuildParameters(query.ClassName)},
{ "key", keyInQuery} { "key", keyInQuery}
}; };
AddCondition(key, "$select", parameters); AddCondition(key, "$select", parameters);
@ -399,7 +324,7 @@ namespace LeanCloud {
public AVQuery<T> WhereDoesNotMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query) public AVQuery<T> WhereDoesNotMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query)
where TOther : AVObject { where TOther : AVObject {
var parameters = new Dictionary<string, object> { var parameters = new Dictionary<string, object> {
{ "query", query.BuildParameters(true)}, { "query", query.BuildParameters(query.ClassName)},
{ "key", keyInQuery} { "key", keyInQuery}
}; };
AddCondition(key, "$dontSelect", parameters); AddCondition(key, "$dontSelect", parameters);
@ -408,7 +333,7 @@ namespace LeanCloud {
public AVQuery<T> WhereMatchesQuery<TOther>(string key, AVQuery<TOther> query) public AVQuery<T> WhereMatchesQuery<TOther>(string key, AVQuery<TOther> query)
where TOther : AVObject { where TOther : AVObject {
AddCondition(key, "$inQuery", query.BuildParameters(true)); AddCondition(key, "$inQuery", query.BuildParameters(query.ClassName));
return this; return this;
} }
@ -453,6 +378,10 @@ namespace LeanCloud {
#endregion #endregion
internal IDictionary<string, object> BuildParameters(string className = null) {
return condition.BuildParameters(className);
}
private string RegexQuote(string input) { private string RegexQuote(string input) {
return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E"; return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E";
} }

View File

@ -703,38 +703,6 @@ namespace LeanCloud
return source.OrderByDescending(GetOrderByPath(keySelector)); return source.OrderByDescending(GetOrderByPath(keySelector));
} }
/// <summary>
/// Performs a subsequent ordering of a query based upon the key selector provided.
/// </summary>
/// <typeparam name="TSource">The type of AVObject being queried for.</typeparam>
/// <typeparam name="TSelector">The type of key returned by keySelector.</typeparam>
/// <param name="source">The query to order.</param>
/// <param name="keySelector">A function to extract a key from the AVObject.</param>
/// <returns>A new AVQuery based on Source whose results will be ordered by
/// the key specified in the keySelector.</returns>
public static AVQuery<TSource> ThenBy<TSource, TSelector>(
this AVQuery<TSource> source, Expression<Func<TSource, TSelector>> keySelector)
where TSource : AVObject
{
return source.ThenBy(GetOrderByPath(keySelector));
}
/// <summary>
/// Performs a subsequent ordering of a query based upon the key selector provided.
/// </summary>
/// <typeparam name="TSource">The type of AVObject being queried for.</typeparam>
/// <typeparam name="TSelector">The type of key returned by keySelector.</typeparam>
/// <param name="source">The query to order.</param>
/// <param name="keySelector">A function to extract a key from the AVObject.</param>
/// <returns>A new AVQuery based on Source whose results will be ordered by
/// the key specified in the keySelector.</returns>
public static AVQuery<TSource> ThenByDescending<TSource, TSelector>(
this AVQuery<TSource> source, Expression<Func<TSource, TSelector>> keySelector)
where TSource : AVObject
{
return source.ThenByDescending(GetOrderByPath(keySelector));
}
/// <summary> /// <summary>
/// Correlates the elements of two queries based on matching keys. /// Correlates the elements of two queries based on matching keys.
/// </summary> /// </summary>

View File

@ -63,7 +63,6 @@ namespace LeanCloud {
} }
return new AVQuery<T>(parent.ClassName) return new AVQuery<T>(parent.ClassName)
.RedirectClassName(key)
.WhereRelatedTo(parent, key); .WhereRelatedTo(parent, key);
} }