├── .gitignore ├── LICENSE ├── README.md ├── crud_routers ├── Cargo.lock ├── Cargo.toml ├── src │ ├── lib.rs │ ├── openapi.rs │ ├── repositories │ │ ├── diesel.rs │ │ ├── mod.rs │ │ └── sea_orm.rs │ └── servers │ │ ├── actix.rs │ │ ├── axum.rs │ │ └── mod.rs └── tests │ ├── openapi.rs │ ├── test_api_spec.json │ └── test_api_spec_without_create_schema.json ├── docs └── assets │ ├── ListAll.png │ └── SwaggerOverview.png ├── examples ├── diesel_axum │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ │ ├── lib.rs │ │ ├── main.rs │ │ ├── models.rs │ │ └── schema.rs └── seaorm_actix │ ├── Cargo.lock │ ├── Cargo.toml │ └── src │ ├── lib.rs │ ├── main.rs │ └── post.rs └── test_utils ├── Cargo.lock ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | **/target/ 2 | .idea/ 3 | 4 | **/diesel.toml 5 | **/.env 6 | **/migrations/ 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Furkan Guvenc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crud_routers 2 | 3 | **crud_routers** is a library to automatically generate crud routes with given schemas. 4 | It is orm and web framework agnostic, highly inspired by [fastapi-crudrouter](https://github.com/awtkns/fastapi-crudrouter). 5 | 6 | [![Crates.io](https://img.shields.io/crates/v/crud_routers)](https://crates.io/crates/crud_routers) 7 | [![Documentation](https://docs.rs/crud_routers/badge.svg)](https://docs.rs/crud_routers) 8 | 9 | ## Basic usage with Axum and Diesel 10 | 11 | ### Installation 12 | ```bash 13 | cargo add crud_routers --features axum,diesel 14 | ``` 15 | 16 | ### Usage 17 | Below is a simple example of what the crud_routers can do. In just ten lines of code, you can generate all 18 | the crud_routers you need for any model. The full example is in [diesel_example folder](examples/diesel_axum) 19 | 20 | ```rust 21 | #[tokio::main] 22 | async fn main() -> io::Result<()> { 23 | let database_url = "postgres://postgres:testpw@localhost/diesel_demo"; 24 | let connection = PgConnection::establish(&database_url).unwrap(); 25 | let shared_state = Arc::new(Mutex::new( 26 | DieselRepository::new(connection, posts::table) 27 | )); 28 | 29 | let router = CrudRouterBuilder::new::() 30 | .schema::() 31 | .create_schema::() 32 | .update_schema::() 33 | .prefix("base/api") 34 | .build_router() 35 | .with_state(shared_state); 36 | 37 | axum::serve(listener, router).await 38 | } 39 | ``` 40 | 41 | ## Features 42 | 43 | ### Orm-Agnostic 44 | 45 | Following ORMs are implemented, and you can activate them with adding necessary features. 46 | 47 | - [Diesel](https://diesel.rs/) with feature "diesel" 48 | - [Sea-orm](https://www.sea-ql.org/SeaORM/) with feature "sea-orm" 49 | 50 | You can easily add new ones by implementing [necessary traits](crud_routers/src/repositories/mod.rs). 51 | 52 | ### Api Server Agnostic 53 | Following api servers are implemented, and you can activate them with adding necessary features. 54 | You can mix and match them with Orms however you want. 55 | 56 | - [Axum](https://github.com/tokio-rs/axum) with feature "axum" 57 | - [Actix](https://actix.rs/) with feature "actix" 58 | 59 | ### OpenApi support 60 | You can easily add [openapi](https://www.openapis.org/) support with feature "openapi" and 61 | deriving [utoipa::ToSchema](https://docs.rs/utoipa/latest/utoipa/derive.ToSchema.html) for your schemas. 62 | You can use all UIs supported by [utoipa](https://github.com/juhaku/utoipa). 63 | 64 | ```rust 65 | let mut openapi = OpenApiBuilder::new() 66 | .info(InfoBuilder::new().title("Diesel Axum example").build()) 67 | .build(); 68 | 69 | let router = CrudRouterBuilder::new::() 70 | .schema::() 71 | .create_schema::() 72 | .update_schema::() 73 | .prefix("base/api") 74 | .build_openapi(&mut openapi) 75 | .build_router() 76 | .with_state(shared_state) 77 | .merge(SwaggerUi::new("/docs/swagger/").url("/api-docs/openapi.json", openapi)); 78 | 79 | ``` 80 | 81 | ![Swagger UI](docs/assets/SwaggerOverview.png) 82 | 83 | ### Pagination 84 | Pagination is automatically setup for you. You can use the `skip` and `limit` query parameters to 85 | paginate your results. 86 | 87 | **Skip**: 88 | Using the `skip` (int) parameter, you can skip a certain number of items before returning the items you want. 89 | 90 | **Limit**: 91 | Using the `limit` (int) parameter, the maximum number of items to be returned can be defined. 92 | 93 | ![Swagger UI](docs/assets/ListAll.png) 94 | 95 | ### Opting Out Routes 96 | If you don't add a schema with `create_schema` then create item route won't be created. 97 | Same applies for `update_schema` method and update item route. 98 | Alternatively all routes can be opted out using disable_*_route methods. 99 | 100 | ```rust 101 | CrudRouterBuilder::new::() 102 | .repository::() 103 | .schema::() 104 | .create_schema::() 105 | .update_schema::() 106 | .disable_list_items_route() 107 | .disable_get_item_route() 108 | .disable_delete_item_route() 109 | .disable_delete_all_items_route() 110 | .disable_create_item_route() 111 | .disable_update_item_route() 112 | ``` 113 | 114 | ### Set tag and prefix 115 | You can set a prefix for your url with `prefix` method. 116 | Leaving prefix makes it the table name. 117 | If "openapi" feature is added then `tag` method 118 | can be used to set the tag for the api spec. 119 | 120 | ```rust 121 | CrudRouterBuilder::new::() 122 | .repository::() 123 | .schema::() 124 | .prefix("base/api") 125 | .tag("My Tag") 126 | ``` 127 | 128 | ### TODO 129 | 130 | - [ ] Add Middleware support 131 | - [ ] Create an [mdBook](https://github.com/rust-lang/mdBook) for documentation 132 | -------------------------------------------------------------------------------- /crud_routers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "crud_routers" 3 | description = "Automatically create crud routes for your favorite api server and orm" 4 | version = "0.1.0" 5 | edition = "2021" 6 | license = "MIT" 7 | keywords = ["crud", "api", "server", "openapi", "web"] 8 | repository = "https://github.com/furkan-guvenc/crud_routers" 9 | 10 | [dependencies] 11 | # databases 12 | diesel = { version = "2" , optional = true} 13 | sea-orm = { version = "1.0.0", optional = true } 14 | 15 | axum = { version = "0.7.5", optional = true} 16 | actix-web = {version = "4", optional = true} 17 | tokio = { version = "1.0", features = ["full"] } 18 | serde = { version = "1.0", features = ["derive"] } 19 | serde_json = "1" 20 | utoipa = { version = "5.1.1" , optional = true} 21 | 22 | [features] 23 | axum = ["dep:axum"] 24 | actix = ["dep:actix-web"] 25 | diesel = ["dep:diesel"] 26 | sea-orm = ["dep:sea-orm"] 27 | openapi = ["dep:utoipa"] 28 | -------------------------------------------------------------------------------- /crud_routers/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use serde::Deserialize; 3 | 4 | mod servers; 5 | mod repositories; 6 | #[cfg(feature = "openapi")] 7 | mod openapi; 8 | 9 | pub use repositories::*; 10 | pub use servers::*; 11 | 12 | pub struct Empty; 13 | pub struct Assigned(PhantomData); 14 | 15 | pub trait Assignable{ 16 | const IS_ASSIGNED: bool; 17 | } 18 | 19 | impl Assignable for Empty{ 20 | const IS_ASSIGNED: bool = false; 21 | } 22 | impl Assignable for Assigned{ 23 | const IS_ASSIGNED: bool = true; 24 | } 25 | 26 | pub struct CrudRouterBuilder<'a, Server: Assignable, Repo, Schema: Assignable, PrimaryKeyType: Assignable, CreateSchema:Assignable, UpdateSchema:Assignable> { 27 | prefix: Option<&'a str>, 28 | tag: Option<&'a str>, 29 | list_items_route_disabled: bool, 30 | get_item_route_disabled: bool, 31 | delete_item_route_disabled: bool, 32 | delete_all_items_route_disabled: bool, 33 | create_item_route_disabled: bool, 34 | update_item_route_disabled: bool, 35 | _marker: PhantomData<(Server, Repo, Schema, PrimaryKeyType, CreateSchema, UpdateSchema)>, 36 | } 37 | 38 | impl<'a, Repo> CrudRouterBuilder<'a, Empty, Repo, Empty, Empty, Empty, Empty> { 39 | pub fn new() -> CrudRouterBuilder<'a, Assigned, Repo, Empty, Empty, Empty, Empty> { 40 | CrudRouterBuilder { 41 | prefix: None, 42 | tag: None, 43 | list_items_route_disabled: false, 44 | get_item_route_disabled: false, 45 | delete_item_route_disabled: false, 46 | delete_all_items_route_disabled: false, 47 | create_item_route_disabled: false, 48 | update_item_route_disabled: false, 49 | _marker: Default::default() 50 | } 51 | } 52 | } 53 | 54 | impl <'a, Server, Repo, Schema: Assignable, PrimaryKeyType: Assignable, CreateSchema:Assignable, UpdateSchema:Assignable> CrudRouterBuilder<'a, Assigned, Repo, Schema, PrimaryKeyType, CreateSchema, UpdateSchema> { 55 | pub fn prefix(self, prefix: &'a str) -> Self{ 56 | CrudRouterBuilder{ 57 | prefix: Some(prefix), 58 | tag: self.tag, 59 | _marker: Default::default(), 60 | list_items_route_disabled: self.list_items_route_disabled, 61 | get_item_route_disabled: self.get_item_route_disabled, 62 | delete_item_route_disabled: self.delete_item_route_disabled, 63 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 64 | create_item_route_disabled: self.create_item_route_disabled, 65 | update_item_route_disabled: self.update_item_route_disabled, 66 | } 67 | } 68 | 69 | #[cfg(feature = "openapi")] 70 | pub fn tag(self, tag: &'a str) -> Self{ 71 | CrudRouterBuilder{ 72 | prefix: self.prefix, 73 | tag: Some(tag), 74 | _marker: Default::default(), 75 | list_items_route_disabled: self.list_items_route_disabled, 76 | get_item_route_disabled: self.get_item_route_disabled, 77 | delete_item_route_disabled: self.delete_item_route_disabled, 78 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 79 | create_item_route_disabled: self.create_item_route_disabled, 80 | update_item_route_disabled: self.update_item_route_disabled, 81 | } 82 | } 83 | } 84 | 85 | impl<'a, Server, Schema: Assignable, PrimaryKeyType: Assignable> CrudRouterBuilder<'a, Assigned, Empty, Schema, PrimaryKeyType, Empty, Empty> { 86 | pub fn repository(self) -> CrudRouterBuilder<'a, Assigned, Repo, Schema, PrimaryKeyType, Empty, Empty>{ 87 | CrudRouterBuilder{ 88 | prefix: self.prefix, 89 | tag: self.tag, 90 | _marker: Default::default(), 91 | list_items_route_disabled: self.list_items_route_disabled, 92 | get_item_route_disabled: self.get_item_route_disabled, 93 | delete_item_route_disabled: self.delete_item_route_disabled, 94 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 95 | create_item_route_disabled: self.create_item_route_disabled, 96 | update_item_route_disabled: self.update_item_route_disabled, 97 | } 98 | } 99 | } 100 | 101 | impl<'a, Server, Repo> CrudRouterBuilder<'a, Assigned, Repo, Empty, Empty, Empty, Empty> { 102 | #[cfg(not(feature = "openapi"))] 103 | pub fn schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, Empty, Empty>{ 104 | CrudRouterBuilder{ 105 | prefix: self.prefix, 106 | tag: self.tag, 107 | _marker: Default::default(), 108 | list_items_route_disabled: self.list_items_route_disabled, 109 | get_item_route_disabled: self.get_item_route_disabled, 110 | delete_item_route_disabled: self.delete_item_route_disabled, 111 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 112 | create_item_route_disabled: self.create_item_route_disabled, 113 | update_item_route_disabled: self.update_item_route_disabled, 114 | } 115 | } 116 | 117 | #[cfg(feature = "openapi")] 118 | pub fn schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, Empty, Empty>{ 119 | CrudRouterBuilder{ 120 | prefix: self.prefix, 121 | tag: self.tag, 122 | _marker: Default::default(), 123 | list_items_route_disabled: self.list_items_route_disabled, 124 | get_item_route_disabled: self.get_item_route_disabled, 125 | delete_item_route_disabled: self.delete_item_route_disabled, 126 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 127 | create_item_route_disabled: self.create_item_route_disabled, 128 | update_item_route_disabled: self.update_item_route_disabled, 129 | } 130 | } 131 | } 132 | 133 | impl<'a, Server, Repo, Schema, PrimaryKeyType, UpdateSchema: Assignable> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, Empty, UpdateSchema> { 134 | #[cfg(not(feature = "openapi"))] 135 | pub fn create_schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, Assigned, UpdateSchema>{ 136 | CrudRouterBuilder{ 137 | prefix: self.prefix, 138 | tag: self.tag, 139 | _marker: Default::default(), 140 | list_items_route_disabled: self.list_items_route_disabled, 141 | get_item_route_disabled: self.get_item_route_disabled, 142 | delete_item_route_disabled: self.delete_item_route_disabled, 143 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 144 | create_item_route_disabled: self.create_item_route_disabled, 145 | update_item_route_disabled: self.update_item_route_disabled, 146 | } 147 | } 148 | 149 | #[cfg(feature = "openapi")] 150 | pub fn create_schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, Assigned, UpdateSchema>{ 151 | CrudRouterBuilder{ 152 | prefix: self.prefix, 153 | tag: self.tag, 154 | _marker: Default::default(), 155 | list_items_route_disabled: self.list_items_route_disabled, 156 | get_item_route_disabled: self.get_item_route_disabled, 157 | delete_item_route_disabled: self.delete_item_route_disabled, 158 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 159 | create_item_route_disabled: self.create_item_route_disabled, 160 | update_item_route_disabled: self.update_item_route_disabled, 161 | } 162 | } 163 | } 164 | 165 | impl, Schema, PrimaryKeyType, CreateSchema: Assignable, UpdateSchema: Assignable> CrudRouterBuilder<'_, Server, Repo, Assigned, Assigned, CreateSchema, UpdateSchema> { 166 | fn get_prefix(&self) -> &str{ 167 | if let Some(prefix) = self.prefix { 168 | prefix 169 | } else { 170 | Repo::get_table_name().leak() 171 | } 172 | } 173 | } 174 | 175 | impl<'a, Server, Repo, Schema, PrimaryKeyType, CreateSchema: Assignable> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, CreateSchema, Empty> { 176 | #[cfg(not(feature = "openapi"))] 177 | pub fn update_schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, CreateSchema, Assigned>{ 178 | CrudRouterBuilder{ 179 | prefix: self.prefix, 180 | tag: self.tag, 181 | _marker: Default::default(), 182 | list_items_route_disabled: self.list_items_route_disabled, 183 | get_item_route_disabled: self.get_item_route_disabled, 184 | delete_item_route_disabled: self.delete_item_route_disabled, 185 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 186 | create_item_route_disabled: self.create_item_route_disabled, 187 | update_item_route_disabled: self.update_item_route_disabled, 188 | } 189 | } 190 | 191 | #[cfg(feature = "openapi")] 192 | pub fn update_schema(self) -> CrudRouterBuilder<'a, Assigned, Repo, Assigned, Assigned, CreateSchema, Assigned>{ 193 | CrudRouterBuilder{ 194 | prefix: self.prefix, 195 | tag: self.tag, 196 | _marker: Default::default(), 197 | list_items_route_disabled: self.list_items_route_disabled, 198 | get_item_route_disabled: self.get_item_route_disabled, 199 | delete_item_route_disabled: self.delete_item_route_disabled, 200 | delete_all_items_route_disabled: self.delete_all_items_route_disabled, 201 | create_item_route_disabled: self.create_item_route_disabled, 202 | update_item_route_disabled: self.update_item_route_disabled, 203 | } 204 | } 205 | } 206 | 207 | impl CrudRouterBuilder<'_, Assigned, Repo, Assigned, Assigned, CreateSchema, UpdateSchema> { 208 | pub fn disable_list_items_route(self) -> Self{ 209 | Self { 210 | list_items_route_disabled: true, 211 | ..self 212 | } 213 | } 214 | 215 | pub fn disable_get_item_route(self) -> Self{ 216 | Self { 217 | get_item_route_disabled: true, 218 | ..self 219 | } 220 | } 221 | 222 | pub fn disable_delete_item_route(self) -> Self{ 223 | Self { 224 | delete_item_route_disabled: true, 225 | ..self 226 | } 227 | } 228 | 229 | pub fn disable_delete_all_items_route(self) -> Self{ 230 | Self { 231 | delete_all_items_route_disabled: true, 232 | ..self 233 | } 234 | } 235 | } 236 | 237 | impl CrudRouterBuilder<'_, Assigned, Repo, Assigned, Assigned, Assigned, UpdateSchema> { 238 | pub fn disable_create_item_route(self) -> Self{ 239 | Self { 240 | create_item_route_disabled: true, 241 | ..self 242 | } 243 | } 244 | } 245 | 246 | impl CrudRouterBuilder<'_, Assigned, Repo, Assigned, Assigned, CreateSchema, Assigned> { 247 | pub fn disable_update_item_route(self) -> Self{ 248 | Self { 249 | update_item_route_disabled: true, 250 | ..self 251 | } 252 | } 253 | } 254 | 255 | #[derive(Deserialize)] 256 | #[cfg_attr(feature = "openapi", derive(utoipa::IntoParams))] 257 | pub struct Pagination{ 258 | skip: Option, 259 | limit: Option, 260 | } 261 | #[cfg(test)] 262 | mod tests { 263 | // Note this useful idiom: importing names from outer (for mod tests) scope. 264 | use super::*; 265 | 266 | struct Schema; 267 | struct CreateSchema; 268 | struct UpdateSchema; 269 | struct PrimaryKeyType; 270 | struct Repo; 271 | impl ReadDeleteRepository for Repo { 272 | fn get_table_name() -> String { 273 | String::from("test_table_name") 274 | } 275 | 276 | async fn list_items(&mut self, _pagination: Pagination) -> Vec { 277 | unimplemented!() 278 | } 279 | 280 | async fn get_item(&mut self, _id: PrimaryKeyType) -> Option { 281 | unimplemented!() 282 | } 283 | 284 | async fn delete_item(&mut self, _id: PrimaryKeyType) { 285 | unimplemented!() 286 | } 287 | 288 | async fn delete_all_items(&mut self) -> usize { 289 | unimplemented!() 290 | } 291 | } 292 | impl CRUDRepository for Repo {} 293 | struct TestServer; 294 | impl ApiServer for TestServer { 295 | fn get_id_path(prefix: &str) -> String { 296 | unimplemented!() 297 | } 298 | } 299 | impl CrudRouterBuilder<'_, Assigned, Repo, Assigned, Assigned, Assigned, Assigned> 300 | { 301 | pub fn test_get_prefix(&self) -> &str { 302 | self.get_prefix() 303 | } 304 | } 305 | 306 | #[test] 307 | fn test_all_routes_enabled() { 308 | let b = CrudRouterBuilder::new::() 309 | .repository::(); 310 | assert!(!b.list_items_route_disabled); 311 | assert!(!b.get_item_route_disabled); 312 | assert!(!b.delete_item_route_disabled); 313 | assert!(!b.delete_all_items_route_disabled); 314 | assert!(!b.create_item_route_disabled); 315 | assert!(!b.update_item_route_disabled); 316 | } 317 | 318 | #[test] 319 | fn test_disable_schema_routes() { 320 | let b = CrudRouterBuilder::new::() 321 | .repository::() 322 | .schema::() 323 | .disable_list_items_route() 324 | .disable_get_item_route() 325 | .disable_delete_item_route() 326 | .disable_delete_all_items_route(); 327 | assert!(b.list_items_route_disabled); 328 | assert!(b.get_item_route_disabled); 329 | assert!(b.delete_item_route_disabled); 330 | assert!(b.delete_all_items_route_disabled); 331 | assert!(!b.create_item_route_disabled); 332 | assert!(!b.update_item_route_disabled); 333 | } 334 | 335 | #[test] 336 | fn test_disable_create_schema_route() { 337 | let b = CrudRouterBuilder::new::() 338 | .repository::() 339 | .schema::() 340 | .create_schema::() 341 | .disable_create_item_route(); 342 | assert!(!b.list_items_route_disabled); 343 | assert!(!b.get_item_route_disabled); 344 | assert!(!b.delete_item_route_disabled); 345 | assert!(!b.delete_all_items_route_disabled); 346 | assert!(b.create_item_route_disabled); 347 | assert!(!b.update_item_route_disabled); 348 | } 349 | 350 | #[test] 351 | fn test_disable_update_schema_route() { 352 | let b = CrudRouterBuilder::new::() 353 | .repository::() 354 | .schema::() 355 | .update_schema::() 356 | .disable_update_item_route(); 357 | assert!(!b.list_items_route_disabled); 358 | assert!(!b.get_item_route_disabled); 359 | assert!(!b.delete_item_route_disabled); 360 | assert!(!b.delete_all_items_route_disabled); 361 | assert!(!b.create_item_route_disabled); 362 | assert!(b.update_item_route_disabled); 363 | } 364 | 365 | #[test] 366 | fn test_prefix() { 367 | let b = CrudRouterBuilder::new::() 368 | .repository::() 369 | .schema::(); 370 | 371 | assert_eq!(b.get_prefix(), "test_table_name"); 372 | 373 | let b = b.prefix("test_prefix"); 374 | assert_eq!(b.get_prefix(), "test_prefix"); 375 | } 376 | 377 | } 378 | -------------------------------------------------------------------------------- /crud_routers/src/openapi.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use utoipa::openapi::request_body::RequestBodyBuilder; 3 | use utoipa::openapi::Tag; 4 | use crate::{ApiServer, Assignable, Assigned, CrudRouterBuilder, Empty, Pagination, ReadDeleteRepository}; 5 | 6 | impl utoipa::PartialSchema for Empty { 7 | fn schema() -> utoipa::openapi::RefOr { 8 | unimplemented!() 9 | } 10 | } 11 | 12 | impl utoipa::ToSchema for Empty { 13 | fn name() -> Cow<'static, str> { 14 | unimplemented!() 15 | } 16 | 17 | fn schemas(_schemas: &mut Vec<(String, utoipa::openapi::RefOr)>) { 18 | unimplemented!() 19 | } 20 | } 21 | 22 | impl utoipa::PartialSchema for Assigned { 23 | fn schema() -> utoipa::openapi::RefOr { 24 | T::schema() 25 | } 26 | } 27 | 28 | impl utoipa::ToSchema for Assigned { 29 | fn name() -> Cow<'static, str> { 30 | T::name() 31 | } 32 | 33 | fn schemas(schemas: &mut Vec<(String, utoipa::openapi::RefOr)>) { 34 | T::schemas(schemas) 35 | } 36 | } 37 | 38 | impl, Schema: utoipa::ToSchema, PrimaryKeyType, CreateSchema: Assignable + utoipa::ToSchema, UpdateSchema: Assignable + utoipa::ToSchema> CrudRouterBuilder<'_, Assigned, Repo, Assigned, Assigned, CreateSchema, UpdateSchema> { 39 | pub fn build_openapi(self, openapi: &mut utoipa::openapi::OpenApi) -> Self { 40 | let table_name = Repo::get_table_name(); 41 | let tag = self.tag.or(Some(&table_name)).unwrap(); 42 | let prefix = self.get_prefix(); 43 | let path = Server::get_path(&prefix); 44 | let id_path = format!("/{}/{{id}}", &prefix); 45 | let mut openapi_paths = utoipa::openapi::path::Paths::new(); 46 | let mut openapi_schemas = Vec::<(String, utoipa::openapi::RefOr)>::new(); 47 | 48 | let id_parameter = utoipa::openapi::path::ParameterBuilder::from(utoipa::openapi::path::Parameter::new("id")) 49 | .parameter_in(utoipa::openapi::path::ParameterIn::Path) 50 | .description(Some(format!("{} id", table_name))) 51 | .schema(Some( 52 | utoipa::openapi::ObjectBuilder::new() 53 | .schema_type(utoipa::openapi::schema::SchemaType::new(utoipa::openapi::schema::Type::Integer)) 54 | )) 55 | .required(utoipa::openapi::Required::True) 56 | .build(); 57 | 58 | let single_item_ref = utoipa::openapi::schema::RefBuilder::new() 59 | .ref_location_from_schema_name(::name()) 60 | .build(); 61 | let single_item_response = utoipa::openapi::content::ContentBuilder::new() 62 | .schema(Some( 63 | single_item_ref.clone() 64 | )).build(); 65 | 66 | if !self.list_items_route_disabled { 67 | let list_of_items_response = utoipa::openapi::content::ContentBuilder::new() 68 | .schema(Some( 69 | utoipa::openapi::schema::ArrayBuilder::new() 70 | .items(single_item_ref.clone())) 71 | ).build(); 72 | 73 | openapi_paths.add_path_operation( 74 | &path, 75 | vec![utoipa::openapi::HttpMethod::Get], 76 | utoipa::openapi::path::OperationBuilder::new() 77 | .tag(tag) 78 | .description(Some(format!("Lists all {}", table_name))) 79 | .operation_id(Some(format!("list_all_{}", table_name))) 80 | .parameters(Some(::into_params(|| Some(utoipa::openapi::path::ParameterIn::Query)))) 81 | .response( 82 | "200", 83 | utoipa::openapi::ResponseBuilder::new() 84 | .description(format!("All {} listed successfully", table_name)) 85 | .content("application/json", list_of_items_response) 86 | .build() 87 | ) 88 | ); 89 | openapi_schemas.push((::name().to_string(), ::schema())); 90 | ::schemas(&mut openapi_schemas); 91 | } 92 | 93 | if !self.get_item_route_disabled { 94 | let optional_item_response = utoipa::openapi::content::ContentBuilder::new() 95 | .schema(Some(utoipa::openapi::schema::OneOfBuilder::new() 96 | .item( 97 | utoipa::openapi::schema::ObjectBuilder::new() 98 | .schema_type(utoipa::openapi::schema::Type::Null) 99 | ) 100 | .item(single_item_ref))).build(); 101 | 102 | openapi_paths.add_path_operation( 103 | &id_path, 104 | vec![utoipa::openapi::HttpMethod::Get], 105 | utoipa::openapi::path::OperationBuilder::new() 106 | .tag(tag) 107 | .description(Some(format!("Gets one {}", table_name))) 108 | .operation_id(Some(format!("get_{}", table_name))) 109 | .parameter(id_parameter.clone()) 110 | .response( 111 | "200", 112 | utoipa::openapi::ResponseBuilder::new() 113 | .description(format!("One {} is fetched successfully", table_name)) 114 | .content( 115 | "application/json", optional_item_response 116 | ).build() 117 | ) 118 | ); 119 | openapi_schemas.push((::name().to_string(), ::schema())); 120 | ::schemas(&mut openapi_schemas); 121 | } 122 | 123 | if !self.delete_all_items_route_disabled { 124 | let integer_response = utoipa::openapi::content::ContentBuilder::new() 125 | .schema(Some( 126 | utoipa::openapi::ObjectBuilder::new() 127 | .schema_type(utoipa::openapi::schema::SchemaType::new(utoipa::openapi::schema::Type::Integer)) 128 | .minimum(Some(0f64)) 129 | )).build(); 130 | 131 | openapi_paths.add_path_operation( 132 | &path, 133 | vec![utoipa::openapi::HttpMethod::Delete], 134 | utoipa::openapi::path::OperationBuilder::new() 135 | .tag(tag) 136 | .description(Some(format!("Deletes all {}", table_name))) 137 | .operation_id(Some(format!("delete_all_{}", table_name))) 138 | .response( 139 | "200", 140 | utoipa::openapi::ResponseBuilder::new() 141 | .description(format!("All {} deleted successfully", table_name)) 142 | .content("text/plain",integer_response).build() 143 | ) 144 | ); 145 | } 146 | 147 | if !self.delete_item_route_disabled { 148 | openapi_paths.add_path_operation( 149 | &id_path, 150 | vec![utoipa::openapi::HttpMethod::Delete], 151 | utoipa::openapi::path::OperationBuilder::new() 152 | .tag(tag) 153 | .description(Some(format!("Deletes one {}", table_name))) 154 | .operation_id(Some(format!("delete_{}", table_name))) 155 | .parameter(id_parameter.clone()) 156 | .response( 157 | "200", 158 | utoipa::openapi::ResponseBuilder::new() 159 | .description(format!("One {} is deleted successfully", table_name)) 160 | .build() 161 | ) 162 | ); 163 | } 164 | 165 | if !self.create_item_route_disabled && CreateSchema::IS_ASSIGNED { 166 | let create_item_request = utoipa::openapi::content::ContentBuilder::new() 167 | .schema(Some( 168 | utoipa::openapi::schema::RefBuilder::new() 169 | .ref_location_from_schema_name(::name()) 170 | .build() 171 | )).build(); 172 | 173 | openapi_paths.add_path_operation( 174 | &path, 175 | vec![utoipa::openapi::HttpMethod::Post], 176 | utoipa::openapi::path::OperationBuilder::new() 177 | .tag(tag) 178 | .description(Some(format!("Creates {}", table_name))) 179 | .operation_id(Some(format!("create_{}", table_name))) 180 | .request_body(Some( 181 | RequestBodyBuilder::new() 182 | .content("application/json", create_item_request) 183 | .required(Some(utoipa::openapi::Required::True)) 184 | .build() 185 | )) 186 | .response( 187 | "200", 188 | utoipa::openapi::ResponseBuilder::new() 189 | .description(format!("One {} is created successfully", table_name)) 190 | .content( 191 | "application/json", 192 | single_item_response.clone() 193 | ) 194 | .build() 195 | ) 196 | ); 197 | openapi_schemas.push((::name().to_string(), ::schema())); 198 | openapi_schemas.push((::name().to_string(), ::schema())); 199 | ::schemas(&mut openapi_schemas); 200 | ::schemas(&mut openapi_schemas); 201 | } 202 | 203 | if !self.update_item_route_disabled && UpdateSchema::IS_ASSIGNED { 204 | let update_item_request = utoipa::openapi::content::ContentBuilder::new() 205 | .schema(Some( 206 | utoipa::openapi::schema::RefBuilder::new() 207 | .ref_location_from_schema_name(::name()) 208 | .build() 209 | )).build(); 210 | 211 | openapi_paths.add_path_operation( 212 | &id_path, 213 | vec![utoipa::openapi::HttpMethod::Put], 214 | utoipa::openapi::path::OperationBuilder::new() 215 | .tag(tag) 216 | .description(Some(format!("Updates {}", table_name))) 217 | .operation_id(Some(format!("update_{}", table_name))) 218 | .parameter(id_parameter) 219 | .request_body(Some( 220 | RequestBodyBuilder::new() 221 | .content("application/json", update_item_request) 222 | .required(Some(utoipa::openapi::Required::True)) 223 | .build() 224 | )) 225 | .response( 226 | "200", 227 | utoipa::openapi::ResponseBuilder::new() 228 | .description(format!("One {} is updated successfully", table_name)) 229 | .content( 230 | "application/json", 231 | single_item_response 232 | ) 233 | .build() 234 | ) 235 | ); 236 | openapi_schemas.push((::name().to_string(), ::schema())); 237 | openapi_schemas.push((::name().to_string(), ::schema())); 238 | ::schemas(&mut openapi_schemas); 239 | ::schemas(&mut openapi_schemas); 240 | } 241 | 242 | openapi.paths.paths.extend(openapi_paths.paths); 243 | let tags = openapi 244 | .tags 245 | .get_or_insert(vec![]); 246 | tags.push(Tag::new(tag)); 247 | let components = openapi 248 | .components 249 | .get_or_insert(utoipa::openapi::Components::new()); 250 | components.schemas.extend(openapi_schemas); 251 | 252 | self 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /crud_routers/src/repositories/diesel.rs: -------------------------------------------------------------------------------- 1 | use diesel::associations::HasTable; 2 | use diesel::connection::LoadConnection; 3 | use diesel::helper_types::{delete, Find, Limit, Offset, Update}; 4 | use diesel::internal::table_macro::{FromClause, SelectStatement, StaticQueryFragment}; 5 | use diesel::prelude::*; 6 | use diesel::query_builder::{AsQuery, InsertStatement, IntoUpdateTarget, QueryFragment, QueryId}; 7 | use diesel::query_dsl::filter_dsl::FindDsl; 8 | use diesel::query_dsl::methods::{ExecuteDsl, LimitDsl, OffsetDsl}; 9 | use diesel::query_dsl::LoadQuery; 10 | use serde::de::DeserializeOwned; 11 | use serde::Serialize; 12 | use crate::Pagination; 13 | use crate::repositories::{CRUDRepository, CreateRepository, ReadDeleteRepository, UpdateRepository}; 14 | 15 | pub struct DieselRepository { 16 | connection: DBConnection, 17 | table: SchemaTable 18 | } 19 | 20 | 21 | impl DieselRepository 22 | where 23 | SchemaTable: Table, 24 | { 25 | pub fn new(connection: DBConnection, table: SchemaTable) -> Self{ 26 | Self{ 27 | connection, 28 | table 29 | } 30 | } 31 | 32 | } 33 | 34 | impl CRUDRepository for DieselRepository {} 35 | 36 | impl ReadDeleteRepository for DieselRepository 37 | where 38 | DBConnection: Connection + LoadConnection + 'static, 39 | SchemaTable: AsQuery>> + QueryFragment + StaticQueryFragment> + Table + QueryId + Copy + Send + 'static, 40 | 41 | PrimaryKeyType: Send + DeserializeOwned + 'static, 42 | SchemaTable::PrimaryKey: EqAll, 43 | 44 | // for list_items 45 | Schema: Serialize + Send + 'static, 46 | for<'a> Offset>>>: LoadQuery<'a, DBConnection, Schema>, 47 | for<'a> Limit>>: LoadQuery<'a, DBConnection, Schema>, 48 | for<'a> Offset>>: LoadQuery<'a, DBConnection, Schema>, 49 | for<'a> SchemaTable: LoadQuery<'a, DBConnection, Schema>, 50 | 51 | // for get_item 52 | SchemaTable: LimitDsl + FindDsl, 53 | Find: LimitDsl, 54 | for<'a> Limit>: LoadQuery<'a, DBConnection, Schema>, 55 | 56 | // for delete_item 57 | Find: HasTable + IntoUpdateTarget, 58 | delete>: ExecuteDsl, 59 | 60 | // for delete_all_items 61 | SchemaTable: IntoUpdateTarget, 62 | delete: ExecuteDsl 63 | 64 | { 65 | fn get_table_name() -> String { 66 | ::STATIC_COMPONENT.0.to_string() 67 | } 68 | 69 | async fn list_items(&mut self, pagination: Pagination) -> Vec { 70 | let result = match (pagination.limit, pagination.skip) { 71 | (Some(limit), Some(skip)) => 72 | OffsetDsl::offset( 73 | LimitDsl::limit(self.table.as_query(), limit as i64), 74 | skip as i64 75 | ) 76 | .load::(&mut self.connection), 77 | (Some(limit), None) => 78 | LimitDsl::limit(self.table.as_query(), limit as i64) 79 | .load::(&mut self.connection), 80 | (None, Some(skip)) => 81 | OffsetDsl::offset(self.table.as_query(), skip as i64) 82 | .load::(&mut self.connection), 83 | (None, None) => 84 | self.table.load::(&mut self.connection), 85 | }; 86 | result.expect("Error loading items") 87 | } 88 | 89 | async fn get_item(&mut self, id: PrimaryKeyType) -> Option { 90 | self.table 91 | .find(id) 92 | .limit(1) 93 | .get_result::(&mut self.connection) 94 | .optional() 95 | .unwrap() 96 | } 97 | async fn delete_item(&mut self, id: PrimaryKeyType) { 98 | diesel::delete(self.table.find(id)) 99 | .execute(&mut self.connection) 100 | .expect("Error deleting item"); 101 | } 102 | 103 | async fn delete_all_items(&mut self) -> usize { 104 | diesel::delete(self.table) 105 | .execute(&mut self.connection) 106 | .expect("Error deleting items") 107 | } 108 | } 109 | 110 | impl CreateRepository for DieselRepository 111 | where 112 | DBConnection: Connection + LoadConnection + 'static, 113 | SchemaTable: AsQuery>> + QueryFragment + StaticQueryFragment + Table + QueryId + Copy + Send + 'static, 114 | 115 | // for create_item 116 | CreateSchema: DeserializeOwned + Insertable + Send + 'static, 117 | for<'a> InsertStatement: AsQuery + LoadQuery<'a, DBConnection, Schema>, 118 | { 119 | async fn create_item(&mut self, new_item: CreateSchema) -> Schema { 120 | diesel::insert_into(self.table) 121 | .values(new_item) 122 | .get_result(&mut self.connection) 123 | .expect("Error creating item") 124 | .into() 125 | } 126 | } 127 | 128 | impl UpdateRepository for DieselRepository 129 | where 130 | DBConnection: Connection + LoadConnection + 'static, 131 | SchemaTable: AsQuery>> + QueryFragment + StaticQueryFragment + Table + QueryId + Copy + Send + 'static, 132 | 133 | PrimaryKeyType: Send + DeserializeOwned + 'static, 134 | SchemaTable::PrimaryKey: EqAll, 135 | 136 | // for get_item 137 | SchemaTable: LimitDsl + FindDsl, 138 | Find: LimitDsl, 139 | for<'a> Limit>: LoadQuery<'a, DBConnection, Schema>, 140 | 141 | // for update_item 142 | UpdateSchema: DeserializeOwned + AsChangeset + Send + 'static, 143 | Find: HasTable + IntoUpdateTarget, 144 | for<'a> Update, UpdateSchema>: AsQuery + LoadQuery<'a, DBConnection, Schema>, 145 | { 146 | async fn update_item(&mut self, id: PrimaryKeyType, item: UpdateSchema) -> Schema { 147 | diesel::update(self.table.find(id)) 148 | .set(item) 149 | .get_result(&mut self.connection) 150 | .expect("Error updating item") 151 | } 152 | } -------------------------------------------------------------------------------- /crud_routers/src/repositories/mod.rs: -------------------------------------------------------------------------------- 1 | 2 | #[cfg(feature = "diesel")] 3 | mod diesel; 4 | #[cfg(feature = "sea-orm")] 5 | mod sea_orm; 6 | 7 | #[cfg(feature = "sea-orm")] 8 | pub use sea_orm::SeaOrmRepository; 9 | #[cfg(feature = "diesel")] 10 | pub use diesel::DieselRepository; 11 | 12 | use crate::Pagination; 13 | 14 | pub trait CRUDRepository{} 15 | 16 | pub trait ReadDeleteRepository: CRUDRepository { 17 | fn get_table_name() -> String; 18 | fn list_items(&mut self, pagination: Pagination) -> impl std::future::Future> + Send; 19 | fn get_item(&mut self, id: PrimaryKeyType) -> impl std::future::Future> + Send; 20 | fn delete_item(&mut self, id: PrimaryKeyType) -> impl std::future::Future + Send; 21 | fn delete_all_items(&mut self) -> impl std::future::Future + Send; 22 | } 23 | 24 | pub trait CreateRepository: CRUDRepository { 25 | fn create_item(&mut self, new_item: CreateSchema) -> impl std::future::Future + Send; 26 | } 27 | 28 | 29 | pub trait UpdateRepository: CRUDRepository { 30 | fn update_item(&mut self, id: PrimaryKeyType, item: UpdateSchema) -> impl std::future::Future + Send; 31 | } 32 | -------------------------------------------------------------------------------- /crud_routers/src/repositories/sea_orm.rs: -------------------------------------------------------------------------------- 1 | use crate::repositories::{CRUDRepository, ReadDeleteRepository, CreateRepository, UpdateRepository}; 2 | use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityName, EntityTrait, FromQueryResult, IntoActiveModel, ModelTrait, PrimaryKeyTrait, QuerySelect, TryIntoModel}; 3 | use serde::de::DeserializeOwned; 4 | use serde::Serialize; 5 | use crate::Pagination; 6 | 7 | pub struct SeaOrmRepository { 8 | connection: DatabaseConnection 9 | } 10 | 11 | impl SeaOrmRepository { 12 | pub fn new(connection: DatabaseConnection) -> Self{ 13 | Self{ 14 | connection 15 | } 16 | } 17 | } 18 | 19 | impl CRUDRepository for SeaOrmRepository {} 20 | 21 | impl ReadDeleteRepository::PrimaryKey as PrimaryKeyTrait>::ValueType> for SeaOrmRepository 22 | where 23 | Schema::Entity: EntityTrait, 24 | Schema: ModelTrait + FromQueryResult + IntoActiveModel<::ActiveModel> + TryFrom<::ActiveModel> + DeserializeOwned + Send, 25 | ::ActiveModel: ActiveModelTrait + From + TryIntoModel + Send, 26 | <::PrimaryKey as PrimaryKeyTrait>::ValueType: DeserializeOwned + Clone 27 | { 28 | fn get_table_name() -> String { 29 | let entity = Schema::Entity::default(); 30 | entity.table_name().to_string() 31 | } 32 | 33 | async fn list_items(&mut self, pagination: Pagination) -> Vec { 34 | Schema::Entity::find().offset(pagination.skip).limit(pagination.limit).all(&self.connection).await.unwrap() 35 | } 36 | 37 | async fn get_item(&mut self, id: <::PrimaryKey as PrimaryKeyTrait>::ValueType) -> Option { 38 | Schema::Entity::find_by_id(id).one(&self.connection).await.unwrap() 39 | } 40 | 41 | async fn delete_item(&mut self, id: <::PrimaryKey as PrimaryKeyTrait>::ValueType) { 42 | Schema::Entity::delete_by_id(id).exec(&self.connection).await.unwrap(); 43 | } 44 | 45 | async fn delete_all_items(&mut self) -> usize { 46 | Schema::Entity::delete_many().exec(&self.connection).await.unwrap().rows_affected as usize 47 | } 48 | } 49 | 50 | impl CreateRepository for SeaOrmRepository 51 | where 52 | Schema::Entity: EntityTrait, 53 | Schema: ModelTrait + IntoActiveModel<::ActiveModel> + TryFrom<::ActiveModel> + DeserializeOwned + Send, 54 | ::ActiveModel: ActiveModelTrait + From + TryIntoModel + Send, 55 | <::PrimaryKey as PrimaryKeyTrait>::ValueType: DeserializeOwned + Clone, 56 | 57 | CreateSchema: Serialize + Send 58 | { 59 | async fn create_item(&mut self, new_item: CreateSchema) -> Schema { 60 | let new_item_json = serde_json::to_value(new_item).unwrap(); 61 | 62 | let active_model = ::ActiveModel::from_json(new_item_json).unwrap(); 63 | 64 | active_model.insert(&self.connection).await.unwrap() 65 | } 66 | } 67 | 68 | impl UpdateRepository::PrimaryKey as PrimaryKeyTrait>::ValueType, UpdateSchema> for SeaOrmRepository 69 | where 70 | Schema::Entity: EntityTrait, 71 | Schema: ModelTrait + FromQueryResult + IntoActiveModel<::ActiveModel> + TryFrom<::ActiveModel> + DeserializeOwned + Send, 72 | ::ActiveModel: ActiveModelTrait + From + TryIntoModel + Send, 73 | <::PrimaryKey as PrimaryKeyTrait>::ValueType: DeserializeOwned + Clone, 74 | 75 | UpdateSchema: Serialize + Send 76 | { 77 | async fn update_item(&mut self, id: <::PrimaryKey as PrimaryKeyTrait>::ValueType, item: UpdateSchema) -> Schema { 78 | let item_json = serde_json::to_value(item).unwrap(); 79 | 80 | let item = Schema::Entity::find_by_id(id.clone()).one(&self.connection).await.unwrap().unwrap(); 81 | let mut active_model = item.into_active_model(); 82 | active_model.set_from_json(item_json).unwrap(); 83 | 84 | active_model.update(&self.connection).await.unwrap() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /crud_routers/src/servers/actix.rs: -------------------------------------------------------------------------------- 1 | use actix_web::{web, HttpResponse, Scope}; 2 | use actix_web::web::{Data, Json, Path, Query}; 3 | use serde::de::DeserializeOwned; 4 | use serde::Serialize; 5 | use tokio::sync::Mutex; 6 | use crate::servers::ApiServer; 7 | use crate::{CrudRouterBuilder, Assigned, Empty, Assignable, Pagination}; 8 | use crate::repositories::{CreateRepository, ReadDeleteRepository, UpdateRepository}; 9 | 10 | pub struct ActixServer {} 11 | 12 | impl ApiServer for ActixServer { 13 | fn get_id_path(prefix: &str) -> String { 14 | format!("/{}/{{id}}", prefix) 15 | } 16 | } 17 | 18 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, CreateSchema, UpdateSchema> 19 | where 20 | R: ReadDeleteRepository + Send + 'static, 21 | Schema: Serialize + Send + 'static, 22 | CreateSchema: Assignable + 'static, 23 | UpdateSchema: Assignable + 'static, 24 | PrimaryKeyType: DeserializeOwned + Send + 'static, 25 | { 26 | 27 | async fn list_items_route( 28 | state: Data>, 29 | pagination: Query 30 | ) -> Json>{ 31 | let mut state = state.lock().await; 32 | 33 | Json(R::list_items(&mut state, pagination.into_inner()).await) 34 | } 35 | async fn get_item_route( 36 | state: Data>, 37 | id: Path 38 | ) -> Json> { 39 | let mut state = state.lock().await; 40 | 41 | Json(state.get_item(id.into_inner()).await) 42 | } 43 | async fn delete_item_route( 44 | state: Data>, 45 | id: Path 46 | ) -> HttpResponse { 47 | let mut state = state.lock().await; 48 | 49 | state.delete_item(id.into_inner()).await; 50 | HttpResponse::Ok().finish() 51 | } 52 | 53 | 54 | async fn delete_all_items_route( 55 | state: Data> 56 | ) -> Json{ 57 | let mut state = state.lock().await; 58 | 59 | Json(state.delete_all_items().await) 60 | } 61 | } 62 | 63 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, UpdateSchema> 64 | where 65 | R: CreateRepository, 66 | Schema: Serialize + Send, 67 | CreateSchema: DeserializeOwned + Send, 68 | { 69 | async fn create_item_route( 70 | state: Data>, 71 | Json(new_item): Json 72 | ) -> Json{ 73 | let mut state = state.lock().await; 74 | 75 | Json(state.create_item(new_item).await) 76 | } 77 | 78 | } 79 | 80 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, CreateSchema, Assigned> 81 | where 82 | R: UpdateRepository, 83 | Schema: Serialize + Send, 84 | UpdateSchema: DeserializeOwned + Send, 85 | { 86 | async fn update_item_route( 87 | state: Data>, 88 | id: Path, 89 | Json(item): Json 90 | ) -> Json{ 91 | let mut state = state.lock().await; 92 | 93 | Json(state.update_item(id.into_inner(), item).await) 94 | } 95 | 96 | } 97 | 98 | 99 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, Assigned> 100 | where 101 | R: ReadDeleteRepository + CreateRepository + UpdateRepository + Send + 'static, 102 | Schema: Serialize + Send + 'static, 103 | CreateSchema: DeserializeOwned + Send + 'static, 104 | UpdateSchema: DeserializeOwned + Send + 'static, 105 | PrimaryKeyType: DeserializeOwned + Send + 'static, 106 | { 107 | pub fn build_router(self) -> Scope { 108 | let mut s = web::scope(""); 109 | let prefix = self.get_prefix(); 110 | let path = ActixServer::get_path(&prefix); 111 | let id_path = ActixServer::get_id_path(&prefix); 112 | 113 | if !self.list_items_route_disabled { 114 | s = s.route(&path, web::get().to(Self::list_items_route)) 115 | } 116 | if !self.create_item_route_disabled { 117 | s = s.route(&path, web::post().to(Self::create_item_route)) 118 | } 119 | if !self.delete_all_items_route_disabled { 120 | s = s.route(&path, web::delete().to(Self::delete_all_items_route)) 121 | } 122 | if !self.get_item_route_disabled { 123 | s = s.route(&id_path, web::get().to(Self::get_item_route)) 124 | } 125 | if !self.update_item_route_disabled { 126 | s = s.route(&id_path, web::put().to(Self::update_item_route)) 127 | } 128 | if !self.delete_item_route_disabled { 129 | s = s.route(&id_path, web::delete().to(Self::delete_item_route)) 130 | } 131 | 132 | s 133 | } 134 | } 135 | 136 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, Empty> 137 | where 138 | R: ReadDeleteRepository + CreateRepository + Send + 'static, 139 | Schema: Serialize + Send + 'static, 140 | CreateSchema: DeserializeOwned + Send + 'static, 141 | PrimaryKeyType: DeserializeOwned + Send + 'static, 142 | { 143 | pub fn build_router(self) -> Scope { 144 | let mut s = web::scope(""); 145 | let prefix = self.get_prefix(); 146 | let path = ActixServer::get_path(&prefix); 147 | let id_path = ActixServer::get_id_path(&prefix); 148 | 149 | if !self.list_items_route_disabled { 150 | s = s.route(&path, web::get().to(Self::list_items_route)) 151 | } 152 | if !self.create_item_route_disabled { 153 | s = s.route(&path, web::post().to(Self::create_item_route)) 154 | } 155 | if !self.delete_all_items_route_disabled { 156 | s = s.route(&path, web::delete().to(Self::delete_all_items_route)) 157 | } 158 | if !self.get_item_route_disabled { 159 | s = s.route(&id_path, web::get().to(Self::get_item_route)) 160 | } 161 | if !self.delete_item_route_disabled { 162 | s = s.route(&id_path, web::delete().to(Self::delete_item_route)) 163 | } 164 | 165 | s 166 | } 167 | } 168 | 169 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Empty, Assigned> 170 | where 171 | R: ReadDeleteRepository + UpdateRepository + Send + 'static, 172 | Schema: Serialize + Send + 'static, 173 | UpdateSchema: DeserializeOwned + Send + 'static, 174 | PrimaryKeyType: DeserializeOwned + Send + 'static, 175 | { 176 | pub fn build_router(self) -> Scope { 177 | let mut s = web::scope(""); 178 | let prefix = self.get_prefix(); 179 | let path = ActixServer::get_path(&prefix); 180 | let id_path = ActixServer::get_id_path(&prefix); 181 | 182 | if !self.list_items_route_disabled { 183 | s = s.route(&path, web::get().to(Self::list_items_route)) 184 | } 185 | if !self.delete_all_items_route_disabled { 186 | s = s.route(&path, web::delete().to(Self::delete_all_items_route)) 187 | } 188 | if !self.get_item_route_disabled { 189 | s = s.route(&id_path, web::get().to(Self::get_item_route)) 190 | } 191 | if !self.update_item_route_disabled { 192 | s = s.route(&id_path, web::put().to(Self::update_item_route)) 193 | } 194 | if !self.delete_item_route_disabled { 195 | s = s.route(&id_path, web::delete().to(Self::delete_item_route)) 196 | } 197 | 198 | s 199 | } 200 | } 201 | 202 | 203 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Empty, Empty> 204 | where 205 | R: ReadDeleteRepository + Send + 'static, 206 | Schema: Serialize + Send + 'static, 207 | PrimaryKeyType: DeserializeOwned + Send + 'static, 208 | { 209 | pub fn build_router(self) -> Scope { 210 | let mut s = web::scope(""); 211 | let prefix = self.get_prefix(); 212 | let path = ActixServer::get_path(&prefix); 213 | let id_path = ActixServer::get_id_path(&prefix); 214 | 215 | if !self.list_items_route_disabled { 216 | s = s.route(&path, web::get().to(Self::list_items_route)) 217 | } 218 | if !self.delete_all_items_route_disabled { 219 | s = s.route(&path, web::delete().to(Self::delete_all_items_route)) 220 | } 221 | if !self.get_item_route_disabled { 222 | s = s.route(&id_path, web::get().to(Self::get_item_route)) 223 | } 224 | if !self.delete_item_route_disabled { 225 | s = s.route(&id_path, web::delete().to(Self::delete_item_route)) 226 | } 227 | 228 | s 229 | } 230 | } -------------------------------------------------------------------------------- /crud_routers/src/servers/axum.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | use axum::extract::{Path, Query, State}; 3 | use axum::{routing, Json, Router}; 4 | use serde::de::DeserializeOwned; 5 | use serde::Serialize; 6 | use tokio::sync::Mutex; 7 | use crate::servers::ApiServer; 8 | use crate::{CrudRouterBuilder, Assigned, Empty, Assignable, Pagination}; 9 | use crate::repositories::{CreateRepository, ReadDeleteRepository, UpdateRepository}; 10 | 11 | pub struct AxumServer; 12 | 13 | impl ApiServer for AxumServer { 14 | fn get_id_path(prefix: &str) -> String { 15 | format!("/{}/:id", prefix) 16 | } 17 | } 18 | 19 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, CreateSchema, UpdateSchema> 20 | where 21 | R: ReadDeleteRepository + Send + 'static, 22 | Schema: Serialize + Send + 'static, 23 | CreateSchema: Assignable + 'static, 24 | UpdateSchema: Assignable + 'static, 25 | PrimaryKeyType: DeserializeOwned + Send + 'static, 26 | { 27 | 28 | async fn list_items_route( 29 | state: State>>, 30 | Query(pagination): Query 31 | ) -> Json>{ 32 | let mut state = state.lock().await; 33 | 34 | R::list_items(&mut state, pagination).await.into() 35 | } 36 | async fn get_item_route( 37 | state: State>>, 38 | Path(id): Path 39 | ) -> Json> { 40 | let mut state = state.lock().await; 41 | 42 | state.get_item(id).await.into() 43 | } 44 | async fn delete_item_route( 45 | state: State>>, 46 | Path(id): Path 47 | ) { 48 | let mut state = state.lock().await; 49 | 50 | state.delete_item(id).await; 51 | } 52 | 53 | 54 | async fn delete_all_items_route( 55 | state: State>> 56 | ) -> Json{ 57 | let mut state = state.lock().await; 58 | 59 | state.delete_all_items().await.into() 60 | } 61 | } 62 | 63 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, UpdateSchema> 64 | where 65 | R: CreateRepository, 66 | Schema: Serialize + Send, 67 | CreateSchema: DeserializeOwned + Send, 68 | { 69 | async fn create_item_route( 70 | state: State>>, 71 | Json(new_item): Json 72 | ) -> Json{ 73 | let mut state = state.lock().await; 74 | 75 | state.create_item(new_item).await.into() 76 | } 77 | 78 | } 79 | 80 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, CreateSchema, Assigned> 81 | where 82 | R: UpdateRepository, 83 | Schema: Serialize + Send, 84 | UpdateSchema: DeserializeOwned + Send, 85 | { 86 | async fn update_item_route( 87 | state: State>>, 88 | Path(id): Path, 89 | Json(item): Json 90 | ) -> Json{ 91 | let mut state = state.lock().await; 92 | 93 | state.update_item(id, item).await.into() 94 | } 95 | 96 | } 97 | 98 | 99 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, Assigned> 100 | where 101 | R: ReadDeleteRepository + CreateRepository + UpdateRepository + Send + 'static, 102 | Schema: Serialize + Send + 'static, 103 | CreateSchema: DeserializeOwned + Send + 'static, 104 | UpdateSchema: DeserializeOwned + Send + 'static, 105 | PrimaryKeyType: DeserializeOwned + Send + 'static, 106 | { 107 | pub fn build_router(self) -> Router>> { 108 | let mut r = Router::new(); 109 | let prefix = self.get_prefix(); 110 | let path = AxumServer::get_path(&prefix); 111 | let id_path = AxumServer::get_id_path(&prefix); 112 | 113 | if !self.list_items_route_disabled { 114 | r = r.route(&path, routing::get(Self::list_items_route)) 115 | } 116 | if !self.create_item_route_disabled { 117 | r = r.route(&path, routing::post(Self::create_item_route)) 118 | } 119 | if !self.delete_all_items_route_disabled { 120 | r = r.route(&path, routing::delete(Self::delete_all_items_route)) 121 | } 122 | if !self.get_item_route_disabled { 123 | r = r.route(&id_path, routing::get(Self::get_item_route)) 124 | } 125 | if !self.update_item_route_disabled { 126 | r = r.route(&id_path, routing::put(Self::update_item_route)) 127 | } 128 | if !self.delete_item_route_disabled { 129 | r = r.route(&id_path, routing::delete(Self::delete_item_route)) 130 | } 131 | 132 | r 133 | } 134 | } 135 | 136 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Assigned, Empty> 137 | where 138 | R: ReadDeleteRepository + CreateRepository + Send + 'static, 139 | Schema: Serialize + Send + 'static, 140 | CreateSchema: DeserializeOwned + Send + 'static, 141 | PrimaryKeyType: DeserializeOwned + Send + 'static, 142 | { 143 | pub fn build_router(self) -> Router>> { 144 | let mut r = Router::new(); 145 | let prefix = self.get_prefix(); 146 | let path = AxumServer::get_path(&prefix); 147 | let id_path = AxumServer::get_id_path(&prefix); 148 | 149 | if !self.list_items_route_disabled { 150 | r = r.route(&path, routing::get(Self::list_items_route)) 151 | } 152 | if !self.create_item_route_disabled { 153 | r = r.route(&path, routing::post(Self::create_item_route)) 154 | } 155 | if !self.delete_all_items_route_disabled { 156 | r = r.route(&path, routing::delete(Self::delete_all_items_route)) 157 | } 158 | if !self.get_item_route_disabled { 159 | r = r.route(&id_path, routing::get(Self::get_item_route)) 160 | } 161 | if !self.delete_item_route_disabled { 162 | r = r.route(&id_path, routing::delete(Self::delete_item_route)) 163 | } 164 | 165 | r 166 | } 167 | } 168 | 169 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Empty, Assigned> 170 | where 171 | R: ReadDeleteRepository + UpdateRepository + Send + 'static, 172 | Schema: Serialize + Send + 'static, 173 | UpdateSchema: DeserializeOwned + Send + 'static, 174 | PrimaryKeyType: DeserializeOwned + Send + 'static, 175 | { 176 | pub fn build_router(self) -> Router>> { 177 | let mut r = Router::new(); 178 | let prefix = self.get_prefix(); 179 | let path = AxumServer::get_path(&prefix); 180 | let id_path = AxumServer::get_id_path(&prefix); 181 | 182 | if !self.list_items_route_disabled { 183 | r = r.route(&path, routing::get(Self::list_items_route)) 184 | } 185 | if !self.delete_all_items_route_disabled { 186 | r = r.route(&path, routing::delete(Self::delete_all_items_route)) 187 | } 188 | if !self.get_item_route_disabled { 189 | r = r.route(&id_path, routing::get(Self::get_item_route)) 190 | } 191 | if !self.update_item_route_disabled { 192 | r = r.route(&id_path, routing::put(Self::update_item_route)) 193 | } 194 | if !self.delete_item_route_disabled { 195 | r = r.route(&id_path, routing::delete(Self::delete_item_route)) 196 | } 197 | 198 | r 199 | } 200 | } 201 | 202 | 203 | impl CrudRouterBuilder<'_, Assigned, R, Assigned, Assigned, Empty, Empty> 204 | where 205 | R: ReadDeleteRepository + Send + 'static, 206 | Schema: Serialize + Send + 'static, 207 | PrimaryKeyType: DeserializeOwned + Send + 'static, 208 | { 209 | pub fn build_router(self) -> Router>> { 210 | let mut r = Router::new(); 211 | let prefix = self.get_prefix(); 212 | let path = AxumServer::get_path(&prefix); 213 | let id_path = AxumServer::get_id_path(&prefix); 214 | 215 | if !self.list_items_route_disabled { 216 | r = r.route(&path, routing::get(Self::list_items_route)) 217 | } 218 | if !self.delete_all_items_route_disabled { 219 | r = r.route(&path, routing::delete(Self::delete_all_items_route)) 220 | } 221 | if !self.get_item_route_disabled { 222 | r = r.route(&id_path, routing::get(Self::get_item_route)) 223 | } 224 | if !self.delete_item_route_disabled { 225 | r = r.route(&id_path, routing::delete(Self::delete_item_route)) 226 | } 227 | 228 | r 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /crud_routers/src/servers/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "axum")] 2 | mod axum; 3 | #[cfg(feature = "actix")] 4 | mod actix; 5 | 6 | #[cfg(feature = "axum")] 7 | pub use axum::AxumServer; 8 | #[cfg(feature = "actix")] 9 | pub use actix::ActixServer; 10 | 11 | pub trait ApiServer { 12 | fn get_path(prefix: &str) -> String { 13 | format!("/{}", prefix) 14 | } 15 | 16 | fn get_id_path(prefix: &str) -> String; 17 | } 18 | -------------------------------------------------------------------------------- /crud_routers/tests/openapi.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | use utoipa::openapi::{InfoBuilder, OpenApi, OpenApiBuilder}; 3 | use utoipa::{ToSchema}; 4 | use crud_routers::{ApiServer, CRUDRepository, CrudRouterBuilder, Pagination, ReadDeleteRepository}; 5 | 6 | #[derive(ToSchema)] 7 | pub struct Post { 8 | pub id: i32, 9 | pub title: String, 10 | pub body: String, 11 | pub published: bool, 12 | } 13 | 14 | 15 | #[derive(ToSchema)] 16 | pub struct NewPost { 17 | pub title: String, 18 | pub body: String, 19 | pub published: bool, 20 | } 21 | 22 | 23 | #[derive(ToSchema)] 24 | pub struct PostForm { 25 | title: Option, 26 | body: Option, 27 | published: Option, 28 | } 29 | struct PrimaryKeyType; 30 | struct Repo; 31 | impl CRUDRepository for Repo {} 32 | 33 | impl ReadDeleteRepository for Repo { 34 | fn get_table_name() -> String { 35 | String::from("test_table_name") 36 | } 37 | 38 | async fn list_items(&mut self, _pagination: Pagination) -> Vec { 39 | unimplemented!() 40 | } 41 | 42 | async fn get_item(&mut self, _id: PrimaryKeyType) -> Option { 43 | unimplemented!() 44 | } 45 | 46 | async fn delete_item(&mut self, _id: PrimaryKeyType) { 47 | unimplemented!() 48 | } 49 | 50 | async fn delete_all_items(&mut self) -> usize { 51 | unimplemented!() 52 | } 53 | } 54 | 55 | struct TestServer; 56 | impl ApiServer for TestServer { 57 | fn get_id_path(prefix: &str) -> String { 58 | unimplemented!() 59 | } 60 | } 61 | 62 | fn get_default_openapi() -> OpenApi { 63 | OpenApiBuilder::new() 64 | .info(InfoBuilder::new() 65 | .title("Test api") 66 | .version("0.1.0") 67 | .build()) 68 | .build() 69 | } 70 | 71 | #[test] 72 | fn openapi_spec() { 73 | let mut api = get_default_openapi(); 74 | 75 | let b = CrudRouterBuilder::new::() 76 | .repository::() 77 | .prefix("base/api") 78 | .tag("table_name") 79 | .schema::() 80 | .create_schema::() 81 | .update_schema::() 82 | .build_openapi(&mut api); 83 | 84 | let expected_api_spec = fs::read_to_string("tests/test_api_spec.json").unwrap(); 85 | 86 | assert_eq!(api.to_json().unwrap(), expected_api_spec); 87 | } 88 | 89 | #[test] 90 | fn openapi_spec_without_create_schema() { 91 | let mut api = get_default_openapi(); 92 | 93 | let b = CrudRouterBuilder::new::() 94 | .repository::() 95 | .prefix("base/api") 96 | .tag("table_name") 97 | .schema::() 98 | .update_schema::() 99 | .build_openapi(&mut api); 100 | 101 | let expected_api_spec = fs::read_to_string("tests/test_api_spec_without_create_schema.json").unwrap(); 102 | 103 | assert_eq!(api.to_json().unwrap(), expected_api_spec); 104 | } 105 | -------------------------------------------------------------------------------- /crud_routers/tests/test_api_spec.json: -------------------------------------------------------------------------------- 1 | {"openapi":"3.1.0","info":{"title":"Test api","version":"0.1.0"},"paths":{"/base/api":{"get":{"tags":["table_name"],"description":"Lists all test_table_name","operationId":"list_all_test_table_name","parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"limit","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"All test_table_name listed successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}}}}},"post":{"tags":["table_name"],"description":"Creates test_table_name","operationId":"create_test_table_name","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewPost"}}},"required":true},"responses":{"200":{"description":"One test_table_name is created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}}}},"delete":{"tags":["table_name"],"description":"Deletes all test_table_name","operationId":"delete_all_test_table_name","responses":{"200":{"description":"All test_table_name deleted successfully","content":{"text/plain":{"schema":{"type":"integer","minimum":0}}}}}}},"/base/api/{id}":{"get":{"tags":["table_name"],"description":"Gets one test_table_name","operationId":"get_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"One test_table_name is fetched successfully","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Post"}]}}}}}},"put":{"tags":["table_name"],"description":"Updates test_table_name","operationId":"update_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostForm"}}},"required":true},"responses":{"200":{"description":"One test_table_name is updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}}}},"delete":{"tags":["table_name"],"description":"Deletes one test_table_name","operationId":"delete_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"One test_table_name is deleted successfully"}}}}},"components":{"schemas":{"NewPost":{"type":"object","required":["title","body","published"],"properties":{"body":{"type":"string"},"published":{"type":"boolean"},"title":{"type":"string"}}},"Post":{"type":"object","required":["id","title","body","published"],"properties":{"body":{"type":"string"},"id":{"type":"integer","format":"int32"},"published":{"type":"boolean"},"title":{"type":"string"}}},"PostForm":{"type":"object","properties":{"body":{"type":["string","null"]},"published":{"type":["boolean","null"]},"title":{"type":["string","null"]}}}}},"tags":[{"name":"table_name"}]} -------------------------------------------------------------------------------- /crud_routers/tests/test_api_spec_without_create_schema.json: -------------------------------------------------------------------------------- 1 | {"openapi":"3.1.0","info":{"title":"Test api","version":"0.1.0"},"paths":{"/base/api":{"get":{"tags":["table_name"],"description":"Lists all test_table_name","operationId":"list_all_test_table_name","parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}},{"name":"limit","in":"query","required":false,"schema":{"type":["integer","null"],"format":"int64","minimum":0}}],"responses":{"200":{"description":"All test_table_name listed successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Post"}}}}}}},"delete":{"tags":["table_name"],"description":"Deletes all test_table_name","operationId":"delete_all_test_table_name","responses":{"200":{"description":"All test_table_name deleted successfully","content":{"text/plain":{"schema":{"type":"integer","minimum":0}}}}}}},"/base/api/{id}":{"get":{"tags":["table_name"],"description":"Gets one test_table_name","operationId":"get_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"One test_table_name is fetched successfully","content":{"application/json":{"schema":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Post"}]}}}}}},"put":{"tags":["table_name"],"description":"Updates test_table_name","operationId":"update_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostForm"}}},"required":true},"responses":{"200":{"description":"One test_table_name is updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Post"}}}}}},"delete":{"tags":["table_name"],"description":"Deletes one test_table_name","operationId":"delete_test_table_name","parameters":[{"name":"id","in":"path","description":"test_table_name id","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"One test_table_name is deleted successfully"}}}}},"components":{"schemas":{"Post":{"type":"object","required":["id","title","body","published"],"properties":{"body":{"type":"string"},"id":{"type":"integer","format":"int32"},"published":{"type":"boolean"},"title":{"type":"string"}}},"PostForm":{"type":"object","properties":{"body":{"type":["string","null"]},"published":{"type":["boolean","null"]},"title":{"type":["string","null"]}}}}},"tags":[{"name":"table_name"}]} -------------------------------------------------------------------------------- /docs/assets/ListAll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/furkan-guvenc/crud_routers/bafc56d9ed1c9cf23e8855fb1b917a6da3ad0b6f/docs/assets/ListAll.png -------------------------------------------------------------------------------- /docs/assets/SwaggerOverview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/furkan-guvenc/crud_routers/bafc56d9ed1c9cf23e8855fb1b917a6da3ad0b6f/docs/assets/SwaggerOverview.png -------------------------------------------------------------------------------- /examples/diesel_axum/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.22.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "adler2" 22 | version = "2.0.0" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 25 | 26 | [[package]] 27 | name = "aho-corasick" 28 | version = "1.1.3" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 31 | dependencies = [ 32 | "memchr", 33 | ] 34 | 35 | [[package]] 36 | name = "arbitrary" 37 | version = "1.3.2" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" 40 | dependencies = [ 41 | "derive_arbitrary", 42 | ] 43 | 44 | [[package]] 45 | name = "async-trait" 46 | version = "0.1.81" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" 49 | dependencies = [ 50 | "proc-macro2", 51 | "quote", 52 | "syn", 53 | ] 54 | 55 | [[package]] 56 | name = "atomic-waker" 57 | version = "1.1.2" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 60 | 61 | [[package]] 62 | name = "autocfg" 63 | version = "1.3.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 66 | 67 | [[package]] 68 | name = "axum" 69 | version = "0.7.5" 70 | source = "registry+https://github.com/rust-lang/crates.io-index" 71 | checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" 72 | dependencies = [ 73 | "async-trait", 74 | "axum-core", 75 | "axum-macros", 76 | "bytes", 77 | "futures-util", 78 | "http", 79 | "http-body", 80 | "http-body-util", 81 | "hyper", 82 | "hyper-util", 83 | "itoa", 84 | "matchit", 85 | "memchr", 86 | "mime", 87 | "percent-encoding", 88 | "pin-project-lite", 89 | "rustversion", 90 | "serde", 91 | "serde_json", 92 | "serde_path_to_error", 93 | "serde_urlencoded", 94 | "sync_wrapper 1.0.1", 95 | "tokio", 96 | "tower", 97 | "tower-layer", 98 | "tower-service", 99 | "tracing", 100 | ] 101 | 102 | [[package]] 103 | name = "axum-core" 104 | version = "0.4.3" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" 107 | dependencies = [ 108 | "async-trait", 109 | "bytes", 110 | "futures-util", 111 | "http", 112 | "http-body", 113 | "http-body-util", 114 | "mime", 115 | "pin-project-lite", 116 | "rustversion", 117 | "sync_wrapper 0.1.2", 118 | "tower-layer", 119 | "tower-service", 120 | "tracing", 121 | ] 122 | 123 | [[package]] 124 | name = "axum-macros" 125 | version = "0.4.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" 128 | dependencies = [ 129 | "heck 0.4.1", 130 | "proc-macro2", 131 | "quote", 132 | "syn", 133 | ] 134 | 135 | [[package]] 136 | name = "backtrace" 137 | version = "0.3.73" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" 140 | dependencies = [ 141 | "addr2line", 142 | "cc", 143 | "cfg-if", 144 | "libc", 145 | "miniz_oxide 0.7.4", 146 | "object", 147 | "rustc-demangle", 148 | ] 149 | 150 | [[package]] 151 | name = "base64" 152 | version = "0.22.1" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 155 | 156 | [[package]] 157 | name = "bitflags" 158 | version = "2.6.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 161 | 162 | [[package]] 163 | name = "block-buffer" 164 | version = "0.10.4" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 167 | dependencies = [ 168 | "generic-array", 169 | ] 170 | 171 | [[package]] 172 | name = "bumpalo" 173 | version = "3.16.0" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 176 | 177 | [[package]] 178 | name = "byteorder" 179 | version = "1.5.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 182 | 183 | [[package]] 184 | name = "bytes" 185 | version = "1.7.1" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" 188 | 189 | [[package]] 190 | name = "cc" 191 | version = "1.1.11" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" 194 | dependencies = [ 195 | "shlex", 196 | ] 197 | 198 | [[package]] 199 | name = "cfg-if" 200 | version = "1.0.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 203 | 204 | [[package]] 205 | name = "core-foundation" 206 | version = "0.9.4" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 209 | dependencies = [ 210 | "core-foundation-sys", 211 | "libc", 212 | ] 213 | 214 | [[package]] 215 | name = "core-foundation-sys" 216 | version = "0.8.7" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 219 | 220 | [[package]] 221 | name = "cpufeatures" 222 | version = "0.2.14" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" 225 | dependencies = [ 226 | "libc", 227 | ] 228 | 229 | [[package]] 230 | name = "crc32fast" 231 | version = "1.4.2" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" 234 | dependencies = [ 235 | "cfg-if", 236 | ] 237 | 238 | [[package]] 239 | name = "crossbeam-utils" 240 | version = "0.8.20" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" 243 | 244 | [[package]] 245 | name = "crud_routers" 246 | version = "0.1.0" 247 | dependencies = [ 248 | "axum", 249 | "diesel", 250 | "serde", 251 | "serde_json", 252 | "tokio", 253 | "utoipa", 254 | ] 255 | 256 | [[package]] 257 | name = "crypto-common" 258 | version = "0.1.6" 259 | source = "registry+https://github.com/rust-lang/crates.io-index" 260 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 261 | dependencies = [ 262 | "generic-array", 263 | "typenum", 264 | ] 265 | 266 | [[package]] 267 | name = "darling" 268 | version = "0.20.10" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 271 | dependencies = [ 272 | "darling_core", 273 | "darling_macro", 274 | ] 275 | 276 | [[package]] 277 | name = "darling_core" 278 | version = "0.20.10" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 281 | dependencies = [ 282 | "fnv", 283 | "ident_case", 284 | "proc-macro2", 285 | "quote", 286 | "strsim", 287 | "syn", 288 | ] 289 | 290 | [[package]] 291 | name = "darling_macro" 292 | version = "0.20.10" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 295 | dependencies = [ 296 | "darling_core", 297 | "quote", 298 | "syn", 299 | ] 300 | 301 | [[package]] 302 | name = "derive_arbitrary" 303 | version = "1.3.2" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" 306 | dependencies = [ 307 | "proc-macro2", 308 | "quote", 309 | "syn", 310 | ] 311 | 312 | [[package]] 313 | name = "diesel" 314 | version = "2.2.2" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "bf97ee7261bb708fa3402fa9c17a54b70e90e3cb98afb3dc8999d5512cb03f94" 317 | dependencies = [ 318 | "bitflags", 319 | "byteorder", 320 | "diesel_derives", 321 | "itoa", 322 | "pq-sys", 323 | ] 324 | 325 | [[package]] 326 | name = "diesel_axum" 327 | version = "0.1.0" 328 | dependencies = [ 329 | "axum", 330 | "crud_routers", 331 | "diesel", 332 | "dotenvy", 333 | "serde", 334 | "serde_json", 335 | "test_utils", 336 | "tokio", 337 | "utoipa", 338 | "utoipa-swagger-ui", 339 | ] 340 | 341 | [[package]] 342 | name = "diesel_derives" 343 | version = "2.2.2" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "d6ff2be1e7312c858b2ef974f5c7089833ae57b5311b334b30923af58e5718d8" 346 | dependencies = [ 347 | "diesel_table_macro_syntax", 348 | "dsl_auto_type", 349 | "proc-macro2", 350 | "quote", 351 | "syn", 352 | ] 353 | 354 | [[package]] 355 | name = "diesel_table_macro_syntax" 356 | version = "0.2.0" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "209c735641a413bc68c4923a9d6ad4bcb3ca306b794edaa7eb0b3228a99ffb25" 359 | dependencies = [ 360 | "syn", 361 | ] 362 | 363 | [[package]] 364 | name = "digest" 365 | version = "0.10.7" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 368 | dependencies = [ 369 | "block-buffer", 370 | "crypto-common", 371 | ] 372 | 373 | [[package]] 374 | name = "displaydoc" 375 | version = "0.2.5" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 378 | dependencies = [ 379 | "proc-macro2", 380 | "quote", 381 | "syn", 382 | ] 383 | 384 | [[package]] 385 | name = "dotenvy" 386 | version = "0.15.7" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 389 | 390 | [[package]] 391 | name = "dsl_auto_type" 392 | version = "0.1.2" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "c5d9abe6314103864cc2d8901b7ae224e0ab1a103a0a416661b4097b0779b607" 395 | dependencies = [ 396 | "darling", 397 | "either", 398 | "heck 0.5.0", 399 | "proc-macro2", 400 | "quote", 401 | "syn", 402 | ] 403 | 404 | [[package]] 405 | name = "either" 406 | version = "1.13.0" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 409 | 410 | [[package]] 411 | name = "encoding_rs" 412 | version = "0.8.34" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 415 | dependencies = [ 416 | "cfg-if", 417 | ] 418 | 419 | [[package]] 420 | name = "equivalent" 421 | version = "1.0.1" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 424 | 425 | [[package]] 426 | name = "errno" 427 | version = "0.3.9" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 430 | dependencies = [ 431 | "libc", 432 | "windows-sys 0.52.0", 433 | ] 434 | 435 | [[package]] 436 | name = "fastrand" 437 | version = "2.1.1" 438 | source = "registry+https://github.com/rust-lang/crates.io-index" 439 | checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" 440 | 441 | [[package]] 442 | name = "flate2" 443 | version = "1.0.34" 444 | source = "registry+https://github.com/rust-lang/crates.io-index" 445 | checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" 446 | dependencies = [ 447 | "crc32fast", 448 | "miniz_oxide 0.8.0", 449 | ] 450 | 451 | [[package]] 452 | name = "fnv" 453 | version = "1.0.7" 454 | source = "registry+https://github.com/rust-lang/crates.io-index" 455 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 456 | 457 | [[package]] 458 | name = "foreign-types" 459 | version = "0.3.2" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 462 | dependencies = [ 463 | "foreign-types-shared", 464 | ] 465 | 466 | [[package]] 467 | name = "foreign-types-shared" 468 | version = "0.1.1" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 471 | 472 | [[package]] 473 | name = "form_urlencoded" 474 | version = "1.2.1" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 477 | dependencies = [ 478 | "percent-encoding", 479 | ] 480 | 481 | [[package]] 482 | name = "futures-channel" 483 | version = "0.3.30" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" 486 | dependencies = [ 487 | "futures-core", 488 | ] 489 | 490 | [[package]] 491 | name = "futures-core" 492 | version = "0.3.30" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" 495 | 496 | [[package]] 497 | name = "futures-sink" 498 | version = "0.3.30" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" 501 | 502 | [[package]] 503 | name = "futures-task" 504 | version = "0.3.30" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" 507 | 508 | [[package]] 509 | name = "futures-util" 510 | version = "0.3.30" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" 513 | dependencies = [ 514 | "futures-core", 515 | "futures-task", 516 | "pin-project-lite", 517 | "pin-utils", 518 | ] 519 | 520 | [[package]] 521 | name = "generic-array" 522 | version = "0.14.7" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 525 | dependencies = [ 526 | "typenum", 527 | "version_check", 528 | ] 529 | 530 | [[package]] 531 | name = "getrandom" 532 | version = "0.2.15" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 535 | dependencies = [ 536 | "cfg-if", 537 | "libc", 538 | "wasi", 539 | ] 540 | 541 | [[package]] 542 | name = "gimli" 543 | version = "0.29.0" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" 546 | 547 | [[package]] 548 | name = "h2" 549 | version = "0.4.6" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" 552 | dependencies = [ 553 | "atomic-waker", 554 | "bytes", 555 | "fnv", 556 | "futures-core", 557 | "futures-sink", 558 | "http", 559 | "indexmap", 560 | "slab", 561 | "tokio", 562 | "tokio-util", 563 | "tracing", 564 | ] 565 | 566 | [[package]] 567 | name = "hashbrown" 568 | version = "0.14.5" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 571 | 572 | [[package]] 573 | name = "heck" 574 | version = "0.4.1" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 577 | 578 | [[package]] 579 | name = "heck" 580 | version = "0.5.0" 581 | source = "registry+https://github.com/rust-lang/crates.io-index" 582 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 583 | 584 | [[package]] 585 | name = "hermit-abi" 586 | version = "0.3.9" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 589 | 590 | [[package]] 591 | name = "http" 592 | version = "1.1.0" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 595 | dependencies = [ 596 | "bytes", 597 | "fnv", 598 | "itoa", 599 | ] 600 | 601 | [[package]] 602 | name = "http-body" 603 | version = "1.0.1" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 606 | dependencies = [ 607 | "bytes", 608 | "http", 609 | ] 610 | 611 | [[package]] 612 | name = "http-body-util" 613 | version = "0.1.2" 614 | source = "registry+https://github.com/rust-lang/crates.io-index" 615 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 616 | dependencies = [ 617 | "bytes", 618 | "futures-util", 619 | "http", 620 | "http-body", 621 | "pin-project-lite", 622 | ] 623 | 624 | [[package]] 625 | name = "httparse" 626 | version = "1.9.4" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" 629 | 630 | [[package]] 631 | name = "httpdate" 632 | version = "1.0.3" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 635 | 636 | [[package]] 637 | name = "hyper" 638 | version = "1.4.1" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 641 | dependencies = [ 642 | "bytes", 643 | "futures-channel", 644 | "futures-util", 645 | "h2", 646 | "http", 647 | "http-body", 648 | "httparse", 649 | "httpdate", 650 | "itoa", 651 | "pin-project-lite", 652 | "smallvec", 653 | "tokio", 654 | "want", 655 | ] 656 | 657 | [[package]] 658 | name = "hyper-rustls" 659 | version = "0.27.3" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" 662 | dependencies = [ 663 | "futures-util", 664 | "http", 665 | "hyper", 666 | "hyper-util", 667 | "rustls", 668 | "rustls-pki-types", 669 | "tokio", 670 | "tokio-rustls", 671 | "tower-service", 672 | ] 673 | 674 | [[package]] 675 | name = "hyper-tls" 676 | version = "0.6.0" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 679 | dependencies = [ 680 | "bytes", 681 | "http-body-util", 682 | "hyper", 683 | "hyper-util", 684 | "native-tls", 685 | "tokio", 686 | "tokio-native-tls", 687 | "tower-service", 688 | ] 689 | 690 | [[package]] 691 | name = "hyper-util" 692 | version = "0.1.7" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" 695 | dependencies = [ 696 | "bytes", 697 | "futures-channel", 698 | "futures-util", 699 | "http", 700 | "http-body", 701 | "hyper", 702 | "pin-project-lite", 703 | "socket2", 704 | "tokio", 705 | "tower", 706 | "tower-service", 707 | "tracing", 708 | ] 709 | 710 | [[package]] 711 | name = "ident_case" 712 | version = "1.0.1" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 715 | 716 | [[package]] 717 | name = "idna" 718 | version = "0.5.0" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 721 | dependencies = [ 722 | "unicode-bidi", 723 | "unicode-normalization", 724 | ] 725 | 726 | [[package]] 727 | name = "indexmap" 728 | version = "2.4.0" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" 731 | dependencies = [ 732 | "equivalent", 733 | "hashbrown", 734 | "serde", 735 | ] 736 | 737 | [[package]] 738 | name = "ipnet" 739 | version = "2.10.1" 740 | source = "registry+https://github.com/rust-lang/crates.io-index" 741 | checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" 742 | 743 | [[package]] 744 | name = "itoa" 745 | version = "1.0.11" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 748 | 749 | [[package]] 750 | name = "js-sys" 751 | version = "0.3.70" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" 754 | dependencies = [ 755 | "wasm-bindgen", 756 | ] 757 | 758 | [[package]] 759 | name = "libc" 760 | version = "0.2.155" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 763 | 764 | [[package]] 765 | name = "linux-raw-sys" 766 | version = "0.4.14" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 769 | 770 | [[package]] 771 | name = "lock_api" 772 | version = "0.4.12" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 775 | dependencies = [ 776 | "autocfg", 777 | "scopeguard", 778 | ] 779 | 780 | [[package]] 781 | name = "lockfree-object-pool" 782 | version = "0.1.6" 783 | source = "registry+https://github.com/rust-lang/crates.io-index" 784 | checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" 785 | 786 | [[package]] 787 | name = "log" 788 | version = "0.4.22" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 791 | 792 | [[package]] 793 | name = "matchit" 794 | version = "0.7.3" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" 797 | 798 | [[package]] 799 | name = "memchr" 800 | version = "2.7.4" 801 | source = "registry+https://github.com/rust-lang/crates.io-index" 802 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 803 | 804 | [[package]] 805 | name = "mime" 806 | version = "0.3.17" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 809 | 810 | [[package]] 811 | name = "mime_guess" 812 | version = "2.0.5" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" 815 | dependencies = [ 816 | "mime", 817 | "unicase", 818 | ] 819 | 820 | [[package]] 821 | name = "miniz_oxide" 822 | version = "0.7.4" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 825 | dependencies = [ 826 | "adler", 827 | ] 828 | 829 | [[package]] 830 | name = "miniz_oxide" 831 | version = "0.8.0" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 834 | dependencies = [ 835 | "adler2", 836 | ] 837 | 838 | [[package]] 839 | name = "mio" 840 | version = "1.0.2" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 843 | dependencies = [ 844 | "hermit-abi", 845 | "libc", 846 | "wasi", 847 | "windows-sys 0.52.0", 848 | ] 849 | 850 | [[package]] 851 | name = "native-tls" 852 | version = "0.2.12" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 855 | dependencies = [ 856 | "libc", 857 | "log", 858 | "openssl", 859 | "openssl-probe", 860 | "openssl-sys", 861 | "schannel", 862 | "security-framework", 863 | "security-framework-sys", 864 | "tempfile", 865 | ] 866 | 867 | [[package]] 868 | name = "object" 869 | version = "0.36.3" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" 872 | dependencies = [ 873 | "memchr", 874 | ] 875 | 876 | [[package]] 877 | name = "once_cell" 878 | version = "1.19.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 881 | 882 | [[package]] 883 | name = "openssl" 884 | version = "0.10.66" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" 887 | dependencies = [ 888 | "bitflags", 889 | "cfg-if", 890 | "foreign-types", 891 | "libc", 892 | "once_cell", 893 | "openssl-macros", 894 | "openssl-sys", 895 | ] 896 | 897 | [[package]] 898 | name = "openssl-macros" 899 | version = "0.1.1" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 902 | dependencies = [ 903 | "proc-macro2", 904 | "quote", 905 | "syn", 906 | ] 907 | 908 | [[package]] 909 | name = "openssl-probe" 910 | version = "0.1.5" 911 | source = "registry+https://github.com/rust-lang/crates.io-index" 912 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 913 | 914 | [[package]] 915 | name = "openssl-sys" 916 | version = "0.9.103" 917 | source = "registry+https://github.com/rust-lang/crates.io-index" 918 | checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" 919 | dependencies = [ 920 | "cc", 921 | "libc", 922 | "pkg-config", 923 | "vcpkg", 924 | ] 925 | 926 | [[package]] 927 | name = "parking_lot" 928 | version = "0.12.3" 929 | source = "registry+https://github.com/rust-lang/crates.io-index" 930 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 931 | dependencies = [ 932 | "lock_api", 933 | "parking_lot_core", 934 | ] 935 | 936 | [[package]] 937 | name = "parking_lot_core" 938 | version = "0.9.10" 939 | source = "registry+https://github.com/rust-lang/crates.io-index" 940 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 941 | dependencies = [ 942 | "cfg-if", 943 | "libc", 944 | "redox_syscall", 945 | "smallvec", 946 | "windows-targets", 947 | ] 948 | 949 | [[package]] 950 | name = "percent-encoding" 951 | version = "2.3.1" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 954 | 955 | [[package]] 956 | name = "pin-project" 957 | version = "1.1.5" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" 960 | dependencies = [ 961 | "pin-project-internal", 962 | ] 963 | 964 | [[package]] 965 | name = "pin-project-internal" 966 | version = "1.1.5" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" 969 | dependencies = [ 970 | "proc-macro2", 971 | "quote", 972 | "syn", 973 | ] 974 | 975 | [[package]] 976 | name = "pin-project-lite" 977 | version = "0.2.14" 978 | source = "registry+https://github.com/rust-lang/crates.io-index" 979 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 980 | 981 | [[package]] 982 | name = "pin-utils" 983 | version = "0.1.0" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 986 | 987 | [[package]] 988 | name = "pkg-config" 989 | version = "0.3.30" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" 992 | 993 | [[package]] 994 | name = "pq-sys" 995 | version = "0.6.1" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "a24ff9e4cf6945c988f0db7005d87747bf72864965c3529d259ad155ac41d584" 998 | dependencies = [ 999 | "vcpkg", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "proc-macro2" 1004 | version = "1.0.86" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 1007 | dependencies = [ 1008 | "unicode-ident", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "quote" 1013 | version = "1.0.36" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 1016 | dependencies = [ 1017 | "proc-macro2", 1018 | ] 1019 | 1020 | [[package]] 1021 | name = "redox_syscall" 1022 | version = "0.5.3" 1023 | source = "registry+https://github.com/rust-lang/crates.io-index" 1024 | checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" 1025 | dependencies = [ 1026 | "bitflags", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "regex" 1031 | version = "1.11.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" 1034 | dependencies = [ 1035 | "aho-corasick", 1036 | "memchr", 1037 | "regex-automata", 1038 | "regex-syntax", 1039 | ] 1040 | 1041 | [[package]] 1042 | name = "regex-automata" 1043 | version = "0.4.8" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" 1046 | dependencies = [ 1047 | "aho-corasick", 1048 | "memchr", 1049 | "regex-syntax", 1050 | ] 1051 | 1052 | [[package]] 1053 | name = "regex-syntax" 1054 | version = "0.8.5" 1055 | source = "registry+https://github.com/rust-lang/crates.io-index" 1056 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 1057 | 1058 | [[package]] 1059 | name = "reqwest" 1060 | version = "0.12.8" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" 1063 | dependencies = [ 1064 | "base64", 1065 | "bytes", 1066 | "encoding_rs", 1067 | "futures-core", 1068 | "futures-util", 1069 | "h2", 1070 | "http", 1071 | "http-body", 1072 | "http-body-util", 1073 | "hyper", 1074 | "hyper-rustls", 1075 | "hyper-tls", 1076 | "hyper-util", 1077 | "ipnet", 1078 | "js-sys", 1079 | "log", 1080 | "mime", 1081 | "native-tls", 1082 | "once_cell", 1083 | "percent-encoding", 1084 | "pin-project-lite", 1085 | "rustls-pemfile", 1086 | "serde", 1087 | "serde_json", 1088 | "serde_urlencoded", 1089 | "sync_wrapper 1.0.1", 1090 | "system-configuration", 1091 | "tokio", 1092 | "tokio-native-tls", 1093 | "tower-service", 1094 | "url", 1095 | "wasm-bindgen", 1096 | "wasm-bindgen-futures", 1097 | "web-sys", 1098 | "windows-registry", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "ring" 1103 | version = "0.17.8" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 1106 | dependencies = [ 1107 | "cc", 1108 | "cfg-if", 1109 | "getrandom", 1110 | "libc", 1111 | "spin", 1112 | "untrusted", 1113 | "windows-sys 0.52.0", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "rust-embed" 1118 | version = "8.5.0" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "fa66af4a4fdd5e7ebc276f115e895611a34739a9c1c01028383d612d550953c0" 1121 | dependencies = [ 1122 | "rust-embed-impl", 1123 | "rust-embed-utils", 1124 | "walkdir", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "rust-embed-impl" 1129 | version = "8.5.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "6125dbc8867951125eec87294137f4e9c2c96566e61bf72c45095a7c77761478" 1132 | dependencies = [ 1133 | "proc-macro2", 1134 | "quote", 1135 | "rust-embed-utils", 1136 | "syn", 1137 | "walkdir", 1138 | ] 1139 | 1140 | [[package]] 1141 | name = "rust-embed-utils" 1142 | version = "8.5.0" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "2e5347777e9aacb56039b0e1f28785929a8a3b709e87482e7442c72e7c12529d" 1145 | dependencies = [ 1146 | "sha2", 1147 | "walkdir", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "rustc-demangle" 1152 | version = "0.1.24" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1155 | 1156 | [[package]] 1157 | name = "rustix" 1158 | version = "0.38.34" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" 1161 | dependencies = [ 1162 | "bitflags", 1163 | "errno", 1164 | "libc", 1165 | "linux-raw-sys", 1166 | "windows-sys 0.52.0", 1167 | ] 1168 | 1169 | [[package]] 1170 | name = "rustls" 1171 | version = "0.23.14" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" 1174 | dependencies = [ 1175 | "once_cell", 1176 | "rustls-pki-types", 1177 | "rustls-webpki", 1178 | "subtle", 1179 | "zeroize", 1180 | ] 1181 | 1182 | [[package]] 1183 | name = "rustls-pemfile" 1184 | version = "2.2.0" 1185 | source = "registry+https://github.com/rust-lang/crates.io-index" 1186 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1187 | dependencies = [ 1188 | "rustls-pki-types", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "rustls-pki-types" 1193 | version = "1.9.0" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" 1196 | 1197 | [[package]] 1198 | name = "rustls-webpki" 1199 | version = "0.102.8" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 1202 | dependencies = [ 1203 | "ring", 1204 | "rustls-pki-types", 1205 | "untrusted", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "rustversion" 1210 | version = "1.0.17" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 1213 | 1214 | [[package]] 1215 | name = "ryu" 1216 | version = "1.0.18" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 1219 | 1220 | [[package]] 1221 | name = "same-file" 1222 | version = "1.0.6" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1225 | dependencies = [ 1226 | "winapi-util", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "schannel" 1231 | version = "0.1.24" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" 1234 | dependencies = [ 1235 | "windows-sys 0.59.0", 1236 | ] 1237 | 1238 | [[package]] 1239 | name = "scopeguard" 1240 | version = "1.2.0" 1241 | source = "registry+https://github.com/rust-lang/crates.io-index" 1242 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1243 | 1244 | [[package]] 1245 | name = "security-framework" 1246 | version = "2.11.1" 1247 | source = "registry+https://github.com/rust-lang/crates.io-index" 1248 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 1249 | dependencies = [ 1250 | "bitflags", 1251 | "core-foundation", 1252 | "core-foundation-sys", 1253 | "libc", 1254 | "security-framework-sys", 1255 | ] 1256 | 1257 | [[package]] 1258 | name = "security-framework-sys" 1259 | version = "2.12.0" 1260 | source = "registry+https://github.com/rust-lang/crates.io-index" 1261 | checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" 1262 | dependencies = [ 1263 | "core-foundation-sys", 1264 | "libc", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "serde" 1269 | version = "1.0.207" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" 1272 | dependencies = [ 1273 | "serde_derive", 1274 | ] 1275 | 1276 | [[package]] 1277 | name = "serde_derive" 1278 | version = "1.0.207" 1279 | source = "registry+https://github.com/rust-lang/crates.io-index" 1280 | checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" 1281 | dependencies = [ 1282 | "proc-macro2", 1283 | "quote", 1284 | "syn", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "serde_json" 1289 | version = "1.0.124" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" 1292 | dependencies = [ 1293 | "itoa", 1294 | "memchr", 1295 | "ryu", 1296 | "serde", 1297 | ] 1298 | 1299 | [[package]] 1300 | name = "serde_path_to_error" 1301 | version = "0.1.16" 1302 | source = "registry+https://github.com/rust-lang/crates.io-index" 1303 | checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" 1304 | dependencies = [ 1305 | "itoa", 1306 | "serde", 1307 | ] 1308 | 1309 | [[package]] 1310 | name = "serde_urlencoded" 1311 | version = "0.7.1" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1314 | dependencies = [ 1315 | "form_urlencoded", 1316 | "itoa", 1317 | "ryu", 1318 | "serde", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "sha2" 1323 | version = "0.10.8" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1326 | dependencies = [ 1327 | "cfg-if", 1328 | "cpufeatures", 1329 | "digest", 1330 | ] 1331 | 1332 | [[package]] 1333 | name = "shlex" 1334 | version = "1.3.0" 1335 | source = "registry+https://github.com/rust-lang/crates.io-index" 1336 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1337 | 1338 | [[package]] 1339 | name = "signal-hook-registry" 1340 | version = "1.4.2" 1341 | source = "registry+https://github.com/rust-lang/crates.io-index" 1342 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 1343 | dependencies = [ 1344 | "libc", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "simd-adler32" 1349 | version = "0.3.7" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" 1352 | 1353 | [[package]] 1354 | name = "slab" 1355 | version = "0.4.9" 1356 | source = "registry+https://github.com/rust-lang/crates.io-index" 1357 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1358 | dependencies = [ 1359 | "autocfg", 1360 | ] 1361 | 1362 | [[package]] 1363 | name = "smallvec" 1364 | version = "1.13.2" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 1367 | 1368 | [[package]] 1369 | name = "socket2" 1370 | version = "0.5.7" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 1373 | dependencies = [ 1374 | "libc", 1375 | "windows-sys 0.52.0", 1376 | ] 1377 | 1378 | [[package]] 1379 | name = "spin" 1380 | version = "0.9.8" 1381 | source = "registry+https://github.com/rust-lang/crates.io-index" 1382 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1383 | 1384 | [[package]] 1385 | name = "strsim" 1386 | version = "0.11.1" 1387 | source = "registry+https://github.com/rust-lang/crates.io-index" 1388 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1389 | 1390 | [[package]] 1391 | name = "subtle" 1392 | version = "2.6.1" 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" 1394 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1395 | 1396 | [[package]] 1397 | name = "syn" 1398 | version = "2.0.74" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" 1401 | dependencies = [ 1402 | "proc-macro2", 1403 | "quote", 1404 | "unicode-ident", 1405 | ] 1406 | 1407 | [[package]] 1408 | name = "sync_wrapper" 1409 | version = "0.1.2" 1410 | source = "registry+https://github.com/rust-lang/crates.io-index" 1411 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 1412 | 1413 | [[package]] 1414 | name = "sync_wrapper" 1415 | version = "1.0.1" 1416 | source = "registry+https://github.com/rust-lang/crates.io-index" 1417 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 1418 | dependencies = [ 1419 | "futures-core", 1420 | ] 1421 | 1422 | [[package]] 1423 | name = "system-configuration" 1424 | version = "0.6.1" 1425 | source = "registry+https://github.com/rust-lang/crates.io-index" 1426 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 1427 | dependencies = [ 1428 | "bitflags", 1429 | "core-foundation", 1430 | "system-configuration-sys", 1431 | ] 1432 | 1433 | [[package]] 1434 | name = "system-configuration-sys" 1435 | version = "0.6.0" 1436 | source = "registry+https://github.com/rust-lang/crates.io-index" 1437 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1438 | dependencies = [ 1439 | "core-foundation-sys", 1440 | "libc", 1441 | ] 1442 | 1443 | [[package]] 1444 | name = "tempfile" 1445 | version = "3.12.0" 1446 | source = "registry+https://github.com/rust-lang/crates.io-index" 1447 | checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" 1448 | dependencies = [ 1449 | "cfg-if", 1450 | "fastrand", 1451 | "once_cell", 1452 | "rustix", 1453 | "windows-sys 0.59.0", 1454 | ] 1455 | 1456 | [[package]] 1457 | name = "test_utils" 1458 | version = "0.1.0" 1459 | dependencies = [ 1460 | "mime", 1461 | "reqwest", 1462 | "serde", 1463 | "serde_json", 1464 | ] 1465 | 1466 | [[package]] 1467 | name = "thiserror" 1468 | version = "1.0.64" 1469 | source = "registry+https://github.com/rust-lang/crates.io-index" 1470 | checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" 1471 | dependencies = [ 1472 | "thiserror-impl", 1473 | ] 1474 | 1475 | [[package]] 1476 | name = "thiserror-impl" 1477 | version = "1.0.64" 1478 | source = "registry+https://github.com/rust-lang/crates.io-index" 1479 | checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" 1480 | dependencies = [ 1481 | "proc-macro2", 1482 | "quote", 1483 | "syn", 1484 | ] 1485 | 1486 | [[package]] 1487 | name = "tinyvec" 1488 | version = "1.8.0" 1489 | source = "registry+https://github.com/rust-lang/crates.io-index" 1490 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 1491 | dependencies = [ 1492 | "tinyvec_macros", 1493 | ] 1494 | 1495 | [[package]] 1496 | name = "tinyvec_macros" 1497 | version = "0.1.1" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1500 | 1501 | [[package]] 1502 | name = "tokio" 1503 | version = "1.39.2" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" 1506 | dependencies = [ 1507 | "backtrace", 1508 | "bytes", 1509 | "libc", 1510 | "mio", 1511 | "parking_lot", 1512 | "pin-project-lite", 1513 | "signal-hook-registry", 1514 | "socket2", 1515 | "tokio-macros", 1516 | "windows-sys 0.52.0", 1517 | ] 1518 | 1519 | [[package]] 1520 | name = "tokio-macros" 1521 | version = "2.4.0" 1522 | source = "registry+https://github.com/rust-lang/crates.io-index" 1523 | checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" 1524 | dependencies = [ 1525 | "proc-macro2", 1526 | "quote", 1527 | "syn", 1528 | ] 1529 | 1530 | [[package]] 1531 | name = "tokio-native-tls" 1532 | version = "0.3.1" 1533 | source = "registry+https://github.com/rust-lang/crates.io-index" 1534 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 1535 | dependencies = [ 1536 | "native-tls", 1537 | "tokio", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "tokio-rustls" 1542 | version = "0.26.0" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 1545 | dependencies = [ 1546 | "rustls", 1547 | "rustls-pki-types", 1548 | "tokio", 1549 | ] 1550 | 1551 | [[package]] 1552 | name = "tokio-util" 1553 | version = "0.7.12" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" 1556 | dependencies = [ 1557 | "bytes", 1558 | "futures-core", 1559 | "futures-sink", 1560 | "pin-project-lite", 1561 | "tokio", 1562 | ] 1563 | 1564 | [[package]] 1565 | name = "tower" 1566 | version = "0.4.13" 1567 | source = "registry+https://github.com/rust-lang/crates.io-index" 1568 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1569 | dependencies = [ 1570 | "futures-core", 1571 | "futures-util", 1572 | "pin-project", 1573 | "pin-project-lite", 1574 | "tokio", 1575 | "tower-layer", 1576 | "tower-service", 1577 | "tracing", 1578 | ] 1579 | 1580 | [[package]] 1581 | name = "tower-layer" 1582 | version = "0.3.3" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1585 | 1586 | [[package]] 1587 | name = "tower-service" 1588 | version = "0.3.3" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1591 | 1592 | [[package]] 1593 | name = "tracing" 1594 | version = "0.1.40" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 1597 | dependencies = [ 1598 | "log", 1599 | "pin-project-lite", 1600 | "tracing-core", 1601 | ] 1602 | 1603 | [[package]] 1604 | name = "tracing-core" 1605 | version = "0.1.32" 1606 | source = "registry+https://github.com/rust-lang/crates.io-index" 1607 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 1608 | dependencies = [ 1609 | "once_cell", 1610 | ] 1611 | 1612 | [[package]] 1613 | name = "try-lock" 1614 | version = "0.2.5" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1617 | 1618 | [[package]] 1619 | name = "typenum" 1620 | version = "1.17.0" 1621 | source = "registry+https://github.com/rust-lang/crates.io-index" 1622 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1623 | 1624 | [[package]] 1625 | name = "unicase" 1626 | version = "2.8.0" 1627 | source = "registry+https://github.com/rust-lang/crates.io-index" 1628 | checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" 1629 | 1630 | [[package]] 1631 | name = "unicode-bidi" 1632 | version = "0.3.15" 1633 | source = "registry+https://github.com/rust-lang/crates.io-index" 1634 | checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" 1635 | 1636 | [[package]] 1637 | name = "unicode-ident" 1638 | version = "1.0.12" 1639 | source = "registry+https://github.com/rust-lang/crates.io-index" 1640 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 1641 | 1642 | [[package]] 1643 | name = "unicode-normalization" 1644 | version = "0.1.23" 1645 | source = "registry+https://github.com/rust-lang/crates.io-index" 1646 | checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" 1647 | dependencies = [ 1648 | "tinyvec", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "untrusted" 1653 | version = "0.9.0" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1656 | 1657 | [[package]] 1658 | name = "url" 1659 | version = "2.5.2" 1660 | source = "registry+https://github.com/rust-lang/crates.io-index" 1661 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 1662 | dependencies = [ 1663 | "form_urlencoded", 1664 | "idna", 1665 | "percent-encoding", 1666 | ] 1667 | 1668 | [[package]] 1669 | name = "utoipa" 1670 | version = "5.1.1" 1671 | source = "registry+https://github.com/rust-lang/crates.io-index" 1672 | checksum = "8861811f7213bb866cd02319acb69a15b0ef8ca46874e805bd92d488c779036a" 1673 | dependencies = [ 1674 | "indexmap", 1675 | "serde", 1676 | "serde_json", 1677 | "utoipa-gen", 1678 | ] 1679 | 1680 | [[package]] 1681 | name = "utoipa-gen" 1682 | version = "5.1.1" 1683 | source = "registry+https://github.com/rust-lang/crates.io-index" 1684 | checksum = "5fadf94f07d67df4b15e6490dd9a9d59d7374849413e7f137eafe52fdcbd0db5" 1685 | dependencies = [ 1686 | "proc-macro2", 1687 | "quote", 1688 | "syn", 1689 | ] 1690 | 1691 | [[package]] 1692 | name = "utoipa-swagger-ui" 1693 | version = "8.0.2" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "1054c946332dfc6e4bc31f704aa714fcbed73e9f412dd939f9ed86869e6304c3" 1696 | dependencies = [ 1697 | "axum", 1698 | "mime_guess", 1699 | "regex", 1700 | "rust-embed", 1701 | "serde", 1702 | "serde_json", 1703 | "url", 1704 | "utoipa", 1705 | "zip", 1706 | ] 1707 | 1708 | [[package]] 1709 | name = "vcpkg" 1710 | version = "0.2.15" 1711 | source = "registry+https://github.com/rust-lang/crates.io-index" 1712 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1713 | 1714 | [[package]] 1715 | name = "version_check" 1716 | version = "0.9.5" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 1719 | 1720 | [[package]] 1721 | name = "walkdir" 1722 | version = "2.5.0" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1725 | dependencies = [ 1726 | "same-file", 1727 | "winapi-util", 1728 | ] 1729 | 1730 | [[package]] 1731 | name = "want" 1732 | version = "0.3.1" 1733 | source = "registry+https://github.com/rust-lang/crates.io-index" 1734 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1735 | dependencies = [ 1736 | "try-lock", 1737 | ] 1738 | 1739 | [[package]] 1740 | name = "wasi" 1741 | version = "0.11.0+wasi-snapshot-preview1" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1744 | 1745 | [[package]] 1746 | name = "wasm-bindgen" 1747 | version = "0.2.93" 1748 | source = "registry+https://github.com/rust-lang/crates.io-index" 1749 | checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" 1750 | dependencies = [ 1751 | "cfg-if", 1752 | "once_cell", 1753 | "wasm-bindgen-macro", 1754 | ] 1755 | 1756 | [[package]] 1757 | name = "wasm-bindgen-backend" 1758 | version = "0.2.93" 1759 | source = "registry+https://github.com/rust-lang/crates.io-index" 1760 | checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" 1761 | dependencies = [ 1762 | "bumpalo", 1763 | "log", 1764 | "once_cell", 1765 | "proc-macro2", 1766 | "quote", 1767 | "syn", 1768 | "wasm-bindgen-shared", 1769 | ] 1770 | 1771 | [[package]] 1772 | name = "wasm-bindgen-futures" 1773 | version = "0.4.43" 1774 | source = "registry+https://github.com/rust-lang/crates.io-index" 1775 | checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" 1776 | dependencies = [ 1777 | "cfg-if", 1778 | "js-sys", 1779 | "wasm-bindgen", 1780 | "web-sys", 1781 | ] 1782 | 1783 | [[package]] 1784 | name = "wasm-bindgen-macro" 1785 | version = "0.2.93" 1786 | source = "registry+https://github.com/rust-lang/crates.io-index" 1787 | checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" 1788 | dependencies = [ 1789 | "quote", 1790 | "wasm-bindgen-macro-support", 1791 | ] 1792 | 1793 | [[package]] 1794 | name = "wasm-bindgen-macro-support" 1795 | version = "0.2.93" 1796 | source = "registry+https://github.com/rust-lang/crates.io-index" 1797 | checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" 1798 | dependencies = [ 1799 | "proc-macro2", 1800 | "quote", 1801 | "syn", 1802 | "wasm-bindgen-backend", 1803 | "wasm-bindgen-shared", 1804 | ] 1805 | 1806 | [[package]] 1807 | name = "wasm-bindgen-shared" 1808 | version = "0.2.93" 1809 | source = "registry+https://github.com/rust-lang/crates.io-index" 1810 | checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" 1811 | 1812 | [[package]] 1813 | name = "web-sys" 1814 | version = "0.3.70" 1815 | source = "registry+https://github.com/rust-lang/crates.io-index" 1816 | checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" 1817 | dependencies = [ 1818 | "js-sys", 1819 | "wasm-bindgen", 1820 | ] 1821 | 1822 | [[package]] 1823 | name = "winapi-util" 1824 | version = "0.1.9" 1825 | source = "registry+https://github.com/rust-lang/crates.io-index" 1826 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1827 | dependencies = [ 1828 | "windows-sys 0.59.0", 1829 | ] 1830 | 1831 | [[package]] 1832 | name = "windows-registry" 1833 | version = "0.2.0" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 1836 | dependencies = [ 1837 | "windows-result", 1838 | "windows-strings", 1839 | "windows-targets", 1840 | ] 1841 | 1842 | [[package]] 1843 | name = "windows-result" 1844 | version = "0.2.0" 1845 | source = "registry+https://github.com/rust-lang/crates.io-index" 1846 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 1847 | dependencies = [ 1848 | "windows-targets", 1849 | ] 1850 | 1851 | [[package]] 1852 | name = "windows-strings" 1853 | version = "0.1.0" 1854 | source = "registry+https://github.com/rust-lang/crates.io-index" 1855 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 1856 | dependencies = [ 1857 | "windows-result", 1858 | "windows-targets", 1859 | ] 1860 | 1861 | [[package]] 1862 | name = "windows-sys" 1863 | version = "0.52.0" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1866 | dependencies = [ 1867 | "windows-targets", 1868 | ] 1869 | 1870 | [[package]] 1871 | name = "windows-sys" 1872 | version = "0.59.0" 1873 | source = "registry+https://github.com/rust-lang/crates.io-index" 1874 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1875 | dependencies = [ 1876 | "windows-targets", 1877 | ] 1878 | 1879 | [[package]] 1880 | name = "windows-targets" 1881 | version = "0.52.6" 1882 | source = "registry+https://github.com/rust-lang/crates.io-index" 1883 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1884 | dependencies = [ 1885 | "windows_aarch64_gnullvm", 1886 | "windows_aarch64_msvc", 1887 | "windows_i686_gnu", 1888 | "windows_i686_gnullvm", 1889 | "windows_i686_msvc", 1890 | "windows_x86_64_gnu", 1891 | "windows_x86_64_gnullvm", 1892 | "windows_x86_64_msvc", 1893 | ] 1894 | 1895 | [[package]] 1896 | name = "windows_aarch64_gnullvm" 1897 | version = "0.52.6" 1898 | source = "registry+https://github.com/rust-lang/crates.io-index" 1899 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1900 | 1901 | [[package]] 1902 | name = "windows_aarch64_msvc" 1903 | version = "0.52.6" 1904 | source = "registry+https://github.com/rust-lang/crates.io-index" 1905 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1906 | 1907 | [[package]] 1908 | name = "windows_i686_gnu" 1909 | version = "0.52.6" 1910 | source = "registry+https://github.com/rust-lang/crates.io-index" 1911 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1912 | 1913 | [[package]] 1914 | name = "windows_i686_gnullvm" 1915 | version = "0.52.6" 1916 | source = "registry+https://github.com/rust-lang/crates.io-index" 1917 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1918 | 1919 | [[package]] 1920 | name = "windows_i686_msvc" 1921 | version = "0.52.6" 1922 | source = "registry+https://github.com/rust-lang/crates.io-index" 1923 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1924 | 1925 | [[package]] 1926 | name = "windows_x86_64_gnu" 1927 | version = "0.52.6" 1928 | source = "registry+https://github.com/rust-lang/crates.io-index" 1929 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1930 | 1931 | [[package]] 1932 | name = "windows_x86_64_gnullvm" 1933 | version = "0.52.6" 1934 | source = "registry+https://github.com/rust-lang/crates.io-index" 1935 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1936 | 1937 | [[package]] 1938 | name = "windows_x86_64_msvc" 1939 | version = "0.52.6" 1940 | source = "registry+https://github.com/rust-lang/crates.io-index" 1941 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1942 | 1943 | [[package]] 1944 | name = "zeroize" 1945 | version = "1.8.1" 1946 | source = "registry+https://github.com/rust-lang/crates.io-index" 1947 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1948 | 1949 | [[package]] 1950 | name = "zip" 1951 | version = "2.2.0" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" 1954 | dependencies = [ 1955 | "arbitrary", 1956 | "crc32fast", 1957 | "crossbeam-utils", 1958 | "displaydoc", 1959 | "flate2", 1960 | "indexmap", 1961 | "memchr", 1962 | "thiserror", 1963 | "zopfli", 1964 | ] 1965 | 1966 | [[package]] 1967 | name = "zopfli" 1968 | version = "0.8.1" 1969 | source = "registry+https://github.com/rust-lang/crates.io-index" 1970 | checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" 1971 | dependencies = [ 1972 | "bumpalo", 1973 | "crc32fast", 1974 | "lockfree-object-pool", 1975 | "log", 1976 | "once_cell", 1977 | "simd-adler32", 1978 | ] 1979 | -------------------------------------------------------------------------------- /examples/diesel_axum/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diesel_axum" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | crud_routers = { path = "../../crud_routers", features = ["axum", "diesel", "openapi"] } 8 | 9 | diesel = { version = "2", features = ["postgres"] } 10 | axum = { version = "0.7.5", features = ["macros"]} 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1" 13 | tokio = { version = "1.0", features = ["full"] } 14 | dotenvy = "0.15" 15 | utoipa = "5.1.1" 16 | utoipa-swagger-ui = {version = "8.0.2", features = ["axum"]} 17 | 18 | [dev-dependencies] 19 | test_utils = { path = "../../test_utils" } 20 | -------------------------------------------------------------------------------- /examples/diesel_axum/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod models; 2 | pub mod schema; 3 | 4 | use std::env; 5 | use diesel::{Connection, PgConnection}; 6 | use dotenvy::dotenv; 7 | use std::sync::Arc; 8 | use axum::Router; 9 | use axum::serve::Serve; 10 | use tokio::net::TcpListener; 11 | use tokio::sync::Mutex; 12 | use utoipa::openapi::{InfoBuilder, OpenApiBuilder}; 13 | use utoipa_swagger_ui::SwaggerUi; 14 | use crud_routers::{AxumServer, CrudRouterBuilder, DieselRepository}; 15 | use crate::models::{NewPost, Post, PostForm}; 16 | use crate::schema::posts; 17 | 18 | pub fn run(listener: TcpListener) -> Serve { 19 | let mut openapi = OpenApiBuilder::new() 20 | .info(InfoBuilder::new().title("Diesel Axum example").build()) 21 | .build(); 22 | 23 | let connection = establish_connection(); 24 | let shared_state = Arc::new(Mutex::new( 25 | DieselRepository::new(connection, posts::table) 26 | )); 27 | 28 | let router = CrudRouterBuilder::new::() 29 | .schema::() 30 | .create_schema::() 31 | .update_schema::() 32 | .prefix("base/api") 33 | .build_openapi(&mut openapi) 34 | .build_router() 35 | .with_state(shared_state) 36 | .merge(SwaggerUi::new("/docs/swagger/").url("/api-docs/openapi.json", openapi)); 37 | 38 | axum::serve(listener, router) 39 | } 40 | 41 | 42 | pub fn establish_connection() -> PgConnection { 43 | dotenv().ok(); 44 | 45 | let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); 46 | PgConnection::establish(&database_url) 47 | .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) 48 | } 49 | 50 | -------------------------------------------------------------------------------- /examples/diesel_axum/src/main.rs: -------------------------------------------------------------------------------- 1 | use diesel_axum::run; 2 | use std::io; 3 | use tokio::net::TcpListener; 4 | 5 | #[tokio::main] 6 | async fn main() -> io::Result<()> { 7 | let listener = TcpListener::bind("127.0.0.1:8008").await 8 | .expect("Could not bind TCP listener"); 9 | run(listener).await 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use crate::run; 15 | use tokio::net::TcpListener; 16 | use test_utils::{TestApp, e2e_test}; 17 | 18 | async fn spawn_app() -> TestApp{ 19 | let listener = TcpListener::bind("127.0.0.1:0").await 20 | .expect("Could not bind TCP listener"); 21 | let port = listener.local_addr().unwrap().port(); 22 | tokio::spawn(async move { 23 | run(listener).await.unwrap(); 24 | }); 25 | 26 | TestApp::new(format!("http://127.0.0.1:{}", port), "base/api") 27 | } 28 | 29 | #[tokio::test] 30 | async fn e2e(){ 31 | let app = spawn_app().await; 32 | 33 | e2e_test(app).await; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /examples/diesel_axum/src/models.rs: -------------------------------------------------------------------------------- 1 | use diesel::prelude::*; 2 | use serde::{Serialize, Deserialize}; 3 | use utoipa::ToSchema; 4 | use crate::schema::posts; 5 | 6 | #[derive(Serialize, Queryable, Selectable, ToSchema)] 7 | #[diesel(table_name = crate::schema::posts)] 8 | #[diesel(check_for_backend(diesel::pg::Pg))] 9 | pub struct Post { 10 | pub id: i32, 11 | pub title: String, 12 | pub body: String, 13 | pub published: bool, 14 | } 15 | 16 | 17 | #[derive(Deserialize, Insertable, ToSchema)] 18 | #[diesel(table_name = posts)] 19 | pub struct NewPost { 20 | pub title: String, 21 | pub body: String, 22 | pub published: bool, 23 | } 24 | 25 | 26 | #[derive(Deserialize, AsChangeset, ToSchema)] 27 | #[diesel(table_name = posts)] 28 | pub struct PostForm { 29 | title: Option, 30 | body: Option, 31 | published: Option, 32 | } -------------------------------------------------------------------------------- /examples/diesel_axum/src/schema.rs: -------------------------------------------------------------------------------- 1 | // @generated automatically by Diesel CLI. 2 | 3 | diesel::table! { 4 | posts (id) { 5 | id -> Int4, 6 | title -> Varchar, 7 | body -> Text, 8 | published -> Bool, 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/seaorm_actix/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "seaorm_actix" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | crud_routers = { path = "../../crud_routers", features = ["actix", "sea-orm"] } 8 | 9 | sea-orm = { version = "1.0.0", features = ["runtime-tokio-native-tls", "sqlx-postgres"] } 10 | actix-web = "4" 11 | serde = { version = "1.0", features = ["derive"] } 12 | serde_json = "1" 13 | tokio = { version = "1.0", features = ["full"] } 14 | dotenvy = "0.15" 15 | 16 | [dev-dependencies] 17 | test_utils = { path = "../../test_utils" } 18 | -------------------------------------------------------------------------------- /examples/seaorm_actix/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::net::TcpListener; 3 | use actix_web::dev::Server; 4 | use actix_web::{App, HttpServer}; 5 | use actix_web::web::Data; 6 | use dotenvy::dotenv; 7 | use sea_orm::{Database, DatabaseConnection}; 8 | use tokio::sync::Mutex; 9 | use crud_routers::{ActixServer, CrudRouterBuilder, SeaOrmRepository}; 10 | 11 | pub mod post; 12 | 13 | pub async fn run(listener: TcpListener) -> std::io::Result { 14 | let connection = establish_connection().await; 15 | 16 | let shared_state = Data::new(Mutex::new( SeaOrmRepository::new(connection))); 17 | 18 | let server = HttpServer::new(move || { 19 | App::new() 20 | .app_data(shared_state.clone()) 21 | .service( 22 | CrudRouterBuilder::new::() 23 | .repository::() 24 | .schema::() 25 | .create_schema::() 26 | .update_schema::() 27 | .build_router() 28 | ) 29 | }) 30 | .listen(listener)? 31 | .run(); 32 | 33 | Ok(server) 34 | } 35 | 36 | async fn establish_connection() -> DatabaseConnection { 37 | dotenv().ok(); 38 | 39 | let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); 40 | Database::connect(&database_url) 41 | .await 42 | .expect("Error connecting to database") 43 | } 44 | -------------------------------------------------------------------------------- /examples/seaorm_actix/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::net::TcpListener; 3 | use seaorm_actix::run; 4 | 5 | #[actix_web::main] 6 | async fn main() -> io::Result<()> { 7 | let listener = TcpListener::bind("127.0.0.1:8080") 8 | .expect("Could not bind TCP listener"); 9 | run(listener).await?.await 10 | } 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use crate::run; 15 | use std::net::TcpListener; 16 | use test_utils::{TestApp, e2e_test}; 17 | 18 | async fn spawn_app() -> TestApp{ 19 | let listener = TcpListener::bind("127.0.0.1:0") 20 | .expect("Could not bind TCP listener"); 21 | let port = listener.local_addr().unwrap().port(); 22 | let server = run(listener).await.expect("Failed to bind address"); 23 | let _ = tokio::spawn(server); 24 | 25 | TestApp::new(format!("http://127.0.0.1:{}", port), "posts") 26 | } 27 | 28 | #[tokio::test] 29 | async fn e2e(){ 30 | let app = spawn_app().await; 31 | 32 | e2e_test(app).await; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /examples/seaorm_actix/src/post.rs: -------------------------------------------------------------------------------- 1 | use sea_orm::entity::prelude::*; 2 | use serde::{Deserialize, Serialize}; 3 | 4 | #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)] 5 | #[sea_orm(table_name = "posts")] 6 | pub struct Model { 7 | #[sea_orm(primary_key)] 8 | #[serde(skip_deserializing)] 9 | pub id: i32, 10 | pub title: String, 11 | #[sea_orm(column_type = "Text")] 12 | pub body: String, 13 | pub published: bool, 14 | } 15 | 16 | #[derive(Serialize, Deserialize)] 17 | pub struct NewPost { 18 | pub title: String, 19 | pub body: String, 20 | pub published: bool, 21 | } 22 | 23 | #[derive(Serialize, Deserialize)] 24 | pub struct PostForm { 25 | title: Option, 26 | body: Option, 27 | published: Option, 28 | } 29 | 30 | #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] 31 | pub enum Relation {} 32 | 33 | impl ActiveModelBehavior for ActiveModel {} 34 | -------------------------------------------------------------------------------- /test_utils/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "atomic-waker" 22 | version = "1.1.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.4.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 31 | 32 | [[package]] 33 | name = "backtrace" 34 | version = "0.3.74" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 37 | dependencies = [ 38 | "addr2line", 39 | "cfg-if", 40 | "libc", 41 | "miniz_oxide", 42 | "object", 43 | "rustc-demangle", 44 | "windows-targets", 45 | ] 46 | 47 | [[package]] 48 | name = "base64" 49 | version = "0.22.1" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 52 | 53 | [[package]] 54 | name = "bitflags" 55 | version = "2.6.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 58 | 59 | [[package]] 60 | name = "bumpalo" 61 | version = "3.16.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" 64 | 65 | [[package]] 66 | name = "bytes" 67 | version = "1.7.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" 70 | 71 | [[package]] 72 | name = "cc" 73 | version = "1.1.25" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "e8d9e0b4957f635b8d3da819d0db5603620467ecf1f692d22a8c2717ce27e6d8" 76 | dependencies = [ 77 | "shlex", 78 | ] 79 | 80 | [[package]] 81 | name = "cfg-if" 82 | version = "1.0.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 85 | 86 | [[package]] 87 | name = "core-foundation" 88 | version = "0.9.4" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 91 | dependencies = [ 92 | "core-foundation-sys", 93 | "libc", 94 | ] 95 | 96 | [[package]] 97 | name = "core-foundation-sys" 98 | version = "0.8.7" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 101 | 102 | [[package]] 103 | name = "encoding_rs" 104 | version = "0.8.34" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" 107 | dependencies = [ 108 | "cfg-if", 109 | ] 110 | 111 | [[package]] 112 | name = "equivalent" 113 | version = "1.0.1" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 116 | 117 | [[package]] 118 | name = "errno" 119 | version = "0.3.9" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" 122 | dependencies = [ 123 | "libc", 124 | "windows-sys 0.52.0", 125 | ] 126 | 127 | [[package]] 128 | name = "fastrand" 129 | version = "2.1.1" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" 132 | 133 | [[package]] 134 | name = "fnv" 135 | version = "1.0.7" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 138 | 139 | [[package]] 140 | name = "foreign-types" 141 | version = "0.3.2" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" 144 | dependencies = [ 145 | "foreign-types-shared", 146 | ] 147 | 148 | [[package]] 149 | name = "foreign-types-shared" 150 | version = "0.1.1" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" 153 | 154 | [[package]] 155 | name = "form_urlencoded" 156 | version = "1.2.1" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 159 | dependencies = [ 160 | "percent-encoding", 161 | ] 162 | 163 | [[package]] 164 | name = "futures-channel" 165 | version = "0.3.31" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 168 | dependencies = [ 169 | "futures-core", 170 | ] 171 | 172 | [[package]] 173 | name = "futures-core" 174 | version = "0.3.31" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 177 | 178 | [[package]] 179 | name = "futures-sink" 180 | version = "0.3.31" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 183 | 184 | [[package]] 185 | name = "futures-task" 186 | version = "0.3.31" 187 | source = "registry+https://github.com/rust-lang/crates.io-index" 188 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 189 | 190 | [[package]] 191 | name = "futures-util" 192 | version = "0.3.31" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 195 | dependencies = [ 196 | "futures-core", 197 | "futures-task", 198 | "pin-project-lite", 199 | "pin-utils", 200 | ] 201 | 202 | [[package]] 203 | name = "getrandom" 204 | version = "0.2.15" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 207 | dependencies = [ 208 | "cfg-if", 209 | "libc", 210 | "wasi", 211 | ] 212 | 213 | [[package]] 214 | name = "gimli" 215 | version = "0.31.1" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 218 | 219 | [[package]] 220 | name = "h2" 221 | version = "0.4.6" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" 224 | dependencies = [ 225 | "atomic-waker", 226 | "bytes", 227 | "fnv", 228 | "futures-core", 229 | "futures-sink", 230 | "http", 231 | "indexmap", 232 | "slab", 233 | "tokio", 234 | "tokio-util", 235 | "tracing", 236 | ] 237 | 238 | [[package]] 239 | name = "hashbrown" 240 | version = "0.15.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" 243 | 244 | [[package]] 245 | name = "hermit-abi" 246 | version = "0.3.9" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" 249 | 250 | [[package]] 251 | name = "http" 252 | version = "1.1.0" 253 | source = "registry+https://github.com/rust-lang/crates.io-index" 254 | checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" 255 | dependencies = [ 256 | "bytes", 257 | "fnv", 258 | "itoa", 259 | ] 260 | 261 | [[package]] 262 | name = "http-body" 263 | version = "1.0.1" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 266 | dependencies = [ 267 | "bytes", 268 | "http", 269 | ] 270 | 271 | [[package]] 272 | name = "http-body-util" 273 | version = "0.1.2" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" 276 | dependencies = [ 277 | "bytes", 278 | "futures-util", 279 | "http", 280 | "http-body", 281 | "pin-project-lite", 282 | ] 283 | 284 | [[package]] 285 | name = "httparse" 286 | version = "1.9.5" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" 289 | 290 | [[package]] 291 | name = "hyper" 292 | version = "1.4.1" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" 295 | dependencies = [ 296 | "bytes", 297 | "futures-channel", 298 | "futures-util", 299 | "h2", 300 | "http", 301 | "http-body", 302 | "httparse", 303 | "itoa", 304 | "pin-project-lite", 305 | "smallvec", 306 | "tokio", 307 | "want", 308 | ] 309 | 310 | [[package]] 311 | name = "hyper-rustls" 312 | version = "0.27.3" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" 315 | dependencies = [ 316 | "futures-util", 317 | "http", 318 | "hyper", 319 | "hyper-util", 320 | "rustls", 321 | "rustls-pki-types", 322 | "tokio", 323 | "tokio-rustls", 324 | "tower-service", 325 | ] 326 | 327 | [[package]] 328 | name = "hyper-tls" 329 | version = "0.6.0" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" 332 | dependencies = [ 333 | "bytes", 334 | "http-body-util", 335 | "hyper", 336 | "hyper-util", 337 | "native-tls", 338 | "tokio", 339 | "tokio-native-tls", 340 | "tower-service", 341 | ] 342 | 343 | [[package]] 344 | name = "hyper-util" 345 | version = "0.1.9" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" 348 | dependencies = [ 349 | "bytes", 350 | "futures-channel", 351 | "futures-util", 352 | "http", 353 | "http-body", 354 | "hyper", 355 | "pin-project-lite", 356 | "socket2", 357 | "tokio", 358 | "tower-service", 359 | "tracing", 360 | ] 361 | 362 | [[package]] 363 | name = "idna" 364 | version = "0.5.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" 367 | dependencies = [ 368 | "unicode-bidi", 369 | "unicode-normalization", 370 | ] 371 | 372 | [[package]] 373 | name = "indexmap" 374 | version = "2.6.0" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" 377 | dependencies = [ 378 | "equivalent", 379 | "hashbrown", 380 | ] 381 | 382 | [[package]] 383 | name = "ipnet" 384 | version = "2.10.1" 385 | source = "registry+https://github.com/rust-lang/crates.io-index" 386 | checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" 387 | 388 | [[package]] 389 | name = "itoa" 390 | version = "1.0.11" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 393 | 394 | [[package]] 395 | name = "js-sys" 396 | version = "0.3.70" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" 399 | dependencies = [ 400 | "wasm-bindgen", 401 | ] 402 | 403 | [[package]] 404 | name = "libc" 405 | version = "0.2.159" 406 | source = "registry+https://github.com/rust-lang/crates.io-index" 407 | checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" 408 | 409 | [[package]] 410 | name = "linux-raw-sys" 411 | version = "0.4.14" 412 | source = "registry+https://github.com/rust-lang/crates.io-index" 413 | checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" 414 | 415 | [[package]] 416 | name = "log" 417 | version = "0.4.22" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 420 | 421 | [[package]] 422 | name = "memchr" 423 | version = "2.7.4" 424 | source = "registry+https://github.com/rust-lang/crates.io-index" 425 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 426 | 427 | [[package]] 428 | name = "mime" 429 | version = "0.3.17" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 432 | 433 | [[package]] 434 | name = "miniz_oxide" 435 | version = "0.8.0" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" 438 | dependencies = [ 439 | "adler2", 440 | ] 441 | 442 | [[package]] 443 | name = "mio" 444 | version = "1.0.2" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" 447 | dependencies = [ 448 | "hermit-abi", 449 | "libc", 450 | "wasi", 451 | "windows-sys 0.52.0", 452 | ] 453 | 454 | [[package]] 455 | name = "native-tls" 456 | version = "0.2.12" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" 459 | dependencies = [ 460 | "libc", 461 | "log", 462 | "openssl", 463 | "openssl-probe", 464 | "openssl-sys", 465 | "schannel", 466 | "security-framework", 467 | "security-framework-sys", 468 | "tempfile", 469 | ] 470 | 471 | [[package]] 472 | name = "object" 473 | version = "0.36.5" 474 | source = "registry+https://github.com/rust-lang/crates.io-index" 475 | checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" 476 | dependencies = [ 477 | "memchr", 478 | ] 479 | 480 | [[package]] 481 | name = "once_cell" 482 | version = "1.20.2" 483 | source = "registry+https://github.com/rust-lang/crates.io-index" 484 | checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" 485 | 486 | [[package]] 487 | name = "openssl" 488 | version = "0.10.66" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" 491 | dependencies = [ 492 | "bitflags", 493 | "cfg-if", 494 | "foreign-types", 495 | "libc", 496 | "once_cell", 497 | "openssl-macros", 498 | "openssl-sys", 499 | ] 500 | 501 | [[package]] 502 | name = "openssl-macros" 503 | version = "0.1.1" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" 506 | dependencies = [ 507 | "proc-macro2", 508 | "quote", 509 | "syn", 510 | ] 511 | 512 | [[package]] 513 | name = "openssl-probe" 514 | version = "0.1.5" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" 517 | 518 | [[package]] 519 | name = "openssl-sys" 520 | version = "0.9.103" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" 523 | dependencies = [ 524 | "cc", 525 | "libc", 526 | "pkg-config", 527 | "vcpkg", 528 | ] 529 | 530 | [[package]] 531 | name = "percent-encoding" 532 | version = "2.3.1" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 535 | 536 | [[package]] 537 | name = "pin-project-lite" 538 | version = "0.2.14" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" 541 | 542 | [[package]] 543 | name = "pin-utils" 544 | version = "0.1.0" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 547 | 548 | [[package]] 549 | name = "pkg-config" 550 | version = "0.3.31" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" 553 | 554 | [[package]] 555 | name = "proc-macro2" 556 | version = "1.0.86" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" 559 | dependencies = [ 560 | "unicode-ident", 561 | ] 562 | 563 | [[package]] 564 | name = "quote" 565 | version = "1.0.37" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 568 | dependencies = [ 569 | "proc-macro2", 570 | ] 571 | 572 | [[package]] 573 | name = "reqwest" 574 | version = "0.12.8" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" 577 | dependencies = [ 578 | "base64", 579 | "bytes", 580 | "encoding_rs", 581 | "futures-core", 582 | "futures-util", 583 | "h2", 584 | "http", 585 | "http-body", 586 | "http-body-util", 587 | "hyper", 588 | "hyper-rustls", 589 | "hyper-tls", 590 | "hyper-util", 591 | "ipnet", 592 | "js-sys", 593 | "log", 594 | "mime", 595 | "native-tls", 596 | "once_cell", 597 | "percent-encoding", 598 | "pin-project-lite", 599 | "rustls-pemfile", 600 | "serde", 601 | "serde_json", 602 | "serde_urlencoded", 603 | "sync_wrapper", 604 | "system-configuration", 605 | "tokio", 606 | "tokio-native-tls", 607 | "tower-service", 608 | "url", 609 | "wasm-bindgen", 610 | "wasm-bindgen-futures", 611 | "web-sys", 612 | "windows-registry", 613 | ] 614 | 615 | [[package]] 616 | name = "ring" 617 | version = "0.17.8" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" 620 | dependencies = [ 621 | "cc", 622 | "cfg-if", 623 | "getrandom", 624 | "libc", 625 | "spin", 626 | "untrusted", 627 | "windows-sys 0.52.0", 628 | ] 629 | 630 | [[package]] 631 | name = "rustc-demangle" 632 | version = "0.1.24" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 635 | 636 | [[package]] 637 | name = "rustix" 638 | version = "0.38.37" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" 641 | dependencies = [ 642 | "bitflags", 643 | "errno", 644 | "libc", 645 | "linux-raw-sys", 646 | "windows-sys 0.52.0", 647 | ] 648 | 649 | [[package]] 650 | name = "rustls" 651 | version = "0.23.14" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "415d9944693cb90382053259f89fbb077ea730ad7273047ec63b19bc9b160ba8" 654 | dependencies = [ 655 | "once_cell", 656 | "rustls-pki-types", 657 | "rustls-webpki", 658 | "subtle", 659 | "zeroize", 660 | ] 661 | 662 | [[package]] 663 | name = "rustls-pemfile" 664 | version = "2.2.0" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 667 | dependencies = [ 668 | "rustls-pki-types", 669 | ] 670 | 671 | [[package]] 672 | name = "rustls-pki-types" 673 | version = "1.9.0" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" 676 | 677 | [[package]] 678 | name = "rustls-webpki" 679 | version = "0.102.8" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" 682 | dependencies = [ 683 | "ring", 684 | "rustls-pki-types", 685 | "untrusted", 686 | ] 687 | 688 | [[package]] 689 | name = "ryu" 690 | version = "1.0.18" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 693 | 694 | [[package]] 695 | name = "schannel" 696 | version = "0.1.24" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" 699 | dependencies = [ 700 | "windows-sys 0.59.0", 701 | ] 702 | 703 | [[package]] 704 | name = "security-framework" 705 | version = "2.11.1" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" 708 | dependencies = [ 709 | "bitflags", 710 | "core-foundation", 711 | "core-foundation-sys", 712 | "libc", 713 | "security-framework-sys", 714 | ] 715 | 716 | [[package]] 717 | name = "security-framework-sys" 718 | version = "2.12.0" 719 | source = "registry+https://github.com/rust-lang/crates.io-index" 720 | checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" 721 | dependencies = [ 722 | "core-foundation-sys", 723 | "libc", 724 | ] 725 | 726 | [[package]] 727 | name = "serde" 728 | version = "1.0.210" 729 | source = "registry+https://github.com/rust-lang/crates.io-index" 730 | checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" 731 | dependencies = [ 732 | "serde_derive", 733 | ] 734 | 735 | [[package]] 736 | name = "serde_derive" 737 | version = "1.0.210" 738 | source = "registry+https://github.com/rust-lang/crates.io-index" 739 | checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" 740 | dependencies = [ 741 | "proc-macro2", 742 | "quote", 743 | "syn", 744 | ] 745 | 746 | [[package]] 747 | name = "serde_json" 748 | version = "1.0.128" 749 | source = "registry+https://github.com/rust-lang/crates.io-index" 750 | checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" 751 | dependencies = [ 752 | "itoa", 753 | "memchr", 754 | "ryu", 755 | "serde", 756 | ] 757 | 758 | [[package]] 759 | name = "serde_urlencoded" 760 | version = "0.7.1" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 763 | dependencies = [ 764 | "form_urlencoded", 765 | "itoa", 766 | "ryu", 767 | "serde", 768 | ] 769 | 770 | [[package]] 771 | name = "shlex" 772 | version = "1.3.0" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 775 | 776 | [[package]] 777 | name = "slab" 778 | version = "0.4.9" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 781 | dependencies = [ 782 | "autocfg", 783 | ] 784 | 785 | [[package]] 786 | name = "smallvec" 787 | version = "1.13.2" 788 | source = "registry+https://github.com/rust-lang/crates.io-index" 789 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 790 | 791 | [[package]] 792 | name = "socket2" 793 | version = "0.5.7" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" 796 | dependencies = [ 797 | "libc", 798 | "windows-sys 0.52.0", 799 | ] 800 | 801 | [[package]] 802 | name = "spin" 803 | version = "0.9.8" 804 | source = "registry+https://github.com/rust-lang/crates.io-index" 805 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 806 | 807 | [[package]] 808 | name = "subtle" 809 | version = "2.6.1" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 812 | 813 | [[package]] 814 | name = "syn" 815 | version = "2.0.79" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" 818 | dependencies = [ 819 | "proc-macro2", 820 | "quote", 821 | "unicode-ident", 822 | ] 823 | 824 | [[package]] 825 | name = "sync_wrapper" 826 | version = "1.0.1" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" 829 | dependencies = [ 830 | "futures-core", 831 | ] 832 | 833 | [[package]] 834 | name = "system-configuration" 835 | version = "0.6.1" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 838 | dependencies = [ 839 | "bitflags", 840 | "core-foundation", 841 | "system-configuration-sys", 842 | ] 843 | 844 | [[package]] 845 | name = "system-configuration-sys" 846 | version = "0.6.0" 847 | source = "registry+https://github.com/rust-lang/crates.io-index" 848 | checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 849 | dependencies = [ 850 | "core-foundation-sys", 851 | "libc", 852 | ] 853 | 854 | [[package]] 855 | name = "tempfile" 856 | version = "3.13.0" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" 859 | dependencies = [ 860 | "cfg-if", 861 | "fastrand", 862 | "once_cell", 863 | "rustix", 864 | "windows-sys 0.59.0", 865 | ] 866 | 867 | [[package]] 868 | name = "test_utils" 869 | version = "0.1.0" 870 | dependencies = [ 871 | "mime", 872 | "reqwest", 873 | "serde", 874 | "serde_json", 875 | ] 876 | 877 | [[package]] 878 | name = "tinyvec" 879 | version = "1.8.0" 880 | source = "registry+https://github.com/rust-lang/crates.io-index" 881 | checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" 882 | dependencies = [ 883 | "tinyvec_macros", 884 | ] 885 | 886 | [[package]] 887 | name = "tinyvec_macros" 888 | version = "0.1.1" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 891 | 892 | [[package]] 893 | name = "tokio" 894 | version = "1.40.0" 895 | source = "registry+https://github.com/rust-lang/crates.io-index" 896 | checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" 897 | dependencies = [ 898 | "backtrace", 899 | "bytes", 900 | "libc", 901 | "mio", 902 | "pin-project-lite", 903 | "socket2", 904 | "windows-sys 0.52.0", 905 | ] 906 | 907 | [[package]] 908 | name = "tokio-native-tls" 909 | version = "0.3.1" 910 | source = "registry+https://github.com/rust-lang/crates.io-index" 911 | checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" 912 | dependencies = [ 913 | "native-tls", 914 | "tokio", 915 | ] 916 | 917 | [[package]] 918 | name = "tokio-rustls" 919 | version = "0.26.0" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" 922 | dependencies = [ 923 | "rustls", 924 | "rustls-pki-types", 925 | "tokio", 926 | ] 927 | 928 | [[package]] 929 | name = "tokio-util" 930 | version = "0.7.12" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" 933 | dependencies = [ 934 | "bytes", 935 | "futures-core", 936 | "futures-sink", 937 | "pin-project-lite", 938 | "tokio", 939 | ] 940 | 941 | [[package]] 942 | name = "tower-service" 943 | version = "0.3.3" 944 | source = "registry+https://github.com/rust-lang/crates.io-index" 945 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 946 | 947 | [[package]] 948 | name = "tracing" 949 | version = "0.1.40" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" 952 | dependencies = [ 953 | "pin-project-lite", 954 | "tracing-core", 955 | ] 956 | 957 | [[package]] 958 | name = "tracing-core" 959 | version = "0.1.32" 960 | source = "registry+https://github.com/rust-lang/crates.io-index" 961 | checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" 962 | dependencies = [ 963 | "once_cell", 964 | ] 965 | 966 | [[package]] 967 | name = "try-lock" 968 | version = "0.2.5" 969 | source = "registry+https://github.com/rust-lang/crates.io-index" 970 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 971 | 972 | [[package]] 973 | name = "unicode-bidi" 974 | version = "0.3.17" 975 | source = "registry+https://github.com/rust-lang/crates.io-index" 976 | checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" 977 | 978 | [[package]] 979 | name = "unicode-ident" 980 | version = "1.0.13" 981 | source = "registry+https://github.com/rust-lang/crates.io-index" 982 | checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" 983 | 984 | [[package]] 985 | name = "unicode-normalization" 986 | version = "0.1.24" 987 | source = "registry+https://github.com/rust-lang/crates.io-index" 988 | checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" 989 | dependencies = [ 990 | "tinyvec", 991 | ] 992 | 993 | [[package]] 994 | name = "untrusted" 995 | version = "0.9.0" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 998 | 999 | [[package]] 1000 | name = "url" 1001 | version = "2.5.2" 1002 | source = "registry+https://github.com/rust-lang/crates.io-index" 1003 | checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 1004 | dependencies = [ 1005 | "form_urlencoded", 1006 | "idna", 1007 | "percent-encoding", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "vcpkg" 1012 | version = "0.2.15" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 1015 | 1016 | [[package]] 1017 | name = "want" 1018 | version = "0.3.1" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1021 | dependencies = [ 1022 | "try-lock", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "wasi" 1027 | version = "0.11.0+wasi-snapshot-preview1" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1030 | 1031 | [[package]] 1032 | name = "wasm-bindgen" 1033 | version = "0.2.93" 1034 | source = "registry+https://github.com/rust-lang/crates.io-index" 1035 | checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" 1036 | dependencies = [ 1037 | "cfg-if", 1038 | "once_cell", 1039 | "wasm-bindgen-macro", 1040 | ] 1041 | 1042 | [[package]] 1043 | name = "wasm-bindgen-backend" 1044 | version = "0.2.93" 1045 | source = "registry+https://github.com/rust-lang/crates.io-index" 1046 | checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" 1047 | dependencies = [ 1048 | "bumpalo", 1049 | "log", 1050 | "once_cell", 1051 | "proc-macro2", 1052 | "quote", 1053 | "syn", 1054 | "wasm-bindgen-shared", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "wasm-bindgen-futures" 1059 | version = "0.4.43" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" 1062 | dependencies = [ 1063 | "cfg-if", 1064 | "js-sys", 1065 | "wasm-bindgen", 1066 | "web-sys", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "wasm-bindgen-macro" 1071 | version = "0.2.93" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" 1074 | dependencies = [ 1075 | "quote", 1076 | "wasm-bindgen-macro-support", 1077 | ] 1078 | 1079 | [[package]] 1080 | name = "wasm-bindgen-macro-support" 1081 | version = "0.2.93" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" 1084 | dependencies = [ 1085 | "proc-macro2", 1086 | "quote", 1087 | "syn", 1088 | "wasm-bindgen-backend", 1089 | "wasm-bindgen-shared", 1090 | ] 1091 | 1092 | [[package]] 1093 | name = "wasm-bindgen-shared" 1094 | version = "0.2.93" 1095 | source = "registry+https://github.com/rust-lang/crates.io-index" 1096 | checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" 1097 | 1098 | [[package]] 1099 | name = "web-sys" 1100 | version = "0.3.70" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" 1103 | dependencies = [ 1104 | "js-sys", 1105 | "wasm-bindgen", 1106 | ] 1107 | 1108 | [[package]] 1109 | name = "windows-registry" 1110 | version = "0.2.0" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" 1113 | dependencies = [ 1114 | "windows-result", 1115 | "windows-strings", 1116 | "windows-targets", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "windows-result" 1121 | version = "0.2.0" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" 1124 | dependencies = [ 1125 | "windows-targets", 1126 | ] 1127 | 1128 | [[package]] 1129 | name = "windows-strings" 1130 | version = "0.1.0" 1131 | source = "registry+https://github.com/rust-lang/crates.io-index" 1132 | checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" 1133 | dependencies = [ 1134 | "windows-result", 1135 | "windows-targets", 1136 | ] 1137 | 1138 | [[package]] 1139 | name = "windows-sys" 1140 | version = "0.52.0" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1143 | dependencies = [ 1144 | "windows-targets", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "windows-sys" 1149 | version = "0.59.0" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1152 | dependencies = [ 1153 | "windows-targets", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "windows-targets" 1158 | version = "0.52.6" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1161 | dependencies = [ 1162 | "windows_aarch64_gnullvm", 1163 | "windows_aarch64_msvc", 1164 | "windows_i686_gnu", 1165 | "windows_i686_gnullvm", 1166 | "windows_i686_msvc", 1167 | "windows_x86_64_gnu", 1168 | "windows_x86_64_gnullvm", 1169 | "windows_x86_64_msvc", 1170 | ] 1171 | 1172 | [[package]] 1173 | name = "windows_aarch64_gnullvm" 1174 | version = "0.52.6" 1175 | source = "registry+https://github.com/rust-lang/crates.io-index" 1176 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1177 | 1178 | [[package]] 1179 | name = "windows_aarch64_msvc" 1180 | version = "0.52.6" 1181 | source = "registry+https://github.com/rust-lang/crates.io-index" 1182 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1183 | 1184 | [[package]] 1185 | name = "windows_i686_gnu" 1186 | version = "0.52.6" 1187 | source = "registry+https://github.com/rust-lang/crates.io-index" 1188 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1189 | 1190 | [[package]] 1191 | name = "windows_i686_gnullvm" 1192 | version = "0.52.6" 1193 | source = "registry+https://github.com/rust-lang/crates.io-index" 1194 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1195 | 1196 | [[package]] 1197 | name = "windows_i686_msvc" 1198 | version = "0.52.6" 1199 | source = "registry+https://github.com/rust-lang/crates.io-index" 1200 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1201 | 1202 | [[package]] 1203 | name = "windows_x86_64_gnu" 1204 | version = "0.52.6" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1207 | 1208 | [[package]] 1209 | name = "windows_x86_64_gnullvm" 1210 | version = "0.52.6" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1213 | 1214 | [[package]] 1215 | name = "windows_x86_64_msvc" 1216 | version = "0.52.6" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1219 | 1220 | [[package]] 1221 | name = "zeroize" 1222 | version = "1.8.1" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 1225 | -------------------------------------------------------------------------------- /test_utils/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "test_utils" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | reqwest = "0.12" 8 | serde = { version = "1.0" } 9 | serde_json = "1" 10 | mime = "0.3.17" 11 | -------------------------------------------------------------------------------- /test_utils/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde::Serialize; 2 | use serde_json::{json, Value}; 3 | 4 | pub struct TestApp{ 5 | pub address: String, 6 | pub api_client: reqwest::Client 7 | } 8 | 9 | impl TestApp { 10 | pub fn new(mut address: String, prefix: &str) -> Self{ 11 | address.push('/'); 12 | address.push_str(prefix); 13 | Self{ 14 | address, 15 | api_client: reqwest::Client::new() 16 | } 17 | } 18 | async fn list_all(&self, skip: Option, limit: Option) -> reqwest::Response { 19 | let mut r = self.api_client.get(&self.address); 20 | if let Some(skip) = skip { 21 | r = r.query(&[("skip", skip.to_string())]); 22 | } 23 | 24 | if let Some(limit) = limit { 25 | r = r.query(&[("limit", limit.to_string())]); 26 | } 27 | 28 | r 29 | .send() 30 | .await 31 | .expect("Failed to execute request.") 32 | } 33 | async fn get(&self, id: i64) -> reqwest::Response { 34 | self.api_client.get(&format!("{}/{}", &self.address, id)) 35 | .send() 36 | .await 37 | .expect("Failed to execute request.") 38 | } 39 | async fn create(&self, body: impl Serialize) -> reqwest::Response { 40 | self.api_client.post(&self.address) 41 | .header("Content-Type", mime::APPLICATION_JSON.as_ref()) 42 | .body(reqwest::Body::from(serde_json::to_vec(&body).unwrap())) 43 | .send() 44 | .await 45 | .expect("Failed to execute request.") 46 | } 47 | async fn update(&self, id: i64, body: impl Serialize) -> reqwest::Response { 48 | self.api_client.put(&format!("{}/{}", &self.address, id)) 49 | .body(reqwest::Body::from(serde_json::to_vec(&body).unwrap())) 50 | .header("Content-Type", mime::APPLICATION_JSON.as_ref()) 51 | .send() 52 | .await 53 | .expect("Failed to execute request.") 54 | } 55 | async fn delete(&self, id: i64) -> reqwest::Response { 56 | self.api_client.delete(&format!("{}/{}", &self.address, id)) 57 | .send() 58 | .await 59 | .expect("Failed to execute request.") 60 | } 61 | async fn delete_all(&self) -> reqwest::Response { 62 | self.api_client.delete(&self.address) 63 | .send() 64 | .await 65 | .expect("Failed to execute request.") 66 | } 67 | } 68 | 69 | pub async fn e2e_test(app: TestApp){ 70 | // no posts in the beginning 71 | let response = app.list_all(None, None).await; 72 | 73 | assert!(response.status().is_success()); 74 | assert_eq!("[]", response.text().await.unwrap(), "All posts have to be deleted in db"); 75 | 76 | // insert a post 77 | let response = app.create( 78 | &json!({"title": "Post", "body": "Body", "published": false}) 79 | ).await; 80 | 81 | assert!(response.status().is_success()); 82 | 83 | let body = response.bytes().await.unwrap(); 84 | let body: Value = serde_json::from_slice(&body).unwrap(); 85 | assert_eq!(*body.get("title").unwrap(), json!("Post")); 86 | assert_eq!(*body.get("body").unwrap(), json!("Body")); 87 | assert_eq!(*body.get("published").unwrap(), json!(false)); 88 | 89 | // insert 2 more and get all 90 | let _ = app.create( 91 | &json!({"title": "Post", "body": "Body", "published": false}) 92 | ).await; 93 | 94 | let _ = app.create( 95 | &json!({"title": "Post", "body": "Body", "published": false}) 96 | ).await; 97 | 98 | // get all 3 of them 99 | let response = app.list_all(None, None).await; 100 | 101 | assert!(response.status().is_success()); 102 | 103 | let body = response.bytes().await.unwrap(); 104 | let mut body: Value = serde_json::from_slice(&body).unwrap(); 105 | let posts = body.as_array_mut().unwrap(); 106 | assert_eq!(posts.len(), 3); 107 | for body in posts.iter() { 108 | assert_eq!(*body.get("title").unwrap(), json!("Post")); 109 | assert_eq!(*body.get("body").unwrap(), json!("Body")); 110 | assert_eq!(*body.get("published").unwrap(), json!(false)); 111 | } 112 | 113 | let post_ids = posts.iter_mut().map(|p| p.as_object_mut().unwrap().remove("id").unwrap().as_i64().unwrap()).collect::>(); 114 | 115 | // skip 1 and limit 1 116 | let response = app.list_all(Some(1), Some(1)).await; 117 | 118 | assert!(response.status().is_success()); 119 | 120 | let body = response.bytes().await.unwrap(); 121 | let mut body: Value = serde_json::from_slice(&body).unwrap(); 122 | let posts = body.as_array_mut().unwrap(); 123 | assert_eq!(posts.len(), 1); 124 | 125 | assert_eq!(posts[0].get("id").unwrap().as_i64().unwrap(), post_ids[1]); 126 | 127 | // update the first one 128 | let first_post_id = post_ids[0]; 129 | *posts[0].get_mut("body").unwrap() = json!("First Post Body"); 130 | 131 | let response = app.update(first_post_id, &posts[0]).await; 132 | 133 | assert!(response.status().is_success()); 134 | 135 | // get the updated one 136 | let response = app.get(first_post_id).await; 137 | assert!(response.status().is_success()); 138 | let body = response.bytes().await.unwrap(); 139 | let body: Value = serde_json::from_slice(&body).unwrap(); 140 | assert_eq!(*body.get("id").unwrap(), json!(first_post_id)); 141 | assert_eq!(*body.get("title").unwrap(), json!("Post")); 142 | assert_eq!(*body.get("body").unwrap(), json!("First Post Body")); 143 | assert_eq!(*body.get("published").unwrap(), json!(false)); 144 | 145 | // delete first one 146 | let response = app.delete(first_post_id).await; 147 | 148 | assert!(response.status().is_success()); 149 | 150 | // try to get the deleted one 151 | let response = app.get(first_post_id).await; 152 | 153 | assert!(response.status().is_success()); 154 | let body = response.bytes().await.unwrap(); 155 | assert_eq!(&body[..], b"null"); 156 | 157 | // get 2 of them 158 | let response = app.list_all(None, None).await; 159 | 160 | assert!(response.status().is_success()); 161 | 162 | let body = response.bytes().await.unwrap(); 163 | let mut body: Value = serde_json::from_slice(&body).unwrap(); 164 | let posts = body.as_array_mut().unwrap(); 165 | assert_eq!(posts.len(), 2); 166 | for body in posts.iter() { 167 | assert_eq!(*body.get("title").unwrap(), json!("Post")); 168 | assert_eq!(*body.get("body").unwrap(), json!("Body")); 169 | assert_eq!(*body.get("published").unwrap(), json!(false)); 170 | } 171 | 172 | // delete all 173 | let response = app.delete_all().await; 174 | 175 | assert!(response.status().is_success()); 176 | 177 | // all posts should be deleted 178 | let response = app.list_all(None, None).await; 179 | 180 | assert!(response.status().is_success()); 181 | 182 | let body = response.bytes().await.unwrap(); 183 | assert_eq!(&body[..], b"[]"); 184 | } --------------------------------------------------------------------------------