Merge pull request #60 from onerain88/chore
Chore
commit
cc73b21673
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"python.pythonPath": "/Users/onerainyu/opt/anaconda3/bin/python"
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,12 @@
|
||||||
<Compile Include="..\Storage\Internal\Query\LCCompositionalCondition.cs">
|
<Compile Include="..\Storage\Internal\Query\LCCompositionalCondition.cs">
|
||||||
<Link>Internal\Query\LCCompositionalCondition.cs</Link>
|
<Link>Internal\Query\LCCompositionalCondition.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="..\Storage\LCCaptchaClient.cs">
|
||||||
|
<Link>LCCaptchaClient.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="..\Storage\LCSMSClient.cs">
|
||||||
|
<Link>LCSMSClient.cs</Link>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Newtonsoft.Json">
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LeanCloud;
|
||||||
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
|
using static NUnit.Framework.TestContext;
|
||||||
|
|
||||||
|
namespace Storage.Test {
|
||||||
|
public class CaptchaTest {
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() {
|
||||||
|
LCLogger.LogDelegate += Utils.Print;
|
||||||
|
LCApplication.Initialize(Utils.AppId, Utils.AppKey, Utils.AppServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown() {
|
||||||
|
LCLogger.LogDelegate -= Utils.Print;
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Test]
|
||||||
|
public async Task Request() {
|
||||||
|
LCCapture captcha = await LCCaptchaClient.RequestCaptcha();
|
||||||
|
WriteLine($"url: {captcha.Url}");
|
||||||
|
WriteLine($"token: {captcha.Token}");
|
||||||
|
Assert.NotNull(captcha);
|
||||||
|
Assert.NotNull(captcha.Url);
|
||||||
|
Assert.NotNull(captcha.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Test]
|
||||||
|
public async Task Verify() {
|
||||||
|
await LCCaptchaClient.VerifyCaptcha("on2r", "1TUDkEMu");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ using System.Collections.Generic;
|
||||||
using LeanCloud;
|
using LeanCloud;
|
||||||
using LeanCloud.Storage;
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
|
using static NUnit.Framework.TestContext;
|
||||||
|
|
||||||
namespace Storage.Test {
|
namespace Storage.Test {
|
||||||
public class ObjectTest {
|
public class ObjectTest {
|
||||||
[SetUp]
|
[SetUp]
|
||||||
|
@ -144,5 +146,73 @@ namespace Storage.Test {
|
||||||
TestContext.WriteLine(hello["content"]);
|
TestContext.WriteLine(hello["content"]);
|
||||||
Assert.IsNull(hello["content"]);
|
Assert.IsNull(hello["content"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task OperateNullProperty() {
|
||||||
|
LCObject obj = new LCObject("Hello");
|
||||||
|
obj.Increment("intValue", 123);
|
||||||
|
obj.Increment("intValue", 321);
|
||||||
|
obj.Add("intList", 1);
|
||||||
|
obj.Add("intList", 2);
|
||||||
|
obj.Add("intList", 3);
|
||||||
|
await obj.Save();
|
||||||
|
|
||||||
|
WriteLine(obj["intValue"]);
|
||||||
|
Assert.AreEqual(obj["intValue"], 444);
|
||||||
|
List<object> intList = obj["intList"] as List<object>;
|
||||||
|
WriteLine(intList.Count);
|
||||||
|
Assert.AreEqual(intList.Count, 3);
|
||||||
|
Assert.AreEqual(intList[0], 1);
|
||||||
|
Assert.AreEqual(intList[1], 2);
|
||||||
|
Assert.AreEqual(intList[2], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task FetchAll() {
|
||||||
|
List<LCObject> list = new List<LCObject> {
|
||||||
|
LCObject.CreateWithoutData("Hello", "5e8fe86938ed12000870ae82"),
|
||||||
|
LCObject.CreateWithoutData("Hello", "5e8fe867158a7a0006be0feb"),
|
||||||
|
LCObject.CreateWithoutData("Hello", "5e8fe84e5c385800081a1d64"),
|
||||||
|
};
|
||||||
|
await LCObject.FetchAll(list);
|
||||||
|
Assert.Greater(list.Count, 0);
|
||||||
|
foreach (LCObject obj in list) {
|
||||||
|
Assert.NotNull(obj["intList"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Serialization() {
|
||||||
|
LCObject obj = new LCObject("Hello");
|
||||||
|
obj["intValue"] = 123;
|
||||||
|
obj["boolValue"] = true;
|
||||||
|
obj["stringValue"] = "hello, world";
|
||||||
|
obj["time"] = DateTime.Now;
|
||||||
|
obj["intList"] = new List<int> { 1, 1, 2, 3, 5, 8 };
|
||||||
|
obj["stringMap"] = new Dictionary<string, object> {
|
||||||
|
{ "k1", 111 },
|
||||||
|
{ "k2", true },
|
||||||
|
{ "k3", "haha" }
|
||||||
|
};
|
||||||
|
LCObject nestedObj = new LCObject("World");
|
||||||
|
nestedObj["content"] = "7788";
|
||||||
|
obj["objectValue"] = nestedObj;
|
||||||
|
obj["pointerList"] = new List<object> {
|
||||||
|
new LCObject("World"),
|
||||||
|
nestedObj
|
||||||
|
};
|
||||||
|
await obj.Save();
|
||||||
|
|
||||||
|
string json = obj.ToString();
|
||||||
|
WriteLine(json);
|
||||||
|
LCObject newObj = LCObject.ParseObject(json);
|
||||||
|
Assert.NotNull(newObj.ObjectId);
|
||||||
|
Assert.NotNull(newObj.ClassName);
|
||||||
|
Assert.NotNull(newObj.CreatedAt);
|
||||||
|
Assert.NotNull(newObj.UpdatedAt);
|
||||||
|
Assert.AreEqual(newObj["intValue"], 123);
|
||||||
|
Assert.AreEqual(newObj["boolValue"], true);
|
||||||
|
Assert.AreEqual(newObj["stringValue"], "hello, world");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>);
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using LeanCloud;
|
||||||
|
using LeanCloud.Storage;
|
||||||
|
|
||||||
|
namespace Storage.Test {
|
||||||
|
public class SMSTest {
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp() {
|
||||||
|
LCLogger.LogDelegate += Utils.Print;
|
||||||
|
LCApplication.Initialize(Utils.AppId, Utils.AppKey, Utils.AppServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TearDown]
|
||||||
|
public void TearDown() {
|
||||||
|
LCLogger.LogDelegate -= Utils.Print;
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Test]
|
||||||
|
public async Task RequestSMS() {
|
||||||
|
await LCSMSClient.RequestSMSCode("15101006007",
|
||||||
|
template: "test_template",
|
||||||
|
signature: "flutter-test",
|
||||||
|
variables: new Dictionary<string, object> {
|
||||||
|
{ "k1", "v1" }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Test]
|
||||||
|
public async Task RequestVoice() {
|
||||||
|
await LCSMSClient.RequestVoiceCode("+8615101006007");
|
||||||
|
}
|
||||||
|
|
||||||
|
//[Test]
|
||||||
|
public async Task Verify() {
|
||||||
|
await LCSMSClient.VerifyMobilePhone("15101006007", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -79,6 +79,7 @@ namespace Storage.Test {
|
||||||
public async Task LoginAnonymous() {
|
public async Task LoginAnonymous() {
|
||||||
LCUser user = await LCUser.LoginAnonymously();
|
LCUser user = await LCUser.LoginAnonymously();
|
||||||
Assert.NotNull(user.ObjectId);
|
Assert.NotNull(user.ObjectId);
|
||||||
|
Assert.IsTrue(user.IsAnonymous);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
|
|
@ -3,6 +3,10 @@ using LeanCloud;
|
||||||
|
|
||||||
namespace Storage.Test {
|
namespace Storage.Test {
|
||||||
public static class Utils {
|
public static class Utils {
|
||||||
|
internal const string AppId = "ikGGdRE2YcVOemAaRbgp1xGJ-gzGzoHsz";
|
||||||
|
internal const string AppKey = "NUKmuRbdAhg1vrb2wexYo1jo";
|
||||||
|
internal const string AppServer = "https://ikggdre2.lc-cn-n1-shared.com";
|
||||||
|
|
||||||
internal static void Print(LCLogLevel level, string info) {
|
internal static void Print(LCLogLevel level, string info) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LCLogLevel.Debug:
|
case LCLogLevel.Debug:
|
||||||
|
|
|
@ -55,11 +55,17 @@ namespace LeanCloud.Storage.Internal.Object {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Dictionary<string, object> dict = new Dictionary<string, object> {
|
Dictionary<string, object> dict = new Dictionary<string, object> {
|
||||||
{ "className", objectData.ClassName },
|
{ "className", objectData.ClassName }
|
||||||
{ "objectId", objectData.ObjectId },
|
|
||||||
{ "createdAt", objectData.CreatedAt },
|
|
||||||
{ "updatedAt", objectData.UpdatedAt },
|
|
||||||
};
|
};
|
||||||
|
if (!string.IsNullOrEmpty(objectData.ObjectId)) {
|
||||||
|
dict["objectId"] = objectData.ObjectId;
|
||||||
|
}
|
||||||
|
if (objectData.CreatedAt != null) {
|
||||||
|
dict["createdAt"] = objectData.CreatedAt;
|
||||||
|
}
|
||||||
|
if (objectData.UpdatedAt != null) {
|
||||||
|
dict["updatedAt"] = objectData.UpdatedAt;
|
||||||
|
}
|
||||||
if (objectData.CustomPropertyDict != null) {
|
if (objectData.CustomPropertyDict != null) {
|
||||||
foreach (KeyValuePair<string, object> kv in objectData.CustomPropertyDict) {
|
foreach (KeyValuePair<string, object> kv in objectData.CustomPropertyDict) {
|
||||||
string key = kv.Key;
|
string key = kv.Key;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using LeanCloud.Storage.Internal.Codec;
|
using LeanCloud.Storage.Internal.Codec;
|
||||||
|
|
||||||
namespace LeanCloud.Storage.Internal.Operation {
|
namespace LeanCloud.Storage.Internal.Operation {
|
||||||
|
@ -16,11 +17,15 @@ namespace LeanCloud.Storage.Internal.Operation {
|
||||||
return previousOp;
|
return previousOp;
|
||||||
}
|
}
|
||||||
if (previousOp is LCAddOperation addOp) {
|
if (previousOp is LCAddOperation addOp) {
|
||||||
valueList.AddRange(addOp.valueList);
|
List<object> list = new List<object>(addOp.valueList);
|
||||||
|
list.AddRange(valueList);
|
||||||
|
valueList = list;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
if (previousOp is LCAddUniqueOperation addUniqueOp) {
|
if (previousOp is LCAddUniqueOperation addUniqueOp) {
|
||||||
valueList.AddRange(addUniqueOp.values);
|
List<object> list = addUniqueOp.values.ToList();
|
||||||
|
list.AddRange(valueList);
|
||||||
|
valueList = list;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
throw new ArgumentException("Operation is invalid after previous operation.");
|
throw new ArgumentException("Operation is invalid after previous operation.");
|
||||||
|
|
|
@ -17,7 +17,10 @@ namespace LeanCloud.Storage.Internal.Operation {
|
||||||
return previousOp;
|
return previousOp;
|
||||||
}
|
}
|
||||||
if (previousOp is LCRemoveOperation removeOp) {
|
if (previousOp is LCRemoveOperation removeOp) {
|
||||||
valueList.AddRange(removeOp.valueList);
|
List<object> list = new List<object>(removeOp.valueList);
|
||||||
|
list.AddRange(valueList);
|
||||||
|
valueList = list;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
throw new ArgumentException("Operation is invalid after previous operation.");
|
throw new ArgumentException("Operation is invalid after previous operation.");
|
||||||
}
|
}
|
||||||
|
@ -30,7 +33,10 @@ namespace LeanCloud.Storage.Internal.Operation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Apply(object oldValue, string key) {
|
public object Apply(object oldValue, string key) {
|
||||||
List<object> list = new List<object>(oldValue as IEnumerable<object>);
|
List<object> list = new List<object>();
|
||||||
|
if (oldValue != null) {
|
||||||
|
list.AddRange(oldValue as IEnumerable<object>);
|
||||||
|
}
|
||||||
list.RemoveAll(item => valueList.Contains(item));
|
list.RemoveAll(item => valueList.Contains(item));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LeanCloud.Storage {
|
||||||
|
/// <summary>
|
||||||
|
/// 验证码
|
||||||
|
/// </summary>
|
||||||
|
public class LCCapture {
|
||||||
|
public string Url {
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Token {
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证码工具类
|
||||||
|
/// </summary>
|
||||||
|
public static class LCCaptchaClient {
|
||||||
|
/// <summary>
|
||||||
|
/// 请求验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="width">验证码图片宽度</param>
|
||||||
|
/// <param name="height">验证码图片高度</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task<LCCapture> RequestCaptcha(int width = 82,
|
||||||
|
int height = 39) {
|
||||||
|
string path = "requestCaptcha";
|
||||||
|
Dictionary<string, object> queryParams = new Dictionary<string, object> {
|
||||||
|
{ "width", width },
|
||||||
|
{ "height", height }
|
||||||
|
};
|
||||||
|
Dictionary<string, object> response = await LCApplication.HttpClient.Get<Dictionary<string, object>>(path, queryParams: queryParams);
|
||||||
|
return new LCCapture {
|
||||||
|
Url = response["captcha_url"] as string,
|
||||||
|
Token = response["captcha_token"] as string
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <param name="token"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task VerifyCaptcha(string code,
|
||||||
|
string token) {
|
||||||
|
if (string.IsNullOrEmpty(code)) {
|
||||||
|
throw new ArgumentNullException(nameof(code));
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(token)) {
|
||||||
|
throw new ArgumentNullException(nameof(token));
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = "verifyCaptcha";
|
||||||
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
||||||
|
{ "captcha_code", code },
|
||||||
|
{ "captcha_token", token }
|
||||||
|
};
|
||||||
|
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using LeanCloud.Storage.Internal.Object;
|
using LeanCloud.Storage.Internal.Object;
|
||||||
using LeanCloud.Storage.Internal.Operation;
|
using LeanCloud.Storage.Internal.Operation;
|
||||||
using LeanCloud.Storage.Internal.Codec;
|
using LeanCloud.Storage.Internal.Codec;
|
||||||
|
@ -412,6 +413,43 @@ namespace LeanCloud.Storage {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<IEnumerable<LCObject>> FetchAll(IEnumerable<LCObject> objects) {
|
||||||
|
if (objects == null || objects.Count() == 0) {
|
||||||
|
throw new ArgumentNullException(nameof(objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<LCObject> uniqueObjects = objects.Where(item => item.ObjectId != null);
|
||||||
|
List<Dictionary<string, object>> requestList = uniqueObjects.Select(item => {
|
||||||
|
string path = $"/{LCApplication.APIVersion}/classes/{item.ClassName}/{item.ObjectId}";
|
||||||
|
return new Dictionary<string, object> {
|
||||||
|
{ "path", path },
|
||||||
|
{ "method", "GET" }
|
||||||
|
};
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
||||||
|
{ "requests", LCEncoder.Encode(requestList) }
|
||||||
|
};
|
||||||
|
List<Dictionary<string, object>> results = await LCApplication.HttpClient.Post<List<Dictionary<string, object>>>("batch",
|
||||||
|
data: data);
|
||||||
|
Dictionary<string, LCObjectData> dict = new Dictionary<string, LCObjectData>();
|
||||||
|
foreach (Dictionary<string, object> item in results) {
|
||||||
|
if (item.TryGetValue("error", out object error)) {
|
||||||
|
int code = (int)error;
|
||||||
|
string message = item["error"] as string;
|
||||||
|
throw new LCException(code, message);
|
||||||
|
}
|
||||||
|
Dictionary<string, object> d = item["success"] as Dictionary<string, object>;
|
||||||
|
string objectId = d["objectId"] as string;
|
||||||
|
dict[objectId] = LCObjectData.Decode(d);
|
||||||
|
}
|
||||||
|
foreach (LCObject obj in objects) {
|
||||||
|
LCObjectData objData = dict[obj.ObjectId];
|
||||||
|
obj.Merge(objData);
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
public static void RegisterSubclass<T>(string className, Func<T> constructor) where T : LCObject {
|
public static void RegisterSubclass<T>(string className, Func<T> constructor) where T : LCObject {
|
||||||
Type classType = typeof(T);
|
Type classType = typeof(T);
|
||||||
LCSubclassInfo subclassInfo = new LCSubclassInfo(className, classType, constructor);
|
LCSubclassInfo subclassInfo = new LCSubclassInfo(className, classType, constructor);
|
||||||
|
@ -419,12 +457,27 @@ namespace LeanCloud.Storage {
|
||||||
subclassTypeDict[classType] = subclassInfo;
|
subclassTypeDict[classType] = subclassInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApplyOperation(string key, ILCOperation op) {
|
/// <summary>
|
||||||
if (operationDict.TryGetValue(key, out ILCOperation previousOp)) {
|
/// 序列化为 json 字符串
|
||||||
operationDict[key] = op.MergeWithPrevious(previousOp);
|
/// </summary>
|
||||||
} else {
|
/// <returns></returns>
|
||||||
operationDict[key] = op;
|
public override string ToString() {
|
||||||
|
return JsonConvert.SerializeObject(LCObjectData.Encode(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化为 LCObject 对象
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static LCObject ParseObject(string json) {
|
||||||
|
LCObjectData objectData = LCObjectData.Decode(JsonConvert.DeserializeObject<Dictionary<string, object>>(json));
|
||||||
|
LCObject obj = Create(objectData.ClassName);
|
||||||
|
obj.Merge(objectData);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ApplyOperation(string key, ILCOperation op) {
|
||||||
if (op is LCDeleteOperation) {
|
if (op is LCDeleteOperation) {
|
||||||
estimatedData.Remove(key);
|
estimatedData.Remove(key);
|
||||||
} else {
|
} else {
|
||||||
|
@ -434,6 +487,11 @@ namespace LeanCloud.Storage {
|
||||||
estimatedData[key] = op.Apply(null, key);
|
estimatedData[key] = op.Apply(null, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (operationDict.TryGetValue(key, out ILCOperation previousOp)) {
|
||||||
|
operationDict[key] = op.MergeWithPrevious(previousOp);
|
||||||
|
} else {
|
||||||
|
operationDict[key] = op;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Merge(LCObjectData objectData) {
|
internal void Merge(LCObjectData objectData) {
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LeanCloud.Storage {
|
||||||
|
/// <summary>
|
||||||
|
/// 短信工具类
|
||||||
|
/// </summary>
|
||||||
|
public static class LCSMSClient {
|
||||||
|
/// <summary>
|
||||||
|
/// 请求短信验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mobile"></param>
|
||||||
|
/// <param name="template"></param>
|
||||||
|
/// <param name="signature"></param>
|
||||||
|
/// <param name="captchaToken"></param>
|
||||||
|
/// <param name="variables"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task RequestSMSCode(string mobile,
|
||||||
|
string template = null,
|
||||||
|
string signature = null,
|
||||||
|
string captchaToken = null,
|
||||||
|
Dictionary<string, object> variables = null) {
|
||||||
|
if (string.IsNullOrEmpty(mobile)) {
|
||||||
|
throw new ArgumentNullException(nameof(mobile));
|
||||||
|
}
|
||||||
|
|
||||||
|
string path = "requestSmsCode";
|
||||||
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
||||||
|
{ "mobilePhoneNumber", mobile }
|
||||||
|
};
|
||||||
|
if (!string.IsNullOrEmpty(template)) {
|
||||||
|
data["template"] = template;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(signature)) {
|
||||||
|
data["sign"] = signature;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(captchaToken)) {
|
||||||
|
data["validate_token"] = captchaToken;
|
||||||
|
}
|
||||||
|
if (variables != null) {
|
||||||
|
foreach (KeyValuePair<string, object> kv in variables) {
|
||||||
|
data[kv.Key] = kv.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 请求语音验证码
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mobile"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task RequestVoiceCode(string mobile) {
|
||||||
|
string path = "requestSmsCode";
|
||||||
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
||||||
|
{ "mobilePhoneNumber", mobile },
|
||||||
|
{ "smsType", "voice" }
|
||||||
|
};
|
||||||
|
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证手机号
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mobile"></param>
|
||||||
|
/// <param name="code"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static async Task VerifyMobilePhone(string mobile, string code) {
|
||||||
|
string path = $"verifySmsCode/{code}";
|
||||||
|
Dictionary<string, object> data = new Dictionary<string, object> {
|
||||||
|
{ "mobilePhoneNumber", mobile }
|
||||||
|
};
|
||||||
|
await LCApplication.HttpClient.Post<Dictionary<string, object>>(path, data: data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,6 +67,12 @@ namespace LeanCloud.Storage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是匿名登录
|
||||||
|
/// </summary>
|
||||||
|
public bool IsAnonymous => AuthData != null &&
|
||||||
|
AuthData.ContainsKey("anonymous");
|
||||||
|
|
||||||
static LCUser currentUser;
|
static LCUser currentUser;
|
||||||
|
|
||||||
public static Task<LCUser> GetCurrent() {
|
public static Task<LCUser> GetCurrent() {
|
||||||
|
|
Loading…
Reference in New Issue