Delveroff
Delveroff
CCConvex Community
Created by Delveroff on 9/3/2024 in #support-community
How to store tree-like data?
I want to implement something like Git, where you have a tree-structure of revisions. - Every revision has a hash (it's id) - Every revision has a parent revision (null for the root) - Every revision may have children revisions (like branching) Example of such a tree:
A -> B -> C -> D
\-> C2
A -> B -> C -> D
\-> C2
I want to be able to fetch a revision as well as it's ancestors up to the root:
await findAncestors('D') // A, B, C, D
await findAncestors('C') // A, B, C
await findAncestors('C2') // A, B, C2
await findAncestors('D') // A, B, C, D
await findAncestors('C') // A, B, C
await findAncestors('C2') // A, B, C2
Reads are often. Writes are not, and most of them are new revisions (leafs). For now, I see several ways of doing this:
type Revision = {
parentId: DocId<'revisions'> // need recursive query? what about indexing?
}
type Revision = {
parentId: DocId<'revisions'> // need recursive query? what about indexing?
}
type Revision = {
children: Array<DocId<'revisions'>> // what about cascade deletes? also indexing
}
type Revision = {
children: Array<DocId<'revisions'>> // what about cascade deletes? also indexing
}
type Revision = {
path: Array<DocId<'revisions'>> // seems attractive if indexing by the array
}
type Revision = {
path: Array<DocId<'revisions'>> // seems attractive if indexing by the array
}
10 replies
CCConvex Community
Created by Delveroff on 8/9/2024 in #support-community
Wrong types for `PaginationResult`
continueCursor should be string | null, now it's just string
import type { PaginationResult } from 'convex/server'
import { describe, expect, it } from 'vitest'
import { convexTester } from '~/convex/utils/setup.testing'
import { api } from '../_generated/api'
import type { Doc, Id } from '../_generated/dataModel'

describe.concurrent.only('posts', () => {
it('should return empty collection on no data', async () => {
const t = convexTester()
expect(
await t.query(api.user.posts.default, {
userId: '1;users' as Id<'users'>,
cursor: null,
}),
).toEqual({
// @ts-expect-error the tests passes, therefore, the value is null
continueCursor: null,
isDone: true,
page: [],
} satisfies PaginationResult<Doc<'posts'>>)
})
})
import type { PaginationResult } from 'convex/server'
import { describe, expect, it } from 'vitest'
import { convexTester } from '~/convex/utils/setup.testing'
import { api } from '../_generated/api'
import type { Doc, Id } from '../_generated/dataModel'

describe.concurrent.only('posts', () => {
it('should return empty collection on no data', async () => {
const t = convexTester()
expect(
await t.query(api.user.posts.default, {
userId: '1;users' as Id<'users'>,
cursor: null,
}),
).toEqual({
// @ts-expect-error the tests passes, therefore, the value is null
continueCursor: null,
isDone: true,
page: [],
} satisfies PaginationResult<Doc<'posts'>>)
})
})
Maybe it's just testing behavior. If it is, then there's a bug in convex-test.
10 replies
CCConvex Community
Created by Delveroff on 8/8/2024 in #support-community
A couple of questions about tsconfig
1. What's the reason of excluding the generated folder? We import modules from it anyway, just without autocomplete. 2. How to see the code that's being sent to Convex (queries, actions, etc.). I'm mostly interested in imported "shared" modules. 3. Is it okay to include ../**/*? Of course, excluding node_modules etc. The motivation for these questions is because I consider moving Convex's tsconfig to the root:
tsconfig.base.json
tsconfig.app.json
tsconfig.convex.json
tsconfig.base.json
tsconfig.app.json
tsconfig.convex.json
That way, I could be able to freely share any code. The base config I mentioned above contains most of the options that's common between my App and Convex.
11 replies
CCConvex Community
Created by Delveroff on 8/4/2024 in #support-community
ConvexAuth+Next.js: should I implement `/api/sign-in`?
I try to set up ConvexAuth+Next.js. When I call useAuthActions().signIn('resend', formData), I see that the request goes to my server's api/sign-in, which is 404. I read here that this is the default value. However, the docs does not mention that I have to configure this route somehow. I thought this is handled by convexAuthMiddleware, but this isn't true. I even tried to do the following, but without success:
import { ConvexAuthNextjsServerProvider } from '@convex-dev/auth/nextjs/server'
import type { PropsWithChildren } from 'react'

export function ConvexServerProvider({ children }: PropsWithChildren) {
return (
<ConvexAuthNextjsServerProvider
apiRoute={`${process.env['NEXT_PUBLIC_CONVEX_URL']}/auth/sign-in`}
>
{children}
</ConvexAuthNextjsServerProvider>
)
}
import { ConvexAuthNextjsServerProvider } from '@convex-dev/auth/nextjs/server'
import type { PropsWithChildren } from 'react'

export function ConvexServerProvider({ children }: PropsWithChildren) {
return (
<ConvexAuthNextjsServerProvider
apiRoute={`${process.env['NEXT_PUBLIC_CONVEX_URL']}/auth/sign-in`}
>
{children}
</ConvexAuthNextjsServerProvider>
)
}
Maybe I'm missing something but it's really unclear what to do with the api/sign-in route. Also, I'm acknowledged that auth.js, especially next-auth, tells us to create these routes. But since Convex Auth docs doesn't mention it, I'm not sure if these two approaches will conflict.
55 replies
CCConvex Community
Created by Delveroff on 7/31/2024 in #support-community
Schema Intersection
I try to create the following model:
type Asset = {
status: 'created' | 'removed'
} & (
| {
type: 'image'
src: string
}
| {
type: 'text'
value: string
}
)
type Asset = {
status: 'created' | 'removed'
} & (
| {
type: 'image'
src: string
}
| {
type: 'text'
value: string
}
)
I've read about unions at the top level here: https://docs.convex.dev/database/schemas#unions However, as you can see, I need the status field that is true for all asset types. I tried to do this:
defineSchema({
assets: defineTable({
status: v.string(), // union of literals
...v.union( // Argument of type is not assignable to parameter of type Record<string, GenericValidator>
v.object({type: v.literal('image'), src: v.string()}),
v.object({type: v.literal('text'), value: v.string()})
)
})
})
defineSchema({
assets: defineTable({
status: v.string(), // union of literals
...v.union( // Argument of type is not assignable to parameter of type Record<string, GenericValidator>
v.object({type: v.literal('image'), src: v.string()}),
v.object({type: v.literal('text'), value: v.string()})
)
})
})
For now, I can't understand how to implement the aforementioned type. Seems like it lacks v.intersection() API.
8 replies