GetStream / stream-chat-swift

๐Ÿ’ฌ iOS Chat SDK in Swift - Build your own app chat experience for iOS using the official Stream Chat API
https://getstream.io/chat/sdk/ios/
Other
861 stars 211 forks source link

fix: avoid FALSEPREDICATE for user-defined FilterKey #3482

Closed kaijietti closed 1 week ago

kaijietti commented 2 weeks ago

๐Ÿ”— Issue Links

None. The issue is easy to reproduce.

Filter is mainly used in two cases:

  1. Construct the payload of the request sent to Stream backend API.
  2. Construct the predicate of the request sent to CoreData Database.

After creating a ChatChannelListController, the controller owns a query inside which is a filter. The filter is mix-used in the above two cases. On one hand, stream API supprt filtering extraData of channel. So user can defined their custom field via extension:

extension FilterKey where Scope: AnyChannelListFilterScope {
  static var customField1: FilterKey<Scope, Bool> { "customField1" }
  static var customField2: FilterKey<Scope, String> { "customField2" }
}

and use it in this way:

extension ChannelListQuery {
  static func custom(id: UserModel.ID) -> Self {
    Self(
      filter: .and([
        .or([
          .equal(.customField1, to: true),
          .or([
            .equal(.customField2, to: "1"),
            .equal(.customField2, to: "2"),
          ])
        ]),
        .containMembers(userIds: [id.rawValue]),
        .equal(.frozen, to: false),
        .equal(.hidden, to: false),
        .equal(.disabled, to: false),
      ]),
      sort: [.init(key: .lastMessageAt)],
      pageSize: 20,
      messagesLimit: 3
    )
  }
}

We have checked the the query sent to the stream backend is correct as it should be.

However, on the other hand, the filter inside the query is also used in the process of constructing predicate of request sent to the local Database. And since the custom FilterKey has no related ChannelDTO field, so the KeyPathString is nil, and thus for all custom FilterKey, the predicate is actually a nil. This works fine when the filter is so flat. But when all the subpredicates inside a logicalPredicate are custom Filterkey, all the NSPredicate? they return is nil and thus being filtered out when using .compactMap(...), and the predicate would be NSCompoundPredicate(andPredicateWithSubpredicates: []) or NSCompoundPredicate(orPredicateWithSubpredicates: []) which is actually a FALSEPREDICATE. And since the final predicate is an .and operator, the predicate is always false and no data is fetched back. https://github.com/GetStream/stream-chat-swift/blob/f908d69751e92feb3b645042dd00fb46dfa5bb73/Sources/StreamChat/Database/DTOs/ChannelDTO.swift#L411-L415

๐ŸŽฏ Goal

Make sure the request SQL sent to the CoreData DB is correct (or, avoid FALSEPREDICATE) when user is using compound predicate in which all the subpredicates are related to user-defined FilterKey.

๐Ÿ“ Summary

Provide bullet points with the most important changes in the codebase.

๐Ÿ›  Implementation

Provide a detailed description of the implementation and explain your decisions if you find them relevant.

๐ŸŽจ Showcase

Add relevant screenshots and/or videos/gifs to easily see what this PR changes, if applicable.

Before After
img img

๐Ÿงช Manual Testing Notes

Explain how this change can be tested manually, if applicable.

โ˜‘๏ธ Contributor Checklist

๐ŸŽ Meme

Provide a funny gif or image that relates to your work on this pull request. (Optional)