conradkoh
conradkoh
CCConvex Community
Created by conradkoh on 11/21/2024 in #support-community
customQuery methods not findable from other package
No description
6 replies
CCConvex Community
Created by conradkoh on 9/10/2024 in #support-community
Is Convex websockets down?
No description
30 replies
CCConvex Community
Created by conradkoh on 8/13/2024 in #support-community
Errors when type inference for custom actions
I have a helper function to try to populate the context with session information for a user, but run into type inference errors. My best guess is that there is some problem with cyclic references. Any advice on how to do these kinds of patterns without forcing "any" somewhere into the code?
2 replies
CCConvex Community
Created by conradkoh on 7/13/2024 in #support-community
Slow deployments during dev
I noticed that deployments from the dev environment have started to take around 15 seconds. I’m not too sure if it has always been the case. I don’t much much more info - but just wondering if this is something others are already experiencing and if this is a known issue (or if not an issue, whether to just accept it). Thanks a bunch!
6 replies
CCConvex Community
Created by conradkoh on 7/3/2024 in #support-community
Request for a command like convex dev --local
Has a feature been considered for dev mode, where the open source binary is automatically published to an npm package so that it is available for a simple 1. Addition of a package to package.json 2. Run a single command within a project to connect to a local DB (e.g. convex-local start) I encountered a scenario today where I think this might be useful. I was checking out an old branch on another computer that I was doing development on that had some changes I forgot about. However, I couldn't test out the changes in the branch because the shared dev environment already had documents that couldn't be rolled back. The result is that I couldn't start the app in that branch. I imagine this will be an increasing issue as more developers are added to projects. It seems worthwhile to provide an easy isolated dev mode for checking out old versions of the code, or preventing conflicts between developers modifying the same dev state.
7 replies
CCConvex Community
Created by conradkoh on 6/29/2024 in #support-community
convex-test fails for nested optional properties used in index
Hi, I am reporting a bug that happens in convex-test, when you use an optional property in an index. In this example, you see that add_info is an optional property (by way of being excluded in one of the types within a discriminated union type). 1. There is no type error 2. The test fails in convex-test 3. The test passes against the live convex server I've also create a full reproduction with different scenarios (refer to commit history) here. - https://github.com/conradkoh/convex-test-index-bug-repo/commits/master/ Thanks in advance. Schema
export default defineSchema({
user: defineTable(
v.union(
v.object({
timestamp: v.number(),
type: v.literal('without_age'),
name: v.string(),
}),
v.object({
timestamp: v.number(),
type: v.literal('with_age'),
name: v.string(),
add_info: v.object({
age: v.number(),
}),
})
)
).index('by_age_timestamp', ['add_info.age', 'timestamp']),
});
export default defineSchema({
user: defineTable(
v.union(
v.object({
timestamp: v.number(),
type: v.literal('without_age'),
name: v.string(),
}),
v.object({
timestamp: v.number(),
type: v.literal('with_age'),
name: v.string(),
add_info: v.object({
age: v.number(),
}),
})
)
).index('by_age_timestamp', ['add_info.age', 'timestamp']),
});
Query Code
const users = await ctx.db
.query('user')
.withIndex('by_age_timestamp', (f) =>
f.eq('add_info.age', age).gt('timestamp', 0)
)
.collect();
const users = await ctx.db
.query('user')
.withIndex('by_age_timestamp', (f) =>
f.eq('add_info.age', age).gt('timestamp', 0)
)
.collect();
Test
it('local: should not return users that have no age', async () => {
const t = convexTest(schema);
await t.mutation(api.user.create, createUserParams);
const users = await t.query(api.user.list, queryParams);
expect(users).toEqual([]);
});
it('local: should not return users that have no age', async () => {
const t = convexTest(schema);
await t.mutation(api.user.create, createUserParams);
const users = await t.query(api.user.list, queryParams);
expect(users).toEqual([]);
});
Error
TypeError: Cannot convert undefined or null to object
❯ isSimpleObject node_modules/convex-test/dist/index.js:415:30
413| const isSimple = prototype === null ||
414| prototype === Object.prototype ||
415| // Objects generated from other contexts (e.…
| ^
TypeError: Cannot convert undefined or null to object
❯ isSimpleObject node_modules/convex-test/dist/index.js:415:30
413| const isSimple = prototype === null ||
414| prototype === Object.prototype ||
415| // Objects generated from other contexts (e.…
| ^
18 replies
CCConvex Community
Created by conradkoh on 5/22/2024 in #support-community
convex-test does not work in yarn workspace
When following the guide on convex.dev, if one is using a yarn workspace with packages hoisted, convex-test will error out and not be able to find the _generated directory. This was the guide I followed: - https://docs.convex.dev/functions/testing
FAIL convex/budget.test.ts > create / update budgets
Error: Could not find the "_generated" directory, make sure to run `npx convex dev` or `npx convex codegen`. If your Convex functions aren't defined in a directory called "convex" sibling to your node_modules, provide the second argument to `convexTest`
❯ findModulesRoot ../../node_modules/convex-test/dist/index.js:889:11
887| "`npx convex dev` or `npx convex codegen`. " +
888| (userProvidedModules
889| ? "Make sure your `import.meta.glob` includes the files in the " +
| ^
890| '"_generated" directory'
891| : "If your Convex functions aren't defined in a directory " +
❯ moduleCache ../../node_modules/convex-test/dist/index.js:871:20
❯ Module.convexTest ../../node_modules/convex-test/dist/index.js:918:18
❯ convex/budget.test.ts:9:13
FAIL convex/budget.test.ts > create / update budgets
Error: Could not find the "_generated" directory, make sure to run `npx convex dev` or `npx convex codegen`. If your Convex functions aren't defined in a directory called "convex" sibling to your node_modules, provide the second argument to `convexTest`
❯ findModulesRoot ../../node_modules/convex-test/dist/index.js:889:11
887| "`npx convex dev` or `npx convex codegen`. " +
888| (userProvidedModules
889| ? "Make sure your `import.meta.glob` includes the files in the " +
| ^
890| '"_generated" directory'
891| : "If your Convex functions aren't defined in a directory " +
❯ moduleCache ../../node_modules/convex-test/dist/index.js:871:20
❯ Module.convexTest ../../node_modules/convex-test/dist/index.js:918:18
❯ convex/budget.test.ts:9:13
This is because of how the library uses import.meta.glob with the assumption that the relative path of node_modules is ../../../convex/**/*.*s relative to where the library is. This is untrue for workspaces where packages are hoisted. A workaround exists, by ensuring that the "nohoist" option is used in the workspace. It would be good to include in the docs, or update such that convex-test can run as expected even when it is hoisted to the workspace root (e.g. by using the directory of the process perhaps).
13 replies
CCConvex Community
Created by conradkoh on 5/16/2024 in #support-community
Debugging slow performance of queries
No description
21 replies
CCConvex Community
Created by conradkoh on 4/13/2024 in #support-community
Using SessionProvider with SSR
No description
118 replies
CCConvex Community
Created by conradkoh on 4/10/2024 in #support-community
Race condition when reading and writing data
I encountered a race condition somewhere in my code and I can't figure out where my understanding is lacking in how convex handles concurrent write requests. This is the query for my code, where I am attempting to use convex as a cache, while I am migrating my system over. The way it works is that my system will call convex to update the cache when the data in my other backend changes. The frontend is subscribed to convex as the source of truth.
/**
* This should be called by the server
*/
export const update = mutation({
args: {
accessTokenHash: v.string(),
userId: v.string(),
accounts: v.array(AccountValue()),
},
handler: async (ctx, args) => {
const tokenHash = args.accessTokenHash;

//invalidate all other user accounts caches
const caches = await ctx.db
.query('cache_userAccounts')
.withIndex('by_userId', (q) => q.eq('userId', args.userId))
.collect();

//grant access to updater
const existsForToken =
caches.find(
(v) => v.tokenHash === tokenHash && v.userId == args.userId
) != undefined;
if (!existsForToken) {
await ctx.db.insert('cache_userAccounts', {
tokenHash: tokenHash,
userId: args.userId,
accounts: args.accounts,
});
}

//update all caches
await Promise.allSettled(
caches.map(async (cache) => {
await ctx.db.patch(cache._id, {
tokenHash: tokenHash,
userId: args.userId,
accounts: args.accounts,
});
})
);
},
});
/**
* This should be called by the server
*/
export const update = mutation({
args: {
accessTokenHash: v.string(),
userId: v.string(),
accounts: v.array(AccountValue()),
},
handler: async (ctx, args) => {
const tokenHash = args.accessTokenHash;

//invalidate all other user accounts caches
const caches = await ctx.db
.query('cache_userAccounts')
.withIndex('by_userId', (q) => q.eq('userId', args.userId))
.collect();

//grant access to updater
const existsForToken =
caches.find(
(v) => v.tokenHash === tokenHash && v.userId == args.userId
) != undefined;
if (!existsForToken) {
await ctx.db.insert('cache_userAccounts', {
tokenHash: tokenHash,
userId: args.userId,
accounts: args.accounts,
});
}

//update all caches
await Promise.allSettled(
caches.map(async (cache) => {
await ctx.db.patch(cache._id, {
tokenHash: tokenHash,
userId: args.userId,
accounts: args.accounts,
});
})
);
},
});
The issue I am facing is that existsForToken returns false and multiple repeated rows are inserted into the table, with the same tokenHash and userId. my intent is for the tokenHash + userId to for a unique pair. I've seen some other threads where .withIndex(<index name>).unique() was suggested, but I don't really see how .unique() is helpful, because this errors out on read (aka the data is already in an inconsistent state).
5 replies
CCConvex Community
Created by conradkoh on 2/24/2024 in #support-community
Stale while revalidate for re-subscribed queries
Between page navigations, pages mount queries that subscribe or unsubscribe. This results in loaders always triggering on a new subscription when a user navigates. Proposal: To improve the time to render, serve stale data from a cache (in memory) while the query subscription is still pending, especially if the user was on that page in the same session. In this case, we use non-persistent storage for the objects, so a session is assumed to be until the user refreshes the page. Here's a proof of concept: https://github.com/conradkoh/baby-tracker/blob/master/apps/mobile/lib/convex/use_query_swr.tsx#L5-L46 This solution duplicates in memory the objects returned from the server. If there is first class support for such caching from the library, similar to how react-query does it, but with real time features, it would be amazing.
75 replies
CCConvex Community
Created by conradkoh on 2/22/2024 in #support-community
usePaginatedQuery never hits the cache (on the same client)
pagination is often used to reduce the number of rows scanned in the backend, and lazily load rows. Problem: When applying usePaginatedQuery, the cache is always missed when navigating between pages, that share a convex client. Example flow: 1. User loads app (convex context at root) 2. User goes to page 1 (load paginated query) 3. User navigates to page 2 (unmount paginated query) 4. User navigates to page 3 (load paginated query) - this misses the cache Expected result: Paginated query should serve from the cache, based on the page number, across the app. If users want to always bust the cache, they can add a parameter to args to do it. This also allows more granular control (e.g. embedding the screen name that the user is accessing from) to determine which screens share a cache and which screens don't. Reference: https://github.com/get-convex/convex-js/blob/250cf7985f5e69817e2b51d4558c166940b870c5/src/react/use_paginated_query.ts#L373-L400
35 replies
CCConvex Community
Created by conradkoh on 2/22/2024 in #support-community
Query functions caching fails when used with third party libraries
This is not strictly a bug with convex, but is common enough that many applications would run into this issue when trying to use any third party library, resulting in major cache misses that are only found after release. Problem: Convex disables caching when the Date constructor is invoked. However, the date constructor is not always invoked by the dev, but could be by a third party library (such as date libraries that are used to parse and transform dates). This results in the query being uncached and an elevated number of row reads. Proposal: The build should fail if the a query uses the Date constructor, requiring the user to explicitly call a method ctx.disableCache() at the start of the query.
16 replies
CCConvex Community
Created by conradkoh on 2/15/2024 in #support-community
React useQuery not updating on reconnect
I am using Convex on React Native with expo. The issue I am facing is that when the Convex client connection state comes back to being "ready" - aka connection is re-established, old queries are not updated. Is there a recommendation on how to resolve this? Considering the useQuery hook returns only the results and has to refetch function, I am unsure of how to proceed without reloading the entire screen. Ideally, the queries should refetch events that occurred since the latest successful update.
50 replies