* AVQueryController.cs: chore: 简化 AVQuery 逻辑,将查询条件逻辑转移至
QueryCondition * AVQuery.cs: * IQueryCondition.cs: * QueryEqualCondition.cs: * AVQueryExtensions.cs: * QueryCompositionalCondition.cs:
parent
06707f75fe
commit
3f57be22a2
|
@ -7,16 +7,13 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class AVQueryController {
|
||||
public async Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query, AVUser user,
|
||||
CancellationToken cancellationToken) where T : AVObject {
|
||||
public async Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
||||
return from item in items
|
||||
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance);
|
||||
}
|
||||
|
||||
public async Task<int> CountAsync<T>(AVQuery<T> query,
|
||||
AVUser user,
|
||||
CancellationToken cancellationToken) where T : AVObject {
|
||||
public async Task<int> CountAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||
var parameters = query.BuildParameters();
|
||||
parameters["limit"] = 0;
|
||||
parameters["count"] = 1;
|
||||
|
@ -24,9 +21,7 @@ namespace LeanCloud.Storage.Internal {
|
|||
return Convert.ToInt32(ret);
|
||||
}
|
||||
|
||||
public async Task<IObjectState> FirstAsync<T>(AVQuery<T> query,
|
||||
AVUser user,
|
||||
CancellationToken cancellationToken) where T : AVObject {
|
||||
public async Task<IObjectState> FirstAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||
var parameters = query.BuildParameters();
|
||||
parameters["limit"] = 1;
|
||||
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
using System;
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public interface IQueryCondition : IEquatable<IQueryCondition>, IJsonConvertible {
|
||||
/// <summary>
|
||||
/// 查询条件接口
|
||||
/// IEquatable<IQueryCondition> 用于比对(替换)相同的查询条件
|
||||
/// IJsonConvertible 用于生成序列化 Dictionary
|
||||
/// </summary>
|
||||
internal interface IQueryCondition : IEquatable<IQueryCondition>, IJsonConvertible {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
internal class QueryCompositionalCondition : IQueryCondition {
|
||||
|
@ -11,10 +11,9 @@ namespace LeanCloud.Storage.Internal {
|
|||
readonly List<IQueryCondition> conditions;
|
||||
readonly string composition;
|
||||
|
||||
internal ReadOnlyCollection<string> orderBy;
|
||||
internal List<string> orderBy;
|
||||
internal HashSet<string> includes;
|
||||
internal HashSet<string> selectedKeys;
|
||||
internal string redirectClassNameForKey;
|
||||
internal int skip;
|
||||
internal int limit;
|
||||
|
||||
|
@ -25,6 +24,8 @@ namespace LeanCloud.Storage.Internal {
|
|||
limit = 30;
|
||||
}
|
||||
|
||||
#region IQueryCondition
|
||||
|
||||
public bool Equals(IQueryCondition other) {
|
||||
return false;
|
||||
}
|
||||
|
@ -45,41 +46,149 @@ 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;
|
||||
#endregion
|
||||
|
||||
#region where
|
||||
|
||||
public void WhereContainedIn<T>(string key, IEnumerable<T> values) {
|
||||
AddCondition(key, "$in", values.ToList());
|
||||
}
|
||||
|
||||
public void WhereContainsAll<T>(string key, IEnumerable<T> values) {
|
||||
AddCondition(key, "$all", values.ToList());
|
||||
}
|
||||
|
||||
public void WhereContains(string key, string substring) {
|
||||
AddCondition(key, "$regex", RegexQuote(substring));
|
||||
}
|
||||
|
||||
public void WhereDoesNotExist(string key) {
|
||||
AddCondition(key, "$exists", false);
|
||||
}
|
||||
|
||||
public void WhereDoesNotMatchQuery<T>(string key, AVQuery<T> query) where T : AVObject {
|
||||
AddCondition(key, "$notInQuery", query.BuildParameters(query.ClassName));
|
||||
}
|
||||
|
||||
public void WhereEndsWith(string key, string suffix) {
|
||||
AddCondition(key, "$regex", RegexQuote(suffix) + "$");
|
||||
}
|
||||
|
||||
public void WhereEqualTo(string key, object value) {
|
||||
AddCondition(new QueryEqualCondition(key, value));
|
||||
}
|
||||
|
||||
public void WhereSizeEqualTo(string key, uint size) {
|
||||
AddCondition(key, "$size", size);
|
||||
}
|
||||
|
||||
public void WhereExists(string key) {
|
||||
AddCondition(key, "$exists", true);
|
||||
}
|
||||
|
||||
public void WhereGreaterThan(string key, object value) {
|
||||
AddCondition(key, "$gt", value);
|
||||
}
|
||||
|
||||
public void WhereGreaterThanOrEqualTo(string key, object value) {
|
||||
AddCondition(key, "$gte", value);
|
||||
}
|
||||
|
||||
public void WhereLessThan(string key, object value) {
|
||||
AddCondition(key, "$lt", value);
|
||||
}
|
||||
|
||||
public void WhereLessThanOrEqualTo(string key, object value) {
|
||||
AddCondition(key, "$lte", value);
|
||||
}
|
||||
|
||||
public void WhereMatches(string key, Regex regex, string modifiers) {
|
||||
if (!regex.Options.HasFlag(RegexOptions.ECMAScript)) {
|
||||
throw new ArgumentException(
|
||||
"Only ECMAScript-compatible regexes are supported. Please use the ECMAScript RegexOptions flag when creating your regex.");
|
||||
}
|
||||
AddCondition(key, "$regex", regex.ToString());
|
||||
AddCondition(key, "options", modifiers);
|
||||
}
|
||||
|
||||
public void WhereMatches(string key, Regex regex) {
|
||||
WhereMatches(key, regex, null);
|
||||
}
|
||||
|
||||
public void WhereMatches(string key, string pattern, string modifiers) {
|
||||
WhereMatches(key, new Regex(pattern, RegexOptions.ECMAScript), modifiers);
|
||||
}
|
||||
|
||||
public void WhereMatches(string key, string pattern) {
|
||||
WhereMatches(key, pattern, null);
|
||||
}
|
||||
|
||||
public void WhereMatchesKeyInQuery<T>(string key, string keyInQuery, AVQuery<T> query) where T : AVObject {
|
||||
var parameters = new Dictionary<string, object> {
|
||||
{ "query", query.BuildParameters(query.ClassName)},
|
||||
{ "key", keyInQuery}
|
||||
};
|
||||
AddCondition(key, "$select", parameters);
|
||||
}
|
||||
|
||||
public void WhereDoesNotMatchesKeyInQuery<T>(string key, string keyInQuery, AVQuery<T> query) where T : AVObject {
|
||||
var parameters = new Dictionary<string, object> {
|
||||
{ "query", query.BuildParameters(query.ClassName)},
|
||||
{ "key", keyInQuery}
|
||||
};
|
||||
AddCondition(key, "$dontSelect", parameters);
|
||||
}
|
||||
|
||||
public void WhereMatchesQuery<T>(string key, AVQuery<T> query) where T : AVObject {
|
||||
AddCondition(key, "$inQuery", query.BuildParameters(query.ClassName));
|
||||
}
|
||||
|
||||
public void WhereNear(string key, AVGeoPoint point) {
|
||||
AddCondition(key, "$nearSphere", point);
|
||||
}
|
||||
|
||||
public void WhereNotContainedIn<T>(string key, IEnumerable<T> values) {
|
||||
AddCondition(key, "$nin", values.ToList());
|
||||
}
|
||||
|
||||
public void WhereNotEqualTo(string key, object value) {
|
||||
AddCondition(key, "$ne", value);
|
||||
}
|
||||
|
||||
public void WhereStartsWith(string key, string suffix) {
|
||||
AddCondition(key, "$regex", "^" + RegexQuote(suffix));
|
||||
}
|
||||
|
||||
public void WhereWithinGeoBox(string key, AVGeoPoint southwest, AVGeoPoint northeast) {
|
||||
Dictionary<string, object> value = new Dictionary<string, object> {
|
||||
{ "$box", new[] { southwest, northeast } }
|
||||
};
|
||||
AddCondition(key, "$within", value);
|
||||
}
|
||||
|
||||
public void WhereWithinDistance(string key, AVGeoPoint point, AVGeoDistance maxDistance) {
|
||||
AddCondition(key, "$nearSphere", point);
|
||||
AddCondition(key, "$maxDistance", maxDistance.Radians);
|
||||
}
|
||||
|
||||
public void WhereRelatedTo(AVObject parent, string key) {
|
||||
AddCondition(new QueryRelatedCondition(parent, key));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal void OrderBy(string key) {
|
||||
orderBy = new ReadOnlyCollection<string>(new List<string> { key });
|
||||
if (orderBy == null) {
|
||||
orderBy = new List<string>();
|
||||
}
|
||||
orderBy.Add(key);
|
||||
}
|
||||
|
||||
internal void OrderByDescending(string key) {
|
||||
orderBy = new ReadOnlyCollection<string>(new List<string> { "-" + key });
|
||||
if (orderBy == null) {
|
||||
orderBy = new List<string>();
|
||||
}
|
||||
orderBy.Add($"-{key}");
|
||||
}
|
||||
|
||||
internal void Include(string key) {
|
||||
|
@ -112,6 +221,15 @@ namespace LeanCloud.Storage.Internal {
|
|||
limit = count;
|
||||
}
|
||||
|
||||
internal void AddCondition(string key, string op, object value) {
|
||||
QueryOperationCondition cond = new QueryOperationCondition {
|
||||
Key = key,
|
||||
Op = op,
|
||||
Value = value
|
||||
};
|
||||
AddCondition(cond);
|
||||
}
|
||||
|
||||
internal void AddCondition(IQueryCondition condition) {
|
||||
if (condition == null) {
|
||||
return;
|
||||
|
@ -122,5 +240,35 @@ namespace LeanCloud.Storage.Internal {
|
|||
});
|
||||
conditions.Add(condition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构建查询字符串
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal 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;
|
||||
}
|
||||
result["skip"] = skip;
|
||||
result["limit"] = limit;
|
||||
return result;
|
||||
}
|
||||
|
||||
string RegexQuote(string input) {
|
||||
return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
public class QueryEqualCondition : IQueryCondition {
|
||||
internal class QueryEqualCondition : IQueryCondition {
|
||||
string key;
|
||||
object value;
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace LeanCloud.Storage.Internal {
|
||||
/// <summary>
|
||||
/// So here's the deal. We have a lot of internal APIs for AVObject, AVUser, etc.
|
||||
///
|
||||
/// These cannot be 'internal' anymore if we are fully modularizing things out, because
|
||||
/// they are no longer a part of the same library, especially as we create things like
|
||||
/// Installation inside push library.
|
||||
///
|
||||
/// So this class contains a bunch of extension methods that can live inside another
|
||||
/// namespace, which 'wrap' the intenral APIs that already exist.
|
||||
/// </summary>
|
||||
public static class AVQueryExtensions {
|
||||
public static string GetClassName<T>(this AVQuery<T> query) where T: AVObject {
|
||||
return query.ClassName;
|
||||
}
|
||||
|
||||
public static object GetConstraint<T>(this AVQuery<T> query, string key) where T : AVObject {
|
||||
return query.GetConstraint(key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,20 +30,14 @@ namespace LeanCloud {
|
|||
|
||||
internal QueryCompositionalCondition condition;
|
||||
|
||||
internal static AVQueryController QueryController {
|
||||
static AVQueryController QueryController {
|
||||
get {
|
||||
return AVPlugins.Instance.QueryController;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ObjectSubclassingController SubclassingController {
|
||||
get {
|
||||
return AVPlugins.Instance.SubclassingController;
|
||||
}
|
||||
}
|
||||
|
||||
public AVQuery()
|
||||
: this(SubclassingController.GetClassName(typeof(T))) {
|
||||
: this(AVPlugins.Instance.SubclassingController.GetClassName(typeof(T))) {
|
||||
}
|
||||
|
||||
public AVQuery(string className) {
|
||||
|
@ -54,6 +48,8 @@ namespace LeanCloud {
|
|||
condition = new QueryCompositionalCondition();
|
||||
}
|
||||
|
||||
#region Composition
|
||||
|
||||
public static AVQuery<T> And(IEnumerable<AVQuery<T>> queries) {
|
||||
AVQuery<T> composition = new AVQuery<T>();
|
||||
string className = null;
|
||||
|
@ -62,7 +58,7 @@ namespace LeanCloud {
|
|||
if (className != null && className != query.ClassName) {
|
||||
throw new ArgumentException("All of the queries in an or query must be on the same class.");
|
||||
}
|
||||
composition.AddCondition(query.condition);
|
||||
composition.condition.AddCondition(query.condition);
|
||||
className = query.ClassName;
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +76,7 @@ namespace LeanCloud {
|
|||
if (className != null && className != query.ClassName) {
|
||||
throw new ArgumentException("All of the queries in an or query must be on the same class.");
|
||||
}
|
||||
composition.AddCondition(query.condition);
|
||||
composition.condition.AddCondition(query.condition);
|
||||
className = query.ClassName;
|
||||
}
|
||||
}
|
||||
|
@ -88,14 +84,16 @@ namespace LeanCloud {
|
|||
return composition;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual async Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default) {
|
||||
IEnumerable<IObjectState> states = await QueryController.FindAsync(this, AVUser.CurrentUser, cancellationToken);
|
||||
IEnumerable<IObjectState> states = await QueryController.FindAsync(this, cancellationToken);
|
||||
return (from state in states
|
||||
select AVObject.FromState<T>(state, ClassName));
|
||||
}
|
||||
|
||||
public virtual async Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default) {
|
||||
IObjectState state = await QueryController.FirstAsync<T>(this, AVUser.CurrentUser, cancellationToken);
|
||||
IObjectState state = await QueryController.FirstAsync<T>(this, cancellationToken);
|
||||
return state == null ? default : AVObject.FromState<T>(state, ClassName);
|
||||
}
|
||||
|
||||
|
@ -109,7 +107,7 @@ namespace LeanCloud {
|
|||
}
|
||||
|
||||
public virtual Task<int> CountAsync(CancellationToken cancellationToken = default) {
|
||||
return QueryController.CountAsync(this, AVUser.CurrentUser, cancellationToken);
|
||||
return QueryController.CountAsync(this, cancellationToken);
|
||||
}
|
||||
|
||||
public virtual async Task<T> GetAsync(string objectId, CancellationToken cancellationToken) {
|
||||
|
@ -224,78 +222,72 @@ namespace LeanCloud {
|
|||
#region Where
|
||||
|
||||
public AVQuery<T> WhereContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
||||
AddCondition(key, "$in", values.ToList());
|
||||
condition.WhereContainedIn(key, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereContainsAll<TIn>(string key, IEnumerable<TIn> values) {
|
||||
AddCondition(key, "$all", values.ToList());
|
||||
condition.WhereContainsAll(key, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereContains(string key, string substring) {
|
||||
AddCondition(key, "$regex", RegexQuote(substring));
|
||||
condition.WhereContains(key, substring);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereDoesNotExist(string key) {
|
||||
AddCondition(key, "$exists", false);
|
||||
condition.WhereDoesNotExist(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereDoesNotMatchQuery<TOther>(string key, AVQuery<TOther> query)
|
||||
where TOther : AVObject {
|
||||
AddCondition(key, "$notInQuery", query.BuildParameters(query.ClassName));
|
||||
public AVQuery<T> WhereDoesNotMatchQuery<TOther>(string key, AVQuery<TOther> query) where TOther : AVObject {
|
||||
condition.WhereDoesNotMatchQuery(key, query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereEndsWith(string key, string suffix) {
|
||||
AddCondition(key, "$regex", RegexQuote(suffix) + "$");
|
||||
condition.WhereEndsWith(key, suffix);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereEqualTo(string key, object value) {
|
||||
AddCondition(new QueryEqualCondition(key, value));
|
||||
condition.WhereEqualTo(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereSizeEqualTo(string key, uint size) {
|
||||
AddCondition(key, "$size", size);
|
||||
condition.WhereSizeEqualTo(key, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereExists(string key) {
|
||||
AddCondition(key, "$exists", true);
|
||||
condition.WhereExists(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereGreaterThan(string key, object value) {
|
||||
AddCondition(key, "$gt", value);
|
||||
condition.WhereGreaterThan(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereGreaterThanOrEqualTo(string key, object value) {
|
||||
AddCondition(key, "$gte", value);
|
||||
condition.WhereGreaterThanOrEqualTo(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereLessThan(string key, object value) {
|
||||
AddCondition(key, "$lt", value);
|
||||
condition.WhereLessThan(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereLessThanOrEqualTo(string key, object value) {
|
||||
AddCondition(key, "$lte", value);
|
||||
condition.WhereLessThanOrEqualTo(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereMatches(string key, Regex regex, string modifiers) {
|
||||
if (!regex.Options.HasFlag(RegexOptions.ECMAScript)) {
|
||||
throw new ArgumentException(
|
||||
"Only ECMAScript-compatible regexes are supported. Please use the ECMAScript RegexOptions flag when creating your regex.");
|
||||
}
|
||||
AddCondition(key, "$regex", regex.ToString());
|
||||
AddCondition(key, "options", modifiers);
|
||||
condition.WhereMatches(key, regex, modifiers);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -311,68 +303,53 @@ namespace LeanCloud {
|
|||
return WhereMatches(key, pattern, null);
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query)
|
||||
where TOther : AVObject {
|
||||
var parameters = new Dictionary<string, object> {
|
||||
{ "query", query.BuildParameters(query.ClassName)},
|
||||
{ "key", keyInQuery}
|
||||
};
|
||||
AddCondition(key, "$select", parameters);
|
||||
public AVQuery<T> WhereMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query) where TOther : AVObject {
|
||||
condition.WhereMatchesKeyInQuery(key, keyInQuery, query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereDoesNotMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query)
|
||||
where TOther : AVObject {
|
||||
var parameters = new Dictionary<string, object> {
|
||||
{ "query", query.BuildParameters(query.ClassName)},
|
||||
{ "key", keyInQuery}
|
||||
};
|
||||
AddCondition(key, "$dontSelect", parameters);
|
||||
public AVQuery<T> WhereDoesNotMatchesKeyInQuery<TOther>(string key, string keyInQuery, AVQuery<TOther> query) where TOther : AVObject {
|
||||
condition.WhereDoesNotMatchesKeyInQuery(key, keyInQuery, query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereMatchesQuery<TOther>(string key, AVQuery<TOther> query)
|
||||
where TOther : AVObject {
|
||||
AddCondition(key, "$inQuery", query.BuildParameters(query.ClassName));
|
||||
public AVQuery<T> WhereMatchesQuery<TOther>(string key, AVQuery<TOther> query) where TOther : AVObject {
|
||||
condition.WhereMatchesQuery(key, query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereNear(string key, AVGeoPoint point) {
|
||||
AddCondition(key, "$nearSphere", point);
|
||||
condition.WhereNear(key, point);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereNotContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
||||
AddCondition(key, "$nin", values.ToList());
|
||||
condition.WhereNotContainedIn(key, values);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereNotEqualTo(string key, object value) {
|
||||
AddCondition(key, "$ne", value);
|
||||
condition.WhereNotEqualTo(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereStartsWith(string key, string suffix) {
|
||||
AddCondition(key, "$regex", "^" + RegexQuote(suffix));
|
||||
condition.WhereStartsWith(key, suffix);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereWithinGeoBox(string key, AVGeoPoint southwest, AVGeoPoint northeast) {
|
||||
Dictionary<string, object> value = new Dictionary<string, object> {
|
||||
{ "$box", new[] { southwest, northeast } }
|
||||
};
|
||||
AddCondition(key, "$within", value);
|
||||
condition.WhereWithinGeoBox(key, southwest, northeast);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereWithinDistance(string key, AVGeoPoint point, AVGeoDistance maxDistance) {
|
||||
AddCondition(key, "$nearSphere", point);
|
||||
AddCondition(key, "$maxDistance", maxDistance.Radians);
|
||||
condition.WhereWithinDistance(key, point, maxDistance);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AVQuery<T> WhereRelatedTo(AVObject parent, string key) {
|
||||
AddCondition(new QueryRelatedCondition(parent, key));
|
||||
condition.WhereRelatedTo(parent, key);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -382,26 +359,8 @@ namespace LeanCloud {
|
|||
return condition.BuildParameters(className);
|
||||
}
|
||||
|
||||
private string RegexQuote(string input) {
|
||||
return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E";
|
||||
}
|
||||
|
||||
public IDictionary<string, object> BuildWhere() {
|
||||
IDictionary<string, object> where = condition.ToJSON();
|
||||
return where;
|
||||
}
|
||||
|
||||
void AddCondition(string key, string op, object value) {
|
||||
QueryOperationCondition cond = new QueryOperationCondition {
|
||||
Key = key,
|
||||
Op = op,
|
||||
Value = value
|
||||
};
|
||||
condition.AddCondition(cond);
|
||||
}
|
||||
|
||||
void AddCondition(IQueryCondition cond) {
|
||||
condition.AddCondition(cond);
|
||||
return condition.ToJSON();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue