* RoleTest.cs:

* QueryTest.cs:
* RelationTest.cs:
* SubClassTest.cs:
* LCIMConversationQuery.cs:
* LCCompositionalCondition.cs:

* LCQuery.cs: chore: 支持更丰富的查询
oneRain 2020-05-06 16:02:26 +08:00
parent 8a6aff4199
commit e801478fad
7 changed files with 233 additions and 58 deletions

View File

@ -184,7 +184,7 @@ namespace LeanCloud.Realtime {
/// <param name="key"></param> /// <param name="key"></param>
/// <returns></returns> /// <returns></returns>
public LCIMConversationQuery OrderBy(string key) { public LCIMConversationQuery OrderBy(string key) {
Condition.OrderBy(key); Condition.OrderByAscending(key);
return this; return this;
} }

View File

@ -1,4 +1,5 @@
using NUnit.Framework; using NUnit.Framework;
using System.Collections.ObjectModel;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using LeanCloud; using LeanCloud;
@ -21,7 +22,7 @@ namespace Storage.Test {
public async Task BaseQuery() { public async Task BaseQuery() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Hello"); LCQuery<LCObject> query = new LCQuery<LCObject>("Hello");
query.Limit(2); query.Limit(2);
List<LCObject> list = await query.Find(); ReadOnlyCollection<LCObject> list = await query.Find();
TestContext.WriteLine(list.Count); TestContext.WriteLine(list.Count);
Assert.AreEqual(list.Count, 2); Assert.AreEqual(list.Count, 2);
@ -53,8 +54,8 @@ namespace Storage.Test {
[Test] [Test]
public async Task OrderBy() { public async Task OrderBy() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Account"); LCQuery<LCObject> query = new LCQuery<LCObject>("Account");
query.OrderBy("balance"); query.OrderByAscending("balance");
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
Assert.LessOrEqual((int)results[0]["balance"], (int)results[1]["balance"]); Assert.LessOrEqual((int)results[0]["balance"], (int)results[1]["balance"]);
query = new LCQuery<LCObject>("Account"); query = new LCQuery<LCObject>("Account");
@ -63,6 +64,22 @@ namespace Storage.Test {
Assert.GreaterOrEqual((int)results[0]["balance"], (int)results[1]["balance"]); Assert.GreaterOrEqual((int)results[0]["balance"], (int)results[1]["balance"]);
} }
[Test]
public async Task AddOrder() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Account");
query.AddAscendingOrder("balance");
query.AddDescendingOrder("createdAt");
ReadOnlyCollection<LCObject> results = await query.Find();
for (int i = 0; i + 1 < results.Count; i++) {
LCObject a1 = results[i];
LCObject a2 = results[i + 1];
int b1 = (int)a1["balance"];
int b2 = (int)a2["balance"];
Assert.IsTrue(b1 < b2 ||
a1.CreatedAt.CompareTo(a2.CreatedAt) >= 0);
}
}
[Test] [Test]
public async Task Include() { public async Task Include() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Hello"); LCQuery<LCObject> query = new LCQuery<LCObject>("Hello");
@ -91,7 +108,7 @@ namespace Storage.Test {
public async Task GreaterQuery() { public async Task GreaterQuery() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Account"); LCQuery<LCObject> query = new LCQuery<LCObject>("Account");
query.WhereGreaterThan("balance", 200); query.WhereGreaterThan("balance", 200);
List<LCObject> list = await query.Find(); ReadOnlyCollection<LCObject> list = await query.Find();
TestContext.WriteLine(list.Count); TestContext.WriteLine(list.Count);
Assert.Greater(list.Count, 0); Assert.Greater(list.Count, 0);
} }
@ -103,12 +120,12 @@ namespace Storage.Test {
LCQuery<LCObject> q2 = new LCQuery<LCObject>("Account"); LCQuery<LCObject> q2 = new LCQuery<LCObject>("Account");
q2.WhereLessThan("balance", 500); q2.WhereLessThan("balance", 500);
LCQuery<LCObject> query = LCQuery<LCObject>.And(new List<LCQuery<LCObject>> { q1, q2 }); LCQuery<LCObject> query = LCQuery<LCObject>.And(new List<LCQuery<LCObject>> { q1, q2 });
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
TestContext.WriteLine(results.Count); TestContext.WriteLine(results.Count);
results.ForEach(item => { foreach (LCObject item in results) {
int balance = (int)item["balance"]; int balance = (int)item["balance"];
Assert.IsTrue(balance >= 100 || balance <= 500); Assert.IsTrue(balance >= 100 || balance <= 500);
}); }
} }
[Test] [Test]
@ -118,12 +135,12 @@ namespace Storage.Test {
LCQuery<LCObject> q2 = new LCQuery<LCObject>("Account"); LCQuery<LCObject> q2 = new LCQuery<LCObject>("Account");
q2.WhereGreaterThanOrEqualTo("balance", 500); q2.WhereGreaterThanOrEqualTo("balance", 500);
LCQuery<LCObject> query = LCQuery<LCObject>.Or(new List<LCQuery<LCObject>> { q1, q2 }); LCQuery<LCObject> query = LCQuery<LCObject>.Or(new List<LCQuery<LCObject>> { q1, q2 });
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
TestContext.WriteLine(results.Count); TestContext.WriteLine(results.Count);
results.ForEach(item => { foreach (LCObject item in results) {
int balance = (int)item["balance"]; int balance = (int)item["balance"];
Assert.IsTrue(balance <= 100 || balance >= 500); Assert.IsTrue(balance <= 100 || balance >= 500);
}); }
} }
[Test] [Test]
@ -141,28 +158,28 @@ namespace Storage.Test {
public async Task Exist() { public async Task Exist() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Account"); LCQuery<LCObject> query = new LCQuery<LCObject>("Account");
query.WhereExists("user"); query.WhereExists("user");
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
Assert.NotNull(item["user"]); Assert.NotNull(item["user"]);
}); }
query = new LCQuery<LCObject>("Account"); query = new LCQuery<LCObject>("Account");
query.WhereDoesNotExist("user"); query.WhereDoesNotExist("user");
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
Assert.IsNull(item["user"]); Assert.IsNull(item["user"]);
}); }
} }
[Test] [Test]
public async Task Select() { public async Task Select() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Account"); LCQuery<LCObject> query = new LCQuery<LCObject>("Account");
query.Select("balance"); query.Select("balance");
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
Assert.NotNull(item["balance"]); Assert.NotNull(item["balance"]);
Assert.IsNull(item["user"]); Assert.IsNull(item["user"]);
}); }
} }
[Test] [Test]
@ -170,29 +187,29 @@ namespace Storage.Test {
// Start // Start
LCQuery<LCObject> query = new LCQuery<LCObject>("Hello"); LCQuery<LCObject> query = new LCQuery<LCObject>("Hello");
query.WhereStartsWith("stringValue", "hello"); query.WhereStartsWith("stringValue", "hello");
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
string str = item["stringValue"] as string; string str = item["stringValue"] as string;
Assert.IsTrue(str.StartsWith("hello")); Assert.IsTrue(str.StartsWith("hello"));
}); }
// End // End
query = new LCQuery<LCObject>("Hello"); query = new LCQuery<LCObject>("Hello");
query.WhereEndsWith("stringValue", "world"); query.WhereEndsWith("stringValue", "world");
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
string str = item["stringValue"] as string; string str = item["stringValue"] as string;
Assert.IsTrue(str.EndsWith("world")); Assert.IsTrue(str.EndsWith("world"));
}); }
// Contains // Contains
query = new LCQuery<LCObject>("Hello"); query = new LCQuery<LCObject>("Hello");
query.WhereContains("stringValue", ","); query.WhereContains("stringValue", ",");
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
string str = item["stringValue"] as string; string str = item["stringValue"] as string;
Assert.IsTrue(str.Contains(',')); Assert.IsTrue(str.Contains(','));
}); }
} }
[Test] [Test]
@ -200,46 +217,60 @@ namespace Storage.Test {
// equal // equal
LCQuery<LCObject> query = new LCQuery<LCObject>("Book"); LCQuery<LCObject> query = new LCQuery<LCObject>("Book");
query.WhereEqualTo("pages", 3); query.WhereEqualTo("pages", 3);
List<LCObject>results = await query.Find(); ReadOnlyCollection<LCObject>results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
List<object> pages = item["pages"] as List<object>; List<object> pages = item["pages"] as List<object>;
Assert.IsTrue(pages.Contains(3)); Assert.IsTrue(pages.Contains(3));
}); }
// contain all // contain all
List<int> containAlls = new List<int> { 1, 2, 3, 4, 5, 6, 7 }; List<int> containAlls = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
query = new LCQuery<LCObject>("Book"); query = new LCQuery<LCObject>("Book");
query.WhereContainsAll("pages", containAlls); query.WhereContainsAll("pages", containAlls);
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
List<object> pages = item["pages"] as List<object>; List<object> pages = item["pages"] as List<object>;
pages.ForEach(i => { pages.ForEach(i => {
Assert.IsTrue(pages.Contains(i)); Assert.IsTrue(pages.Contains(i));
}); });
}); }
// contain in // contain in
List<int> containIns = new List<int> { 4, 5, 6 }; List<int> containIns = new List<int> { 4, 5, 6 };
query = new LCQuery<LCObject>("Book"); query = new LCQuery<LCObject>("Book");
query.WhereContainedIn("pages", containIns); query.WhereContainedIn("pages", containIns);
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
List<object> pages = item["pages"] as List<object>; List<object> pages = item["pages"] as List<object>;
bool f = false; bool f = false;
containIns.ForEach(i => { containIns.ForEach(i => {
f |= pages.Contains(i); f |= pages.Contains(i);
}); });
Assert.IsTrue(f); Assert.IsTrue(f);
}
// not contain in
List<int> notContainIns = new List<int> { 1, 2, 3 };
query = new LCQuery<LCObject>("Book");
query.WhereNotContainedIn("pages", notContainIns);
results = await query.Find();
foreach (LCObject item in results) {
List<object> pages = item["pages"] as List<object>;
bool f = true;
notContainIns.ForEach(i => {
f &= !pages.Contains(i);
}); });
Assert.IsTrue(f);
}
// size // size
query = new LCQuery<LCObject>("Book"); query = new LCQuery<LCObject>("Book");
query.WhereSizeEqualTo("pages", 7); query.WhereSizeEqualTo("pages", 7);
results = await query.Find(); results = await query.Find();
results.ForEach(item => { foreach (LCObject item in results) {
List<object> pages = item["pages"] as List<object>; List<object> pages = item["pages"] as List<object>;
Assert.AreEqual(pages.Count, 7); Assert.AreEqual(pages.Count, 7);
}); }
} }
[Test] [Test]
@ -253,7 +284,7 @@ namespace Storage.Test {
LCQuery<LCObject> query = new LCQuery<LCObject>("Todo"); LCQuery<LCObject> query = new LCQuery<LCObject>("Todo");
LCGeoPoint point = new LCGeoPoint(39.91, 116.41); LCGeoPoint point = new LCGeoPoint(39.91, 116.41);
query.WhereNear("location", point); query.WhereNear("location", point);
List<LCObject> results = await query.Find(); ReadOnlyCollection<LCObject> results = await query.Find();
Assert.Greater(results.Count, 0); Assert.Greater(results.Count, 0);
// in box // in box
@ -264,5 +295,47 @@ namespace Storage.Test {
results = await query.Find(); results = await query.Find();
Assert.Greater(results.Count, 0); Assert.Greater(results.Count, 0);
} }
[Test]
public async Task Regex() {
LCQuery<LCObject> query = new LCQuery<LCObject>("Hello");
query.WhereMatches("stringValue", "^HEllo.*", modifiers: "i");
ReadOnlyCollection<LCObject> results = await query.Find();
Assert.Greater(results.Count, 0);
foreach (LCObject item in results) {
string str = item["stringValue"] as string;
Assert.IsTrue(str.StartsWith("hello"));
}
}
[Test]
public async Task InQuery() {
LCQuery<LCObject> worldQuery = new LCQuery<LCObject>("World");
worldQuery.WhereEqualTo("content", "7788");
LCQuery<LCObject> helloQuery = new LCQuery<LCObject>("Hello");
helloQuery.WhereMatchesQuery("objectValue", worldQuery);
helloQuery.Include("objectValue");
ReadOnlyCollection<LCObject> hellos = await helloQuery.Find();
Assert.Greater(hellos.Count, 0);
foreach (LCObject item in hellos) {
LCObject world = item["objectValue"] as LCObject;
Assert.AreEqual(world["content"], "7788");
}
}
[Test]
public async Task NotInQuery() {
LCQuery<LCObject> worldQuery = new LCQuery<LCObject>("World");
worldQuery.WhereEqualTo("content", "7788");
LCQuery<LCObject> helloQuery = new LCQuery<LCObject>("Hello");
helloQuery.WhereDoesNotMatchQuery("objectValue", worldQuery);
helloQuery.Include("objectValue");
ReadOnlyCollection<LCObject> hellos = await helloQuery.Find();
Assert.Greater(hellos.Count, 0);
foreach (LCObject item in hellos) {
LCObject world = item["objectValue"] as LCObject;
Assert.IsTrue(world == null || world["content"] != "7788");
}
}
} }
} }

View File

@ -1,6 +1,6 @@
using NUnit.Framework; using NUnit.Framework;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.ObjectModel;
using LeanCloud; using LeanCloud;
using LeanCloud.Storage; using LeanCloud.Storage;
@ -56,11 +56,11 @@ namespace Storage.Test {
Assert.NotNull(relation.TargetClass); Assert.NotNull(relation.TargetClass);
LCQuery<LCObject> relationQuery = relation.Query; LCQuery<LCObject> relationQuery = relation.Query;
List<LCObject> list = await relationQuery.Find(); ReadOnlyCollection<LCObject> results = await relationQuery.Find();
list.ForEach(item => { foreach (LCObject item in results) {
TestContext.WriteLine(item.ObjectId); TestContext.WriteLine(item.ObjectId);
Assert.NotNull(item.ObjectId); Assert.NotNull(item.ObjectId);
}); }
} }
} }
} }

View File

@ -1,6 +1,6 @@
using NUnit.Framework; using NUnit.Framework;
using System; using System;
using System.Collections.Generic; using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using LeanCloud; using LeanCloud;
using LeanCloud.Storage; using LeanCloud.Storage;
@ -34,8 +34,8 @@ namespace Storage.Test {
[Test] [Test]
public async Task Query() { public async Task Query() {
LCQuery<LCRole> query = LCRole.GetQuery(); LCQuery<LCRole> query = LCRole.GetQuery();
List<LCRole> list = await query.Find(); ReadOnlyCollection<LCRole> results = await query.Find();
list.ForEach(item => { foreach (LCRole item in results) {
TestContext.WriteLine($"{item.ObjectId} : {item.Name}"); TestContext.WriteLine($"{item.ObjectId} : {item.Name}");
Assert.NotNull(item.ObjectId); Assert.NotNull(item.ObjectId);
Assert.NotNull(item.Name); Assert.NotNull(item.Name);
@ -43,7 +43,7 @@ namespace Storage.Test {
TestContext.WriteLine(item.Users.GetType()); TestContext.WriteLine(item.Users.GetType());
Assert.IsTrue(item.Roles is LCRelation<LCRole>); Assert.IsTrue(item.Roles is LCRelation<LCRole>);
Assert.IsTrue(item.Users is LCRelation<LCUser>); Assert.IsTrue(item.Users is LCRelation<LCUser>);
}); }
} }
} }
} }

