diff --git a/Storage/Storage/Public/AVObject.cs b/Storage/Storage/Public/AVObject.cs index 61ec98f..984bf63 100644 --- a/Storage/Storage/Public/AVObject.cs +++ b/Storage/Storage/Public/AVObject.cs @@ -27,7 +27,7 @@ namespace LeanCloud /// to specify which existing data to retrieve. /// /// - public class AVObject : IEnumerable>, INotifyPropertyChanged, INotifyPropertyUpdated, INotifyCollectionPropertyUpdated, IAVObject + public class AVObject : IEnumerable>, INotifyPropertyChanged, INotifyPropertyUpdated, INotifyCollectionPropertyUpdated { private static readonly string AutoClassName = "_Automatic"; diff --git a/Storage/Storage/Public/IAVQuery.cs b/Storage/Storage/Public/IAVQuery.cs deleted file mode 100644 index 35b64e7..0000000 --- a/Storage/Storage/Public/IAVQuery.cs +++ /dev/null @@ -1,1100 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using LeanCloud.Storage.Internal; - -namespace LeanCloud -{ - /// - /// Query 对象的基础接口 - /// - public interface IAVQuery - { - - } - - /// - /// LeanCloud 存储对象的接触接口 - /// - public interface IAVObject - { - - } - - public abstract class AVQueryBase : IAVQuery - where T : IAVObject - { - internal string className; - internal Dictionary where; - internal ReadOnlyCollection orderBy; - internal ReadOnlyCollection includes; - internal ReadOnlyCollection selectedKeys; - internal String redirectClassNameForKey; - internal int? skip; - internal int? limit; - - /// - /// 构建查询字符串 - /// - /// 是否包含 ClassName - /// - public IDictionary BuildParameters(bool includeClassName = false) - { - Dictionary result = new Dictionary(); - if (where != null) - { - result["where"] = PointerOrLocalIdEncoder.Instance.Encode(where); - } - 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; - } - - public virtual Dictionary Where - { - get - { - return this.where; - } - set - { - this.where = value; - } - } - - public virtual IDictionary MergeWhere(IDictionary primary, IDictionary secondary) - { - if (secondary == null) - { - return primary; - } - var newWhere = new Dictionary(primary); - foreach (var pair in secondary) - { - var condition = pair.Value as IDictionary; - if (newWhere.ContainsKey(pair.Key)) - { - var oldCondition = newWhere[pair.Key] as IDictionary; - if (oldCondition == null || condition == null) - { - throw new ArgumentException("More than one where clause for the given key provided."); - } - var newCondition = new Dictionary(oldCondition); - foreach (var conditionPair in condition) - { - if (newCondition.ContainsKey(conditionPair.Key)) - { - throw new ArgumentException("More than one condition for the given key provided."); - } - newCondition[conditionPair.Key] = conditionPair.Value; - } - newWhere[pair.Key] = newCondition; - } - else - { - newWhere[pair.Key] = pair.Value; - } - } - return newWhere; - } - } - - public abstract class AVQueryPair - where S : IAVQuery - where T : IAVObject - - { - protected readonly string className; - protected readonly Dictionary where; - protected readonly ReadOnlyCollection orderBy; - protected readonly ReadOnlyCollection includes; - protected readonly ReadOnlyCollection selectedKeys; - protected readonly String redirectClassNameForKey; - protected readonly int? skip; - protected readonly int? limit; - - internal string ClassName { get { return className; } } - - private string relativeUri; - internal string RelativeUri - { - get - { - string rtn = string.Empty; - if (string.IsNullOrEmpty(relativeUri)) - { - rtn = "classes/" + Uri.EscapeDataString(this.className); - } - else - { - rtn = relativeUri; - } - return rtn; - } - set - { - relativeUri = value; - } - } - public Dictionary Condition - { - get { return this.where; } - } - - protected AVQueryPair() - { - - } - - public abstract S CreateInstance(IDictionary where = null, - IEnumerable replacementOrderBy = null, - IEnumerable thenBy = null, - int? skip = null, - int? limit = null, - IEnumerable includes = null, - IEnumerable selectedKeys = null, - String redirectClassNameForKey = null); - - /// - /// Private constructor for composition of queries. A Source query is required, - /// but the remaining values can be null if they won't be changed in this - /// composition. - /// - protected AVQueryPair(AVQueryPair source, - IDictionary where = null, - IEnumerable replacementOrderBy = null, - IEnumerable thenBy = null, - int? skip = null, - int? limit = null, - IEnumerable includes = null, - IEnumerable selectedKeys = null, - String redirectClassNameForKey = null) - { - if (source == null) - { - throw new ArgumentNullException("Source"); - } - - className = source.className; - this.where = source.where; - this.orderBy = source.orderBy; - this.skip = source.skip; - this.limit = source.limit; - this.includes = source.includes; - this.selectedKeys = source.selectedKeys; - this.redirectClassNameForKey = source.redirectClassNameForKey; - - if (where != null) - { - var newWhere = MergeWhereClauses(where); - this.where = new Dictionary(newWhere); - } - - if (replacementOrderBy != null) - { - this.orderBy = new ReadOnlyCollection(replacementOrderBy.ToList()); - } - - if (thenBy != null) - { - if (this.orderBy == null) - { - throw new ArgumentException("You must call OrderBy before calling ThenBy."); - } - var newOrderBy = new List(this.orderBy); - newOrderBy.AddRange(thenBy); - this.orderBy = new ReadOnlyCollection(newOrderBy); - } - - // Remove duplicates. - if (this.orderBy != null) - { - var newOrderBy = new HashSet(this.orderBy); - this.orderBy = new ReadOnlyCollection(newOrderBy.ToList()); - } - - if (skip != null) - { - this.skip = (this.skip ?? 0) + skip; - } - - if (limit != null) - { - this.limit = limit; - } - - if (includes != null) - { - var newIncludes = MergeIncludes(includes); - this.includes = new ReadOnlyCollection(newIncludes.ToList()); - } - - if (selectedKeys != null) - { - var newSelectedKeys = MergeSelectedKeys(selectedKeys); - this.selectedKeys = new ReadOnlyCollection(newSelectedKeys.ToList()); - } - - if (redirectClassNameForKey != null) - { - this.redirectClassNameForKey = redirectClassNameForKey; - } - } - - public AVQueryPair(string className) - { - if (string.IsNullOrEmpty(className)) - { - throw new ArgumentNullException("className", "Must specify a AVObject class name when creating a AVQuery."); - } - this.className = className; - } - - private HashSet MergeIncludes(IEnumerable includes) - { - if (this.includes == null) - { - return new HashSet(includes); - } - var newIncludes = new HashSet(this.includes); - foreach (var item in includes) - { - newIncludes.Add(item); - } - return newIncludes; - } - - private HashSet MergeSelectedKeys(IEnumerable selectedKeys) - { - if (this.selectedKeys == null) - { - return new HashSet(selectedKeys); - } - var newSelectedKeys = new HashSet(this.selectedKeys); - foreach (var item in selectedKeys) - { - newSelectedKeys.Add(item); - } - return newSelectedKeys; - } - - private IDictionary MergeWhereClauses(IDictionary where) - { - return MergeWhere(this.where, where); - } - - public virtual IDictionary MergeWhere(IDictionary primary, IDictionary secondary) - { - if (secondary == null) - { - return primary; - } - if (primary == null) - { - return secondary; - } - var newWhere = new Dictionary(primary); - foreach (var pair in secondary) - { - var condition = pair.Value as IDictionary; - if (newWhere.ContainsKey(pair.Key)) - { - var oldCondition = newWhere[pair.Key] as IDictionary; - if (oldCondition == null || condition == null) - { - throw new ArgumentException("More than one where clause for the given key provided."); - } - var newCondition = new Dictionary(oldCondition); - foreach (var conditionPair in condition) - { - if (newCondition.ContainsKey(conditionPair.Key)) - { - throw new ArgumentException("More than one condition for the given key provided."); - } - newCondition[conditionPair.Key] = conditionPair.Value; - } - newWhere[pair.Key] = newCondition; - } - else - { - newWhere[pair.Key] = pair.Value; - } - } - return newWhere; - } - - /// - /// Constructs a query that is the or of the given queries. - /// - /// The list of AVQueries to 'or' together. - /// A AVeQquery that is the 'or' of the passed in queries. - public static Q Or(IEnumerable queries) - where Q : AVQueryBase - where O : IAVObject - { - string className = null; - var orValue = new List>(); - // We need to cast it to non-generic IEnumerable because of AOT-limitation - var nonGenericQueries = (IEnumerable)queries; - Q current = null; - foreach (var obj in nonGenericQueries) - { - var q = (Q)obj; - current = q; - if (className != null && q.className != className) - { - throw new ArgumentException( - "All of the queries in an or query must be on the same class."); - } - className = q.className; - var parameters = q.BuildParameters(); - if (parameters.Count == 0) - { - continue; - } - object where; - if (!parameters.TryGetValue("where", out where) || parameters.Count > 1) - { - throw new ArgumentException( - "None of the queries in an or query can have non-filtering clauses"); - } - orValue.Add(where as IDictionary); - } - current.Where = new Dictionary() - { - {"$or", orValue} - }; - return current; - } - - #region Order By - - /// - /// Sorts the results in ascending order by the given key. - /// This will override any existing ordering for the query. - /// - /// The key to order by. - /// A new query with the additional constraint. - public virtual S OrderBy(string key) - { - return CreateInstance(replacementOrderBy: new List { key }); - } - - /// - /// Sorts the results in descending order by the given key. - /// This will override any existing ordering for the query. - /// - /// The key to order by. - /// A new query with the additional constraint. - public virtual S OrderByDescending(string key) - { - return CreateInstance(replacementOrderBy: new List { "-" + key }); - } - - /// - /// Sorts the results in ascending order by the given key, after previous - /// ordering has been applied. - /// - /// This method can only be called if there is already an - /// or - /// on this query. - /// - /// The key to order by. - /// A new query with the additional constraint. - public virtual S ThenBy(string key) - { - return CreateInstance(thenBy: new List { key }); - } - - /// - /// Sorts the results in descending order by the given key, after previous - /// ordering has been applied. - /// - /// This method can only be called if there is already an - /// or on this query. - /// - /// The key to order by. - /// A new query with the additional constraint. - public virtual S ThenByDescending(string key) - { - return CreateInstance(thenBy: new List { "-" + key }); - } - - #endregion - - /// - /// Include nested AVObjects for the provided key. You can use dot notation - /// to specify which fields in the included objects should also be fetched. - /// - /// The key that should be included. - /// A new query with the additional constraint. - public virtual S Include(string key) - { - return CreateInstance(includes: new List { key }); - } - - /// - /// Restrict the fields of returned AVObjects to only include the provided key. - /// If this is called multiple times, then all of the keys specified in each of - /// the calls will be included. - /// - /// The key that should be included. - /// A new query with the additional constraint. - public virtual S Select(string key) - { - return CreateInstance(selectedKeys: new List { key }); - } - - /// - /// Skips a number of results before returning. This is useful for pagination - /// of large queries. Chaining multiple skips together will cause more results - /// to be skipped. - /// - /// The number of results to skip. - /// A new query with the additional constraint. - public virtual S Skip(int count) - { - return CreateInstance(skip: count); - } - - /// - /// Controls the maximum number of results that are returned. Setting a negative - /// limit denotes retrieval without a limit. Chaining multiple limits - /// results in the last limit specified being used. The default limit is - /// 100, with a maximum of 1000 results being returned at a time. - /// - /// The maximum number of results to return. - /// A new query with the additional constraint. - public virtual S Limit(int count) - { - return CreateInstance(limit: count); - } - - internal virtual S RedirectClassName(String key) - { - return CreateInstance(redirectClassNameForKey: key); - } - - #region Where - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// contained in the provided list of values. - /// - /// The key to check. - /// The values that will match. - /// A new query with the additional constraint. - public virtual S WhereContainedIn(string key, IEnumerable values) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$in", values.ToList()}}} - }); - } - - /// - /// Add a constraint to the querey that requires a particular key's value to be - /// a list containing all of the elements in the provided list of values. - /// - /// The key to check. - /// The values that will match. - /// A new query with the additional constraint. - public virtual S WhereContainsAll(string key, IEnumerable values) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$all", values.ToList()}}} - }); - } - - /// - /// Adds a constraint for finding string values that contain a provided string. - /// This will be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The substring that the value must contain. - /// A new query with the additional constraint. - public virtual S WhereContains(string key, string substring) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$regex", RegexQuote(substring)}}} - }); - } - - /// - /// Adds a constraint for finding objects that do not contain a given key. - /// - /// The key that should not exist. - /// A new query with the additional constraint. - public virtual S WhereDoesNotExist(string key) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$exists", false}}} - }); - } - - /// - /// Adds a constraint to the query that requires that a particular key's value - /// does not match another AVQuery. This only works on keys whose values are - /// AVObjects or lists of AVObjects. - /// - /// The key to check. - /// The query that the value should not match. - /// A new query with the additional constraint. - public virtual S WhereDoesNotMatchQuery(string key, AVQuery query) - where TOther : AVObject - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$notInQuery", query.BuildParameters(true)}}} - }); - } - - /// - /// Adds a constraint for finding string values that end with a provided string. - /// This will be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The substring that the value must end with. - /// A new query with the additional constraint. - public virtual S WhereEndsWith(string key, string suffix) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$regex", RegexQuote(suffix) + "$"}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// equal to the provided value. - /// - /// The key to check. - /// The value that the AVObject must contain. - /// A new query with the additional constraint. - public virtual S WhereEqualTo(string key, object value) - { - return CreateInstance(where: new Dictionary { - { key, value} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's size to be - /// equal to the provided size. - /// - /// The size equal to. - /// The key to check. - /// The value that the size must be. - /// A new query with the additional constraint. - public virtual S WhereSizeEqualTo(string key, uint size) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$size", size}}} - }); - } - - /// - /// Adds a constraint for finding objects that contain a given key. - /// - /// The key that should exist. - /// A new query with the additional constraint. - public virtual S WhereExists(string key) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$exists", true}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// greater than the provided value. - /// - /// The key to check. - /// The value that provides a lower bound. - /// A new query with the additional constraint. - public virtual S WhereGreaterThan(string key, object value) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$gt", value}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// greater or equal to than the provided value. - /// - /// The key to check. - /// The value that provides a lower bound. - /// A new query with the additional constraint. - public virtual S WhereGreaterThanOrEqualTo(string key, object value) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$gte", value}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// less than the provided value. - /// - /// The key to check. - /// The value that provides an upper bound. - /// A new query with the additional constraint. - public virtual S WhereLessThan(string key, object value) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$lt", value}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// less than or equal to the provided value. - /// - /// The key to check. - /// The value that provides a lower bound. - /// A new query with the additional constraint. - public virtual S WhereLessThanOrEqualTo(string key, object value) - { - return CreateInstance(where: new Dictionary{ - { key, new Dictionary{{"$lte", value}}} - }); - } - - /// - /// Adds a regular expression constraint for finding string values that match the provided - /// regular expression. This may be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The regular expression pattern to match. The Regex must - /// have the options flag set. - /// Any of the following supported PCRE modifiers: - /// i - Case insensitive search - /// m Search across multiple lines of input - /// A new query with the additional constraint. - public virtual S 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."); - } - return CreateInstance(where: new Dictionary { - { key, EncodeRegex(regex, modifiers)} - }); - } - - /// - /// Adds a regular expression constraint for finding string values that match the provided - /// regular expression. This may be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The regular expression pattern to match. The Regex must - /// have the options flag set. - /// A new query with the additional constraint. - public virtual S WhereMatches(string key, Regex regex) - { - return WhereMatches(key, regex, null); - } - - /// - /// Adds a regular expression constraint for finding string values that match the provided - /// regular expression. This may be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The PCRE regular expression pattern to match. - /// Any of the following supported PCRE modifiers: - /// i - Case insensitive search - /// m Search across multiple lines of input - /// A new query with the additional constraint. - public virtual S WhereMatches(string key, string pattern, string modifiers = null) - { - return WhereMatches(key, new Regex(pattern, RegexOptions.ECMAScript), modifiers); - } - - /// - /// Adds a regular expression constraint for finding string values that match the provided - /// regular expression. This may be slow for large data sets. - /// - /// The key that the string to match is stored in. - /// The PCRE regular expression pattern to match. - /// A new query with the additional constraint. - public virtual S WhereMatches(string key, string pattern) - { - return WhereMatches(key, pattern, null); - } - - /// - /// Adds a constraint to the query that requires a particular key's value - /// to match a value for a key in the results of another AVQuery. - /// - /// The key whose value is being checked. - /// The key in the objects from the subquery to look in. - /// The subquery to run - /// A new query with the additional constraint. - public virtual S WhereMatchesKeyInQuery(string key, - string keyInQuery, - AVQuery query) where TOther : AVObject - { - var parameters = new Dictionary { - { "query", query.BuildParameters(true)}, - { "key", keyInQuery} - }; - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$select", parameters}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value - /// does not match any value for a key in the results of another AVQuery. - /// - /// The key whose value is being checked. - /// The key in the objects from the subquery to look in. - /// The subquery to run - /// A new query with the additional constraint. - public virtual S WhereDoesNotMatchesKeyInQuery(string key, - string keyInQuery, - AVQuery query) where TOther : AVObject - { - var parameters = new Dictionary { - { "query", query.BuildParameters(true)}, - { "key", keyInQuery} - }; - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$dontSelect", parameters}}} - }); - } - - /// - /// Adds a constraint to the query that requires that a particular key's value - /// matches another AVQuery. This only works on keys whose values are - /// AVObjects or lists of AVObjects. - /// - /// The key to check. - /// The query that the value should match. - /// A new query with the additional constraint. - public virtual S WhereMatchesQuery(string key, AVQuery query) - where TOther : AVObject - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$inQuery", query.BuildParameters(true)}}} - }); - } - - /// - /// Adds a proximity-based constraint for finding objects with keys whose GeoPoint - /// values are near the given point. - /// - /// The key that the AVGeoPoint is stored in. - /// The reference AVGeoPoint. - /// A new query with the additional constraint. - public virtual S WhereNear(string key, AVGeoPoint point) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$nearSphere", point}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value to be - /// contained in the provided list of values. - /// - /// The key to check. - /// The values that will match. - /// A new query with the additional constraint. - public virtual S WhereNotContainedIn(string key, IEnumerable values) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$nin", values.ToList()}}} - }); - } - - /// - /// Adds a constraint to the query that requires a particular key's value not - /// to be equal to the provided value. - /// - /// The key to check. - /// The value that that must not be equalled. - /// A new query with the additional constraint. - public virtual S WhereNotEqualTo(string key, object value) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$ne", value}}} - }); - } - - /// - /// Adds a constraint for finding string values that start with the provided string. - /// This query will use the backend index, so it will be fast even with large data sets. - /// - /// The key that the string to match is stored in. - /// The substring that the value must start with. - /// A new query with the additional constraint. - public virtual S WhereStartsWith(string key, string suffix) - { - return CreateInstance(where: new Dictionary { - { key, new Dictionary{{"$regex", "^" + RegexQuote(suffix)}}} - }); - } - - /// - /// Add a constraint to the query that requires a particular key's coordinates to be - /// contained within a given rectangular geographic bounding box. - /// - /// The key to be constrained. - /// The lower-left inclusive corner of the box. - /// The upper-right inclusive corner of the box. - /// A new query with the additional constraint. - public virtual S WhereWithinGeoBox(string key, - AVGeoPoint southwest, - AVGeoPoint northeast) - { - - return this.CreateInstance(where: new Dictionary - { - { - key, - new Dictionary - { - { - "$within", - new Dictionary { - { "$box", new[] {southwest, northeast}} - } - } - } - } - }); - } - - /// - /// Adds a proximity-based constraint for finding objects with keys whose GeoPoint - /// values are near the given point and within the maximum distance given. - /// - /// The key that the AVGeoPoint is stored in. - /// The reference AVGeoPoint. - /// The maximum distance (in radians) of results to return. - /// A new query with the additional constraint. - public virtual S WhereWithinDistance( - string key, AVGeoPoint point, AVGeoDistance maxDistance) - { - var nearWhere = new Dictionary { - { key, new Dictionary{{"$nearSphere", point}}} - }; - var mergedWhere = MergeWhere(nearWhere, new Dictionary { - { key, new Dictionary{{"$maxDistance", maxDistance.Radians}}} - }); - return CreateInstance(where: mergedWhere); - } - - internal virtual S WhereRelatedTo(AVObject parent, string key) - { - return CreateInstance(where: new Dictionary { - { - "$relatedTo", - new Dictionary { - { "object", parent}, - { "key", key} - } - } - }); - } - - #endregion - - /// - /// Retrieves a list of AVObjects that satisfy this query from LeanCloud. - /// - /// The list of AVObjects that match this query. - public virtual Task> FindAsync() - { - return FindAsync(CancellationToken.None); - } - - /// - /// Retrieves a list of AVObjects that satisfy this query from LeanCloud. - /// - /// The cancellation token. - /// The list of AVObjects that match this query. - public abstract Task> FindAsync(CancellationToken cancellationToken); - - - /// - /// Retrieves at most one AVObject that satisfies this query. - /// - /// A single AVObject that satisfies this query, or else null. - public virtual Task FirstOrDefaultAsync() - { - return FirstOrDefaultAsync(CancellationToken.None); - } - - /// - /// Retrieves at most one AVObject that satisfies this query. - /// - /// The cancellation token. - /// A single AVObject that satisfies this query, or else null. - public abstract Task FirstOrDefaultAsync(CancellationToken cancellationToken); - - /// - /// Retrieves at most one AVObject that satisfies this query. - /// - /// A single AVObject that satisfies this query. - /// If no results match the query. - public virtual Task FirstAsync() - { - return FirstAsync(CancellationToken.None); - } - - /// - /// Retrieves at most one AVObject that satisfies this query. - /// - /// The cancellation token. - /// A single AVObject that satisfies this query. - /// If no results match the query. - public abstract Task FirstAsync(CancellationToken cancellationToken); - - /// - /// Counts the number of objects that match this query. - /// - /// The number of objects that match this query. - public virtual Task CountAsync() - { - return CountAsync(CancellationToken.None); - } - - /// - /// Counts the number of objects that match this query. - /// - /// The cancellation token. - /// The number of objects that match this query. - public abstract Task CountAsync(CancellationToken cancellationToken); - - /// - /// Constructs a AVObject whose id is already known by fetching data - /// from the server. - /// - /// ObjectId of the AVObject to fetch. - /// The AVObject for the given objectId. - public virtual Task GetAsync(string objectId) - { - return GetAsync(objectId, CancellationToken.None); - } - - /// - /// Constructs a AVObject whose id is already known by fetching data - /// from the server. - /// - /// ObjectId of the AVObject to fetch. - /// The cancellation token. - /// The AVObject for the given objectId. - public abstract Task GetAsync(string objectId, CancellationToken cancellationToken); - - internal object GetConstraint(string key) - { - return where == null ? null : where.GetOrDefault(key, null); - } - - /// - /// 构建查询字符串 - /// - /// 是否包含 ClassName - /// - public IDictionary BuildParameters(bool includeClassName = false) - { - Dictionary result = new Dictionary(); - if (where != null) - { - result["where"] = PointerOrLocalIdEncoder.Instance.Encode(where); - } - 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; - } - - private string RegexQuote(string input) - { - return "\\Q" + input.Replace("\\E", "\\E\\\\E\\Q") + "\\E"; - } - - private string GetRegexOptions(Regex regex, string modifiers) - { - string result = modifiers ?? ""; - if (regex.Options.HasFlag(RegexOptions.IgnoreCase) && !modifiers.Contains("i")) - { - result += "i"; - } - if (regex.Options.HasFlag(RegexOptions.Multiline) && !modifiers.Contains("m")) - { - result += "m"; - } - return result; - } - - private IDictionary EncodeRegex(Regex regex, string modifiers) - { - var options = GetRegexOptions(regex, modifiers); - var dict = new Dictionary(); - dict["$regex"] = regex.ToString(); - if (!string.IsNullOrEmpty(options)) - { - dict["$options"] = options; - } - return dict; - } - } -}