* LCIMConversation.cs: chore: 会话自定义属性

* LCIMClient.cs:
* Conversation.cs:
* LCDecoder.cs:
* LCEncoder.cs:
* LCEqualCondition.cs:
* ILCQueryCondition.cs:
* LCRelatedCondition.cs:
* LCIMConversationQuery.cs:
* LCOperationCondition.cs:
* LCIMTemporaryConversation.cs:
* LCCompositionalCondition.cs:
oneRain 2020-03-17 11:41:38 +08:00
parent 6d4befe446
commit 05e642237e
12 changed files with 625 additions and 77 deletions

View File

@ -2,7 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Linq; using System.Linq;
using Newtonsoft.Json;
using LeanCloud.Realtime.Protocol; using LeanCloud.Realtime.Protocol;
using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Realtime { namespace LeanCloud.Realtime {
public class LCIMConversation { public class LCIMConversation {
@ -11,7 +13,11 @@ namespace LeanCloud.Realtime {
} }
public string Name { public string Name {
get; set; get {
return this["name"] as string;
} set {
this["name"] = value;
}
} }
public string CreatorId { public string CreatorId {
@ -30,7 +36,22 @@ namespace LeanCloud.Realtime {
get; set; get; set;
} }
public bool IsMute => false; public DateTime LastMessageAt {
get; internal set;
}
public object this[string key] {
get {
return customProperties[key];
}
set {
customProperties[key] = value;
}
}
public bool IsMute {
get; private set;
}
public virtual bool IsSystem => false; public virtual bool IsSystem => false;
@ -38,39 +59,122 @@ namespace LeanCloud.Realtime {
private readonly LCIMClient client; private readonly LCIMClient client;
private Dictionary<string, object> customProperties;
internal LCIMConversation(LCIMClient client) { internal LCIMConversation(LCIMClient client) {
this.client = client; this.client = client;
customProperties = new Dictionary<string, object>();
} }
public void Set(string key, object value) { /// <summary>
// 自定义属性 /// 获取对话人数,或暂态对话的在线人数
/// </summary>
} /// <returns></returns>
public async Task<int> Count() { public async Task<int> Count() {
return 0; ConvCommand conv = new ConvCommand {
Cid = Id,
};
GenericCommand command = client.NewCommand(CommandType.Conv, OpType.Count);
command.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(command);
return response.ConvMessage.Count;
} }
public async Task<LCIMConversation> Save() { public async Task<LCIMConversation> Save() {
ConvCommand conv = new ConvCommand {
Cid = Id,
};
// 注意序列化是否与存储一致
string json = JsonConvert.SerializeObject(LCEncoder.Encode(customProperties));
conv.Attr = new JsonObjectMessage {
Data = json
};
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Update);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
JsonObjectMessage attr = response.ConvMessage.AttrModified;
// 更新自定义属性
if (attr != null) {
Dictionary<string, object> data = JsonConvert.DeserializeObject<Dictionary<string, object>>(attr.Data);
Dictionary<string, object> objectData = LCDecoder.Decode(data) as Dictionary<string, object>;
foreach (KeyValuePair<string, object> kv in objectData) {
customProperties[kv.Key] = kv.Value;
}
}
return this; return this;
} }
public async Task Add(List<string> clientIdList) { /// <summary>
/// 添加用户到对话
/// </summary>
/// <param name="clientIds">用户 Id</param>
/// <returns></returns>
public async Task<LCIMConversation> Add(IEnumerable<string> clientIds) {
if (clientIds == null || clientIds.Count() == 0) {
throw new ArgumentNullException(nameof(clientIds));
}
ConvCommand conv = new ConvCommand {
Cid = Id,
};
conv.M.AddRange(clientIds);
// TODO 签名参数
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Add);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
List<string> allowedIds = response.ConvMessage.AllowedPids.ToList();
List<ErrorCommand> failedIds = response.ConvMessage.FailedPids.ToList();
// TODO 转化为返回
return this;
} }
public async Task Remove(List<string> removeIdList) { /// <summary>
/// 删除用户
/// </summary>
/// <param name="removeIds">用户 Id</param>
/// <returns></returns>
public async Task<LCIMConversation> Remove(IEnumerable<string> removeIds) {
if (removeIds == null || removeIds.Count() == 0) {
throw new ArgumentNullException(nameof(removeIds));
}
ConvCommand conv = new ConvCommand {
Cid = Id,
};
conv.M.AddRange(removeIds);
// TODO 签名参数
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Remove);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
List<string> allowedIds = response.ConvMessage.AllowedPids.ToList();
List<ErrorCommand> failedIds = response.ConvMessage.FailedPids.ToList();
// TODO 转化为返回
return this;
} }
/// <summary>
/// 加入对话
/// </summary>
/// <returns></returns>
public async Task<LCIMConversation> Join() { public async Task<LCIMConversation> Join() {
return this; return await Add(new string[] { client.ClientId });
} }
/// <summary>
/// 离开对话
/// </summary>
/// <returns></returns>
public async Task<LCIMConversation> Quit() { public async Task<LCIMConversation> Quit() {
return this; return await Remove(new string[] { client.ClientId });
} }
/// <summary>
/// 发送消息
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task<LCIMMessage> Send(LCIMMessage message) { public async Task<LCIMMessage> Send(LCIMMessage message) {
DirectCommand direct = new DirectCommand { DirectCommand direct = new DirectCommand {
FromPeerId = client.ClientId, FromPeerId = client.ClientId,
@ -88,30 +192,108 @@ namespace LeanCloud.Realtime {
} }
public async Task<LCIMRecalledMessage> Recall(LCIMMessage message) { public async Task<LCIMRecalledMessage> Recall(LCIMMessage message) {
if (message == null) {
throw new ArgumentNullException(nameof(message));
}
PatchCommand patch = new PatchCommand();
PatchItem item = new PatchItem {
Cid = Id,
Mid = message.Id,
Recall = true
};
patch.Patches.Add(item);
GenericCommand request = client.NewCommand(CommandType.Patch, OpType.Modify);
request.PatchMessage = patch;
GenericCommand response = await client.client.SendRequest(request);
return null; return null;
} }
/// <summary>
/// 静音
/// </summary>
/// <returns></returns>
public async Task<LCIMConversation> Mute() { public async Task<LCIMConversation> Mute() {
ConvCommand conv = new ConvCommand {
Cid = Id
};
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Mute);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
IsMute = true;
return this; return this;
} }
/// <summary>
/// 取消静音
/// </summary>
/// <returns></returns>
public async Task<LCIMConversation> Unmute() { public async Task<LCIMConversation> Unmute() {
ConvCommand conv = new ConvCommand {
Cid = Id
};
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Unmute);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
IsMute = false;
return this; return this;
} }
public async Task MuteMemberList(List<string> clientIdList) { /// <summary>
/// 禁言
/// </summary>
/// <param name="clientIds"></param>
/// <returns></returns>
public async Task MuteMembers(IEnumerable<string> clientIds) {
if (clientIds == null || clientIds.Count() == 0) {
throw new ArgumentNullException(nameof(clientIds));
}
ConvCommand conv = new ConvCommand {
Cid = Id
};
conv.M.AddRange(clientIds);
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.AddShutup);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
} }
public async Task UnmuteMemberList(List<string> clientIdList) { /// <summary>
/// 取消禁言
/// </summary>
/// <param name="clientIdList"></param>
/// <returns></returns>
public async Task UnmuteMembers(IEnumerable<string> clientIds) {
if (clientIds == null || clientIds.Count() == 0) {
throw new ArgumentNullException(nameof(clientIds));
}
ConvCommand conv = new ConvCommand {
Cid = Id
};
conv.M.AddRange(clientIds);
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Remove);
request.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(request);
} }
public async Task BlockMemberList(List<string> clientIdList) { /// <summary>
/// 将用户加入黑名单
/// </summary>
/// <param name="clientIds"></param>
/// <returns></returns>
public async Task BlockMembers(IEnumerable<string> clientIds) {
if (clientIds == null || clientIds.Count() == 0) {
throw new ArgumentNullException(nameof(clientIds));
}
BlacklistCommand blacklist = new BlacklistCommand {
SrcCid = Id,
};
GenericCommand request = client.NewCommand(CommandType.Blacklist, OpType.Block);
request.BlacklistMessage = blacklist;
await client.client.SendRequest(request);
} }
public async Task UnblockMemberList(List<string> clientIdList) { public async Task UnblockMembers(IEnumerable<string> clientIds) {
} }
@ -124,6 +306,10 @@ namespace LeanCloud.Realtime {
} }
public async Task<LCIMConversationMemberInfo> GetMemberInfo(string memberId) { public async Task<LCIMConversationMemberInfo> GetMemberInfo(string memberId) {
if (string.IsNullOrEmpty(memberId)) {
throw new ArgumentNullException(nameof(memberId));
}
return null; return null;
} }

View File

@ -1,7 +1,256 @@
using System; using System;
using System.Threading.Tasks;
using System.Collections;
using System.Collections.Generic;
using LeanCloud.Storage.Internal.Query;
using LeanCloud.Realtime.Protocol;
namespace LeanCloud.Realtime { namespace LeanCloud.Realtime {
public class LCIMConversationQuery { public class LCIMConversationQuery {
public LCIMConversationQuery() { private LCCompositionalCondition condition;
private LCIMClient client;
public LCIMConversationQuery(LCIMClient client) {
condition = new LCCompositionalCondition();
this.client = client;
}
/// <summary>
/// 等于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereEqualTo(string key, object value) {
condition.WhereEqualTo(key, value);
return this;
}
/// <summary>
/// 不等于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereNotEqualTo(string key, object value) {
condition.WhereNotEqualTo(key, value);
return this;
}
/// <summary>
/// 包含
/// </summary>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns></returns>
public LCIMConversationQuery WhereContainedIn(string key, IEnumerable values) {
condition.WhereContainedIn(key, values);
return this;
}
/// <summary>
/// 包含全部
/// </summary>
/// <param name="key"></param>
/// <param name="values"></param>
/// <returns></returns>
public LCIMConversationQuery WhereContainsAll(string key, IEnumerable values) {
condition.WhereContainsAll(key, values);
return this;
}
/// <summary>
/// 存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery WhereExists(string key) {
condition.WhereExists(key);
return this;
}
/// <summary>
/// 不存在
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery WhereDoesNotExist(string key) {
condition.WhereDoesNotExist(key);
return this;
}
/// <summary>
/// 长度等于
/// </summary>
/// <param name="key"></param>
/// <param name="size"></param>
/// <returns></returns>
public LCIMConversationQuery WhereSizeEqualTo(string key, int size) {
condition.WhereSizeEqualTo(key, size);
return this;
}
/// <summary>
/// 大于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereGreaterThan(string key, object value) {
condition.WhereGreaterThan(key, value);
return this;
}
/// <summary>
/// 大于等于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereGreaterThanOrEqualTo(string key, object value) {
condition.WhereGreaterThanOrEqualTo(key, value);
return this;
}
/// <summary>
/// 小于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereLessThan(string key, object value) {
condition.WhereLessThan(key, value);
return this;
}
/// <summary>
/// 小于等于
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery WhereLessThanOrEqualTo(string key, object value) {
condition.WhereLessThanOrEqualTo(key, value);
return this;
}
/// <summary>
/// 前缀
/// </summary>
/// <param name="key"></param>
/// <param name="prefix"></param>
/// <returns></returns>
public LCIMConversationQuery WhereStartsWith(string key, string prefix) {
condition.WhereStartsWith(key, prefix);
return this;
}
/// <summary>
/// 后缀
/// </summary>
/// <param name="key"></param>
/// <param name="suffix"></param>
/// <returns></returns>
public LCIMConversationQuery WhereEndsWith(string key, string suffix) {
condition.WhereEndsWith(key, suffix);
return this;
}
/// <summary>
/// 字符串包含
/// </summary>
/// <param name="key"></param>
/// <param name="subString"></param>
/// <returns></returns>
public LCIMConversationQuery WhereContains(string key, string subString) {
condition.WhereContains(key, subString);
return this;
}
/// <summary>
/// 按 key 升序
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery OrderBy(string key) {
condition.OrderBy(key);
return this;
}
/// <summary>
/// 按 key 降序
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery OrderByDescending(string key) {
condition.OrderByDescending(key);
return this;
}
/// <summary>
/// 拉取 key 的完整对象
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery Include(string key) {
condition.Include(key);
return this;
}
/// <summary>
/// 包含 key
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public LCIMConversationQuery Select(string key) {
condition.Select(key);
return this;
}
/// <summary>
/// 跳过
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery Skip(int value) {
condition.Skip = value;
return this;
}
/// <summary>
/// 限制数量
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public LCIMConversationQuery Limit(int value) {
condition.Limit = value;
return this;
}
public bool WithLastMessageRefreshed {
get; set;
}
public async Task<List<LCIMConversation>> Find() {
GenericCommand command = new GenericCommand {
Cmd = CommandType.Conv,
Op = OpType.Query,
AppId = LCApplication.AppId,
PeerId = client.ClientId,
};
ConvCommand conv = new ConvCommand();
string where = condition.BuildWhere();
if (!string.IsNullOrEmpty(where)) {
conv.Where = JsonObjectMessage.Parser.ParseJson(where);
}
command.ConvMessage = conv;
GenericCommand response = await client.client.SendRequest(command);
JsonObjectMessage results = response.ConvMessage.Results;
List<LCIMConversation> convList = null;
// TODO 反序列化
return convList;
} }
} }
} }

