Skip to content

Commit efd7c38

Browse files
committed
fix: hide search by midpoint behind a flag
1 parent 544753a commit efd7c38

File tree

3 files changed

+96
-48
lines changed

3 files changed

+96
-48
lines changed

src/utils.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,12 +310,18 @@ export function formatMessage<StreamChatGenerics extends ExtendableGenerics = De
310310

311311
export const findIndexInSortedArray = <T, L>({
312312
needle,
313+
returnOnMidMatch,
313314
sortedArray,
314315
selectValueToCompare = (e) => e,
315316
sortDirection = 'ascending',
316317
}: {
317318
needle: T;
318319
sortedArray: readonly T[];
320+
/**
321+
* Returns the index of the midpoint if it matches the target value.
322+
* Should be enabled only if the searched array cannot contain duplicates.
323+
*/
324+
returnOnMidMatch?: boolean;
319325
/**
320326
* In array of objects (like messages), pick a specific
321327
* property to compare needle value to.
@@ -353,7 +359,7 @@ export const findIndexInSortedArray = <T, L>({
353359

354360
const comparableMiddle = selectValueToCompare(sortedArray[middle]);
355361

356-
if (comparableNeedle === comparableMiddle) return middle;
362+
if (returnOnMidMatch && comparableNeedle === comparableMiddle) return middle;
357363

358364
if (
359365
(sortDirection === 'ascending' && comparableNeedle < comparableMiddle) ||

test/unit/channel_state.js

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,38 @@ describe('ChannelState addMessagesSorted', function () {
9797

9898
it('add a message with same created_at', async function () {
9999
const state = new ChannelState();
100-
101-
for (let i = 0; i < 10; i++) {
102-
state.addMessagesSorted([generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.00${i}Z` })]);
100+
const pairCount = 10;
101+
const msgCount = pairCount * 2;
102+
103+
for (let i = 0; i < msgCount; i+=2) {
104+
state.addMessagesSorted([
105+
generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.0${i.toString().padStart(2, '0')}Z` }),
106+
generateMsg({ id: `${i+1}`, date: `2020-01-01T00:00:00.0${i.toString().padStart(2, '0')}Z` }),
107+
]
108+
);
103109
}
104110

105-
for (let i = 10; i < state.messages.length - 1; i++) {
106-
for (let j = i + 1; i < state.messages.length - 1; j++)
107-
expect(state.messages[i].created_at.getTime()).to.be.lessThan(state.messages[j].created_at.getTime());
111+
for (let i = 0; i < msgCount; i+=2) {
112+
expect(state.messages[i].created_at.getTime()).to.be.eq(state.messages[i+1].created_at.getTime());
113+
if (i+2 < msgCount) {
114+
expect(state.messages[i].created_at.getTime()).to.be.lessThan(state.messages[i + 2].created_at.getTime());
115+
}
108116
}
109117

110-
expect(state.messages).to.have.length(10);
111-
state.addMessagesSorted([generateMsg({ id: 'id', date: `2020-01-01T00:00:00.007Z` })]);
112-
expect(state.messages).to.have.length(11);
113-
expect(state.messages[7].id).to.be.equal('id');
114-
expect(state.messages[8].id).to.be.equal('7');
118+
expect(state.messages).to.have.length(msgCount);
119+
state.addMessagesSorted([generateMsg({ id: '1stAdded', date: `2020-01-01T00:00:00.014Z` })]);
120+
121+
expect(state.messages).to.have.length(msgCount + 1);
122+
expect(state.messages[14].id).to.be.equal('14');
123+
expect(state.messages[15].id).to.be.equal('15');
124+
expect(state.messages[16].id).to.be.equal('1stAdded');
125+
state.addMessagesSorted([generateMsg({ id: '2ndAdded', date: `2020-01-01T00:00:00.014Z` })]);
126+
127+
expect(state.messages).to.have.length(msgCount + 2);
128+
expect(state.messages[14].id).to.be.equal('14');
129+
expect(state.messages[15].id).to.be.equal('15');
130+
expect(state.messages[16].id).to.be.equal('1stAdded');
131+
expect(state.messages[17].id).to.be.equal('2ndAdded');
115132
});
116133

117134
it('add lots of messages in order', async function () {

test/unit/utils.test.ts

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -125,59 +125,84 @@ describe('findIndexInSortedArray', () => {
125125
const messages = generateMessages({ sort: 'asc' }).map(formatMessage);
126126

127127
it('finds index of the message with closest matching created_at', () => {
128-
const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse);
128+
[
129+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), returnOnMidMatch: true},
130+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), returnOnMidMatch: false},
131+
].forEach(({newMessage, returnOnMidMatch}) => {
132+
const index = findIndexInSortedArray({
133+
needle: newMessage,
134+
returnOnMidMatch,
135+
sortedArray: messages,
136+
sortDirection: 'ascending',
137+
selectValueToCompare: (v) => v.created_at.getTime(),
138+
});
139+
140+
expect(index).to.equal(3);
141+
})
129142

130-
const index = findIndexInSortedArray({
131-
needle: newMessage,
132-
sortedArray: messages,
133-
sortDirection: 'ascending',
134-
selectValueToCompare: (v) => v.created_at.getTime(),
135-
});
136-
137-
expect(index).to.equal(3);
138143
});
139144

140145
it('finds exact index', () => {
141-
const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse);
142-
143-
const index = findIndexInSortedArray({
144-
needle: newMessage,
145-
sortedArray: messages,
146-
sortDirection: 'ascending',
147-
selectValueToCompare: (v) => v.created_at.getTime(),
146+
[
147+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse), returnOnMidMatch: true},
148+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse), returnOnMidMatch: false},
149+
].forEach(({newMessage, returnOnMidMatch}) => {
150+
const index = findIndexInSortedArray({
151+
needle: newMessage,
152+
returnOnMidMatch,
153+
sortedArray: messages,
154+
sortDirection: 'ascending',
155+
selectValueToCompare: (v) => v.created_at.getTime(),
156+
});
157+
158+
if (returnOnMidMatch) {
159+
expect(index).to.equal(2);
160+
} else {
161+
expect(index).to.equal(3);
162+
}
148163
});
149-
150-
expect(index).to.equal(2);
151164
});
152165
});
153166

154167
describe('descending order', () => {
155168
const messages = generateMessages({ sort: 'desc' }).map(formatMessage);
156169

157170
it('finds index of the message with closest matching created_at', () => {
158-
const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse);
159-
160-
const index = findIndexInSortedArray({
161-
needle: newMessage,
162-
sortedArray: messages,
163-
sortDirection: 'descending',
164-
selectValueToCompare: (v) => v.created_at.getTime(),
171+
[
172+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), returnOnMidMatch: true},
173+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse), returnOnMidMatch: false},
174+
].forEach(({newMessage, returnOnMidMatch}) => {
175+
176+
const index = findIndexInSortedArray({
177+
needle: newMessage,
178+
returnOnMidMatch,
179+
sortedArray: messages,
180+
sortDirection: 'descending',
181+
selectValueToCompare: (v) => v.created_at.getTime(),
182+
});
183+
184+
expect(index).to.equal(7);
165185
});
166-
167-
expect(index).to.equal(7);
168186
});
169187

170188
it('finds exact index', () => {
171-
const newMessage = formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse);
172-
173-
const index = findIndexInSortedArray({
174-
needle: newMessage,
175-
sortedArray: messages,
176-
sortDirection: 'descending',
177-
selectValueToCompare: (v) => v.created_at.getTime(),
189+
[
190+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse), returnOnMidMatch: true},
191+
{newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse), returnOnMidMatch: false},
192+
].forEach(({newMessage, returnOnMidMatch}) => {
193+
const index = findIndexInSortedArray({
194+
needle: newMessage,
195+
returnOnMidMatch,
196+
sortedArray: messages,
197+
sortDirection: 'descending',
198+
selectValueToCompare: (v) => v.created_at.getTime(),
199+
});
200+
if (returnOnMidMatch) {
201+
expect(index).to.equal(8);
202+
} else {
203+
expect(index).to.equal(9);
204+
}
178205
});
179-
180-
expect(index).to.equal(8);
181206
});
182207
});
183208
});

0 commit comments

Comments
 (0)