ian
ian2y ago

Migrating to 0.13.0

Hey folks, if you are updating your apps to 0.13.0, reach out if you hit any snags or want help understanding any of the changes. I'll open this as a thread. Hopefully it's smooth sailing ⛵️
13 Replies
ian
ianOP2y ago
Release notes are a great place to start. Most of what you need to know is in there: https://blog.convex.dev/announcing-convex-0-13-0/
The Convex Blog
Announcing Convex 0.13.0
Convex 0.13.0 is here and it’s kinda a big deal. There are some big changes to function arguments and actions.
Dima Utkin
Dima Utkin2y ago
"Convex currently has an authentication framework which verifies user identities. In the future we plan to add an authorization framework which will allow developers to define what data a user can access." how far is this on the roadmap? 🙂
ian
ianOP2y ago
Edit: moved to #support-community : https://discord.com/channels/1019350475847499849/1098990952208670840/1098990952208670840 As an update on 0.13.0, I haven't finished updating the convex-helpers repo, so if anyone's trying to use withSession or withUser, you might want to hold off on upgrading. In JS they're pretty easy to update, I'm just working on getting all the typescript types to work
nemophrost
nemophrost2y ago
Hi @ian I just posted in #general as well, but I was wondering about types for paginationOpts when using argument validation. Is there a built-in validator for that?
ian
ianOP2y ago
Ah, good catch. Try this:
args: {
paginationOpts: v.object({
numItems: v.number(),
id: v.number(),
cursor: v.union(v.null(), v.string()),
}),
},
args: {
paginationOpts: v.object({
numItems: v.number(),
id: v.number(),
cursor: v.union(v.null(), v.string()),
}),
},
where numItems comes from your initialNumItems or the loadMore argument, cursor is null for the first request or the cursor of the previous request, and id is an internal detail. I think we should provide v.paginationOpts() as a shortcut - is that what you'd expect? That might also let us hide some of the implementation details for the common case
nemophrost
nemophrost2y ago
Perfect, thanks! Yeah I think v.paginationOpts() would be great. If things like that don't make sense to clutter v then I could see it exported elsewhere.
ian
ianOP2y ago
Filed it, thanks for the suggestion Another engineer suggested that v.any() is probably sufficient, if it's the common case of just passing it into the paginate function. Will save you some typing, and we're tight on types within the paginate function & underlying rust layers.
nemophrost
nemophrost2y ago
Ah, good call. No real need for the code to be aware of the types if that's the case. Do you know if there are plans to add things like .pick .omit .extend .partial to the schema/values lib (similar to zod.dev)? My specific use case it that I have a mutation that only allows updates to certain fields in a document and it would be great to be able to create a validator with .omit and the document object definition instead of manually specifying (duplicating) the types/validators for the fields I want to be allowed. Make sense?
ian
ianOP2y ago
Makes total sense. We're planning to put together a little cookbook with patterns for it, but tl;dr I'd suggest just manipulating them as objects. e.g.:
// in schema.ts
const myTable = { fieldA: v.string(), fieldB: v.number(), ... };
export default defineSchema({...myTable, tableB: {...}, ...tableC});

// in your file:
// omit
const {fieldA, ...withoutA} = myTable;
//pick
const { fieldB } = myTable;
const onlyAB = {fieldA, fieldB};
// extend
const withExtra = { ...myTable, extraField }
// partial
const optionalValues = Object.fromEntries(Object.entries(myTable).map(
([k, v]) => [k, v.optional(v)]
));
// in schema.ts
const myTable = { fieldA: v.string(), fieldB: v.number(), ... };
export default defineSchema({...myTable, tableB: {...}, ...tableC});

// in your file:
// omit
const {fieldA, ...withoutA} = myTable;
//pick
const { fieldB } = myTable;
const onlyAB = {fieldA, fieldB};
// extend
const withExtra = { ...myTable, extraField }
// partial
const optionalValues = Object.fromEntries(Object.entries(myTable).map(
([k, v]) => [k, v.optional(v)]
));
And you might be able to do import s from "./schema"; const myTable = s.tables["myTable"] but I haven't played around with that much. We can make some helper functions you could copy, but they'd probably look similar to the above. Just some sugar on top of manipulating POJOs
nemophrost
nemophrost2y ago
Oh, that's great. I had incorrectly assumed I had to wrap my table definitions in v.object() but given that's not the case (and even if it was I realize now I could just use the vanilla object version to create my modified schemas than wrap them in v.object() at the end) it looks like I have everything I need. Thanks for the great examples! 🤦‍♂️ I'm getting the following error after upgrading and running convex dev
Error: Unable to push deployment config to https://-------------.convex.cloud
✖ Waiting for all table indexes to be backfilled...
400 Bad Request: UnableToPush: Hit an error while pushing:
InvalidTableNameReference; Your validator contains a reference to `v.id("notebooks")`, but `notebooks` isn't defined in your schema.
Error: Unable to push deployment config to https://-------------.convex.cloud
✖ Waiting for all table indexes to be backfilled...
400 Bad Request: UnableToPush: Hit an error while pushing:
InvalidTableNameReference; Your validator contains a reference to `v.id("notebooks")`, but `notebooks` isn't defined in your schema.
I also added argument validation so I assume there is something related to that but my schema clearly shows that I have notebooks in it:
export default defineSchema({
users: defineTable(user).index('by_token', ['tokenIdentifier']),
notebooks: defineTable(notebook),
})
export default defineSchema({
users: defineTable(user).index('by_token', ['tokenIdentifier']),
notebooks: defineTable(notebook),
})
Anything I can do to debug this further? After some further investigation this problem seems to go away if I remove the v.id('tableName') fields in my query/mutation arg validation. Perhaps their is some validation code checks happening before the schema has been updated that it is checking against?
ian
ianOP2y ago
That's very odd. I've been using v.id successfully. I haven't been playing much with breaking up the table and importing from schema in different places. I wonder if it's trying to resolve the function before the schema somehow... if I get a repro I'll dig more, but maybe Monday 🙂 I have a repro, sorry about that. Will follow up when we get to the bottom of it
ballingt
ballingt2y ago
Thanks for reporting @nemophrost, it looks like v.id('tableName') wasn't working — it's not just you. This has been fixed, but you saw a preview of how we'll let folks check validate things more tightly in the future.
ian
ianOP2y ago

Did you find this page helpful?