1use std::{io, path::Path};
2
3use interstice_core::IntersticeError;
4
5pub fn init() -> Result<(), IntersticeError> {
11 println!("Enter the project name: ");
12 let project_name = &mut String::new();
13 io::stdin()
14 .read_line(project_name)
15 .expect("Should be able to read line");
16 let project_name = project_name
17 .parse::<String>()
18 .map_err(|_| IntersticeError::Internal("Failed to read project name".into()))?
19 .trim()
20 .to_string();
21 let project_path = Path::new(&project_name);
22 if project_path.exists() {
23 return Err(IntersticeError::Internal("Directory already exists".into()));
24 }
25 std::fs::create_dir(&project_path).map_err(|err| {
26 IntersticeError::Internal(format!("Failed to create project directory: {}", err))
27 })?;
28
29 let name = project_name.to_lowercase();
30
31 let cargo_toml_content = format!(
33 r#"[package]
34name = "{name}"
35version = "0.1.0"
36edition = "2024"
37
38[lib]
39crate-type = ["cdylib"]
40
41[dependencies]
42interstice-sdk = "0.3.0"
43
44[build-dependencies]
45interstice-sdk = "0.3.0"
46"#,
47 );
48 std::fs::write(project_path.join("Cargo.toml"), cargo_toml_content).map_err(|err| {
49 IntersticeError::Internal(format!("Failed to create Cargo.toml: {}", err))
50 })?;
51
52 let cargo_config_content = r#"[build]
54target = "wasm32-unknown-unknown"
55"#;
56 std::fs::create_dir(project_path.join(".cargo")).map_err(|err| {
57 IntersticeError::Internal(format!("Failed to create .cargo directory: {}", err))
58 })?;
59 std::fs::write(
60 project_path.join(".cargo/config.toml"),
61 cargo_config_content,
62 )
63 .map_err(|err| {
64 IntersticeError::Internal(format!("Failed to create .cargo/config.toml: {}", err))
65 })?;
66
67 let build_rs_content = r#"fn main() {
69 interstice_sdk::bindings::generate_bindings();
70}
71"#;
72 std::fs::create_dir(project_path.join("src")).map_err(|err| {
73 IntersticeError::Internal(format!("Failed to create src directory: {}", err))
74 })?;
75 std::fs::write(project_path.join("build.rs"), build_rs_content)
76 .map_err(|err| IntersticeError::Internal(format!("Failed to create build.rs: {}", err)))?;
77
78 let lib_content = r#"use interstice_sdk::*;
80
81interstice_module!(visibility: Public);
82
83// TABLES
84
85#[table(public)]
86#[derive(Debug)]
87pub struct Greetings {
88 #[primary_key(auto_inc)]
89 pub id: u64,
90 #[index(btree, unique)]
91 pub greeting: String,
92 pub custom: TestCustomType,
93}
94
95#[interstice_type]
96#[derive(Debug, Clone)]
97pub struct TestCustomType {
98 pub val: u32,
99}
100
101// REDUCERS
102#[reducer(on = "init")]
103pub fn init(ctx: ReducerContext) {
104 ctx.log("Hello world !");
105}
106
107#[reducer]
108pub fn hello(ctx: ReducerContext, name: String) {
109 ctx.log(&format!("Saying hello to {}", name));
110 match ctx.current.tables.greetings().insert(Greetings {
111 id: 0,
112 greeting: format!("Hello, {}!", name),
113 custom: TestCustomType { val: 0 },
114 }) {
115 Ok(_) => (),
116 Err(err) => ctx.log(&format!("Failed to insert greeting: {:?}", err)),
117 }
118}
119
120#[reducer(on = "hello.greetings.insert")]
121fn on_greeting_insert(ctx: ReducerContext, inserted_row: Greetings) {
122 ctx.log(&format!("Inserted greeting: {:?}", inserted_row));
123}
124
125#[query]
126fn get_greetings(ctx: QueryContext) -> Vec<Greetings> {
127 ctx.current.tables.greetings().scan().unwrap_or_else(|err| {
128 ctx.log(&format!("Failed to scan greetings: {}", err));
129 vec![]
130 })
131}
132"#;
133
134 std::fs::write(project_path.join("src/lib.rs"), lib_content).map_err(|err| {
135 IntersticeError::Internal(format!("Failed to create src/lib.rs: {}", err))
136 })?;
137 Ok(())
138}