View File

@ -2,6 +2,16 @@
namespace LeanCloud.Realtime { namespace LeanCloud.Realtime {
public class LCIMTemporaryConversation : LCIMConversation { public class LCIMTemporaryConversation : LCIMConversation {
public DateTime ExpiredAt {
get;
}
public bool IsExpired {
get {
return DateTime.Now > ExpiredAt;
}
}
public LCIMTemporaryConversation(LCIMClient client) : base(client) { public LCIMTemporaryConversation(LCIMClient client) : base(client) {
} }
} }

View File

@ -24,24 +24,24 @@ namespace LeanCloud.Realtime {
get; set; get; set;
} }
/// <summary>
/// 当前客户端被服务端强行下线
/// </summary>
public Action OnClosed {
get; set;
}
/// <summary> /// <summary>
/// 客户端连接断开 /// 客户端连接断开
/// </summary> /// </summary>
public Action OnDisconnected { public Action OnPaused {
get; set; get; set;
} }
/// <summary> /// <summary>
/// 客户端连接恢复正常 /// 客户端连接恢复正常
/// </summary> /// </summary>
public Action OnReconnect { public Action OnResume {
get; set;
}
/// <summary>
/// 当前客户端被服务端强行下线
/// </summary>
public Action OnOffline {
get; set; get; set;
} }
@ -75,6 +75,10 @@ namespace LeanCloud.Realtime {
conversationDict = new Dictionary<string, LCIMConversation>(); conversationDict = new Dictionary<string, LCIMConversation>();
} }
/// <summary>
/// 连接
/// </summary>
/// <returns></returns>
public async Task Open() { public async Task Open() {
client = new LCWebSocketClient { client = new LCWebSocketClient {
OnNotification = OnNotification OnNotification = OnNotification
@ -86,6 +90,14 @@ namespace LeanCloud.Realtime {
await client.SendRequest(command); await client.SendRequest(command);
} }
/// <summary>
/// 关闭
/// </summary>
/// <returns></returns>
public async Task Close() {
await client.Close();
}
public async Task<LCIMChatRoom> CreateChatRoom( public async Task<LCIMChatRoom> CreateChatRoom(
string name, string name,
Dictionary<string, object> properties = null) { Dictionary<string, object> properties = null) {
@ -143,16 +155,48 @@ namespace LeanCloud.Realtime {
return conversation; return conversation;
} }
/// <summary>
/// 获取某个特定的对话
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<LCIMConversation> GetConversation(string id) { public async Task<LCIMConversation> GetConversation(string id) {
if (string.IsNullOrEmpty(id)) {
throw new ArgumentNullException(nameof(id));
}
LCIMConversationQuery query = GetQuery();
query.WhereEqualTo("objectId", id)
.Limit(1);
List<LCIMConversation> results = await query.Find();
if (results == null || results.Count < 1) {
return null; return null;
} }
return results[0];
public async Task<List<LCIMConversation>> GetConversationList(List<string> idList) {
return null;
} }
public async Task<LCIMConversationQuery> GetConversationQuery() { /// <summary>
return null; /// 获取某些特定的对话
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
public async Task<List<LCIMConversation>> GetConversationList(IEnumerable<string> ids) {
if (ids == null || ids.Count() == 0) {
throw new ArgumentNullException(nameof(ids));
}
List<LCIMConversation> conversationList = new List<LCIMConversation>();
foreach (string id in ids) {
LCIMConversation conversation = await GetConversation(id);
conversationList.Add(conversation);
}
return conversationList;
}
/// <summary>
/// 获取对话查询对象
/// </summary>
/// <returns></returns>
public LCIMConversationQuery GetQuery() {
return new LCIMConversationQuery(this);
} }
private void OnNotification(GenericCommand notification) { private void OnNotification(GenericCommand notification) {
@ -166,12 +210,22 @@ namespace LeanCloud.Realtime {
} }
private void OnConversationNotification(GenericCommand notification) { private void OnConversationNotification(GenericCommand notification) {
ConvCommand conv = notification.ConvMessage;
switch (notification.Op) { switch (notification.Op) {
case OpType.Joined: case OpType.Joined:
OnConversationJoined(notification.ConvMessage); OnConversationJoined(conv);
break; break;
case OpType.MembersJoined: case OpType.MembersJoined:
OnConversationMembersJoined(notification.ConvMessage); OnConversationMembersJoined(conv);
break;
case OpType.Left:
OnConversationLeft(conv);
break;
case OpType.MembersLeft:
OnConversationMemberLeft(conv);
break;
case OpType.Updated:
OnPropertiesUpdated(conv);
break; break;
default: default:
break; break;
@ -190,6 +244,26 @@ namespace LeanCloud.Realtime {
OnMembersJoined?.Invoke(conversation, conv.M.ToList(), conv.InitBy); OnMembersJoined?.Invoke(conversation, conv.M.ToList(), conv.InitBy);
} }
private void OnConversationLeft(ConvCommand conv) {
if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) {
OnKicked?.Invoke(conversation, conv.InitBy);
}
}
private void OnConversationMemberLeft(ConvCommand conv) {
if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) {
List<string> leftIdList = conv.M.ToList();
OnMembersLeft?.Invoke(conversation, leftIdList, conv.InitBy);
}
}
private void OnPropertiesUpdated(ConvCommand conv) {
if (conversationDict.TryGetValue(conv.Cid, out LCIMConversation conversation)) {
// TODO
}
}
private LCIMConversation GetOrCreateConversation(string convId) { private LCIMConversation GetOrCreateConversation(string convId) {
if (!conversationDict.TryGetValue(convId, out LCIMConversation conversation)) { if (!conversationDict.TryGetValue(convId, out LCIMConversation conversation)) {
conversation = new LCIMConversation(this); conversation = new LCIMConversation(this);

View File

@ -4,8 +4,8 @@ using System.Collections.Generic;
using LeanCloud.Storage.Internal.Object; using LeanCloud.Storage.Internal.Object;
namespace LeanCloud.Storage.Internal.Codec { namespace LeanCloud.Storage.Internal.Codec {
internal static class LCDecoder { public static class LCDecoder {
internal static object Decode(object obj) { public static object Decode(object obj) {
if (obj is IDictionary dict) { if (obj is IDictionary dict) {
if (dict.Contains("__type")) { if (dict.Contains("__type")) {
string type = dict["__type"].ToString(); string type = dict["__type"].ToString();

View File

@ -5,8 +5,8 @@ using LeanCloud.Storage.Internal.Operation;
using LeanCloud.Storage.Internal.Query; using LeanCloud.Storage.Internal.Query;
namespace LeanCloud.Storage.Internal.Codec { namespace LeanCloud.Storage.Internal.Codec {
internal static class LCEncoder { public static class LCEncoder {
internal static object Encode(object obj) { public static object Encode(object obj) {
if (obj is DateTime dateTime) { if (obj is DateTime dateTime) {
return EncodeDateTime(dateTime); return EncodeDateTime(dateTime);
} else if (obj is byte[] bytes) { } else if (obj is byte[] bytes) {

View File

@ -1,7 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace LeanCloud.Storage.Internal.Query { namespace LeanCloud.Storage.Internal.Query {
internal interface ILCQueryCondition { public interface ILCQueryCondition {
bool Equals(ILCQueryCondition other); bool Equals(ILCQueryCondition other);
Dictionary<string, object> Encode(); Dictionary<string, object> Encode();
} }

View File

@ -4,9 +4,9 @@ using Newtonsoft.Json;
using LeanCloud.Storage.Internal.Codec; using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Storage.Internal.Query { namespace LeanCloud.Storage.Internal.Query {
internal class LCCompositionalCondition : ILCQueryCondition { public class LCCompositionalCondition : ILCQueryCondition {
internal const string And = "$and"; public const string And = "$and";
internal const string Or = "$or"; public const string Or = "$or";
readonly string composition; readonly string composition;
@ -16,93 +16,93 @@ namespace LeanCloud.Storage.Internal.Query {
HashSet<string> includes; HashSet<string> includes;
HashSet<string> selectedKeys; HashSet<string> selectedKeys;
internal int Skip { public int Skip {
get; set; get; set;
} }
internal int Limit { public int Limit {
get; set; get; set;
} }
internal LCCompositionalCondition(string composition = And) { public LCCompositionalCondition(string composition = And) {
this.composition = composition; this.composition = composition;
Skip = 0; Skip = 0;
Limit = 30; Limit = 30;
} }
// 查询条件 // 查询条件
internal void WhereEqualTo(string key, object value) { public void WhereEqualTo(string key, object value) {
Add(new LCEqualCondition(key, value)); Add(new LCEqualCondition(key, value));
} }
internal void WhereNotEqualTo(string key, object value) { public void WhereNotEqualTo(string key, object value) {
AddOperation(key, "$ne", value); AddOperation(key, "$ne", value);
} }
internal void WhereContainedIn(string key, IEnumerable values) { public void WhereContainedIn(string key, IEnumerable values) {
AddOperation(key, "$in", values); AddOperation(key, "$in", values);
} }
internal void WhereNotContainedIn(string key, IEnumerable values) { public void WhereNotContainedIn(string key, IEnumerable values) {
AddOperation(key, "nin", values); AddOperation(key, "nin", values);
} }
internal void WhereContainsAll(string key, IEnumerable values) { public void WhereContainsAll(string key, IEnumerable values) {
AddOperation(key, "$all", values); AddOperation(key, "$all", values);
} }
internal void WhereExists(string key) { public void WhereExists(string key) {
AddOperation(key, "$exists", true); AddOperation(key, "$exists", true);
} }
internal void WhereDoesNotExist(string key) { public void WhereDoesNotExist(string key) {
AddOperation(key, "$exists", false); AddOperation(key, "$exists", false);
} }
internal void WhereSizeEqualTo(string key, int size) { public void WhereSizeEqualTo(string key, int size) {
AddOperation(key, "$size", size); AddOperation(key, "$size", size);
} }
internal void WhereGreaterThan(string key, object value) { public void WhereGreaterThan(string key, object value) {
AddOperation(key, "$gt", value); AddOperation(key, "$gt", value);
} }
internal void WhereGreaterThanOrEqualTo(string key, object value) { public void WhereGreaterThanOrEqualTo(string key, object value) {
AddOperation(key, "$gte", value); AddOperation(key, "$gte", value);
} }
internal void WhereLessThan(string key, object value) { public void WhereLessThan(string key, object value) {
AddOperation(key, "$lt", value); AddOperation(key, "$lt", value);
} }
internal void WhereLessThanOrEqualTo(string key, object value) { public void WhereLessThanOrEqualTo(string key, object value) {
AddOperation(key, "$lte", value); AddOperation(key, "$lte", value);
} }
internal void WhereNear(string key, LCGeoPoint point) { public void WhereNear(string key, LCGeoPoint point) {
AddOperation(key, "$nearSphere", point); AddOperation(key, "$nearSphere", point);
} }
internal void WhereWithinGeoBox(string key, LCGeoPoint southwest, LCGeoPoint northeast) { public void WhereWithinGeoBox(string key, LCGeoPoint southwest, LCGeoPoint northeast) {
Dictionary<string, object> value = new Dictionary<string, object> { Dictionary<string, object> value = new Dictionary<string, object> {
{ "$box", new List<object> { southwest, northeast } } { "$box", new List<object> { southwest, northeast } }
}; };
AddOperation(key, "$within", value); AddOperation(key, "$within", value);
} }
internal void WhereRelatedTo(LCObject parent, string key) { public void WhereRelatedTo(LCObject parent, string key) {
Add(new LCRelatedCondition(parent, key)); Add(new LCRelatedCondition(parent, key));
} }
internal void WhereStartsWith(string key, string prefix) { public void WhereStartsWith(string key, string prefix) {
AddOperation(key, "$regex", $"^{prefix}.*"); AddOperation(key, "$regex", $"^{prefix}.*");
} }
internal void WhereEndsWith(string key, string suffix) { public void WhereEndsWith(string key, string suffix) {
AddOperation(key, "$regex", $".*{suffix}$"); AddOperation(key, "$regex", $".*{suffix}$");
} }
internal void WhereContains(string key, string subString) { public void WhereContains(string key, string subString) {
AddOperation(key, "$regex", $".*{subString}.*"); AddOperation(key, "$regex", $".*{subString}.*");
} }
@ -111,7 +111,7 @@ namespace LeanCloud.Storage.Internal.Query {
Add(cond); Add(cond);
} }
internal void Add(ILCQueryCondition cond) { public void Add(ILCQueryCondition cond) {
if (cond == null) { if (cond == null) {
return; return;
} }
@ -123,25 +123,25 @@ namespace LeanCloud.Storage.Internal.Query {
} }
// 筛选条件 // 筛选条件
internal void OrderBy(string key) { public void OrderBy(string key) {
if (orderByList == null) { if (orderByList == null) {
orderByList = new List<string>(); orderByList = new List<string>();
} }
orderByList.Add(key); orderByList.Add(key);
} }
internal void OrderByDescending(string key) { public void OrderByDescending(string key) {
OrderBy($"-{key}"); OrderBy($"-{key}");
} }
internal void Include(string key) { public void Include(string key) {
if (includes == null) { if (includes == null) {
includes = new HashSet<string>(); includes = new HashSet<string>();
} }
includes.Add(key); includes.Add(key);
} }
internal void Select(string key) { public void Select(string key) {
if (selectedKeys == null) { if (selectedKeys == null) {
selectedKeys = new HashSet<string>(); selectedKeys = new HashSet<string>();
} }
@ -165,7 +165,7 @@ namespace LeanCloud.Storage.Internal.Query {
}; };
} }
internal Dictionary<string, object> BuildParams() { public Dictionary<string, object> BuildParams() {
Dictionary<string, object> dict = new Dictionary<string, object> { Dictionary<string, object> dict = new Dictionary<string, object> {
{ "skip", Skip }, { "skip", Skip },
{ "limit", Limit } { "limit", Limit }
@ -185,7 +185,7 @@ namespace LeanCloud.Storage.Internal.Query {
return dict; return dict;
} }
internal string BuildWhere() { public string BuildWhere() {
if (conditionList == null || conditionList.Count == 0) { if (conditionList == null || conditionList.Count == 0) {
return null; return null;
} }

View File

@ -2,11 +2,11 @@
using LeanCloud.Storage.Internal.Codec; using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Storage.Internal.Query { namespace LeanCloud.Storage.Internal.Query {
internal class LCEqualCondition : ILCQueryCondition { public class LCEqualCondition : ILCQueryCondition {
readonly string key; readonly string key;
readonly object value; readonly object value;
internal LCEqualCondition(string key, object value) { public LCEqualCondition(string key, object value) {
this.key = key; this.key = key;
this.value = value; this.value = value;
} }

View File

@ -2,12 +2,12 @@
using LeanCloud.Storage.Internal.Codec; using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Storage.Internal.Query { namespace LeanCloud.Storage.Internal.Query {
internal class LCOperationCondition : ILCQueryCondition { public class LCOperationCondition : ILCQueryCondition {
readonly string key; readonly string key;
readonly string op; readonly string op;
readonly object value; readonly object value;
internal LCOperationCondition(string key, string op, object value) { public LCOperationCondition(string key, string op, object value) {
this.key = key; this.key = key;
this.op = op; this.op = op;
this.value = value; this.value = value;

View File

@ -2,11 +2,11 @@
using LeanCloud.Storage.Internal.Codec; using LeanCloud.Storage.Internal.Codec;
namespace LeanCloud.Storage.Internal.Query { namespace LeanCloud.Storage.Internal.Query {
internal class LCRelatedCondition : ILCQueryCondition { public class LCRelatedCondition : ILCQueryCondition {
readonly LCObject parent; readonly LCObject parent;
readonly string key; readonly string key;
internal LCRelatedCondition(LCObject parent, string key) { public LCRelatedCondition(LCObject parent, string key) {
this.parent = parent; this.parent = parent;
this.key = key; this.key = key;
} }

View File

@ -91,5 +91,34 @@ namespace Realtime.Test {
await tcs.Task; await tcs.Task;
} }
[Test]
public async Task Query() {
LCIMClient client = new LCIMClient("hello123");
await client.Open();
LCIMConversationQuery query = new LCIMConversationQuery(client);
await query.Find();
}
[Test]
public async Task Save() {
string clientId = Guid.NewGuid().ToString();
LCIMClient client = new LCIMClient(clientId);
await client.Open();
string otherId = Guid.NewGuid().ToString();
LCIMConversation conversation = await client.CreateConversation(new List<string> { otherId });
conversation.Name = "leancloud";
conversation["k1"] = "v1";
conversation["k2"] = "v2";
await conversation.Save();
Assert.AreEqual(conversation.Name, "leancloud");
Assert.AreEqual(conversation["k1"], "v1");
Assert.AreEqual(conversation["k2"], "v2");
}
} }
} }