Skip to content

Commit d009882

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

File tree

3 files changed

+119
-48
lines changed

3 files changed

+119
-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: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,39 @@ 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+
]);
103108
}
104109

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());
110+
for (let i = 0; i < msgCount; i += 2) {
111+
expect(state.messages[i].created_at.getTime()).to.be.eq(state.messages[i + 1].created_at.getTime());
112+
if (i + 2 < msgCount) {
113+
expect(state.messages[i].created_at.getTime()).to.be.lessThan(
114+
state.messages[i + 2].created_at.getTime(),
115+
);
116+
}
108117
}
109118

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');
119+
expect(state.messages).to.have.length(msgCount);
120+
state.addMessagesSorted([generateMsg({ id: '1stAdded', date: `2020-01-01T00:00:00.014Z` })]);
121+
122+
expect(state.messages).to.have.length(msgCount + 1);
123+
expect(state.messages[14].id).to.be.equal('14');
124+
expect(state.messages[15].id).to.be.equal('15');
125+
expect(state.messages[16].id).to.be.equal('1stAdded');
126+
state.addMessagesSorted([generateMsg({ id: '2ndAdded', date: `2020-01-01T00:00:00.014Z` })]);
127+
128+
expect(state.messages).to.have.length(msgCount + 2);
129+
expect(state.messages[14].id).to.be.equal('14');
130+
expect(state.messages[15].id).to.be.equal('15');
131+
expect(state.messages[16].id).to.be.equal('1stAdded');
132+
expect(state.messages[17].id).to.be.equal('2ndAdded');
115133
});
116134

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

test/unit/utils.test.ts

Lines changed: 83 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -125,59 +125,106 @@ 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);
129-
130-
const index = findIndexInSortedArray({
131-
needle: newMessage,
132-
sortedArray: messages,
133-
sortDirection: 'ascending',
134-
selectValueToCompare: (v) => v.created_at.getTime(),
128+
[
129+
{
130+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse),
131+
returnOnMidMatch: true,
132+
},
133+
{
134+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse),
135+
returnOnMidMatch: false,
136+
},
137+
].forEach(({ newMessage, returnOnMidMatch }) => {
138+
const index = findIndexInSortedArray({
139+
needle: newMessage,
140+
returnOnMidMatch,
141+
sortedArray: messages,
142+
sortDirection: 'ascending',
143+
selectValueToCompare: (v) => v.created_at.getTime(),
144+
});
145+
146+
expect(index).to.equal(3);
135147
});
136-
137-
expect(index).to.equal(3);
138148
});
139149

140150
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(),
151+
[
152+
{
153+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse),
154+
returnOnMidMatch: true,
155+
},
156+
{
157+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 20 * 1000) }) as MessageResponse),
158+
returnOnMidMatch: false,
159+
},
160+
].forEach(({ newMessage, returnOnMidMatch }) => {
161+
const index = findIndexInSortedArray({
162+
needle: newMessage,
163+
returnOnMidMatch,
164+
sortedArray: messages,
165+
sortDirection: 'ascending',
166+
selectValueToCompare: (v) => v.created_at.getTime(),
167+
});
168+
169+
if (returnOnMidMatch) {
170+
expect(index).to.equal(2);
171+
} else {
172+
expect(index).to.equal(3);
173+
}
148174
});
149-
150-
expect(index).to.equal(2);
151175
});
152176
});
153177

154178
describe('descending order', () => {
155179
const messages = generateMessages({ sort: 'desc' }).map(formatMessage);
156180

157181
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(),
182+
[
183+
{
184+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse),
185+
returnOnMidMatch: true,
186+
},
187+
{
188+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 22 * 1000) }) as MessageResponse),
189+
returnOnMidMatch: false,
190+
},
191+
].forEach(({ newMessage, returnOnMidMatch }) => {
192+
const index = findIndexInSortedArray({
193+
needle: newMessage,
194+
returnOnMidMatch,
195+
sortedArray: messages,
196+
sortDirection: 'descending',
197+
selectValueToCompare: (v) => v.created_at.getTime(),
198+
});
199+
200+
expect(index).to.equal(7);
165201
});
166-
167-
expect(index).to.equal(7);
168202
});
169203

170204
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(),
205+
[
206+
{
207+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse),
208+
returnOnMidMatch: true,
209+
},
210+
{
211+
newMessage: formatMessage(generateMsg({ created_at: new Date(timestamp + 10 * 1000) }) as MessageResponse),
212+
returnOnMidMatch: false,
213+
},
214+
].forEach(({ newMessage, returnOnMidMatch }) => {
215+
const index = findIndexInSortedArray({
216+
needle: newMessage,
217+
returnOnMidMatch,
218+
sortedArray: messages,
219+
sortDirection: 'descending',
220+
selectValueToCompare: (v) => v.created_at.getTime(),
221+
});
222+
if (returnOnMidMatch) {
223+
expect(index).to.equal(8);
224+
} else {
225+
expect(index).to.equal(9);
226+
}
178227
});
179-
180-
expect(index).to.equal(8);
181228
});
182229
});
183230
});

0 commit comments

Comments
 (0)