stream-chat
Version:
JS SDK for the Stream Chat API
97 lines (89 loc) • 3.08 kB
text/typescript
import { BaseSearchSource, type SearchQueryOptions } from './BaseSearchSource';
import { FilterBuilder, type FilterBuilderOptions } from '../pagination';
import type { Channel } from '../channel';
import type {
ChannelMemberResponse,
MemberFilters,
MemberSort,
QueryMembersOptions,
} from '../types';
import type { SearchSourceOptions } from './types';
type CustomContext = Record<string, unknown>;
export type ChannelMemberSearchSourceFilterBuilderContext<
C extends CustomContext = CustomContext,
> = { searchQuery?: string } & C;
export type ChannelMemberSearchSourceOptions = SearchSourceOptions & {
/** Static base filters merged under the dynamically generated ones. */
filters?: MemberFilters;
sort?: MemberSort;
searchOptions?: Omit<QueryMembersOptions, 'limit' | 'offset'>;
};
export class ChannelMemberSearchSource<
TFilterContext extends CustomContext = CustomContext,
> extends BaseSearchSource<ChannelMemberResponse> {
readonly type = 'members';
channel: Channel;
filters: MemberFilters | undefined;
sort: MemberSort | undefined;
searchOptions: Omit<QueryMembersOptions, 'limit' | 'offset'> | undefined;
filterBuilder: FilterBuilder<
MemberFilters,
ChannelMemberSearchSourceFilterBuilderContext<TFilterContext>
>;
constructor(
channel: Channel,
options?: ChannelMemberSearchSourceOptions,
filterBuilderOptions: FilterBuilderOptions<
MemberFilters,
ChannelMemberSearchSourceFilterBuilderContext<TFilterContext>
> = {},
) {
const { filters, sort, searchOptions, ...restOptions } = options || {};
// members are listed with an empty query, so the initial load must be allowed
super({ ...restOptions, allowEmptySearchString: true });
this.channel = channel;
this.filters = filters;
this.sort = sort;
this.searchOptions = searchOptions;
this.filterBuilder = new FilterBuilder<
MemberFilters,
ChannelMemberSearchSourceFilterBuilderContext<TFilterContext>
>({
initialFilterConfig: {
default: {
enabled: true,
generate: ({ searchQuery }) =>
searchQuery
? {
$or: [
{ name: { $autocomplete: searchQuery } },
{ id: { $eq: searchQuery } },
],
}
: null,
},
},
...filterBuilderOptions,
});
}
protected async query(searchQuery: string, queryOptions: SearchQueryOptions = {}) {
const filters = this.filterBuilder.buildFilters({
baseFilters: this.filters,
context: {
searchQuery,
} as ChannelMemberSearchSourceFilterBuilderContext<TFilterContext>,
});
const sort = this.sort ?? [];
const options = { ...this.searchOptions, limit: this.pageSize, offset: this.offset };
const { members } = await this.channel.queryMembers(
filters ?? {},
sort,
options,
queryOptions,
);
return { items: members };
}
protected filterQueryResults(items: ChannelMemberResponse[]) {
return items;
}
}