Skip to content

Commit 701183f

Browse files
Enable midpoint matching in findIndexInSortedArray, use it instead of binarySearchByDateEqualOrNearestGreater
1 parent 93c4e98 commit 701183f

File tree

3 files changed

+91
-60
lines changed

3 files changed

+91
-60
lines changed

src/utils.ts

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ export const findIndexInSortedArray = <T, L>({
353353

354354
const comparableMiddle = selectValueToCompare(sortedArray[middle]);
355355

356-
// if (comparableNeedle === comparableMiddle) return middle;
356+
if (comparableNeedle === comparableMiddle) return middle;
357357

358358
if (
359359
(sortDirection === 'ascending' && comparableNeedle < comparableMiddle) ||
@@ -499,36 +499,6 @@ type MessagePaginationUpdatedParams<StreamChatGenerics extends ExtendableGeneric
499499
messagePaginationOptions?: MessagePaginationOptions;
500500
};
501501

502-
export function binarySearchByDateEqualOrNearestGreater(
503-
array: {
504-
created_at?: string;
505-
}[],
506-
targetDate: Date,
507-
): number {
508-
let left = 0;
509-
let right = array.length - 1;
510-
511-
while (left <= right) {
512-
const mid = Math.floor((left + right) / 2);
513-
const midCreatedAt = array[mid].created_at;
514-
if (!midCreatedAt) {
515-
left += 1;
516-
continue;
517-
}
518-
const midDate = new Date(midCreatedAt);
519-
520-
if (midDate.getTime() === targetDate.getTime()) {
521-
return mid;
522-
} else if (midDate.getTime() < targetDate.getTime()) {
523-
left = mid + 1;
524-
} else {
525-
right = mid - 1;
526-
}
527-
}
528-
529-
return left;
530-
}
531-
532502
const messagePaginationCreatedAtAround = <StreamChatGenerics extends ExtendableGenerics = DefaultGenerics>({
533503
parentSet,
534504
requestedPageSize,
@@ -580,7 +550,12 @@ const messagePaginationCreatedAtAround = <StreamChatGenerics extends ExtendableG
580550
updateHasPrev = firstPageMsgIsFirstInSet;
581551
updateHasNext = lastPageMsgIsLastInSet;
582552
const midPointByCount = Math.floor(returnedPage.length / 2);
583-
const midPointByCreationDate = binarySearchByDateEqualOrNearestGreater(returnedPage, createdAtAroundDate);
553+
const midPointByCreationDate = findIndexInSortedArray<{ created_at: Date }, number>({
554+
needle: { created_at: createdAtAroundDate },
555+
sortedArray: returnedPage.map(formatMessage),
556+
sortDirection: 'ascending',
557+
selectValueToCompare: (message) => message.created_at.getTime(),
558+
});
584559

585560
if (midPointByCreationDate !== -1) {
586561
hasPrev = midPointByCount <= midPointByCreationDate;

test/unit/utils.js

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,23 +2690,3 @@ describe('messageSetPagination', () => {
26902690
});
26912691
});
26922692
});
2693-
2694-
describe('', () => {
2695-
const messages = [
2696-
{ created_at: '2024-08-05T08:55:00.199808Z', id: '0' },
2697-
{ created_at: '2024-08-05T08:55:01.199808Z', id: '1' },
2698-
{ created_at: '2024-08-05T08:55:02.199808Z', id: '2' },
2699-
{ created_at: '2024-08-05T08:55:03.199808Z', id: '3' },
2700-
{ created_at: '2024-08-05T08:55:04.199808Z', id: '4' },
2701-
{ created_at: '2024-08-05T08:55:05.199808Z', id: '5' },
2702-
{ created_at: '2024-08-05T08:55:06.199808Z', id: '6' },
2703-
{ created_at: '2024-08-05T08:55:07.199808Z', id: '7' },
2704-
{ created_at: '2024-08-05T08:55:08.199808Z', id: '8' },
2705-
];
2706-
it('finds the nearest newer item', () => {
2707-
expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:02.299808Z'))).to.eql(3);
2708-
});
2709-
it('finds the nearest matching item', () => {
2710-
expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:07.199808Z'))).to.eql(7);
2711-
});
2712-
});

test/unit/utils.test.ts

Lines changed: 84 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import { v4 as uuidv4 } from 'uuid';
33

44
import { generateMsg } from './test-utils/generateMessage';
55

6-
import { addToMessageList, formatMessage } from '../../src/utils';
6+
import { addToMessageList, findIndexInSortedArray, formatMessage } from '../../src/utils';
77

88
import type { FormatMessageResponse, MessageResponse } from '../../src';
99

1010
describe('addToMessageList', () => {
11-
const timestamp = new Date('2024-09-18T15:30:00.000Z').getTime();
11+
const timestamp = new Date('2024-01-01T00:00:00.000Z').getTime();
1212
// messages with each created_at 10 seconds apart
1313
let messagesBefore: FormatMessageResponse[];
1414

@@ -93,15 +93,91 @@ describe('addToMessageList', () => {
9393
});
9494

9595
it("updates an existing message that wasn't filtered due to changed timestamp (timestampChanged)", () => {
96-
const newMessage = getNewFormattedMessage({ timeOffset: 30 * 1000, id: messagesBefore[4].id });
96+
const newMessage = getNewFormattedMessage({ timeOffset: 30 * 1000, id: messagesBefore[3].id });
9797

98-
expect(messagesBefore[4].id).to.equal(newMessage.id);
99-
expect(messagesBefore[4].text).to.not.equal(newMessage.text);
100-
expect(messagesBefore[4]).to.not.equal(newMessage);
98+
expect(messagesBefore[3].id).to.equal(newMessage.id);
99+
expect(messagesBefore[3].text).to.not.equal(newMessage.text);
100+
expect(messagesBefore[3]).to.not.equal(newMessage);
101101

102-
const messagesAfter = addToMessageList(messagesBefore, newMessage, false, 'created_at', false);
102+
const messagesAfter = addToMessageList(messagesBefore, newMessage, false);
103103

104104
expect(messagesAfter).to.have.length(5);
105-
expect(messagesAfter[4]).to.equal(newMessage);
105+
expect(messagesAfter[3]).to.equal(newMessage);
106+
});
107+
});
108+
109+
describe('findIndexInSortedArray', () => {
110+
const timestamp = new Date('2024-01-01T00:00:00.000Z').getTime();
111+
112+
const generateMessages = ({ count = 10, sort = 'desc' }: { count?: number; sort?: 'asc' | 'desc' } = {}) => {
113+
const messages = Array.from({ length: count }, (_, index) =>
114+
generateMsg({ created_at: new Date(timestamp + index * 10 * 1000).toISOString() }),
115+
);
116+
117+
if (sort === 'desc') {
118+
messages.reverse();
119+
}
120+
121+
return messages as MessageResponse[];
122+
};
123+
124+
describe('ascending order', () => {
125+
const messages = generateMessages({ sort: 'asc' }).map(formatMessage);
126+
127+
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(),
135+
});
136+
137+
expect(index).to.equal(3);
138+
});
139+
140+
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(),
148+
});
149+
150+
expect(index).to.equal(2);
151+
});
152+
});
153+
154+
describe('descending order', () => {
155+
const messages = generateMessages({ sort: 'desc' }).map(formatMessage);
156+
157+
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(),
165+
});
166+
167+
expect(index).to.equal(7);
168+
});
169+
170+
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(),
178+
});
179+
180+
expect(index).to.equal(8);
181+
});
106182
});
107183
});

0 commit comments

Comments
 (0)