* 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 {
|
namespace LeanCloud.Storage.Internal {
|
||||||
public class AVQueryController {
|
public class AVQueryController {
|
||||||
public async Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query, AVUser user,
|
public async Task<IEnumerable<IObjectState>> FindAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||||
CancellationToken cancellationToken) where T : AVObject {
|
|
||||||
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
||||||
return from item in items
|
return from item in items
|
||||||
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance);
|
select AVObjectCoder.Instance.Decode(item as IDictionary<string, object>, AVDecoder.Instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CountAsync<T>(AVQuery<T> query,
|
public async Task<int> CountAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||||
AVUser user,
|
|
||||||
CancellationToken cancellationToken) where T : AVObject {
|
|
||||||
var parameters = query.BuildParameters();
|
var parameters = query.BuildParameters();
|
||||||
parameters["limit"] = 0;
|
parameters["limit"] = 0;
|
||||||
parameters["count"] = 1;
|
parameters["count"] = 1;
|
||||||
|
@ -24,9 +21,7 @@ namespace LeanCloud.Storage.Internal {
|
||||||
return Convert.ToInt32(ret);
|
return Convert.ToInt32(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IObjectState> FirstAsync<T>(AVQuery<T> query,
|
public async Task<IObjectState> FirstAsync<T>(AVQuery<T> query, CancellationToken cancellationToken) where T : AVObject {
|
||||||
AVUser user,
|
|
||||||
CancellationToken cancellationToken) where T : AVObject {
|
|
||||||
var parameters = query.BuildParameters();
|
var parameters = query.BuildParameters();
|
||||||
parameters["limit"] = 1;
|
parameters["limit"] = 1;
|
||||||
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
IList<object> items = await FindAsync<IList<object>>(query.Path, query.BuildParameters(), "results", cancellationToken);
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
namespace LeanCloud.Storage.Internal {
|
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;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal {
|
namespace LeanCloud.Storage.Internal {
|
||||||
internal class QueryCompositionalCondition : IQueryCondition {
|
internal class QueryCompositionalCondition : IQueryCondition {
|
||||||
|
@ -11,10 +11,9 @@ namespace LeanCloud.Storage.Internal {
|
||||||
readonly List<IQueryCondition> conditions;
|
readonly List<IQueryCondition> conditions;
|
||||||
readonly string composition;
|
readonly string composition;
|
||||||
|
|
||||||
internal ReadOnlyCollection<string> orderBy;
|
internal List<string> orderBy;
|
||||||
internal HashSet<string> includes;
|
internal HashSet<string> includes;
|
||||||
internal HashSet<string> selectedKeys;
|
internal HashSet<string> selectedKeys;
|
||||||
internal string redirectClassNameForKey;
|
|
||||||
internal int skip;
|
internal int skip;
|
||||||
internal int limit;
|
internal int limit;
|
||||||
|
|
||||||
|
@ -25,6 +24,8 @@ namespace LeanCloud.Storage.Internal {
|
||||||
limit = 30;
|
limit = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region IQueryCondition
|
||||||
|
|
||||||
public bool Equals(IQueryCondition other) {
|
public bool Equals(IQueryCondition other) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -45,41 +46,149 @@ namespace LeanCloud.Storage.Internal {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
#endregion
|
||||||
/// 构建查询字符串
|
|
||||||
/// </summary>
|
#region where
|
||||||
/// <returns></returns>
|
|
||||||
public IDictionary<string, object> BuildParameters(string className) {
|
public void WhereContainedIn<T>(string key, IEnumerable<T> values) {
|
||||||
Dictionary<string, object> result = new Dictionary<string, object>();
|
AddCondition(key, "$in", values.ToList());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
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) {
|
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) {
|
internal void Include(string key) {
|
||||||
|
@ -112,6 +221,15 @@ namespace LeanCloud.Storage.Internal {
|
||||||
limit = count;
|
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) {
|
internal void AddCondition(IQueryCondition condition) {
|
||||||
if (condition == null) {
|
if (condition == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -122,5 +240,35 @@ namespace LeanCloud.Storage.Internal {
|
||||||
});
|
});
|
||||||
conditions.Add(condition);
|
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;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal {
|
namespace LeanCloud.Storage.Internal {
|
||||||
public class QueryEqualCondition : IQueryCondition {
|
internal class QueryEqualCondition : IQueryCondition {
|
||||||
string key;
|
string key;
|
||||||
object value;
|
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 QueryCompositionalCondition condition;
|
||||||
|
|
||||||
internal static AVQueryController QueryController {
|
static AVQueryController QueryController {
|
||||||
get {
|
get {
|
||||||
return AVPlugins.Instance.QueryController;
|
return AVPlugins.Instance.QueryController;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ObjectSubclassingController SubclassingController {
|
|
||||||
get {
|
|
||||||
return AVPlugins.Instance.SubclassingController;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AVQuery()
|
public AVQuery()
|
||||||
: this(SubclassingController.GetClassName(typeof(T))) {
|
: this(AVPlugins.Instance.SubclassingController.GetClassName(typeof(T))) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery(string className) {
|
public AVQuery(string className) {
|
||||||
|
@ -54,6 +48,8 @@ namespace LeanCloud {
|
||||||
condition = new QueryCompositionalCondition();
|
condition = new QueryCompositionalCondition();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Composition
|
||||||
|
|
||||||
public static AVQuery<T> And(IEnumerable<AVQuery<T>> queries) {
|
public static AVQuery<T> And(IEnumerable<AVQuery<T>> queries) {
|
||||||
AVQuery<T> composition = new AVQuery<T>();
|
AVQuery<T> composition = new AVQuery<T>();
|
||||||
string className = null;
|
string className = null;
|
||||||
|
@ -62,7 +58,7 @@ namespace LeanCloud {
|
||||||
if (className != null && className != query.ClassName) {
|
if (className != null && className != query.ClassName) {
|
||||||
throw new ArgumentException("All of the queries in an or query must be on the same class.");
|
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;
|
className = query.ClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +76,7 @@ namespace LeanCloud {
|
||||||
if (className != null && className != query.ClassName) {
|
if (className != null && className != query.ClassName) {
|
||||||
throw new ArgumentException("All of the queries in an or query must be on the same class.");
|
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;
|
className = query.ClassName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,14 +84,16 @@ namespace LeanCloud {
|
||||||
return composition;
|
return composition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
public virtual async Task<IEnumerable<T>> FindAsync(CancellationToken cancellationToken = default) {
|
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
|
return (from state in states
|
||||||
select AVObject.FromState<T>(state, ClassName));
|
select AVObject.FromState<T>(state, ClassName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<T> FirstOrDefaultAsync(CancellationToken cancellationToken = default) {
|
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);
|
return state == null ? default : AVObject.FromState<T>(state, ClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +107,7 @@ namespace LeanCloud {
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual Task<int> CountAsync(CancellationToken cancellationToken = default) {
|
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) {
|
public virtual async Task<T> GetAsync(string objectId, CancellationToken cancellationToken) {
|
||||||
|
@ -224,78 +222,72 @@ namespace LeanCloud {
|
||||||
#region Where
|
#region Where
|
||||||
|
|
||||||
public AVQuery<T> WhereContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
public AVQuery<T> WhereContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
||||||
AddCondition(key, "$in", values.ToList());
|
condition.WhereContainedIn(key, values);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereContainsAll<TIn>(string key, IEnumerable<TIn> values) {
|
public AVQuery<T> WhereContainsAll<TIn>(string key, IEnumerable<TIn> values) {
|
||||||
AddCondition(key, "$all", values.ToList());
|
condition.WhereContainsAll(key, values);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereContains(string key, string substring) {
|
public AVQuery<T> WhereContains(string key, string substring) {
|
||||||
AddCondition(key, "$regex", RegexQuote(substring));
|
condition.WhereContains(key, substring);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereDoesNotExist(string key) {
|
public AVQuery<T> WhereDoesNotExist(string key) {
|
||||||
AddCondition(key, "$exists", false);
|
condition.WhereDoesNotExist(key);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
condition.WhereDoesNotMatchQuery(key, query);
|
||||||
AddCondition(key, "$notInQuery", query.BuildParameters(query.ClassName));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereEndsWith(string key, string suffix) {
|
public AVQuery<T> WhereEndsWith(string key, string suffix) {
|
||||||
AddCondition(key, "$regex", RegexQuote(suffix) + "$");
|
condition.WhereEndsWith(key, suffix);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereEqualTo(string key, object value) {
|
public AVQuery<T> WhereEqualTo(string key, object value) {
|
||||||
AddCondition(new QueryEqualCondition(key, value));
|
condition.WhereEqualTo(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereSizeEqualTo(string key, uint size) {
|
public AVQuery<T> WhereSizeEqualTo(string key, uint size) {
|
||||||
AddCondition(key, "$size", size);
|
condition.WhereSizeEqualTo(key, size);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereExists(string key) {
|
public AVQuery<T> WhereExists(string key) {
|
||||||
AddCondition(key, "$exists", true);
|
condition.WhereExists(key);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereGreaterThan(string key, object value) {
|
public AVQuery<T> WhereGreaterThan(string key, object value) {
|
||||||
AddCondition(key, "$gt", value);
|
condition.WhereGreaterThan(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereGreaterThanOrEqualTo(string key, object value) {
|
public AVQuery<T> WhereGreaterThanOrEqualTo(string key, object value) {
|
||||||
AddCondition(key, "$gte", value);
|
condition.WhereGreaterThanOrEqualTo(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereLessThan(string key, object value) {
|
public AVQuery<T> WhereLessThan(string key, object value) {
|
||||||
AddCondition(key, "$lt", value);
|
condition.WhereLessThan(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereLessThanOrEqualTo(string key, object value) {
|
public AVQuery<T> WhereLessThanOrEqualTo(string key, object value) {
|
||||||
AddCondition(key, "$lte", value);
|
condition.WhereLessThanOrEqualTo(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereMatches(string key, Regex regex, string modifiers) {
|
public AVQuery<T> WhereMatches(string key, Regex regex, string modifiers) {
|
||||||
if (!regex.Options.HasFlag(RegexOptions.ECMAScript)) {
|
condition.WhereMatches(key, regex, modifiers);
|
||||||
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);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,68 +303,53 @@ namespace LeanCloud {
|
||||||
return WhereMatches(key, pattern, null);
|
return WhereMatches(key, pattern, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
condition.WhereMatchesKeyInQuery(key, keyInQuery, query);
|
||||||
var parameters = new Dictionary<string, object> {
|
|
||||||
{ "query", query.BuildParameters(query.ClassName)},
|
|
||||||
{ "key", keyInQuery}
|
|
||||||
};
|
|
||||||
AddCondition(key, "$select", parameters);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
condition.WhereDoesNotMatchesKeyInQuery(key, keyInQuery, query);
|
||||||
var parameters = new Dictionary<string, object> {
|
|
||||||
{ "query", query.BuildParameters(query.ClassName)},
|
|
||||||
{ "key", keyInQuery}
|
|
||||||
};
|
|
||||||
AddCondition(key, "$dontSelect", parameters);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
condition.WhereMatchesQuery(key, query);
|
||||||
AddCondition(key, "$inQuery", query.BuildParameters(query.ClassName));
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereNear(string key, AVGeoPoint point) {
|
public AVQuery<T> WhereNear(string key, AVGeoPoint point) {
|
||||||
AddCondition(key, "$nearSphere", point);
|
condition.WhereNear(key, point);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereNotContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
public AVQuery<T> WhereNotContainedIn<TIn>(string key, IEnumerable<TIn> values) {
|
||||||
AddCondition(key, "$nin", values.ToList());
|
condition.WhereNotContainedIn(key, values);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereNotEqualTo(string key, object value) {
|
public AVQuery<T> WhereNotEqualTo(string key, object value) {
|
||||||
AddCondition(key, "$ne", value);
|
condition.WhereNotEqualTo(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereStartsWith(string key, string suffix) {
|
public AVQuery<T> WhereStartsWith(string key, string suffix) {
|
||||||
AddCondition(key, "$regex", "^" + RegexQuote(suffix));
|
condition.WhereStartsWith(key, suffix);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereWithinGeoBox(string key, AVGeoPoint southwest, AVGeoPoint northeast) {
|
public AVQuery<T> WhereWithinGeoBox(string key, AVGeoPoint southwest, AVGeoPoint northeast) {
|
||||||
Dictionary<string, object> value = new Dictionary<string, object> {
|
condition.WhereWithinGeoBox(key, southwest, northeast);
|
||||||
{ "$box", new[] { southwest, northeast } }
|
|
||||||
};
|
|
||||||
AddCondition(key, "$within", value);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereWithinDistance(string key, AVGeoPoint point, AVGeoDistance maxDistance) {
|
public AVQuery<T> WhereWithinDistance(string key, AVGeoPoint point, AVGeoDistance maxDistance) {
|
||||||
AddCondition(key, "$nearSphere", point);
|
condition.WhereWithinDistance(key, point, maxDistance);
|
||||||
AddCondition(key, "$maxDistance", maxDistance.Radians);
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AVQuery<T> WhereRelatedTo(AVObject parent, string key) {
|
public AVQuery<T> WhereRelatedTo(AVObject parent, string key) {
|
||||||
AddCondition(new QueryRelatedCondition(parent, key));
|
condition.WhereRelatedTo(parent, key);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,26 +359,8 @@ namespace LeanCloud {
|
||||||
return condition.BuildParameters(className);
|
return condition.BuildParameters(className);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RegexQuote(string input) {
|
|
||||||
return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E";
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary<string, object> BuildWhere() {
|
public IDictionary<string, object> BuildWhere() {
|
||||||
IDictionary<string, object> where = condition.ToJSON();
|
return 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue