Skip to content

Commit c997068

Browse files
committed
feat: offline db for polls wip
1 parent 00ba4d9 commit c997068

File tree

9 files changed

+212
-19
lines changed

9 files changed

+212
-19
lines changed

package/src/store/QuickSqliteClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import type { PreparedQueries, Table } from './types';
3030
*
3131
*/
3232
export class QuickSqliteClient {
33-
static dbVersion = 6;
33+
static dbVersion = 7;
3434

3535
static dbName = DB_NAME;
3636
static dbLocation = DB_LOCATION;

package/src/store/apis/getChannelMessages.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import type { DefaultStreamChatGenerics } from '../../types/types';
88
import { isBlockedMessage } from '../../utils/utils';
99
import { mapStorableToMessage } from '../mappers/mapStorableToMessage';
1010
import { QuickSqliteClient } from '../QuickSqliteClient';
11-
import type { TableRowJoinedUser } from '../types';
11+
import { createSelectQuery } from '../sqlite-utils/createSelectQuery';
12+
import type { TableRow, TableRowJoinedUser } from '../types';
1213

1314
export const getChannelMessages = <
1415
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -35,6 +36,21 @@ export const getChannelMessages = <
3536
}
3637
messageIdVsReactions[reaction.messageId].push(reaction);
3738
});
39+
const messageIdsVsPolls: Record<string, TableRow<'poll'>> = {};
40+
const pollsById: Record<string, TableRow<'poll'>> = {};
41+
const messagesWithPolls = messageRows.filter((message) => !!message.poll_id);
42+
const polls = QuickSqliteClient.executeSql.apply(
43+
null,
44+
createSelectQuery('poll', ['*'], {
45+
id: messagesWithPolls.map((message) => message.poll_id),
46+
}),
47+
);
48+
polls.forEach((poll) => {
49+
pollsById[poll.id] = poll;
50+
});
51+
messagesWithPolls.forEach((message) => {
52+
messageIdsVsPolls[message.poll_id] = pollsById[message.poll_id];
53+
});
3854

3955
// Populate the messages.
4056
const cidVsMessages: Record<string, MessageResponse<StreamChatGenerics>[]> = {};
@@ -48,6 +64,7 @@ export const getChannelMessages = <
4864
mapStorableToMessage<StreamChatGenerics>({
4965
currentUserId,
5066
messageRow: m,
67+
pollRow: messageIdsVsPolls[m.poll_id],
5168
reactionRows: messageIdVsReactions[m.id],
5269
}),
5370
);

package/src/store/apis/updatePollMessage.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { PollResponse } from 'stream-chat';
22

3+
import { mapPollToStorable } from '../mappers/mapPollToStorable';
34
import { QuickSqliteClient } from '../QuickSqliteClient';
45
import { createSelectQuery } from '../sqlite-utils/createSelectQuery';
56
import { createUpdateQuery } from '../sqlite-utils/createUpdateQuery';
@@ -14,29 +15,28 @@ export const updatePollMessage = ({
1415
}) => {
1516
const queries: PreparedQueries[] = [];
1617

17-
const messagesWithPoll = QuickSqliteClient.executeSql.apply(
18+
const pollsFromDB = QuickSqliteClient.executeSql.apply(
1819
null,
19-
createSelectQuery('messages', ['*'], {
20-
poll_id: poll.id,
20+
createSelectQuery('poll', ['*'], {
21+
id: poll.id,
2122
}),
2223
);
2324

24-
for (const message of messagesWithPoll) {
25-
const { latest_votes, own_votes } = JSON.parse(message.poll);
26-
const storablePoll = JSON.stringify({
27-
...poll,
28-
latest_votes,
29-
own_votes,
25+
for (const pollFromDB of pollsFromDB) {
26+
const { latest_votes, own_votes } = pollFromDB;
27+
console.log(own_votes);
28+
const storablePoll = mapPollToStorable({
29+
...pollFromDB,
30+
latest_votes: latest_votes ? JSON.parse(latest_votes) : [],
31+
own_votes: own_votes ? JSON.parse(own_votes) : [],
3032
});
31-
const storableMessage = { ...message, poll: storablePoll };
3233

3334
queries.push(
34-
createUpdateQuery('messages', storableMessage, {
35-
id: message.id,
35+
createUpdateQuery('poll', storablePoll, {
36+
id: poll.id,
3637
}),
3738
);
3839
QuickSqliteClient.logger?.('info', 'updatePoll', {
39-
message: storableMessage,
4040
poll: storablePoll,
4141
});
4242
}

package/src/store/apis/upsertMessages.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { MessageResponse } from 'stream-chat';
22

33
import { mapMessageToStorable } from '../mappers/mapMessageToStorable';
4+
import { mapPollToStorable } from '../mappers/mapPollToStorable';
45
import { mapReactionToStorable } from '../mappers/mapReactionToStorable';
56
import { mapUserToStorable } from '../mappers/mapUserToStorable';
67
import { QuickSqliteClient } from '../QuickSqliteClient';
@@ -16,6 +17,7 @@ export const upsertMessages = ({
1617
const storableMessages: Array<ReturnType<typeof mapMessageToStorable>> = [];
1718
const storableUsers: Array<ReturnType<typeof mapUserToStorable>> = [];
1819
const storableReactions: Array<ReturnType<typeof mapReactionToStorable>> = [];
20+
const storablePolls: Array<ReturnType<typeof mapPollToStorable>> = [];
1921

2022
messages?.forEach((message: MessageResponse) => {
2123
storableMessages.push(mapMessageToStorable(message));
@@ -28,6 +30,9 @@ export const upsertMessages = ({
2830
}
2931
storableReactions.push(mapReactionToStorable(r));
3032
});
33+
if (message.poll) {
34+
storablePolls.push(mapPollToStorable(message.poll));
35+
}
3136
});
3237

3338
const finalQueries = [
@@ -36,11 +41,13 @@ export const upsertMessages = ({
3641
...storableReactions.map((storableReaction) =>
3742
createUpsertQuery('reactions', storableReaction),
3843
),
44+
...storablePolls.map((storablePoll) => createUpsertQuery('poll', storablePoll)),
3945
];
4046

4147
QuickSqliteClient.logger?.('info', 'upsertMessages', {
4248
flush,
4349
messages: storableMessages,
50+
polls: storablePolls,
4451
reactions: storableReactions,
4552
users: storableUsers,
4653
});

package/src/store/mappers/mapMessageToStorable.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import type { FormatMessageResponse, MessageResponse } from 'stream-chat';
22

33
import { mapDateTimeToStorable } from './mapDateTimeToStorable';
44

5+
import { mapPollToStorable } from './mapPollToStorable';
6+
57
import type { TableRow } from '../types';
68

79
export const mapMessageToStorable = (
@@ -28,6 +30,8 @@ export const mapMessageToStorable = (
2830
...extraData
2931
} = message;
3032

33+
const pollInMessage = poll && mapPollToStorable(poll);
34+
3135
return {
3236
attachments: JSON.stringify(attachments),
3337
cid: cid || '',
@@ -36,12 +40,12 @@ export const mapMessageToStorable = (
3640
extraData: JSON.stringify(extraData),
3741
id,
3842
messageTextUpdatedAt: mapDateTimeToStorable(message_text_updated_at),
39-
poll: JSON.stringify(poll),
4043
poll_id: poll_id || '',
4144
reactionGroups: JSON.stringify(reaction_groups),
4245
text,
4346
type,
4447
updatedAt: mapDateTimeToStorable(updated_at),
4548
userId: user?.id,
49+
...(pollInMessage ? { poll: pollInMessage } : {}),
4650
};
4751
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { PollResponse } from 'stream-chat';
2+
3+
import { mapDateTimeToStorable } from './mapDateTimeToStorable';
4+
5+
import type { TableRow } from '../types';
6+
7+
export const mapPollToStorable = (poll: PollResponse): TableRow<'poll'> => {
8+
const {
9+
allow_answers,
10+
allow_user_suggested_options,
11+
answers_count,
12+
created_at,
13+
created_by,
14+
created_by_id,
15+
description,
16+
enforce_unique_vote,
17+
id,
18+
is_closed,
19+
latest_answers,
20+
latest_votes_by_option,
21+
max_votes_allowed,
22+
name,
23+
options,
24+
own_votes,
25+
updated_at,
26+
vote_count,
27+
vote_counts_by_option,
28+
voting_visibility,
29+
} = poll;
30+
31+
return {
32+
allow_answers,
33+
allow_user_suggested_options,
34+
answers_count,
35+
created_at: mapDateTimeToStorable(created_at),
36+
created_by: JSON.stringify(created_by), // decouple the users from the actual poll
37+
created_by_id,
38+
description,
39+
enforce_unique_vote,
40+
id,
41+
is_closed,
42+
latest_answers: JSON.stringify(latest_answers),
43+
latest_votes_by_option: JSON.stringify(latest_votes_by_option),
44+
max_votes_allowed,
45+
name,
46+
options: JSON.stringify(options),
47+
own_votes: JSON.stringify(own_votes),
48+
updated_at,
49+
vote_count,
50+
vote_counts_by_option: JSON.stringify(vote_counts_by_option),
51+
voting_visibility,
52+
};
53+
};

package/src/store/mappers/mapStorableToMessage.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
import type { MessageResponse } from 'stream-chat';
22

3+
import { mapStorableToPoll } from './mapStorableToPoll';
34
import { mapStorableToReaction } from './mapStorableToReaction';
45

56
import { mapStorableToUser } from './mapStorableToUser';
67

78
import type { DefaultStreamChatGenerics } from '../../types/types';
89

9-
import type { TableRowJoinedUser } from '../types';
10+
import type { TableRow, TableRowJoinedUser } from '../types';
1011

1112
export const mapStorableToMessage = <
1213
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
1314
>({
1415
currentUserId,
1516
messageRow,
17+
pollRow,
1618
reactionRows,
1719
}: {
1820
currentUserId: string;
1921
messageRow: TableRowJoinedUser<'messages'>;
22+
pollRow: TableRow<'poll'>;
2023
reactionRows: TableRowJoinedUser<'reactions'>[];
2124
}): MessageResponse<StreamChatGenerics> => {
2225
const {
2326
createdAt,
2427
deletedAt,
2528
extraData,
2629
messageTextUpdatedAt,
27-
poll,
2830
poll_id,
2931
reactionGroups,
3032
updatedAt,
@@ -44,11 +46,11 @@ export const mapStorableToMessage = <
4446
latest_reactions: latestReactions,
4547
message_text_updated_at: messageTextUpdatedAt,
4648
own_reactions: ownReactions,
47-
poll: JSON.parse(poll),
4849
poll_id,
4950
reaction_groups: reactionGroups ? JSON.parse(reactionGroups) : {},
5051
updated_at: updatedAt,
5152
user: mapStorableToUser(user),
53+
...(pollRow ? { poll: mapStorableToPoll(pollRow) } : {}),
5254
...(extraData ? JSON.parse(extraData) : {}),
5355
};
5456
};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { PollResponse, VotingVisibility } from 'stream-chat';
2+
3+
import type { DefaultStreamChatGenerics } from '../../types/types';
4+
import type { TableRow } from '../types';
5+
6+
export const mapStorableToPoll = <
7+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
8+
>(
9+
pollRow: TableRow<'poll'>,
10+
): PollResponse<StreamChatGenerics> => {
11+
const {
12+
allow_answers,
13+
allow_user_suggested_options,
14+
answers_count,
15+
created_at,
16+
created_by,
17+
created_by_id,
18+
description,
19+
enforce_unique_vote,
20+
id,
21+
is_closed,
22+
latest_answers,
23+
latest_votes_by_option,
24+
max_votes_allowed,
25+
name,
26+
options,
27+
own_votes,
28+
updated_at,
29+
vote_count,
30+
vote_counts_by_option,
31+
voting_visibility,
32+
} = pollRow;
33+
34+
return {
35+
allow_answers,
36+
allow_user_suggested_options,
37+
answers_count,
38+
created_at,
39+
created_by: JSON.parse(created_by),
40+
created_by_id,
41+
description,
42+
enforce_unique_vote,
43+
id,
44+
is_closed,
45+
latest_answers: JSON.parse(latest_answers),
46+
latest_votes_by_option: JSON.parse(latest_votes_by_option),
47+
max_votes_allowed,
48+
name,
49+
options: JSON.parse(options),
50+
own_votes: own_votes ? JSON.parse(own_votes) : [],
51+
updated_at,
52+
vote_count,
53+
vote_counts_by_option: JSON.parse(vote_counts_by_option),
54+
voting_visibility: voting_visibility as VotingVisibility | undefined,
55+
};
56+
};

package/src/store/schema.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,38 @@ export const tables: Tables = {
139139
type: 'TEXT',
140140
},
141141
},
142+
poll: {
143+
columns: {
144+
allow_answers: 'BOOLEAN DEFAULT FALSE',
145+
allow_user_suggested_options: 'BOOLEAN DEFAULT FALSE',
146+
answers_count: 'INTEGER DEFAULT 0',
147+
created_at: 'TEXT',
148+
created_by: 'TEXT',
149+
created_by_id: 'TEXT',
150+
description: 'TEXT',
151+
enforce_unique_vote: 'BOOLEAN DEFAULT FALSE',
152+
id: 'TEXT NOT NULL',
153+
is_closed: 'BOOLEAN DEFAULT FALSE',
154+
latest_answers: 'TEXT',
155+
latest_votes_by_option: 'TEXT',
156+
max_votes_allowed: 'INTEGER DEFAULT 1',
157+
name: 'TEXT',
158+
options: 'TEXT',
159+
own_votes: 'TEXT',
160+
updated_at: 'TEXT',
161+
vote_count: 'INTEGER DEFAULT 0',
162+
vote_counts_by_option: 'TEXT',
163+
voting_visibility: 'TEXT',
164+
},
165+
indexes: [
166+
{
167+
columns: ['id'],
168+
name: 'index_poll',
169+
unique: false,
170+
},
171+
],
172+
primaryKey: ['id'],
173+
},
142174
reactions: {
143175
columns: {
144176
createdAt: 'TEXT',
@@ -283,6 +315,28 @@ export type Schema = {
283315
payload: string;
284316
type: ValueOf<PendingTaskTypes>;
285317
};
318+
poll: {
319+
answers_count: number;
320+
created_at: string;
321+
created_by: string;
322+
created_by_id: string;
323+
enforce_unique_vote: boolean;
324+
id: string;
325+
latest_answers: string;
326+
latest_votes_by_option: string;
327+
max_votes_allowed: number;
328+
name: string;
329+
options: string;
330+
updated_at: string;
331+
vote_count: number;
332+
vote_counts_by_option: string;
333+
allow_answers?: boolean;
334+
allow_user_suggested_options?: boolean;
335+
description?: string;
336+
is_closed?: boolean;
337+
own_votes?: string;
338+
voting_visibility?: string;
339+
};
286340
reactions: {
287341
createdAt: string;
288342
messageId: string;

0 commit comments

Comments
 (0)