Files
wx-win-agent/node-agent/WxAgent.Core/WechatContactQuery.cs
T

42 lines
1.8 KiB
C#

namespace WxAgent.Core;
public sealed record WechatDatabaseContact(string Username, string? NickName, string? Remark, string? AvatarUrl)
{
public string DisplayName => !string.IsNullOrWhiteSpace(Remark) ? Remark :
!string.IsNullOrWhiteSpace(NickName) ? NickName : Username;
}
public sealed record WechatContactPage(IReadOnlyList<WechatDatabaseContact> Contacts, int? NextOffset)
{
public bool HasMore => NextOffset is not null;
}
public static class WechatContactQuery
{
// Stable IDs, not display names, define ordering and identity. No UI fallback.
public const string Sql = """
SELECT username, nick_name, remark, small_head_url FROM contact
WHERE ($contains IS NULL OR instr(username, $contains) > 0
OR instr(nick_name, $contains) > 0 OR instr(remark, $contains) > 0)
AND ($groups IS NULL OR (substr(username, -9) = '@chatroom') = $groups)
ORDER BY username COLLATE BINARY LIMIT $limit OFFSET $offset;
""";
public static IReadOnlyList<KeyValuePair<string, object?>> Parameters(int limit, int offset, string? contains, bool? groupsOnly)
{
if (limit is < 1 or > 10000 || offset < 0 || offset > int.MaxValue - limit)
throw new WxAgentException(WxAgentErrorCode.InvalidArgument, "Contact limit must be 1-10000 and offset must leave room for the next page.");
return new KeyValuePair<string, object?>[]
{
new("$limit", limit + 1), new("$offset", offset), new("$contains", contains),
new("$groups", groupsOnly is null ? null : groupsOnly.Value ? 1 : 0)
};
}
public static WechatContactPage Page(IReadOnlyList<WechatDatabaseContact> rows, int limit, int offset)
{
_ = Parameters(limit, offset, null, null);
return new(rows.Take(limit).ToArray(), rows.Count > limit ? offset + limit : null);
}
}