View File

@ -1,6 +1,6 @@
using NUnit.Framework; using NUnit.Framework;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Collections.Generic; using System.Collections.ObjectModel;
using LeanCloud; using LeanCloud;
using LeanCloud.Storage; using LeanCloud.Storage;
@ -63,7 +63,7 @@ namespace Storage.Test {
LCObject.RegisterSubclass<Account>("Account", () => new Account()); LCObject.RegisterSubclass<Account>("Account", () => new Account());
LCQuery<Account> query = new LCQuery<Account>("Account"); LCQuery<Account> query = new LCQuery<Account>("Account");
query.WhereGreaterThan("balance", 500); query.WhereGreaterThan("balance", 500);
List<Account> list = await query.Find(); ReadOnlyCollection<Account> list = await query.Find();
TestContext.WriteLine(list.Count); TestContext.WriteLine(list.Count);
Assert.Greater(list.Count, 0); Assert.Greater(list.Count, 0);
foreach (Account account in list) { foreach (Account account in list) {

View File

@ -44,7 +44,7 @@ namespace LeanCloud.Storage.Internal.Query {
} }
public void WhereNotContainedIn(string key, IEnumerable values) { public void WhereNotContainedIn(string key, IEnumerable values) {
AddOperation(key, "nin", values); AddOperation(key, "$nin", values);
} }
public void WhereContainsAll(string key, IEnumerable values) { public void WhereContainsAll(string key, IEnumerable values) {
@ -106,6 +106,32 @@ namespace LeanCloud.Storage.Internal.Query {
AddOperation(key, "$regex", $".*{subString}.*"); AddOperation(key, "$regex", $".*{subString}.*");
} }
public void WhereMatches(string key, string regex, string modifiers) {
Dictionary<string, object> value = new Dictionary<string, object> {
{ "$regex", regex }
};
if (modifiers != null) {
value["$options"] = modifiers;
}
Add(new LCEqualCondition(key, value));
}
public void WhereMatchesQuery<K>(string key, LCQuery<K> query) where K : LCObject {
Dictionary<string, object> inQuery = new Dictionary<string, object> {
{ "where", query.condition },
{ "className", query.ClassName }
};
AddOperation(key, "$inQuery", inQuery);
}
public void WhereDoesNotMatchQuery<K>(string key, LCQuery<K> query) where K : LCObject {
Dictionary<string, object> inQuery = new Dictionary<string, object> {
{ "where", query.condition },
{ "className", query.ClassName }
};
AddOperation(key, "$notInQuery", inQuery);
}
void AddOperation(string key, string op, object value) { void AddOperation(string key, string op, object value) {
LCOperationCondition cond = new LCOperationCondition(key, op, value); LCOperationCondition cond = new LCOperationCondition(key, op, value);
Add(cond); Add(cond);
@ -123,15 +149,24 @@ namespace LeanCloud.Storage.Internal.Query {
} }
// 筛选条件 // 筛选条件
public void OrderBy(string key) { public void OrderByAscending(string key) {
orderByList = new List<string>();
orderByList.Add(key);
}
public void OrderByDescending(string key) {
OrderByAscending($"-{key}");
}
public void AddAscendingOrder(string key) {
if (orderByList == null) { if (orderByList == null) {
orderByList = new List<string>(); orderByList = new List<string>();
} }
orderByList.Add(key); orderByList.Add(key);
} }
public void OrderByDescending(string key) { public void AddDescendingOrder(string key) {
OrderBy($"-{key}"); AddAscendingOrder($"-{key}");
} }
public void Include(string key) { public void Include(string key) {

View File

@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using LeanCloud.Storage.Internal.Query; using LeanCloud.Storage.Internal.Query;
using LeanCloud.Storage.Internal.Object; using LeanCloud.Storage.Internal.Object;
@ -16,7 +17,7 @@ namespace LeanCloud.Storage {
get; private set; get; private set;
} }
LCCompositionalCondition condition; internal LCCompositionalCondition condition;
public LCQuery(string className) { public LCQuery(string className) {
ClassName = className; ClassName = className;
@ -56,6 +57,17 @@ namespace LeanCloud.Storage {
return this; return this;
} }
/// <summary>
/// 不包含
/// </summary>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns></returns>
public LCQuery<T> WhereNotContainedIn(string key, IEnumerable values) {
condition.WhereNotContainedIn(key, values);
return this;
}
/// <summary> /// <summary>
/// 包含全部 /// 包含全部
/// </summary> /// </summary>
@ -209,13 +221,48 @@ namespace LeanCloud.Storage {
return this; return this;
} }
/// <summary>
/// 正则匹配
/// </summary>
/// <param name="key"></param>
/// <param name="regex"></param>
/// <param name="modifiers"></param>
/// <returns></returns>
public LCQuery<T> WhereMatches(string key, string regex, string modifiers = null) {
condition.WhereMatches(key, regex, modifiers);
return this;
}
/// <summary>
/// 关系查询
/// </summary>
/// <param name="key"></param>
/// <param name="query"></param>
/// <returns></returns>
public LCQuery<T> WhereMatchesQuery<K>(string key, LCQuery<K> query) where K : LCObject {
condition.WhereMatchesQuery(key, query);
return this;
}
/// <summary>
/// 不满足子查询
/// </summary>
/// <typeparam name="K"></typeparam>
/// <param name="key"></param>
/// <param name="query"></param>
/// <returns></returns>
public LCQuery<T> WhereDoesNotMatchQuery<K>(string key, LCQuery<K> query) where K : LCObject {
condition.WhereDoesNotMatchQuery(key, query);
return this;
}
/// <summary> /// <summary>
/// 按 key 升序 /// 按 key 升序
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <returns></returns> /// <returns></returns>
public LCQuery<T> OrderBy(string key) { public LCQuery<T> OrderByAscending(string key) {
condition.OrderBy(key); condition.OrderByAscending(key);
return this; return this;
} }
@ -229,6 +276,26 @@ namespace LeanCloud.Storage {
return this; return this;
} }
/// <summary>
/// 增加按 key 升序
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCQuery<T> AddAscendingOrder(string key) {
condition.AddAscendingOrder(key);
return this;
}
/// <summary>
/// 增加按 key 降序
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCQuery<T> AddDescendingOrder(string key) {
condition.AddDescendingOrder(key);
return this;
}
/// <summary> /// <summary>
/// 拉取 key 的完整对象 /// 拉取 key 的完整对象
/// </summary> /// </summary>
@ -284,7 +351,7 @@ namespace LeanCloud.Storage {
} }
WhereEqualTo("objectId", objectId); WhereEqualTo("objectId", objectId);
Limit(1); Limit(1);
List<T> results = await Find(); ReadOnlyCollection<T> results = await Find();
if (results != null) { if (results != null) {
if (results.Count == 0) { if (results.Count == 0) {
return null; return null;
@ -294,7 +361,7 @@ namespace LeanCloud.Storage {
return null; return null;
} }
public async Task<List<T>> Find() { public async Task<ReadOnlyCollection<T>> Find() {
string path = $"classes/{ClassName}"; string path = $"classes/{ClassName}";
Dictionary<string, object> parameters = BuildParams(); Dictionary<string, object> parameters = BuildParams();
Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>(path, queryParams: parameters); Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>(path, queryParams: parameters);
@ -306,12 +373,12 @@ namespace LeanCloud.Storage {
obj.Merge(objectData); obj.Merge(objectData);
list.Add(obj); list.Add(obj);
} }
return list; return list.AsReadOnly();
} }
public async Task<T> First() { public async Task<T> First() {
Limit(1); Limit(1);
List<T> results = await Find(); ReadOnlyCollection<T> results = await Find();
if (results != null && results.Count > 0) { if (results != null && results.Count > 0) {
return results[0]; return results[0];
} }