1pub const MODEL_STUB: &str = r#"//! {%namespace%}::{%className%}
43//!
44//! 由 `sz-rust make:model` 生成。
45
46use sz_orm_core::model::Model;
47
48/// {%className%} 模型
49///
50/// 对齐 PHP `class {%className%} extends Model`
51pub struct {%className%};
52
53impl Model for {%className%} {
54 fn table_name() -> &'static str {
55 "{%table_name%}"
56 }
57}
58"#;
59
60pub const CONTROLLER_STUB: &str = r#"//! {%namespace%}::{%className%} 控制器
64//!
65//! 由 `sz-rust make:controller` 生成,对齐 PHP `controller.stub`(7 个 RESTful 方法)。
66
67use sz_rust_core::controller::SzController;
68use sz_rust_core::request::Request;
69use sz_rust_core::response::Response;
70
71/// {%className%} 控制器
72pub struct {%className%};
73
74impl {%className%} {
75 /// 列表(GET /{%route%})
76 pub async fn index(_req: Request) -> Response {
77 Response::success("index")
78 }
79
80 /// 新建表单(GET /{%route%}/create)
81 pub async fn create(_req: Request) -> Response {
82 Response::success("create")
83 }
84
85 /// 保存(POST /{%route%})
86 pub async fn save(_req: Request) -> Response {
87 Response::success("save")
88 }
89
90 /// 详情(GET /{%route%}/{id})
91 pub async fn read(_req: Request) -> Response {
92 Response::success("read")
93 }
94
95 /// 编辑表单(GET /{%route%}/{id}/edit)
96 pub async fn edit(_req: Request) -> Response {
97 Response::success("edit")
98 }
99
100 /// 更新(PUT /{%route%}/{id})
101 pub async fn update(_req: Request) -> Response {
102 Response::success("update")
103 }
104
105 /// 删除(DELETE /{%route%}/{id})
106 pub async fn delete(_req: Request) -> Response {
107 Response::success("delete")
108 }
109}
110"#;
111
112pub const CONTROLLER_API_STUB: &str = r#"//! {%namespace%}::{%className%} API 控制器
116//!
117//! 由 `sz-rust make:controller --api` 生成,对齐 PHP `controller.api.stub`(5 个方法)。
118
119use sz_rust_core::request::Request;
120use sz_rust_core::response::Response;
121
122/// {%className%} API 控制器
123pub struct {%className%};
124
125impl {%className%} {
126 /// 列表(GET /{%route%})
127 pub async fn index(_req: Request) -> Response {
128 Response::success("index")
129 }
130
131 /// 保存(POST /{%route%})
132 pub async fn save(_req: Request) -> Response {
133 Response::success("save")
134 }
135
136 /// 详情(GET /{%route%}/{id})
137 pub async fn read(_req: Request) -> Response {
138 Response::success("read")
139 }
140
141 /// 更新(PUT /{%route%}/{id})
142 pub async fn update(_req: Request) -> Response {
143 Response::success("update")
144 }
145
146 /// 删除(DELETE /{%route%}/{id})
147 pub async fn delete(_req: Request) -> Response {
148 Response::success("delete")
149 }
150}
151"#;
152
153pub const CONTROLLER_PLAIN_STUB: &str = r#"//! {%namespace%}::{%className%} 控制器
157//!
158//! 由 `sz-rust make:controller --plain` 生成,对齐 PHP `controller.plain.stub`(空类)。
159
160/// {%className%} 控制器(空骨架)
161pub struct {%className%};
162"#;
163
164pub const MIGRATION_UP_STUB: &str = r#"-- Migration: {%name%}
166-- Direction: UP
167-- Created: {%timestamp%}
168
169-- TODO: 在此编写 up SQL
170-- CREATE TABLE IF NOT EXISTS {%table_name%} (
171-- id BIGINT PRIMARY KEY AUTO_INCREMENT,
172-- created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
173-- updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
174-- );
175"#;
176
177pub const MIGRATION_DOWN_STUB: &str = r#"-- Migration: {%name%}
179-- Direction: DOWN
180-- Created: {%timestamp%}
181
182-- TODO: 在此编写 down SQL
183-- DROP TABLE IF EXISTS {%table_name%};
184"#;
185
186pub fn render_template(template: &str, replacements: &[(&str, &str)]) -> String {
195 let mut result = template.to_string();
196 for (placeholder, value) in replacements {
197 result = result.replace(placeholder, value);
198 }
199 result
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_model_stub_contains_class_placeholder() {
208 assert!(MODEL_STUB.contains("{%className%}"));
209 assert!(MODEL_STUB.contains("{%namespace%}"));
210 assert!(MODEL_STUB.contains("{%table_name%}"));
211 }
212
213 #[test]
214 fn test_controller_stub_has_seven_methods() {
215 assert!(CONTROLLER_STUB.contains("index"));
216 assert!(CONTROLLER_STUB.contains("create"));
217 assert!(CONTROLLER_STUB.contains("save"));
218 assert!(CONTROLLER_STUB.contains("read"));
219 assert!(CONTROLLER_STUB.contains("edit"));
220 assert!(CONTROLLER_STUB.contains("update"));
221 assert!(CONTROLLER_STUB.contains("delete"));
222 }
223
224 #[test]
225 fn test_controller_api_stub_has_five_methods() {
226 assert!(CONTROLLER_API_STUB.contains("index"));
227 assert!(CONTROLLER_API_STUB.contains("save"));
228 assert!(CONTROLLER_API_STUB.contains("read"));
229 assert!(CONTROLLER_API_STUB.contains("update"));
230 assert!(CONTROLLER_API_STUB.contains("delete"));
231 assert!(!CONTROLLER_API_STUB.contains("pub async fn create"));
233 assert!(!CONTROLLER_API_STUB.contains("pub async fn edit"));
234 }
235
236 #[test]
237 fn test_controller_plain_stub_is_empty_class() {
238 assert!(CONTROLLER_PLAIN_STUB.contains("struct {%className%}"));
239 }
240
241 #[test]
242 fn test_migration_stubs_contain_placeholders() {
243 assert!(MIGRATION_UP_STUB.contains("{%name%}"));
244 assert!(MIGRATION_UP_STUB.contains("{%timestamp%}"));
245 assert!(MIGRATION_DOWN_STUB.contains("{%name%}"));
246 assert!(MIGRATION_DOWN_STUB.contains("{%timestamp%}"));
247 }
248
249 #[test]
250 fn test_render_template_basic() {
251 let result = render_template("Hello {%name%}!", &[("{%name%}", "World")]);
252 assert_eq!(result, "Hello World!");
253 }
254
255 #[test]
256 fn test_render_template_multiple_placeholders() {
257 let result = render_template(
258 "{%className%} in {%namespace%}",
259 &[("{%className%}", "User"), ("{%namespace%}", "app::model")],
260 );
261 assert_eq!(result, "User in app::model");
262 }
263
264 #[test]
265 fn test_render_template_no_placeholders() {
266 let result = render_template("no placeholders", &[]);
267 assert_eq!(result, "no placeholders");
268 }
269
270 #[test]
271 fn test_render_template_repeated_placeholders() {
272 let result = render_template("{%x%} and {%x%}", &[("{%x%}", "A")]);
273 assert_eq!(result, "A and A");
274 }
275}