Repository: Wulf/create-rust-app (language: rust)

Issue:
Compilation error after creating the app 
Hi,

I created the directory and the code as per the instructions in the documentation and when I ran `cargo fullstack` I got the error below:
```
error[E0063]: missing fields `model_path` and `schema_path` in initializer of `GenerationConfig<'_>`
  --> .cargo/bin/dsync.rs:19:52
   |
19 |     dsync::generate_files(schema_file, models_dir, GenerationConfig {
   |                                                    ^^^^^^^^^^^^^^^^ missing `model_path` and `schema_path`

```

After some trial and error, this is the fix I applied:
```
pub fn main() {
    let dir = env!("CARGO_MANIFEST_DIR");

    println!("Running dsync (generating model code from `backend/schema.rs`)");

    let schema_file = PathBuf::from_iter([dir, "backend/schema.rs"]);
    let models_dir = PathBuf::from_iter([dir, "backend/models"]);

    let model_path = "models::".to_string();    // <-------------------
    let schema_path = "crate::schema::".to_string();    // <-------------------

    ensure_schema_is_generated(&schema_file);

    dsync::generate_files(schema_file, models_dir, GenerationConfig {
        connection_type: "create_rust_app::Connection".to_string(),
        default_table_options: TableOptions::default()
            .tsync()
            .autogenerated_columns(vec!["id", "created_at", "updated_at"]),
        table_options: HashMap::from([
            // plugin_storage
            ("attachment_blobs", TableOptions::default().ignore()),
            ("attachments", TableOptions::default().ignore()),

            // plugin_auth
            ("role_permissions", TableOptions::default().ignore()),
            ("user_permissions", TableOptions::default().ignore()),
            ("user_roles", TableOptions::default().ignore()),
            ("user_sessions", TableOptions::default().ignore()),
            ("users", TableOptions::default().ignore()),

            // plugin_tasks
            ("fang_tasks", TableOptions::default().ignore()),
         ],
        ),
        model_path,   // <-------------------
        schema_path,   // <-------------------
    });
}
```

So, could you please fix this, or if I did something wrong, which is entirely possible because I am new to the rust ecosystem, could you please update the docs to outline clearly the steps that need to be done in order to successfully run the app?

Thank you,
🙏


Discussion / hints:
Same issue here
This is probably due to a new release of dsync, for now try using an older version (of dsync) while I work on a fix (which might take me a while because I don't have a lot of free bandwidth right now
also, shouldn't model_path be "crate::models::" or did that not work?

see: https://github.com/Wulf/dsync/commit/ec866873bc1d074000082a03a0011bb548e9f39c (the breaking change)

Fix patch:
diff --git a/create-rust-app/src/dev/dev_server.rs b/create-rust-app/src/dev/dev_server.rs
index 523eb98e..417f0d08 100644
--- a/create-rust-app/src/dev/dev_server.rs
+++ b/create-rust-app/src/dev/dev_server.rs
@@ -70,7 +70,7 @@ pub async fn start(
     let app = Router::new()
         .route("/", get(|| async {
             // Let user know the server is running
-            Html(r###"
+            Html(r#"
                 <html style="background-color: #171717; height: 100%; width: 100%;">
                     <head><title>Create Rust App: Development Server</title></head>
                     <body style="text-align: center; color: white; fony-family: sans-serif; padding: 50px;">
@@ -78,7 +78,7 @@ pub async fn start(
                         <h3>Create Rust App: Development Server</h3>
                     </body>
                 </html>
-            "###)
+            "#)
         }))
         .route("/vitejs-down", get(vitejs_down_handler))
         .route("/vitejs-up", get(vitejs_up_handler))
diff --git a/create-rust-app_cli/src/content/project.rs b/create-rust-app_cli/src/content/project.rs
index 23975d43..42efd073 100644
--- a/create-rust-app_cli/src/content/project.rs
+++ b/create-rust-app_cli/src/content/project.rs
@@ -84,11 +84,11 @@ fn add_bins_to_cargo_toml(
         .cra_enabled_features
         .contains(&"plugin_tasks".to_string())
     {
-        r##"
+        r#"
 [[bin]]
 name = "queue"
 path = "backend/queue.rs"
-"##
+"#
     } else {
         ""
     };
diff --git a/create-rust-app_cli/src/plugins/dev.rs b/create-rust-app_cli/src/plugins/dev.rs
index c1990fc5..476ba116 100644
--- a/create-rust-app_cli/src/plugins/dev.rs
+++ b/create-rust-app_cli/src/plugins/dev.rs
@@ -51,15 +51,14 @@ impl Plugin for Dev {
 
         fs::append(
             "frontend/src/dev.tsx",
-            indoc! {r##"
-            // Sets up the development environment.
-            //
-            // Note: When running `cargo frontend` and `cargo backend` individually, "DEV_SERVER_PORT" is not set.
-            //       Use `cargo fullstack` for the full development experience.
-            if (import.meta.env.DEV_SERVER_PORT) {
-                import('./setupDevelopment')
-            }
-        "##},
+            indoc! {r#"// Sets up the development environment.
+//
+// Note: When running `cargo frontend` and `cargo backend` individually, "DEV_SERVER_PORT" is not set.
+//       Use `cargo fullstack` for the full development experience.
+if (import.meta.env.DEV_SERVER_PORT) {
+    import('./setupDevelopment')
+}
+"#},
         )?;
 
         match install_config.backend_framework {
diff --git a/create-rust-app_cli/src/plugins/graphql.rs b/create-rust-app_cli/src/plugins/graphql.rs
index a8e86a08..0cd631f5 100644
--- a/create-rust-app_cli/src/plugins/graphql.rs
+++ b/create-rust-app_cli/src/plugins/graphql.rs
@@ -85,7 +85,7 @@ import { GraphQLPage } from './containers/GraphQLPage'"#,
         fs::replace(
             "frontend/bundles/index.tsx",
             "ReactDOM.createRoot",
-            r##"import {ApolloProvider} from "@apollo/client";
+            r#"import {ApolloProvider} from "@apollo/client";
 import {useAuthenticatedApolloClient} from "../src/hooks/useAuthenticatedApolloClient";
 
 const AuthenticatedApolloProvider = (props: { children: React.ReactNode }) => {
@@ -96,7 +96,7 @@ const AuthenticatedApolloProvider = (props: { children: React.ReactNode }) => {
     </ApolloProvider>
 }
 
-ReactDOM.createRoot"##,
+ReactDOM.createRoot"#,
         )?;
 
         fs::replace(
@@ -108,18 +108,18 @@ ReactDOM.createRoot"##,
 
         fs::replace(
             "frontend/package.json",
-            r##""dependencies": {"##,
-            r##""dependencies": {
+            r#""dependencies": {"#,
+            r#""dependencies": {
     "@apollo/client": "^3.5.10",
     "graphql-ws": "^5.6.4",
-    "graphql": "^16.3.0","##,
+    "graphql": "^16.3.0","#,
         )?;
 
         fs::replace("backend/main.rs", "mod mail;", "mod mail;\nmod graphql;")?;
 
         // update auth plugin's logout button
-        let old_logout_link = r##"{ auth.isAuthenticated && <a className="NavButton" onClick={() => auth.logout()}>Logout</a> }"##;
-        let new_logout_link = r##"{ auth.isAuthenticated && <a className="NavButton" onClick={() => { auth.logout(); apollo.resetStore(); }}>Logout</a> }"##;
+        let old_logout_link = r#"{ auth.isAuthenticated && <a className="NavButton" onClick={() => auth.logout()}>Logout</a> }"#;
+        let new_logout_link = r#"{ auth.isAuthenticated && <a className="NavButton" onClick={() => { auth.logout(); apollo.resetStore(); }}>Logout</a> }"#;
         fs::replace("frontend/src/App.tsx", old_logout_link, new_logout_link)?;
 
         // make sure auth plugin is wrapped on top
diff --git a/create-rust-app_cli/src/plugins/tasks.rs b/create-rust-app_cli/src/plugins/tasks.rs
index 262e9880..c153f32b 100644
--- a/create-rust-app_cli/src/plugins/tasks.rs
+++ b/create-rust-app_cli/src/plugins/tasks.rs
@@ -55,29 +55,28 @@ impl Plugin for Tasks {
 
         crate::content::migration::create(
             "plugin_tasks",
-            indoc! {r##"
-                CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-
-                CREATE TYPE fang_task_state AS ENUM ('new', 'in_progress', 'failed', 'finished', 'retried');
-
-                CREATE TABLE fang_tasks (
-                    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
-                    metadata jsonb NOT NULL,
-                    error_message TEXT,
-                    state fang_task_state DEFAULT 'new' NOT NULL,
-                    task_type VARCHAR DEFAULT 'common' NOT NULL,
-                    uniq_hash CHAR(64),
-                    retries INTEGER DEFAULT 0 NOT NULL,
-                    scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
-                    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
-                    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
-                );
-
-                CREATE INDEX fang_tasks_state_index ON fang_tasks(state);
-                CREATE INDEX fang_tasks_type_index ON fang_tasks(task_type);
-                CREATE INDEX fang_tasks_scheduled_at_index ON fang_tasks(scheduled_at);
-                CREATE INDEX fang_tasks_uniq_hash ON fang_tasks(uniq_hash);
-            "##},
+            indoc! {r#"CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
+
+CREATE TYPE fang_task_state AS ENUM ('new', 'in_progress', 'failed', 'finished', 'retried');
+
+CREATE TABLE fang_tasks (
+    id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
+    metadata jsonb NOT NULL,
+    error_message TEXT,
+    state fang_task_state DEFAULT 'new' NOT NULL,
+    task_type VARCHAR DEFAULT 'common' NOT NULL,
+    uniq_hash CHAR(64),
+    retries INTEGER DEFAULT 0 NOT NULL,
+    scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+    created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
+    updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
+);
+
+CREATE INDEX fang_tasks_state_index ON fang_tasks(state);
+CREATE INDEX fang_tasks_type_index ON fang_tasks(task_type);
+CREATE INDEX fang_tasks_scheduled_at_index ON fang_tasks(scheduled_at);
+CREATE INDEX fang_tasks_uniq_hash ON fang_tasks(uniq_hash);
+"#},
             r#"DROP TABLE fang_tasks;"#,
         )?;
 
diff --git a/create-rust-app_cli/template/.cargo/bin/dsync.rs b/create-rust-app_cli/template/.cargo/bin/dsync.rs
index 782fe756..1163cf21 100644
--- a/create-rust-app_cli/template/.cargo/bin/dsync.rs
+++ b/create-rust-app_cli/template/.cargo/bin/dsync.rs
@@ -1,7 +1,7 @@
-use std::collections::HashMap;
-use std::path::PathBuf;
 use dsync;
 use dsync::{GenerationConfig, TableOptions};
+use std::collections::HashMap;
+use std::path::PathBuf;
 
 pub fn main() {
     let dir = env!("CARGO_MANIFEST_DIR");
@@ -13,32 +13,38 @@ pub fn main() {
 
     ensure_schema_is_generated(&schema_file);
 
-    dsync::generate_files(schema_file, models_dir, GenerationConfig {
-        connection_type: "create_rust_app::Connection".to_string(),
-        default_table_options: TableOptions::default()
-            .tsync()
-            .autogenerated_columns(vec!["id", "created_at", "updated_at"]),
-        table_options: HashMap::from([
-            // plugin_storage
-            ("attachment_blobs", TableOptions::default().ignore()),
-            ("attachments", TableOptions::default().ignore()),
-
-            // plugin_auth
-            ("role_permissions", TableOptions::default().ignore()),
-            ("user_permissions", TableOptions::default().ignore()),
-            ("user_roles", TableOptions::default().ignore()),
-            ("user_sessions", TableOptions::default().ignore()),
-            ("users", TableOptions::default().ignore()),
-
-            // plugin_tasks
-            ("fang_tasks", TableOptions::default().ignore()),
-         ]),
-    });
+    dsync::generate_files(
+        schema_file,
+        models_dir,
+        GenerationConfig {
+            connection_type: "create_rust_app::Connection".to_string(),
+            default_table_options: TableOptions::default().tsync().autogenerated_columns(vec![
+                "id",
+                "created_at",
+                "updated_at",
+            ]),
+            table_options: HashMap::from([
+                // plugin_storage
+                ("attachment_blobs", TableOptions::default().ignore()),
+                ("attachments", TableOptions::default().ignore()),
+                // plugin_auth
+                ("role_permissions", TableOptions::default().ignore()),
+                ("user_permissions", TableOptions::default().ignore()),
+                ("user_roles", TableOptions::default().ignore()),
+                ("user_sessions", TableOptions::default().ignore()),
+                ("users", TableOptions::default().ignore()),
+                // plugin_tasks
+                ("fang_tasks", TableOptions::default().ignore()),
+            ]),
+            model_path: "crate::models::".to_string(),
+            schema_path: "crate::schema::".to_string(),
+        },
+    );
 }
 
 pub fn ensure_schema_is_generated(schema_file: &PathBuf) {
     // check that the diesel schema file is not empty
-    let content =  std::fs::read_to_string(schema_file).unwrap_or_default();
+    let content = std::fs::read_to_string(schema_file).unwrap_or_default();
 
     if content.trim().is_empty() {
         println!("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");


Test patch: