packages feed

convex-schema-parser 0.1.6.0 → 0.1.7.0

raw patch · 5 files changed

+78/−37 lines, 5 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -1,5 +1,11 @@ # Revision history for convex-schema-parser +## 0.1.7.0 -- 2025-07-21++* **Codegen Improvements Rust/Python:**+    * We now generated `<FunctionPrefix>ArgObject`s for convex functions which receive parameters.+    * We now enforce named parameters for the generated python functions.+ ## 0.1.6.0 -- 2025-07-21  * **Codegen Improvements Rust:**
README.md view
@@ -216,7 +216,10 @@ # Additionally, we use `pydantic` for type validation, so we raise these exceptions as well. try:     project_id = convex_api.Id("prj_...")-    project = api.functions.projects.get_project(project_id)+    # NOTE that we force named arguments so you do not accidentally refactor stuff in your convex db+    # and forget to adjust your other projects. See the annotation for the rust example below for+    # the reason.+    project = api.functions.projects.get_project(project_id=project_id)     if project:         print(f"Successfully fetched project: {project.project_name}")     else:@@ -235,7 +238,7 @@ try:     # 1. Call the generated `subscribe_*` method. This returns a generator instantly.     tenant_id = convex_api.Id("tnt_...")-    project_subscription = api.functions.queries.subscribe_fetch_projects(tenant_id)+    project_subscription = api.functions.queries.subscribe_fetch_projects(tenant_id=tenant_id)      print("Subscribed to projects. Waiting for updates... (Press Ctrl+C to stop)") @@ -283,7 +286,13 @@     let project_id = Id::<ProjectsDoc>::new("prj_...".to_string());          // This corresponds to the function `getProject` in `convex/functions/projects.ts`.-    match api.functions().projects().get_project(&project_id).await {+    // NOTE the use of an argument type:+    //    We cannot rely on convex to output deterministic positional args for the type generated for convex+    //    functions. And in case you reorder arguments of the same type (like having two or more strings with+    //    semantic differences) this will simulate "named args".+    //    Especially for generated code, this is safer and keeps the calling site consistent regardless+    //    of refactors in the convex backend.+    match api.functions().projects().get_project(convex_api::types::FunctionsQueriesGetProjectArg { project_id }).await {         Ok(Some(project)) => {             println!("Successfully fetched project: {}", project.project_name.unwrap_or_default());         }@@ -309,7 +318,7 @@ async fn run_subscription() -> anyhow::Result<()> {     // 1. Call the generated `subscribe_*` method.     let tenant_id = convex_api::Id::<convex_api::types::TenantsDoc>::new("tnt_...".to_string());-    let mut project_subscription = api.functions().queries().subscribe_fetch_projects(&tenant_id).await?;+    let mut project_subscription = api.functions().queries().subscribe_fetch_projects(convex_api::types::FunctionsQueriesFetchProjectsArgObject { tenant_id }).await?;      println!("Subscribed to projects. Waiting for updates... (Press Ctrl+C to stop)"); 
convex-schema-parser.cabal view
@@ -1,6 +1,6 @@ cabal-version:   3.0 name:            convex-schema-parser-version:         0.1.6.0+version:         0.1.7.0 license:         MIT author:          Norbert Dzikowski maintainer:      lambdax.one@icloud.com
src/Backend/Python.hs view
@@ -278,7 +278,8 @@       payloadParts = map (\(n, _) -> "\"" ++ n ++ "\": " ++ toSnakeCase n) results       nestedDefs = concatMap (\(_, (_, _, _, defs, _)) -> defs) results       deps = Set.unions $ map (\(_, (_, _, _, _, d)) -> d) results-   in (intercalate ", " sigParts, intercalate ", " payloadParts, nestedDefs, deps)+      argSignature = intercalate ", " sigParts+   in (if length sigParts == 0 then argSignature else "*, " ++ argSignature, intercalate ", " payloadParts, nestedDefs, deps)  -- Helper to get the return type information. getReturnType :: String -> Schema.ConvexType -> (String, Bool, [Definition], Set.Set String)
src/Backend/Rust.hs view
@@ -385,47 +385,72 @@ generateFunction :: Action.ConvexFunction -> (String, [String]) generateFunction func =   let funcName = Action.funcName func-      (argSignature, nestedFromArgs) = generateArgSignature funcName (Action.funcArgs func)+      args = Action.funcArgs func+      fullFuncPath = Action.funcPath func ++ ":" ++ funcName+      (argSignature, nestedFromArgs) = generateArgSignatureStruct fullFuncPath args       funcNameSnake = toSnakeCase funcName       (returnHint, isNullable, nestedFromReturn) = getReturnType funcName (Action.funcReturn func)       handlerCall = case Action.funcType func of         Action.Query -> "query"         Action.Mutation -> "mutation"         Action.Action -> "action"-      fullFuncPath = Action.funcPath func ++ ":" ++ funcName       btreemapConstruction = generateBTreeMap (Action.funcArgs func)       returnHandling = generateReturnHandling returnHint isNullable-      funcCode =-        unlines-          [ indent 1 ("/// Wraps the `" ++ fullFuncPath ++ "` " ++ show (Action.funcType func) ++ "."),-            indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self, " ++ argSignature ++ ") -> Result<" ++ returnHint ++ ", ApiError> {"),-            btreemapConstruction,-            indent 2 ("let result = self.client." ++ handlerCall ++ "(\"" ++ fullFuncPath ++ "\", btmap).await?;"),-            returnHandling,-            indent 1 "}"-          ]+      funcCode = case args of+        [] ->+          unlines+            [ indent 1 ("/// Wraps the `" ++ fullFuncPath ++ "` " ++ show (Action.funcType func) ++ "."),+              indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self) -> Result<" ++ returnHint ++ ", ApiError> {"),+              btreemapConstruction,+              indent 2 ("let result = self.client." ++ handlerCall ++ "(\"" ++ fullFuncPath ++ "\", btmap).await?;"),+              returnHandling,+              indent 1 "}"+            ]+        _ ->+          unlines+            [ indent 1 ("/// Wraps the `" ++ fullFuncPath ++ "` " ++ show (Action.funcType func) ++ "."),+              indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self, arg: " ++ argSignature ++ ") -> Result<" ++ returnHint ++ ", ApiError> {"),+              btreemapConstruction,+              indent 2 ("let result = self.client." ++ handlerCall ++ "(\"" ++ fullFuncPath ++ "\", btmap).await?;"),+              returnHandling,+              indent 1 "}"+            ]    in (funcCode, nestedFromArgs ++ nestedFromReturn)  generateSubscriptionFunction :: Action.ConvexFunction -> (String, [String]) generateSubscriptionFunction func =   let funcName = Action.funcName func-      (argSignature, nestedFromArgs) = generateArgSignature funcName (Action.funcArgs func)+      args = Action.funcArgs func+      (argSignature, nestedFromArgs) = generateArgSignatureStruct fullFuncPath args       funcNameSnake = "subscribe_" ++ toSnakeCase funcName       (returnHint, _, nestedFromReturn) = getReturnType funcName (Action.funcReturn func)       fullFuncPath = Action.funcPath func ++ ":" ++ funcName       btreemapConstruction = generateBTreeMap (Action.funcArgs func)-      funcCode =-        unlines-          [ indent 1 ("/// Subscribes to the `" ++ fullFuncPath ++ "` query."),-            indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self, " ++ argSignature ++ ") -> Result<TypedSubscription<" ++ returnHint ++ ">, ApiError> {"),-            btreemapConstruction,-            indent 2 ("let raw_subscription = self.client.subscribe(\"" ++ fullFuncPath ++ "\", btmap).await?;"),-            indent 2 "Ok(TypedSubscription {",-            indent 3 "raw_subscription,",-            indent 3 "_phantom: PhantomData,",-            indent 2 "})",-            indent 1 "}"-          ]+      funcCode = case args of+        [] ->+          unlines+            [ indent 1 ("/// Subscribes to the `" ++ fullFuncPath ++ "` query."),+              indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self) -> Result<TypedSubscription<" ++ returnHint ++ ">, ApiError> {"),+              btreemapConstruction,+              indent 2 ("let raw_subscription = self.client.subscribe(\"" ++ fullFuncPath ++ "\", btmap).await?;"),+              indent 2 "Ok(TypedSubscription {",+              indent 3 "raw_subscription,",+              indent 3 "_phantom: PhantomData,",+              indent 2 "})",+              indent 1 "}"+            ]+        _ ->+          unlines+            [ indent 1 ("/// Subscribes to the `" ++ fullFuncPath ++ "` query."),+              indent 1 ("pub async fn " ++ funcNameSnake ++ "(&mut self, arg: " ++ argSignature ++ ") -> Result<TypedSubscription<" ++ returnHint ++ ">, ApiError> {"),+              btreemapConstruction,+              indent 2 ("let raw_subscription = self.client.subscribe(\"" ++ fullFuncPath ++ "\", btmap).await?;"),+              indent 2 "Ok(TypedSubscription {",+              indent 3 "raw_subscription,",+              indent 3 "_phantom: PhantomData,",+              indent 2 "})",+              indent 1 "}"+            ]    in (funcCode, nestedFromArgs ++ nestedFromReturn)  generateTypesModule :: P.ParsedProject -> [String] -> String@@ -528,18 +553,18 @@       fieldLine = serdeRename ++ serdeAttrs ++ "\n" ++ indent 2 ("pub " ++ fieldNameSnake ++ ": " ++ rustType ++ ",")    in (fieldLine, nested) -generateArgSignature :: String -> [(String, Schema.ConvexType)] -> (String, [String])-generateArgSignature funcName args =-  let results = map (\(n, t) -> toRustType (funcName ++ capitalize n) t) args-      sigParts = zipWith (\(n, _) (ty, _) -> toSnakeCase n ++ ": " ++ toRustBorrowType ty) args results-      nestedModels = concatMap snd results-   in (intercalate ", " sigParts, nestedModels)+generateArgSignatureStruct :: String -> [(String, Schema.ConvexType)] -> (String, [String])+generateArgSignatureStruct _ [] = ("", [])+generateArgSignatureStruct fullFuncName args =+  let argStructName = toPascalCase $ map (\c -> if (c == '/' || c == ':') then '_' else c) $ fullFuncName ++ "Arg"+      (argCode, subArgs) = generateConstant argStructName $ Schema.VObject args+   in ("types::" ++ argStructName ++ "Object", argCode : subArgs)  generateBTreeMap :: [(String, Schema.ConvexType)] -> String generateBTreeMap [] = indent 2 "let btmap = BTreeMap::new();" generateBTreeMap btmap =   let buildStmts (name, convexType) =-        let varName = toSnakeCase name+        let varName = "arg." ++ toSnakeCase name          in case convexType of               Schema.VObject _ -> indent 1 ("btmap.insert(\"" ++ name ++ "\".to_string(), " ++ varName ++ ".to_convex_value()?);")               Schema.VOptional innerConvexType -> indent 1 ("if let Some(v) = " ++ varName ++ " { btmap.insert(\"" ++ name ++ "\".to_string(), " ++ fieldToConvexValue ("v", innerConvexType) ++ "); }")