Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add isLoaded states, clearCache export #92

Merged
merged 6 commits into from
Sep 13, 2023
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
8 changes: 8 additions & 0 deletions .changeset/chilled-cougars-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@xmtp/react-sdk": patch
---

- Add `isLoaded` state to the `useMessages` and `useConversations` hooks
- Add `clearCache` to exports
- Minor refactor of `useStartConversation` hook to export `conversation` when no initial message is sent
- Access all cached conversations using the client's wallet address
10 changes: 3 additions & 7 deletions dev/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@ services:
environment:
- GOWAKU-NODEKEY=8a30dcb604b0b53627a5adc054dbf434b446628d4bd1eccc681d223f0550ce67
command:
- --ws
- --store
- --message-db-connection-string=postgres://postgres:xmtp@db:5432/postgres?sslmode=disable
- --message-db-reader-connection-string=postgres://postgres:xmtp@db:5432/postgres?sslmode=disable
- --lightpush
- --filter
- --ws-port=9001
- --store.enable
- --store.db-connection-string=postgres://postgres:xmtp@db:5432/postgres?sslmode=disable
- --store.reader-db-connection-string=postgres://postgres:xmtp@db:5432/postgres?sslmode=disable
- --wait-for-db=30s
- --api.authn.enable
ports:
Expand Down
56 changes: 48 additions & 8 deletions packages/react-sdk/src/helpers/caching/conversations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,34 @@ beforeEach(async () => {
describe("getCachedConversationBy", () => {
it("should return undefined if no conversation is found", async () => {
const conversation = await getCachedConversationBy(
"testWalletAddress",
"topic",
"testTopic",
db,
);
expect(conversation).toBeUndefined();
const conversation2 = await getCachedConversationBy("id", 1, db);
const conversation2 = await getCachedConversationBy(
"testWalletAddress",
"id",
1,
db,
);
expect(conversation2).toBeUndefined();
const conversation3 = await getCachedConversationBy(
"testWalletAddress",
"peerAddress",
"testPeerAddress",
db,
);
expect(conversation3).toBeUndefined();
const conversation4 = await getCachedConversationByTopic("testTopic", db);
const conversation4 = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
expect(conversation4).toBeUndefined();
const conversation5 = await getCachedConversationByPeerAddress(
"testWalletAddress",
"testPeerAddress",
db,
);
Expand All @@ -65,22 +77,34 @@ describe("getCachedConversationBy", () => {
} satisfies CachedConversationWithId;
const cachedConversation = await saveConversation(testConversation, db);
const conversation = await getCachedConversationBy(
"testWalletAddress",
"topic",
"testTopic",
db,
);
expect(conversation).toEqual(cachedConversation);
const conversation2 = await getCachedConversationBy("id", 1, db);
const conversation2 = await getCachedConversationBy(
"testWalletAddress",
"id",
1,
db,
);
expect(conversation2).toEqual(cachedConversation);
const conversation3 = await getCachedConversationBy(
"testWalletAddress",
"peerAddress",
"testPeerAddress",
db,
);
expect(conversation3).toEqual(cachedConversation);
const conversation4 = await getCachedConversationByTopic("testTopic", db);
const conversation4 = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
expect(conversation4).toEqual(cachedConversation);
const conversation5 = await getCachedConversationByPeerAddress(
"testWalletAddress",
"testPeerAddress",
db,
);
Expand Down Expand Up @@ -138,6 +162,7 @@ describe("updateConversation", () => {
);

const updatedConversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
Expand All @@ -163,9 +188,16 @@ describe("updateConversationMetadata", () => {
const cachedConversation = await saveConversation(testConversation, db);
expect(cachedConversation).toEqual(testConversation);

await updateConversationMetadata("testTopic", "test", { test: "test" }, db);
await updateConversationMetadata(
"testWalletAddress",
"testTopic",
"test",
{ test: "test" },
db,
);

const updatedConversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
Expand Down Expand Up @@ -193,7 +225,11 @@ describe("setConversationUpdatedAt", () => {

await setConversationUpdatedAt("testTopic", updatedAt, db);

const conversation = await getCachedConversationByTopic("testTopic", db);
const conversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
expect(conversation?.updatedAt).toEqual(updatedAt);
});
});
Expand All @@ -213,11 +249,15 @@ describe("hasConversationTopic", () => {
const cachedConversation = await saveConversation(testConversation, db);
expect(cachedConversation).toEqual(testConversation);

expect(await hasConversationTopic("testTopic", db)).toBe(true);
expect(
await hasConversationTopic("testWalletAddress", "testTopic", db),
).toBe(true);
});

it("should return false if the topic does not exist", async () => {
expect(await hasConversationTopic("testTopic", db)).toBe(false);
expect(
await hasConversationTopic("testWalletAddress", "testTopic", db),
).toBe(false);
});
});

Expand Down
30 changes: 21 additions & 9 deletions packages/react-sdk/src/helpers/caching/conversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type ToFunctionArgs<T> = {
}[keyof T];

type GetCachedConversationBy = (
...args: [...ToFunctionArgs<SearchableProperties>, Dexie]
...args: [string, ...ToFunctionArgs<SearchableProperties>, Dexie]
) => Promise<CachedConversationWithId | undefined>;

export type CachedConversationsTable = Table<CachedConversation, number>;
Expand All @@ -40,6 +40,7 @@ export type CachedConversationWithId = CachedConversation & {
* @returns The cached conversation if found, otherwise `undefined`
*/
export const getCachedConversationBy: GetCachedConversationBy = async (
walletAddress,
key,
value,
db,
Expand All @@ -48,8 +49,10 @@ export const getCachedConversationBy: GetCachedConversationBy = async (
"conversations",
) as CachedConversationsTable;
const conversation = await conversationsTable
.where(key)
.equals(value)
.where({
walletAddress,
[key]: value,
})
.first();
return conversation ? (conversation as CachedConversationWithId) : undefined;
};
Expand All @@ -59,18 +62,22 @@ export const getCachedConversationBy: GetCachedConversationBy = async (
*
* @returns The cached conversation if found, otherwise `undefined`
*/
export const getCachedConversationByTopic = async (topic: string, db: Dexie) =>
getCachedConversationBy("topic", topic, db);
export const getCachedConversationByTopic = async (
walletAddress: string,
topic: string,
db: Dexie,
) => getCachedConversationBy(walletAddress, "topic", topic, db);

/**
* Retrieve a cached conversation by peer address
*
* @returns The cached conversation if found, otherwise `undefined`
*/
export const getCachedConversationByPeerAddress = async (
walletAddress: string,
peerAddress: string,
db: Dexie,
) => getCachedConversationBy("peerAddress", peerAddress, db);
) => getCachedConversationBy(walletAddress, "peerAddress", peerAddress, db);

/**
* Retrieve a conversation from the XMTP client by a topic
Expand Down Expand Up @@ -121,12 +128,13 @@ export const updateConversation = async (
* This is not meant to be called directly
*/
export const updateConversationMetadata = async (
walletAddress: string,
topic: string,
namespace: string,
data: ContentTypeMetadataValues,
db: Dexie,
) => {
const existing = await getCachedConversationByTopic(topic, db);
const existing = await getCachedConversationByTopic(walletAddress, topic, db);
if (existing) {
const metadata = existing.metadata || {};
metadata[namespace] = data;
Expand All @@ -148,8 +156,12 @@ export const setConversationUpdatedAt = async (
/**
* Check to see if a topic exists in the conversations cache
*/
export const hasConversationTopic = async (topic: string, db: Dexie) => {
const existing = await getCachedConversationByTopic(topic, db);
export const hasConversationTopic = async (
walletAddress: string,
topic: string,
db: Dexie,
) => {
const existing = await getCachedConversationByTopic(walletAddress, topic, db);
return !!existing;
};

Expand Down
3 changes: 2 additions & 1 deletion packages/react-sdk/src/helpers/caching/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ export const getDbInstance = (options?: GetDBInstanceOptions) => {
...customSchema,
conversations: `
++id,
[topic+walletAddress],
[walletAddress+topic],
[walletAddress+peerAddress],
createdAt,
peerAddress,
topic,
Expand Down
10 changes: 7 additions & 3 deletions packages/react-sdk/src/helpers/caching/messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,7 @@ describe("processMessage", () => {
expect(mockProcessor3).not.toHaveBeenCalled();

const updatedConversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
Expand Down Expand Up @@ -594,6 +595,7 @@ describe("processMessage", () => {
expect(mockProcessor3).not.toHaveBeenCalled();

const updatedConversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
Expand Down Expand Up @@ -642,6 +644,7 @@ describe("processMessage", () => {
expect(mockProcessor3).not.toHaveBeenCalled();

const updatedConversation = await getCachedConversationByTopic(
"testWalletAddress",
"testTopic",
db,
);
Expand Down Expand Up @@ -882,13 +885,13 @@ describe("processMessage", () => {
isReady: false,
topic: "testTopic",
peerAddress: "testPeerAddress",
walletAddress: "testWalletAddress",
walletAddress: testClient.address,
} satisfies CachedConversation;
const cachedConversation = await saveConversation(testConversation, db);
const sentAt = adjustDate(createdAt, 1000);
const testMessage = {
id: 1,
walletAddress: "testWalletAddress",
walletAddress: testClient.address,
conversationTopic: "testTopic",
content: "test",
contentType: ContentTypeText.toString(),
Expand All @@ -897,7 +900,7 @@ describe("processMessage", () => {
hasSendError: false,
sentAt,
status: "unprocessed",
senderAddress: "testWalletAddress",
senderAddress: testClient.address,
uuid: "testUuid",
xmtpID: "testXmtpId",
} satisfies CachedMessage;
Expand All @@ -924,6 +927,7 @@ describe("processMessage", () => {
expect(mockProcessor3).not.toHaveBeenCalled();

const updatedConversation = await getCachedConversationByTopic(
testClient.address,
"testTopic",
db,
);
Expand Down
2 changes: 2 additions & 0 deletions packages/react-sdk/src/helpers/caching/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export const processMessage = async (
data: ContentTypeMetadataValues,
) => {
await _updateConversationMetadata(
client.address,
conversation.topic,
namespace,
data,
Expand Down Expand Up @@ -503,6 +504,7 @@ export const processUnprocessedMessages = async ({
unprocessed.map(async (unprocessedMessage) => {
// get message's conversation from cache
const conversation = await getCachedConversationByTopic(
client.address,
unprocessedMessage.conversationTopic,
db,
);
Expand Down
Loading