Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 34 additions & 12 deletions package/src/store/__tests__/selectMessagesForChannels.test.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
import { generateChannelResponse } from '../../mock-builders/generator/channel';
import { generateMessage } from '../../mock-builders/generator/message';
import { BetterSqlite } from '../../test-utils/BetterSqlite';
import { getChannels } from '../apis/getChannels';
import { selectMessagesForChannels } from '../apis/queries/selectMessagesForChannels';
import { upsertChannels } from '../apis/upsertChannels';
import { SqliteClient } from '../SqliteClient';

/**
* The client treats the cached page as a `queryChannels` page of 25 messages, so a shorter one reads
* as the start of the channel and older messages never load from the server.
* The client reads the cached page as a channel list page of `message_limit` messages, so a page of
* a different size makes it guess wrongly whether older messages exist, for example that a channel
* with a long history starts at its cached messages.
*/
describe('selectMessagesForChannels', () => {
let cid: string;
let messages: ReturnType<typeof generateMessage>[];

beforeEach(async () => {
await SqliteClient.initializeDatabase();
await BetterSqlite.openDB();
});

afterEach(() => {
BetterSqlite.dropAllTables();
BetterSqlite.closeDB();
});

it("returns a channel's newest 25 messages, oldest first", async () => {
const channelResponse = generateChannelResponse({ members: [], messages: [] });
const cid = channelResponse.channel.cid as string;
const messages = Array.from({ length: 30 }, (_, i) =>
cid = channelResponse.channel.cid as string;
messages = Array.from({ length: 30 }, (_, i) =>
generateMessage({ cid, timestamp: Date.UTC(2020, 0, 1, 0, i) }),
);
channelResponse.messages = messages as unknown as typeof channelResponse.messages;
await upsertChannels({
channels: [channelResponse] as unknown as Parameters<typeof upsertChannels>[0]['channels'],
isLatestMessagesSet: true,
});
});

afterEach(() => {
BetterSqlite.dropAllTables();
BetterSqlite.closeDB();
});

const ids = (rows: { id: string }[]) => rows.map((row) => row.id);

it("returns a channel's newest 25 messages, oldest first, by default", async () => {
const rows = await selectMessagesForChannels([cid]);

expect(rows.map((row) => row.id)).toEqual(messages.slice(-25).map((message) => message.id));
expect(ids(rows)).toEqual(ids(messages.slice(-25)));
});

it("returns a channel's newest `messageLimit` messages", async () => {
expect(ids(await selectMessagesForChannels([cid], 10))).toEqual(ids(messages.slice(-10)));
expect(ids(await selectMessagesForChannels([cid], 50))).toEqual(ids(messages));
});

it('applies the limit that getChannels is given', async () => {
const [channel] = await getChannels({
channelIds: [cid],
messageLimit: 10,
userId: 'some-user',
});

expect(ids(channel.messages)).toEqual(ids(messages.slice(-10)));
});
});
5 changes: 4 additions & 1 deletion package/src/store/apis/getChannelMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,18 @@ import type { TableRow, TableRowJoinedUser } from '../types';
export const getChannelMessages = async ({
channelIds,
userId,
messageLimit,
}: {
channelIds: string[];
userId: string;
messageLimit?: number;
}) => {
SqliteClient.logger?.('info', 'getChannelMessages', {
channelIds,
userId,
messageLimit,
});
const messageRows = await selectMessagesForChannels(channelIds);
const messageRows = await selectMessagesForChannels(channelIds, messageLimit);
const messageIds = messageRows.map(({ id }) => id);

const reactionRows = await selectReactionsForMessages(messageIds, null);
Expand Down
6 changes: 5 additions & 1 deletion package/src/store/apis/getChannels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@ import { SqliteClient } from '../SqliteClient';
*
* @param params.channelIds The channel IDs to fetch.
* @param params.userId The ID of the current user.
* @param params.messageLimit How many of each channel's newest messages to return, 25 by default.
* @returns The channels with their state.
*/
export const getChannels = async ({
channelIds,
userId,
messageLimit,
}: {
channelIds: string[];
userId: string;
messageLimit?: number;
}): Promise<Omit<ChannelStateResponseFields, 'duration'>[]> => {
SqliteClient.logger?.('info', 'getChannels', { channelIds, userId });
SqliteClient.logger?.('info', 'getChannels', { channelIds, userId, messageLimit });

const [channels, cidVsDraft, cidVsMembers, cidVsReads, cidVsMessages, cidVsActiveLocations] =
await Promise.all([
Expand All @@ -36,6 +39,7 @@ export const getChannels = async ({
getChannelMessages({
channelIds,
userId,
messageLimit,
}),
getChannelActiveLocations({ channelIds }),
]);
Expand Down
1 change: 1 addition & 0 deletions package/src/store/apis/getChannelsForFilterSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export const getChannelsForFilterSort = async ({
channels: await getChannels({
channelIds: cids,
userId,
messageLimit: options?.message_limit,
}),
predefinedFilter,
};
Expand Down
9 changes: 7 additions & 2 deletions package/src/store/apis/queries/selectMessagesForChannels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import { tables } from '../../schema';
import { SqliteClient } from '../../SqliteClient';
import type { TableRowJoinedUser } from '../../types';

/** The `message_limit` the client assumes for a channel list query that sets none. */
export const DEFAULT_CHANNEL_LIST_MESSAGE_LIMIT = 25;

export const selectMessagesForChannels = async (
cids: string[],
messageLimit: number = DEFAULT_CHANNEL_LIST_MESSAGE_LIMIT,
): Promise<TableRowJoinedUser<'messages'>[]> => {
const questionMarks = Array(cids.length).fill('?').join(',');
const messagesColumnNames = Object.keys(tables.messages.columns)
Expand All @@ -15,6 +19,7 @@ export const selectMessagesForChannels = async (

SqliteClient.logger?.('info', 'selectMessagesForChannels', {
cids,
messageLimit,
});

const result = await SqliteClient.executeSql(
Expand All @@ -38,9 +43,9 @@ export const selectMessagesForChannels = async (
LEFT JOIN
users b
ON b.id = a.userId
WHERE RowNum <= 25
WHERE RowNum <= ?
ORDER BY a.createdAt ASC`,
cids,
[...cids, messageLimit],
);

return result.map((r) => JSON.parse(r.value));
Expand Down
Loading